]> git.kernelconcepts.de Git - karo-tx-linux.git/commitdiff
Merge branch 'linus' into tracing/core
authorIngo Molnar <mingo@elte.hu>
Sat, 18 Jul 2009 10:19:57 +0000 (12:19 +0200)
committerIngo Molnar <mingo@elte.hu>
Sat, 18 Jul 2009 10:20:01 +0000 (12:20 +0200)
Merge reason: tracing/core was on an older, pre-rc1 base.

Signed-off-by: Ingo Molnar <mingo@elte.hu>
1707 files changed:
.gitignore
Documentation/DocBook/mac80211.tmpl
Documentation/block/data-integrity.txt
Documentation/cgroups/cpusets.txt
Documentation/device-mapper/dm-log.txt [new file with mode: 0644]
Documentation/device-mapper/dm-queue-length.txt [new file with mode: 0644]
Documentation/device-mapper/dm-service-time.txt [new file with mode: 0644]
Documentation/driver-model/driver.txt
Documentation/dvb/get_dvb_firmware
Documentation/feature-removal-schedule.txt
Documentation/filesystems/Locking
Documentation/gcov.txt
Documentation/kernel-parameters.txt
Documentation/kmemleak.txt
Documentation/laptops/thinkpad-acpi.txt
Documentation/leds-lp3944.txt [new file with mode: 0644]
Documentation/powerpc/booting-without-of.txt
Documentation/powerpc/dts-bindings/4xx/emac.txt [new file with mode: 0644]
Documentation/powerpc/dts-bindings/gpio/gpio.txt [new file with mode: 0644]
Documentation/powerpc/dts-bindings/gpio/led.txt
Documentation/powerpc/dts-bindings/gpio/mdio.txt [new file with mode: 0644]
Documentation/powerpc/dts-bindings/marvell.txt [new file with mode: 0644]
Documentation/powerpc/dts-bindings/phy.txt [new file with mode: 0644]
Documentation/powerpc/dts-bindings/spi-bus.txt [new file with mode: 0644]
Documentation/powerpc/dts-bindings/usb-ehci.txt [new file with mode: 0644]
Documentation/powerpc/dts-bindings/xilinx.txt [new file with mode: 0644]
Documentation/scheduler/sched-rt-group.txt
Documentation/sound/alsa/HD-Audio-Models.txt
Documentation/spi/spidev_test.c
Documentation/video4linux/CARDLIST.em28xx
Documentation/x86/00-INDEX
Documentation/x86/exception-tables.txt [moved from Documentation/exception.txt with 75% similarity]
MAINTAINERS
Makefile
arch/alpha/include/asm/percpu.h
arch/alpha/include/asm/thread_info.h
arch/alpha/kernel/ptrace.c
arch/arm/Kconfig.debug
arch/arm/configs/kb9202_defconfig
arch/arm/configs/s3c2410_defconfig
arch/arm/configs/s3c6400_defconfig
arch/arm/configs/tct_hammer_defconfig
arch/arm/configs/u300_defconfig
arch/arm/include/asm/page.h
arch/arm/include/asm/pgtable.h
arch/arm/include/asm/thread_info.h
arch/arm/kernel/irq.c
arch/arm/kernel/vmlinux.lds.S
arch/arm/mach-at91/board-sam9g20ek.c
arch/arm/mach-at91/board-sam9rlek.c
arch/arm/mach-omap1/board-nokia770.c
arch/arm/mach-omap1/mailbox.c
arch/arm/mach-omap2/board-rx51-peripherals.c
arch/arm/mach-omap2/gpmc-onenand.c
arch/arm/mach-omap2/id.c
arch/arm/mach-omap2/mailbox.c
arch/arm/mach-omap2/mmc-twl4030.c
arch/arm/mach-s3c2440/mach-mini2440.c
arch/arm/mach-s3c2442/mach-gta02.c
arch/arm/mach-u300/clock.c
arch/arm/mm/proc-syms.c
arch/arm/plat-omap/dma.c
arch/arm/plat-omap/gpio.c
arch/arm/plat-omap/include/mach/cpu.h
arch/arm/plat-omap/include/mach/dma.h
arch/arm/plat-omap/include/mach/io.h
arch/arm/plat-omap/iommu.c
arch/arm/plat-omap/sram.c
arch/arm/plat-s3c/Makefile
arch/arm/plat-s3c/include/plat/devs.h
arch/arm/plat-s3c24xx/Makefile
arch/arm/plat-s3c24xx/spi-bus0-gpe11_12_13.c
arch/arm/plat-s3c24xx/spi-bus1-gpg5_6_7.c
arch/avr32/include/asm/thread_info.h
arch/avr32/kernel/traps.c
arch/blackfin/include/asm/thread_info.h
arch/blackfin/kernel/ptrace.c
arch/blackfin/kernel/setup.c
arch/blackfin/kernel/sys_bfin.c
arch/blackfin/kernel/traps.c
arch/cris/include/asm/thread_info.h
arch/cris/kernel/sys_cris.c
arch/frv/Kconfig
arch/frv/include/asm/atomic.h
arch/frv/include/asm/perf_counter.h [new file with mode: 0644]
arch/frv/include/asm/system.h
arch/frv/include/asm/thread_info.h
arch/frv/include/asm/unistd.h
arch/frv/kernel/entry.S
arch/frv/kernel/frv_ksyms.c
arch/frv/lib/Makefile
arch/frv/lib/atomic-ops.S
arch/frv/lib/atomic64-ops.S [new file with mode: 0644]
arch/frv/lib/perf_counter.c [new file with mode: 0644]
arch/h8300/include/asm/thread_info.h
arch/ia64/include/asm/fpu.h
arch/ia64/include/asm/thread_info.h
arch/ia64/include/asm/xen/hypervisor.h
arch/ia64/kernel/acpi-processor.c
arch/ia64/kernel/dma-mapping.c
arch/ia64/kernel/esi.c
arch/ia64/kernel/perfmon.c
arch/ia64/kernel/ptrace.c
arch/ia64/kernel/salinfo.c
arch/ia64/kvm/kvm_lib.c
arch/ia64/kvm/process.c
arch/ia64/kvm/vcpu.c
arch/ia64/kvm/vtlb.c
arch/ia64/pci/pci.c
arch/ia64/sn/kernel/io_common.c
arch/m32r/include/asm/thread_info.h
arch/m32r/kernel/ptrace.c
arch/m68k/include/asm/thread_info_mm.h
arch/m68k/include/asm/thread_info_no.h
arch/m68knommu/kernel/process.c
arch/m68knommu/kernel/traps.c
arch/microblaze/Kconfig
arch/microblaze/include/asm/atomic.h
arch/microblaze/include/asm/bitops.h
arch/microblaze/include/asm/bug.h
arch/microblaze/include/asm/bugs.h
arch/microblaze/include/asm/checksum.h
arch/microblaze/include/asm/fb.h [new file with mode: 0644]
arch/microblaze/include/asm/hardirq.h
arch/microblaze/include/asm/ioctls.h
arch/microblaze/include/asm/ipcbuf.h
arch/microblaze/include/asm/irq.h
arch/microblaze/include/asm/mman.h
arch/microblaze/include/asm/mmu.h
arch/microblaze/include/asm/mmu_context.h
arch/microblaze/include/asm/mmu_context_no.h [deleted file]
arch/microblaze/include/asm/module.h
arch/microblaze/include/asm/msgbuf.h
arch/microblaze/include/asm/param.h
arch/microblaze/include/asm/parport.h [new file with mode: 0644]
arch/microblaze/include/asm/pci.h
arch/microblaze/include/asm/posix_types.h
arch/microblaze/include/asm/scatterlist.h
arch/microblaze/include/asm/sembuf.h
arch/microblaze/include/asm/serial.h
arch/microblaze/include/asm/shmbuf.h
arch/microblaze/include/asm/shmparam.h
arch/microblaze/include/asm/siginfo.h
arch/microblaze/include/asm/signal.h
arch/microblaze/include/asm/socket.h
arch/microblaze/include/asm/sockios.h
arch/microblaze/include/asm/stat.h
arch/microblaze/include/asm/swab.h
arch/microblaze/include/asm/syscalls.h
arch/microblaze/include/asm/system.h
arch/microblaze/include/asm/termbits.h
arch/microblaze/include/asm/termios.h
arch/microblaze/include/asm/thread_info.h
arch/microblaze/include/asm/timex.h
arch/microblaze/include/asm/types.h
arch/microblaze/include/asm/ucontext.h
arch/microblaze/include/asm/unistd.h
arch/microblaze/include/asm/vga.h
arch/microblaze/kernel/entry-nommu.S
arch/microblaze/kernel/entry.S
arch/microblaze/kernel/ptrace.c
arch/microblaze/kernel/signal.c
arch/microblaze/kernel/sys_microblaze.c
arch/microblaze/kernel/syscall_table.S
arch/microblaze/lib/Makefile
arch/microblaze/lib/checksum.c [deleted file]
arch/microblaze/mm/init.c
arch/mips/Kconfig
arch/mips/Makefile
arch/mips/ar7/Makefile [new file with mode: 0644]
arch/mips/ar7/clock.c [new file with mode: 0644]
arch/mips/ar7/gpio.c [new file with mode: 0644]
arch/mips/ar7/irq.c [new file with mode: 0644]
arch/mips/ar7/memory.c [new file with mode: 0644]
arch/mips/ar7/platform.c [new file with mode: 0644]
arch/mips/ar7/prom.c [new file with mode: 0644]
arch/mips/ar7/setup.c [new file with mode: 0644]
arch/mips/ar7/time.c [new file with mode: 0644]
arch/mips/cavium-octeon/Makefile
arch/mips/cavium-octeon/dma-octeon.c
arch/mips/cavium-octeon/octeon-irq.c
arch/mips/cavium-octeon/octeon_boot.h [new file with mode: 0644]
arch/mips/cavium-octeon/pci-common.c [deleted file]
arch/mips/cavium-octeon/setup.c
arch/mips/cavium-octeon/smp.c
arch/mips/cobalt/buttons.c
arch/mips/cobalt/lcd.c
arch/mips/cobalt/led.c
arch/mips/cobalt/mtd.c
arch/mips/cobalt/rtc.c
arch/mips/cobalt/serial.c
arch/mips/cobalt/time.c
arch/mips/configs/ar7_defconfig [new file with mode: 0644]
arch/mips/gt64120/wrppmc/serial.c
arch/mips/include/asm/amon.h [new file with mode: 0644]
arch/mips/include/asm/bug.h
arch/mips/include/asm/bugs.h
arch/mips/include/asm/ds1287.h
arch/mips/include/asm/elf.h
arch/mips/include/asm/gcmpregs.h
arch/mips/include/asm/gic.h
arch/mips/include/asm/irq.h
arch/mips/include/asm/irq_gt641xx.h
arch/mips/include/asm/mach-ar7/ar7.h [new file with mode: 0644]
arch/mips/include/asm/mach-ar7/gpio.h [new file with mode: 0644]
arch/mips/include/asm/mach-ar7/irq.h [new file with mode: 0644]
arch/mips/include/asm/mach-ar7/prom.h [new file with mode: 0644]
arch/mips/include/asm/mach-ar7/spaces.h [new file with mode: 0644]
arch/mips/include/asm/mach-ar7/war.h [new file with mode: 0644]
arch/mips/include/asm/mach-cobalt/irq.h
arch/mips/include/asm/mach-cobalt/mach-gt64120.h
arch/mips/include/asm/mmu_context.h
arch/mips/include/asm/octeon/pci-octeon.h [moved from arch/mips/cavium-octeon/pci-common.h with 52% similarity]
arch/mips/include/asm/page.h
arch/mips/include/asm/reg.h
arch/mips/include/asm/smp-ops.h
arch/mips/include/asm/smp.h
arch/mips/include/asm/sn/addrs.h
arch/mips/include/asm/swab.h
arch/mips/include/asm/thread_info.h
arch/mips/include/asm/unistd.h
arch/mips/include/asm/vr41xx/capcella.h
arch/mips/include/asm/vr41xx/giu.h
arch/mips/include/asm/vr41xx/irq.h
arch/mips/include/asm/vr41xx/mpc30x.h
arch/mips/include/asm/vr41xx/pci.h
arch/mips/include/asm/vr41xx/siu.h
arch/mips/include/asm/vr41xx/tb0219.h
arch/mips/include/asm/vr41xx/tb0226.h
arch/mips/include/asm/vr41xx/vr41xx.h
arch/mips/jazz/irq.c
arch/mips/kernel/binfmt_elfo32.c
arch/mips/kernel/cevt-bcm1480.c
arch/mips/kernel/cevt-ds1287.c
arch/mips/kernel/cevt-gt641xx.c
arch/mips/kernel/cevt-r4k.c
arch/mips/kernel/cevt-sb1250.c
arch/mips/kernel/cevt-smtc.c
arch/mips/kernel/cpu-probe.c
arch/mips/kernel/csrc-ioasic.c
arch/mips/kernel/i8253.c
arch/mips/kernel/irq-gic.c
arch/mips/kernel/irq-gt641xx.c
arch/mips/kernel/kgdb.c
arch/mips/kernel/process.c
arch/mips/kernel/ptrace32.c
arch/mips/kernel/scall32-o32.S
arch/mips/kernel/scall64-64.S
arch/mips/kernel/scall64-n32.S
arch/mips/kernel/scall64-o32.S
arch/mips/kernel/smp-cmp.c
arch/mips/kernel/smp-up.c
arch/mips/kernel/smp.c
arch/mips/kernel/smtc.c
arch/mips/kernel/sync-r4k.c
arch/mips/kernel/topology.c
arch/mips/kernel/vpe.c
arch/mips/mipssim/sim_time.c
arch/mips/mm/c-octeon.c
arch/mips/mm/c-r3k.c
arch/mips/mm/c-r4k.c
arch/mips/mm/c-tx39.c
arch/mips/mm/highmem.c
arch/mips/mm/hugetlbpage.c
arch/mips/mm/init.c
arch/mips/mm/page.c
arch/mips/mm/tlb-r3k.c
arch/mips/mm/tlb-r4k.c
arch/mips/mm/tlb-r8k.c
arch/mips/mm/tlbex.c
arch/mips/mti-malta/malta-init.c
arch/mips/mti-malta/malta-int.c
arch/mips/mti-malta/malta-reset.c
arch/mips/pci/Makefile
arch/mips/pci/fixup-capcella.c
arch/mips/pci/fixup-mpc30x.c
arch/mips/pci/fixup-tb0219.c
arch/mips/pci/fixup-tb0226.c
arch/mips/pci/fixup-tb0287.c
arch/mips/pci/msi-octeon.c [moved from arch/mips/cavium-octeon/msi.c with 88% similarity]
arch/mips/pci/ops-vr41xx.c
arch/mips/pci/pci-ip27.c
arch/mips/pci/pci-octeon.c [moved from arch/mips/cavium-octeon/pci.c with 78% similarity]
arch/mips/pci/pci-vr41xx.c
arch/mips/pci/pci-vr41xx.h
arch/mips/pci/pcie-octeon.c [moved from arch/mips/cavium-octeon/pcie.c with 98% similarity]
arch/mips/pmc-sierra/yosemite/smp.c
arch/mips/power/hibernate.S
arch/mips/sgi-ip27/ip27-init.c
arch/mips/sgi-ip27/ip27-irq.c
arch/mips/sgi-ip27/ip27-timer.c
arch/mips/sgi-ip27/ip27-xtalk.c
arch/mips/sibyte/bcm1480/irq.c
arch/mips/sibyte/common/cfe_console.c
arch/mips/sni/time.c
arch/mips/vr41xx/casio-e55/setup.c
arch/mips/vr41xx/common/bcu.c
arch/mips/vr41xx/common/cmu.c
arch/mips/vr41xx/common/giu.c
arch/mips/vr41xx/common/icu.c
arch/mips/vr41xx/common/init.c
arch/mips/vr41xx/common/irq.c
arch/mips/vr41xx/common/pmu.c
arch/mips/vr41xx/common/rtc.c
arch/mips/vr41xx/common/siu.c
arch/mips/vr41xx/common/type.c
arch/mips/vr41xx/ibm-workpad/setup.c
arch/mn10300/include/asm/pci.h
arch/mn10300/include/asm/thread_info.h
arch/mn10300/include/asm/unistd.h
arch/mn10300/kernel/entry.S
arch/mn10300/kernel/ptrace.c
arch/mn10300/kernel/signal.c
arch/mn10300/kernel/sys_mn10300.c
arch/mn10300/kernel/traps.c
arch/mn10300/kernel/vmlinux.lds.S
arch/mn10300/mm/fault.c
arch/mn10300/mm/misalignment.c
arch/parisc/Kconfig
arch/parisc/include/asm/atomic.h
arch/parisc/include/asm/dma.h
arch/parisc/include/asm/perf_counter.h [new file with mode: 0644]
arch/parisc/include/asm/processor.h
arch/parisc/include/asm/system.h
arch/parisc/include/asm/thread_info.h
arch/parisc/include/asm/tlbflush.h
arch/parisc/include/asm/unistd.h
arch/parisc/kernel/cache.c
arch/parisc/kernel/inventory.c
arch/parisc/kernel/irq.c
arch/parisc/kernel/pci-dma.c
arch/parisc/kernel/pci.c
arch/parisc/kernel/process.c
arch/parisc/kernel/processor.c
arch/parisc/kernel/setup.c
arch/parisc/kernel/sys_parisc32.c
arch/parisc/kernel/syscall_table.S
arch/parisc/kernel/time.c
arch/parisc/kernel/traps.c
arch/parisc/lib/checksum.c
arch/parisc/lib/memcpy.c
arch/parisc/math-emu/decode_exc.c
arch/parisc/mm/fault.c
arch/parisc/mm/init.c
arch/powerpc/Kconfig
arch/powerpc/boot/.gitignore
arch/powerpc/boot/dts/amigaone.dts
arch/powerpc/boot/dts/mpc8569mds.dts
arch/powerpc/boot/dts/warp.dts
arch/powerpc/configs/44x/warp_defconfig
arch/powerpc/include/asm/cpm1.h
arch/powerpc/include/asm/delay.h
arch/powerpc/include/asm/dma-mapping.h
arch/powerpc/include/asm/highmem.h
arch/powerpc/include/asm/hw_irq.h
arch/powerpc/include/asm/perf_counter.h
arch/powerpc/include/asm/pte-hash64-64k.h
arch/powerpc/include/asm/rtas.h
arch/powerpc/include/asm/thread_info.h
arch/powerpc/kernel/entry_32.S
arch/powerpc/kernel/head_32.S
arch/powerpc/kernel/mpc7450-pmu.c
arch/powerpc/kernel/of_device.c
arch/powerpc/kernel/power7-pmu.c
arch/powerpc/kernel/ppc970-pmu.c
arch/powerpc/kernel/process.c
arch/powerpc/kernel/ptrace.c
arch/powerpc/kernel/ptrace32.c
arch/powerpc/kernel/rtas.c
arch/powerpc/kernel/setup_32.c
arch/powerpc/kernel/smp.c
arch/powerpc/kernel/udbg_16550.c
arch/powerpc/kernel/vector.S
arch/powerpc/mm/Makefile
arch/powerpc/mm/gup.c
arch/powerpc/mm/highmem.c [new file with mode: 0644]
arch/powerpc/mm/mmu_context_nohash.c
arch/powerpc/mm/pgtable.c
arch/powerpc/mm/slb.c
arch/powerpc/mm/tlb_hash64.c
arch/powerpc/oprofile/cell/vma_map.c
arch/powerpc/platforms/44x/warp.c
arch/powerpc/platforms/82xx/pq2ads-pci-pic.c
arch/powerpc/platforms/85xx/mpc85xx_mds.c
arch/powerpc/platforms/85xx/smp.c
arch/powerpc/platforms/85xx/socrates.c
arch/powerpc/platforms/85xx/xes_mpc85xx.c
arch/powerpc/platforms/cell/axon_msi.c
arch/powerpc/platforms/cell/smp.c
arch/powerpc/platforms/chrp/smp.c
arch/powerpc/platforms/pasemi/setup.c
arch/powerpc/platforms/powermac/cpufreq_64.c
arch/powerpc/platforms/powermac/pic.c
arch/powerpc/platforms/powermac/setup.c
arch/powerpc/platforms/powermac/smp.c
arch/powerpc/platforms/ps3/system-bus.c
arch/powerpc/platforms/pseries/lpar.c
arch/powerpc/platforms/pseries/smp.c
arch/powerpc/platforms/pseries/xics.c
arch/powerpc/sysdev/fsl_rio.c
arch/powerpc/sysdev/ipic.c
arch/powerpc/sysdev/mpic.c
arch/powerpc/sysdev/ppc4xx_pci.c
arch/powerpc/sysdev/qe_lib/qe.c
arch/powerpc/sysdev/qe_lib/qe_ic.c
arch/powerpc/sysdev/uic.c
arch/s390/Kconfig
arch/s390/include/asm/atomic.h
arch/s390/include/asm/kvm_host.h
arch/s390/include/asm/perf_counter.h
arch/s390/include/asm/thread_info.h
arch/s390/kernel/dis.c
arch/s390/kernel/ipl.c
arch/s390/kernel/ptrace.c
arch/s390/kvm/kvm-s390.c
arch/s390/kvm/priv.c
arch/s390/lib/Makefile
arch/s390/lib/delay.c
arch/s390/lib/ucmpdi2.c [new file with mode: 0644]
arch/s390/mm/fault.c
arch/sh/Kconfig.debug
arch/sh/boards/mach-se/7206/io.c
arch/sh/boards/mach-se/7724/setup.c
arch/sh/configs/migor_defconfig
arch/sh/configs/se7724_defconfig
arch/sh/include/asm/perf_counter.h
arch/sh/include/asm/syscall_32.h
arch/sh/include/asm/thread_info.h
arch/sh/include/mach-se/mach/se7724.h
arch/sh/mm/fault_32.c
arch/sh/mm/tlb-sh3.c
arch/sh/mm/tlbflush_64.c
arch/sparc/boot/Makefile
arch/sparc/boot/piggyback_32.c
arch/sparc/boot/piggyback_64.c
arch/sparc/include/asm/thread_info_32.h
arch/sparc/include/asm/thread_info_64.h
arch/sparc/kernel/irq_64.c
arch/sparc/kernel/ptrace_32.c
arch/sparc/kernel/ptrace_64.c
arch/sparc/kernel/time_64.c
arch/sparc/kernel/traps_32.c
arch/sparc/kernel/vio.c
arch/um/drivers/slip_kern.c
arch/um/drivers/slirp_kern.c
arch/um/include/asm/dma-mapping.h
arch/um/include/asm/thread_info.h
arch/um/kernel/sysrq.c
arch/x86/Kconfig
arch/x86/boot/video-bios.c
arch/x86/boot/video-vesa.c
arch/x86/include/asm/acpi.h
arch/x86/include/asm/atomic_32.h
arch/x86/include/asm/atomic_64.h
arch/x86/include/asm/boot.h
arch/x86/include/asm/fixmap.h
arch/x86/include/asm/io_apic.h
arch/x86/include/asm/lguest_hcall.h
arch/x86/include/asm/msr-index.h
arch/x86/include/asm/nmi.h
arch/x86/include/asm/pci.h
arch/x86/include/asm/pci_x86.h
arch/x86/include/asm/percpu.h
arch/x86/include/asm/perf_counter.h
arch/x86/include/asm/proto.h
arch/x86/include/asm/spinlock.h
arch/x86/include/asm/stacktrace.h
arch/x86/include/asm/thread_info.h
arch/x86/kernel/Makefile
arch/x86/kernel/acpi/boot.c
arch/x86/kernel/acpi/cstate.c
arch/x86/kernel/acpi/processor.c
arch/x86/kernel/amd_iommu.c
arch/x86/kernel/amd_iommu_init.c
arch/x86/kernel/apic/apic.c
arch/x86/kernel/apic/es7000_32.c
arch/x86/kernel/apic/io_apic.c
arch/x86/kernel/apic/numaq_32.c
arch/x86/kernel/cpu/amd.c
arch/x86/kernel/cpu/common.c
arch/x86/kernel/cpu/cpufreq/powernow-k8.c
arch/x86/kernel/cpu/cpufreq/powernow-k8.h
arch/x86/kernel/cpu/mcheck/mce.c
arch/x86/kernel/cpu/perf_counter.c
arch/x86/kernel/cpu/perfctr-watchdog.c
arch/x86/kernel/dumpstack.c
arch/x86/kernel/dumpstack_32.c
arch/x86/kernel/dumpstack_64.c
arch/x86/kernel/e820.c
arch/x86/kernel/kvm.c
arch/x86/kernel/pci-dma.c
arch/x86/kernel/pci-gart_64.c
arch/x86/kernel/pvclock.c
arch/x86/kernel/setup.c
arch/x86/kernel/setup_percpu.c
arch/x86/kernel/tlb_uv.c
arch/x86/kernel/traps.c
arch/x86/kvm/mmu.c
arch/x86/kvm/paging_tmpl.h
arch/x86/kvm/vmx.c
arch/x86/kvm/x86.c
arch/x86/kvm/x86_emulate.c
arch/x86/lguest/boot.c
arch/x86/lib/Makefile
arch/x86/lib/atomic64_32.c [new file with mode: 0644]
arch/x86/lib/clear_page_64.S
arch/x86/lib/copy_user_64.S
arch/x86/lib/delay.c
arch/x86/lib/usercopy_32.c
arch/x86/mm/fault.c
arch/x86/mm/init.c
arch/x86/mm/init_64.c
arch/x86/mm/pageattr.c
arch/x86/oprofile/nmi_int.c
arch/x86/pci/acpi.c
arch/x86/pci/amd_bus.c
arch/x86/pci/common.c
arch/x86/pci/i386.c
arch/x86/pci/mmconfig-shared.c
arch/x86/power/Makefile
arch/x86/power/cpu.c
arch/xtensa/include/asm/thread_info.h
arch/xtensa/kernel/traps.c
block/Makefile
block/blk-core.c
block/blk-merge.c
block/bsg.c
block/cfq-iosched.c
block/cmd-filter.c [deleted file]
block/elevator.c
block/scsi_ioctl.c
drivers/acpi/ac.c
drivers/acpi/battery.c
drivers/acpi/blacklist.c
drivers/acpi/bus.c
drivers/acpi/glue.c
drivers/acpi/osl.c
drivers/acpi/pci_bind.c
drivers/acpi/pci_irq.c
drivers/acpi/pci_root.c
drivers/acpi/power.c
drivers/acpi/processor_core.c
drivers/acpi/processor_idle.c
drivers/acpi/scan.c
drivers/acpi/video.c
drivers/acpi/video_detect.c
drivers/amba/bus.c
drivers/ata/ahci.c
drivers/ata/libata-core.c
drivers/ata/libata-eh.c
drivers/ata/pata_at91.c
drivers/base/devres.c
drivers/base/firmware_class.c
drivers/base/power/main.c
drivers/block/DAC960.c
drivers/block/Kconfig
drivers/block/Makefile
drivers/block/amiflop.c
drivers/block/cciss.c
drivers/block/cciss_cmd.h
drivers/block/floppy.c
drivers/block/loop.c
drivers/block/osdblk.c [new file with mode: 0644]
drivers/block/pktcdvd.c
drivers/block/virtio_blk.c
drivers/block/xsysace.c
drivers/bluetooth/hci_vhci.c
drivers/char/Kconfig
drivers/char/Makefile
drivers/char/amiserial.c
drivers/char/bsr.c
drivers/char/cyclades.c
drivers/char/epca.c
drivers/char/hw_random/intel-rng.c
drivers/char/isicom.c
drivers/char/istallion.c
drivers/char/moxa.c
drivers/char/mxser.c
drivers/char/n_hdlc.c
drivers/char/n_r3964.c
drivers/char/n_tty.c
drivers/char/nozomi.c
drivers/char/pty.c
drivers/char/rio/rio_linux.c
drivers/char/riscom8.c
drivers/char/rocket.c
drivers/char/serial167.c
drivers/char/specialix.c
drivers/char/sx.c
drivers/char/synclink.c
drivers/char/synclink_gt.c
drivers/char/synclinkmp.c
drivers/char/tb0219.c
drivers/char/tpm/tpm.c
drivers/char/tty_ioctl.c
drivers/char/tty_ldisc.c
drivers/char/tty_port.c
drivers/char/vr41xx_giu.c
drivers/char/vt.c
drivers/char/vt_ioctl.c
drivers/clocksource/sh_tmu.c
drivers/cpufreq/cpufreq.c
drivers/cpufreq/cpufreq_conservative.c
drivers/cpufreq/cpufreq_ondemand.c
drivers/dma/txx9dmac.c
drivers/edac/amd64_edac.c
drivers/edac/amd64_edac.h
drivers/edac/edac_core.h
drivers/edac/edac_mc_sysfs.c
drivers/edac/mpc85xx_edac.c
drivers/edac/mpc85xx_edac.h
drivers/firewire/core-card.c
drivers/firewire/core-cdev.c
drivers/firewire/core-iso.c
drivers/firewire/core.h
drivers/firewire/sbp2.c
drivers/gpio/Kconfig
drivers/gpio/Makefile
drivers/gpio/pl061.c
drivers/gpio/vr41xx_giu.c [new file with mode: 0644]
drivers/gpu/drm/Kconfig
drivers/gpu/drm/Makefile
drivers/gpu/drm/drm_crtc_helper.c
drivers/gpu/drm/drm_debugfs.c
drivers/gpu/drm/drm_edid.c
drivers/gpu/drm/drm_gem.c
drivers/gpu/drm/drm_stub.c
drivers/gpu/drm/i915/Makefile
drivers/gpu/drm/i915/dvo.h
drivers/gpu/drm/i915/dvo_ch7017.c
drivers/gpu/drm/i915/dvo_ch7xxx.c
drivers/gpu/drm/i915/dvo_ivch.c
drivers/gpu/drm/i915/dvo_sil164.c
drivers/gpu/drm/i915/dvo_tfp410.c
drivers/gpu/drm/i915/i915_dma.c
drivers/gpu/drm/i915/i915_drv.c
drivers/gpu/drm/i915/i915_drv.h
drivers/gpu/drm/i915/i915_gem.c
drivers/gpu/drm/i915/i915_gem_debug.c
drivers/gpu/drm/i915/i915_gem_debugfs.c
drivers/gpu/drm/i915/i915_gem_tiling.c
drivers/gpu/drm/i915/i915_irq.c
drivers/gpu/drm/i915/i915_opregion.c
drivers/gpu/drm/i915/i915_reg.h
drivers/gpu/drm/i915/i915_suspend.c
drivers/gpu/drm/i915/intel_bios.c
drivers/gpu/drm/i915/intel_crt.c
drivers/gpu/drm/i915/intel_display.c
drivers/gpu/drm/i915/intel_dp.c [new file with mode: 0644]
drivers/gpu/drm/i915/intel_dp.h [new file with mode: 0644]
drivers/gpu/drm/i915/intel_dp_i2c.c [new file with mode: 0644]
drivers/gpu/drm/i915/intel_drv.h
drivers/gpu/drm/i915/intel_dvo.c
drivers/gpu/drm/i915/intel_fb.c
drivers/gpu/drm/i915/intel_hdmi.c
drivers/gpu/drm/i915/intel_i2c.c
drivers/gpu/drm/i915/intel_lvds.c
drivers/gpu/drm/i915/intel_modes.c
drivers/gpu/drm/i915/intel_sdvo.c
drivers/gpu/drm/i915/intel_sdvo_regs.h
drivers/gpu/drm/i915/intel_tv.c
drivers/gpu/drm/radeon/radeon_device.c
drivers/gpu/drm/radeon/radeon_drv.c
drivers/gpu/drm/radeon/radeon_fb.c
drivers/gpu/drm/radeon/radeon_object.c
drivers/gpu/drm/ttm/ttm_bo_util.c
drivers/gpu/drm/ttm/ttm_bo_vm.c
drivers/gpu/drm/ttm/ttm_tt.c
drivers/gpu/drm/via/via_irq.c
drivers/hid/usbhid/hid-core.c
drivers/hwmon/abituguru3.c
drivers/hwmon/max6650.c
drivers/hwmon/sht15.c
drivers/i2c/busses/Kconfig
drivers/i2c/busses/Makefile
drivers/i2c/busses/i2c-davinci.c
drivers/i2c/busses/i2c-designware.c [new file with mode: 0644]
drivers/i2c/busses/i2c-ibm_iic.c
drivers/i2c/busses/i2c-omap.c
drivers/i2c/busses/i2c-sh_mobile.c
drivers/i2c/busses/i2c-simtec.c
drivers/ide/cs5520.c
drivers/ide/ide-acpi.c
drivers/ide/ide-cd.c
drivers/ide/ide-devsets.c
drivers/ide/ide-dma.c
drivers/ide/ide-eh.c
drivers/ide/ide-floppy.c
drivers/ide/ide-io.c
drivers/ide/ide-ioctls.c
drivers/ide/ide-iops.c
drivers/ide/ide-pm.c
drivers/ide/ide-probe.c
drivers/ieee1394/sbp2.c
drivers/ieee1394/sbp2.h
drivers/input/keyboard/Kconfig
drivers/input/keyboard/Makefile
drivers/input/keyboard/gpio_keys.c
drivers/input/keyboard/matrix_keypad.c [new file with mode: 0644]
drivers/input/misc/cobalt_btns.c
drivers/input/mouse/gpio_mouse.c
drivers/input/serio/i8042-x86ia64io.h
drivers/input/serio/i8042.c
drivers/input/serio/serio.c
drivers/input/tablet/wacom_wac.c
drivers/isdn/gigaset/ev-layer.c
drivers/isdn/gigaset/isocdata.c
drivers/isdn/hisax/hfc_usb.c
drivers/isdn/i4l/isdn_tty.c
drivers/isdn/mISDN/stack.c
drivers/leds/Kconfig
drivers/leds/Makefile
drivers/leds/leds-alix2.c
drivers/leds/leds-bd2802.c
drivers/leds/leds-cobalt-raq.c
drivers/leds/leds-gpio.c
drivers/leds/leds-lp3944.c [new file with mode: 0644]
drivers/leds/leds-pca9532.c
drivers/lguest/lg.h
drivers/lguest/lguest_user.c
drivers/macintosh/macio_asic.c
drivers/md/Kconfig
drivers/md/Makefile
drivers/md/dm-crypt.c
drivers/md/dm-delay.c
drivers/md/dm-exception-store.c
drivers/md/dm-exception-store.h
drivers/md/dm-io.c
drivers/md/dm-ioctl.c
drivers/md/dm-linear.c
drivers/md/dm-log-userspace-base.c [new file with mode: 0644]
drivers/md/dm-log-userspace-transfer.c [new file with mode: 0644]
drivers/md/dm-log-userspace-transfer.h [new file with mode: 0644]
drivers/md/dm-log.c
drivers/md/dm-mpath.c
drivers/md/dm-path-selector.h
drivers/md/dm-queue-length.c [new file with mode: 0644]
drivers/md/dm-raid1.c
drivers/md/dm-region-hash.c
drivers/md/dm-round-robin.c
drivers/md/dm-service-time.c [new file with mode: 0644]
drivers/md/dm-snap-persistent.c
drivers/md/dm-snap.c
drivers/md/dm-stripe.c
drivers/md/dm-sysfs.c
drivers/md/dm-table.c
drivers/md/dm.c
drivers/md/dm.h
drivers/md/linear.c
drivers/md/md.c
drivers/md/multipath.c
drivers/md/raid0.c
drivers/md/raid1.c
drivers/md/raid10.c
drivers/md/raid5.c
drivers/media/common/tuners/tuner-xc2028.c
drivers/media/dvb/bt8xx/dst_ca.c
drivers/media/dvb/dvb-core/dvbdev.h
drivers/media/dvb/ttpci/Kconfig
drivers/media/dvb/ttpci/av7110.c
drivers/media/radio/radio-mr800.c
drivers/media/radio/radio-si470x.c
drivers/media/video/Kconfig
drivers/media/video/Makefile
drivers/media/video/bt8xx/bttv-driver.c
drivers/media/video/cx18/cx18-cards.c
drivers/media/video/cx18/cx18-dvb.c
drivers/media/video/cx23885/cx23885-417.c
drivers/media/video/cx23885/cx23885-dvb.c
drivers/media/video/cx23885/cx23885-video.c
drivers/media/video/cx23885/cx23885.h
drivers/media/video/cx88/cx88-blackbird.c
drivers/media/video/cx88/cx88-video.c
drivers/media/video/dabusb.c
drivers/media/video/em28xx/Kconfig
drivers/media/video/em28xx/em28xx-cards.c
drivers/media/video/em28xx/em28xx-core.c
drivers/media/video/em28xx/em28xx-dvb.c
drivers/media/video/em28xx/em28xx-i2c.c
drivers/media/video/em28xx/em28xx-video.c
drivers/media/video/em28xx/em28xx.h
drivers/media/video/gspca/stv06xx/stv06xx.h
drivers/media/video/mt9v011.c [new file with mode: 0644]
drivers/media/video/mt9v011.h [new file with mode: 0644]
drivers/media/video/pwc/pwc-if.c
drivers/media/video/pwc/pwc.h
drivers/media/video/s2255drv.c
drivers/media/video/saa5246a.c
drivers/media/video/saa5249.c
drivers/media/video/saa7134/saa7134-empress.c
drivers/media/video/se401.c
drivers/media/video/soc_camera.c
drivers/media/video/stk-webcam.c
drivers/media/video/stradis.c
drivers/media/video/stv680.c
drivers/media/video/usbvideo/vicam.c
drivers/media/video/usbvision/usbvision-video.c
drivers/media/video/v4l2-dev.c
drivers/media/video/vivi.c
drivers/media/video/zoran/zoran_driver.c
drivers/mfd/dm355evm_msp.c
drivers/mfd/ezx-pcap.c
drivers/mfd/sm501.c
drivers/misc/sgi-gru/grufile.c
drivers/misc/sgi-gru/grukservices.c
drivers/misc/sgi-xp/xpnet.c
drivers/mmc/host/mmc_spi.c
drivers/mtd/cmdlinepart.c
drivers/mtd/devices/m25p80.c
drivers/mtd/inftlcore.c
drivers/mtd/maps/integrator-flash.c
drivers/mtd/nand/atmel_nand.c
drivers/mtd/nand/omap2.c
drivers/mtd/nftlcore.c
drivers/mtd/ubi/build.c
drivers/mtd/ubi/debug.c
drivers/mtd/ubi/debug.h
drivers/mtd/ubi/io.c
drivers/mtd/ubi/scan.c
drivers/mtd/ubi/scan.h
drivers/mtd/ubi/ubi-media.h
drivers/mtd/ubi/ubi.h
drivers/mtd/ubi/wl.c
drivers/net/8139too.c
drivers/net/Kconfig
drivers/net/a2065.c
drivers/net/arcnet/arcnet.c
drivers/net/arm/ixp4xx_eth.c
drivers/net/atl1c/atl1c_ethtool.c
drivers/net/atl1e/atl1e_ethtool.c
drivers/net/atlx/atl2.c
drivers/net/benet/be.h
drivers/net/benet/be_ethtool.c
drivers/net/benet/be_hw.h
drivers/net/benet/be_main.c
drivers/net/bmac.c
drivers/net/bnx2.c
drivers/net/bnx2x.h
drivers/net/bnx2x_main.c
drivers/net/can/Kconfig
drivers/net/cpmac.c
drivers/net/cs89x0.c
drivers/net/cxgb3/cxgb3_main.c
drivers/net/davinci_emac.c
drivers/net/dl2k.c
drivers/net/e1000/e1000_main.c
drivers/net/e1000e/defines.h
drivers/net/e1000e/hw.h
drivers/net/e1000e/ich8lan.c
drivers/net/e1000e/lib.c
drivers/net/e1000e/netdev.c
drivers/net/e1000e/phy.c
drivers/net/ehea/ehea_main.c
drivers/net/epic100.c
drivers/net/fealnx.c
drivers/net/fec.c
drivers/net/fec.h
drivers/net/forcedeth.c
drivers/net/fsl_pq_mdio.c
drivers/net/gianfar.c
drivers/net/hamachi.c
drivers/net/hamradio/baycom_epp.c
drivers/net/hamradio/baycom_par.c
drivers/net/hamradio/baycom_ser_fdx.c
drivers/net/hamradio/baycom_ser_hdx.c
drivers/net/igb/e1000_82575.c
drivers/net/igb/igb_main.c
drivers/net/irda/bfin_sir.c
drivers/net/irda/irtty-sir.c
drivers/net/isa-skeleton.c
drivers/net/ixgbe/ixgbe_dcb_nl.c
drivers/net/ixgbe/ixgbe_ethtool.c
drivers/net/ixgbe/ixgbe_main.c
drivers/net/ixgbe/ixgbe_phy.c
drivers/net/mdio.c
drivers/net/mlx4/cmd.c
drivers/net/mlx4/main.c
drivers/net/natsemi.c
drivers/net/ne.c
drivers/net/netxen/netxen_nic.h
drivers/net/netxen/netxen_nic_hdr.h
drivers/net/netxen/netxen_nic_init.c
drivers/net/netxen/netxen_nic_main.c
drivers/net/pci-skeleton.c
drivers/net/pcmcia/ibmtr_cs.c
drivers/net/pcmcia/nmclan_cs.c
drivers/net/pcmcia/pcnet_cs.c
drivers/net/pcnet32.c
drivers/net/phy/phy.c
drivers/net/phy/phy_device.c
drivers/net/plip.c
drivers/net/ppp_async.c
drivers/net/ppp_synctty.c
drivers/net/ps3_gelic_net.c
drivers/net/ps3_gelic_wireless.c
drivers/net/qla3xxx.c
drivers/net/qlge/qlge.h
drivers/net/qlge/qlge_ethtool.c
drivers/net/qlge/qlge_main.c
drivers/net/qlge/qlge_mpi.c
drivers/net/r6040.c
drivers/net/sh_eth.c
drivers/net/sky2.c
drivers/net/smc91x.c
drivers/net/smsc911x.c
drivers/net/starfire.c
drivers/net/sundance.c
drivers/net/sunvnet.c
drivers/net/tsi108_eth.c
drivers/net/tulip/de2104x.c
drivers/net/tulip/tulip_core.c
drivers/net/tulip/winbond-840.c
drivers/net/tun.c
drivers/net/usb/cdc_eem.c
drivers/net/usb/dm9601.c
drivers/net/usb/kaweth.c
drivers/net/usb/net1080.c
drivers/net/usb/pegasus.c
drivers/net/usb/rndis_host.c
drivers/net/usb/smsc95xx.c
drivers/net/usb/usbnet.c
drivers/net/veth.c
drivers/net/via-rhine.c
drivers/net/wan/hd64570.c
drivers/net/wan/hd64572.c
drivers/net/wan/sbni.c
drivers/net/wireless/ath/Kconfig
drivers/net/wireless/ath/ath9k/xmit.c
drivers/net/wireless/b43/b43.h
drivers/net/wireless/b43/main.c
drivers/net/wireless/b43/pcmcia.c
drivers/net/wireless/b43legacy/b43legacy.h
drivers/net/wireless/b43legacy/main.c
drivers/net/wireless/iwmc3200wifi/Kconfig
drivers/net/wireless/mac80211_hwsim.c
drivers/net/wireless/orinoco/main.c
drivers/net/wireless/p54/p54common.c
drivers/net/wireless/ray_cs.c
drivers/net/wireless/wavelan_cs.c
drivers/net/wireless/zd1211rw/zd_usb.c
drivers/net/yellowfin.c
drivers/oprofile/oprofile_stats.c
drivers/parisc/ccio-dma.c
drivers/parisc/dino.c
drivers/parisc/eisa.c
drivers/parisc/eisa_enumerator.c
drivers/parisc/gsc.c
drivers/parisc/gsc.h
drivers/parisc/iosapic.c
drivers/parisc/lba_pci.c
drivers/parisc/sba_iommu.c
drivers/parisc/superio.c
drivers/parport/parport_pc.c
drivers/pci/hotplug/acpi_pcihp.c
drivers/pci/hotplug/acpiphp_glue.c
drivers/pci/hotplug/cpci_hotplug_core.c
drivers/pci/hotplug/cpqphp_ctrl.c
drivers/pci/hotplug/cpqphp_sysfs.c
drivers/pci/hotplug/pci_hotplug_core.c
drivers/pci/hotplug/pciehp_ctrl.c
drivers/pci/intel-iommu.c
drivers/pci/intr_remapping.c
drivers/pci/intr_remapping.h
drivers/pci/iova.c
drivers/pci/msi.c
drivers/pci/msi.h
drivers/pci/pci.c
drivers/pci/pcie/aer/ecrc.c
drivers/pci/quirks.c
drivers/pci/slot.c
drivers/pci/syscall.c
drivers/pcmcia/tcic.c
drivers/pcmcia/vrc4171_card.c
drivers/pcmcia/vrc4173_cardu.c
drivers/pcmcia/vrc4173_cardu.h
drivers/platform/x86/Kconfig
drivers/platform/x86/Makefile
drivers/platform/x86/acerhdf.c [new file with mode: 0644]
drivers/platform/x86/asus-laptop.c
drivers/platform/x86/asus_acpi.c
drivers/platform/x86/dell-wmi.c
drivers/platform/x86/eeepc-laptop.c
drivers/platform/x86/hp-wmi.c
drivers/platform/x86/thinkpad_acpi.c
drivers/pnp/pnpacpi/rsparser.c
drivers/power/Kconfig
drivers/power/Makefile
drivers/power/da9030_battery.c
drivers/power/ds2760_battery.c
drivers/power/max17040_battery.c [new file with mode: 0644]
drivers/power/wm97xx_battery.c
drivers/rtc/rtc-bfin.c
drivers/rtc/rtc-ds1374.c
drivers/rtc/rtc-vr41xx.c
drivers/s390/block/dasd_eckd.c
drivers/s390/block/dasd_erp.c
drivers/s390/block/dasd_fba.c
drivers/s390/block/dasd_int.h
drivers/s390/block/dasd_ioctl.c
drivers/s390/block/dcssblk.c
drivers/s390/block/xpram.c
drivers/s390/char/monreader.c
drivers/s390/char/sclp_rw.h
drivers/s390/char/vmwatchdog.c
drivers/scsi/atari_NCR5380.c
drivers/scsi/cxgb3i/Kbuild
drivers/scsi/cxgb3i/cxgb3i_iscsi.c
drivers/scsi/fnic/fnic_main.c
drivers/scsi/fnic/fnic_scsi.c
drivers/scsi/ibmvscsi/ibmvscsi.c
drivers/scsi/mac53c94.c
drivers/scsi/qla2xxx/qla_mid.c
drivers/scsi/scsi_transport_fc.c
drivers/scsi/sg.c
drivers/scsi/sun3_NCR5380.c
drivers/scsi/zalon.c
drivers/serial/8250_pci.c
drivers/serial/bfin_sport_uart.c
drivers/serial/icom.c
drivers/serial/jsm/jsm_tty.c
drivers/serial/msm_serial.c
drivers/serial/serial_txx9.c
drivers/serial/sh-sci.c
drivers/serial/vr41xx_siu.c
drivers/spi/omap_uwire.c
drivers/spi/spi_bitbang.c
drivers/spi/spidev.c
drivers/ssb/driver_mipscore.c
drivers/ssb/pcmcia.c
drivers/staging/comedi/drivers/jr3_pci.c
drivers/staging/comedi/drivers/s626.c
drivers/staging/go7007/s2250-loader.c
drivers/staging/meilhaus/TODO
drivers/staging/octeon/Makefile
drivers/staging/octeon/ethernet-common.c [deleted file]
drivers/staging/octeon/ethernet-common.h [deleted file]
drivers/staging/octeon/ethernet-defines.h
drivers/staging/octeon/ethernet-rgmii.c
drivers/staging/octeon/ethernet-sgmii.c
drivers/staging/octeon/ethernet-spi.c
drivers/staging/octeon/ethernet-tx.c
drivers/staging/octeon/ethernet-tx.h
drivers/staging/octeon/ethernet-xaui.c
drivers/staging/octeon/ethernet.c
drivers/staging/octeon/octeon-ethernet.h
drivers/staging/rspiusb/rspiusb.c
drivers/staging/rt2870/rt2870.h
drivers/staging/rtl8187se/ieee80211/ieee80211_softmac_wx.c
drivers/staging/rtl8192su/Kconfig
drivers/staging/rtl8192su/ieee80211/ieee80211_module.c
drivers/staging/rtl8192su/ieee80211/ieee80211_softmac_wx.c
drivers/staging/rtl8192su/r8192U_core.c
drivers/staging/rtl8192su/r8192U_pm.c
drivers/staging/serqt_usb2/serqt_usb2.c
drivers/staging/stlc45xx/stlc45xx.c
drivers/staging/usbip/usbip_common.c
drivers/staging/vt6655/device_main.c
drivers/telephony/ixj.c
drivers/telephony/phonedev.c
drivers/usb/class/cdc-acm.c
drivers/usb/class/cdc-wdm.c
drivers/usb/class/usbtmc.c
drivers/usb/core/Kconfig
drivers/usb/core/devices.c
drivers/usb/core/devio.c
drivers/usb/core/hcd.c
drivers/usb/core/hcd.h
drivers/usb/core/hub.c
drivers/usb/core/hub.h
drivers/usb/core/message.c
drivers/usb/gadget/Kconfig
drivers/usb/gadget/amd5536udc.c
drivers/usb/gadget/audio.c
drivers/usb/gadget/ether.c
drivers/usb/gadget/langwell_udc.c
drivers/usb/gadget/pxa25x_udc.c
drivers/usb/gadget/rndis.c
drivers/usb/gadget/s3c2410_udc.c
drivers/usb/host/Kconfig
drivers/usb/host/ehci-au1xxx.c
drivers/usb/host/ehci-fsl.c
drivers/usb/host/ehci-hcd.c
drivers/usb/host/ehci-ixp4xx.c
drivers/usb/host/ehci-orion.c
drivers/usb/host/ehci-pci.c
drivers/usb/host/ehci-ppc-of.c
drivers/usb/host/ehci-ps3.c
drivers/usb/host/ehci-q.c
drivers/usb/host/ehci-sched.c
drivers/usb/host/ehci.h
drivers/usb/host/fhci-sched.c
drivers/usb/host/isp1760-if.c
drivers/usb/host/r8a66597-hcd.c
drivers/usb/misc/iowarrior.c
drivers/usb/misc/rio500.c
drivers/usb/misc/usblcd.c
drivers/usb/mon/mon_bin.c
drivers/usb/musb/cppi_dma.h
drivers/usb/musb/davinci.c
drivers/usb/musb/musb_core.h
drivers/usb/musb/musb_host.c
drivers/usb/otg/Kconfig
drivers/usb/otg/Makefile
drivers/usb/otg/langwell_otg.c [deleted file]
drivers/usb/otg/nop-usb-xceiv.c
drivers/usb/serial/console.c
drivers/usb/serial/cp210x.c
drivers/usb/serial/cypress_m8.c
drivers/usb/serial/ftdi_sio.c
drivers/usb/serial/ftdi_sio.h
drivers/usb/serial/generic.c
drivers/usb/serial/mos7840.c
drivers/usb/serial/option.c
drivers/usb/serial/pl2303.c
drivers/usb/serial/pl2303.h
drivers/usb/serial/sierra.c
drivers/usb/serial/ti_usb_3410_5052.c
drivers/usb/serial/usb-serial.c
drivers/usb/storage/option_ms.c
drivers/uwb/hwa-rc.c
drivers/uwb/wlp/txrx.c
drivers/video/Kconfig
drivers/video/amba-clcd.c
drivers/video/atafb.c
drivers/video/atmel_lcdfb.c
drivers/video/aty/atyfb.h
drivers/video/aty/atyfb_base.c
drivers/video/aty/mach64_accel.c
drivers/video/backlight/tdo24m.c
drivers/video/cobalt_lcdfb.c
drivers/video/fbmem.c
drivers/video/fsl-diu-fb.c
drivers/video/hitfb.c
drivers/video/i810/i810_main.c
drivers/video/matrox/matroxfb_DAC1064.c
drivers/video/matrox/matroxfb_Ti3026.c
drivers/video/matrox/matroxfb_base.c
drivers/video/matrox/matroxfb_crtc2.c
drivers/video/mx3fb.c
drivers/video/omap/omapfb_main.c
drivers/video/platinumfb.c
drivers/video/pxafb.c
drivers/video/s3c-fb.c
drivers/video/sh7760fb.c
drivers/video/sh_mobile_lcdcfb.c
drivers/video/sis/sis_main.c
drivers/video/sm501fb.c
drivers/video/stifb.c
drivers/video/w100fb.c
drivers/virtio/virtio_pci.c
drivers/vlynq/Kconfig
drivers/vlynq/vlynq.c
drivers/w1/slaves/w1_ds2760.c
drivers/w1/slaves/w1_ds2760.h
drivers/watchdog/bcm47xx_wdt.c
drivers/watchdog/sa1100_wdt.c
drivers/watchdog/w83627hf_wdt.c
drivers/watchdog/w83697ug_wdt.c
drivers/watchdog/wdrtas.c
drivers/xen/events.c
fs/adfs/super.c
fs/afs/dir.c
fs/afs/flock.c
fs/afs/mntpt.c
fs/afs/super.c
fs/aio.c
fs/autofs4/dev-ioctl.c
fs/bfs/dir.c
fs/bfs/file.c
fs/binfmt_elf.c
fs/bio-integrity.c
fs/bio.c
fs/btrfs/acl.c
fs/btrfs/async-thread.c
fs/btrfs/btrfs_inode.h
fs/btrfs/compression.c
fs/btrfs/ctree.h
fs/btrfs/extent-tree.c
fs/btrfs/file.c
fs/btrfs/inode.c
fs/btrfs/ioctl.c
fs/btrfs/relocation.c
fs/btrfs/super.c
fs/btrfs/transaction.c
fs/char_dev.c
fs/cifs/CHANGES
fs/cifs/asn1.c
fs/cifs/cifs_spnego.c
fs/cifs/cifsacl.c
fs/cifs/cifsfs.c
fs/cifs/cifsfs.h
fs/cifs/cifsglob.h
fs/cifs/cifspdu.h
fs/cifs/cifsproto.h
fs/cifs/cifssmb.c
fs/cifs/connect.c
fs/cifs/dir.c
fs/cifs/dns_resolve.c
fs/cifs/file.c
fs/cifs/inode.c
fs/cifs/link.c
fs/cifs/netmisc.c
fs/cifs/readdir.c
fs/cifs/sess.c
fs/cifs/xattr.c
fs/compat.c
fs/compat_ioctl.c
fs/devpts/inode.c
fs/dlm/lock.c
fs/dlm/lowcomms.c
fs/dlm/plock.c
fs/eventfd.c
fs/exec.c
fs/exofs/common.h
fs/exofs/dir.c
fs/exofs/exofs.h
fs/exofs/file.c
fs/exofs/inode.c
fs/exofs/namei.c
fs/exofs/osd.c
fs/exofs/super.c
fs/exofs/symlink.c
fs/ext2/acl.c
fs/ext2/acl.h
fs/ext2/ext2.h
fs/ext2/inode.c
fs/ext2/ioctl.c
fs/ext2/namei.c
fs/ext2/super.c
fs/ext3/acl.c
fs/ext3/acl.h
fs/ext3/inode.c
fs/ext3/super.c
fs/ext4/acl.c
fs/ext4/acl.h
fs/ext4/ext4.h
fs/ext4/ext4_jbd2.c
fs/ext4/ext4_jbd2.h
fs/ext4/extents.c
fs/ext4/ialloc.c
fs/ext4/inode.c
fs/ext4/ioctl.c
fs/ext4/mballoc.c
fs/ext4/super.c
fs/fat/dir.c
fs/fat/file.c
fs/fat/namei_msdos.c
fs/fat/namei_vfat.c
fs/fcntl.c
fs/freevxfs/vxfs_super.c
fs/fs-writeback.c
fs/fuse/dev.c
fs/fuse/dir.c
fs/fuse/file.c
fs/fuse/fuse_i.h
fs/fuse/inode.c
fs/gfs2/trace_gfs2.h
fs/hfs/super.c
fs/hfsplus/super.c
fs/hostfs/hostfs_kern.c
fs/hpfs/dir.c
fs/hpfs/file.c
fs/hpfs/hpfs_fn.h
fs/hpfs/inode.c
fs/hpfs/namei.c
fs/inode.c
fs/ioctl.c
fs/isofs/inode.c
fs/jbd2/journal.c
fs/jbd2/transaction.c
fs/jffs2/acl.c
fs/jffs2/acl.h
fs/jffs2/erase.c
fs/jffs2/jffs2_fs_i.h
fs/jffs2/os-linux.h
fs/jffs2/readinode.c
fs/jffs2/scan.c
fs/jffs2/super.c
fs/jfs/acl.c
fs/jfs/jfs_incore.h
fs/jfs/super.c
fs/jfs/xattr.c
fs/lockd/clntproc.c
fs/lockd/svc4proc.c
fs/lockd/svcproc.c
fs/namei.c
fs/namespace.c
fs/nfs/delegation.c
fs/nfs/dir.c
fs/nfs/file.c
fs/nfs/getroot.c
fs/nfs/inode.c
fs/nfs/nfs4proc.c
fs/nfs/read.c
fs/nfs/write.c
fs/nfsd/nfsctl.c
fs/nfsd/nfssvc.c
fs/nfsd/vfs.c
fs/nilfs2/bmap.c
fs/nilfs2/cpfile.c
fs/nilfs2/dat.c
fs/nilfs2/dir.c
fs/nilfs2/inode.c
fs/nilfs2/nilfs.h
fs/nilfs2/segment.c
fs/nilfs2/super.c
fs/notify/inotify/inotify_user.c
fs/ocfs2/dlmglue.c
fs/ocfs2/dlmglue.h
fs/ocfs2/file.c
fs/ocfs2/inode.c
fs/ocfs2/ioctl.c
fs/ocfs2/journal.c
fs/ocfs2/journal.h
fs/ocfs2/namei.c
fs/ocfs2/ocfs2.h
fs/ocfs2/stack_o2cb.c
fs/ocfs2/stack_user.c
fs/ocfs2/stackglue.c
fs/ocfs2/stackglue.h
fs/ocfs2/suballoc.c
fs/ocfs2/super.c
fs/ocfs2/sysfile.c
fs/open.c
fs/partitions/check.c
fs/quota/dquot.c
fs/reiserfs/inode.c
fs/reiserfs/journal.c
fs/reiserfs/resize.c
fs/reiserfs/super.c
fs/reiserfs/xattr.c
fs/reiserfs/xattr_acl.c
fs/squashfs/super.c
fs/super.c
fs/sync.c
fs/sysfs/bin.c
fs/ubifs/io.c
fs/ubifs/ioctl.c
fs/ubifs/recovery.c
fs/ubifs/replay.c
fs/ubifs/scan.c
fs/ubifs/super.c
fs/ubifs/ubifs.h
fs/ubifs/xattr.c
fs/udf/balloc.c
fs/udf/lowlevel.c
fs/xfs/linux-2.6/kmem.c
fs/xfs/linux-2.6/xfs_acl.c
fs/xfs/linux-2.6/xfs_buf.c
fs/xfs/linux-2.6/xfs_file.c
fs/xfs/xfs_acl.h
fs/xfs/xfs_iget.c
fs/xfs/xfs_inode.h
include/acpi/acpi_bus.h
include/acpi/acpi_drivers.h
include/acpi/processor.h
include/acpi/video.h
include/asm-generic/percpu.h
include/asm-generic/vmlinux.lds.h
include/drm/drm_edid.h
include/drm/drm_pciids.h
include/linux/Kbuild
include/linux/acpi.h
include/linux/aio.h
include/linux/audit.h
include/linux/backing-dev.h
include/linux/bio.h
include/linux/blkdev.h
include/linux/clockchips.h
include/linux/connector.h
include/linux/console_struct.h
include/linux/crash_dump.h
include/linux/device-mapper.h
include/linux/device.h
include/linux/dm-ioctl.h
include/linux/dm-log-userspace.h [new file with mode: 0644]
include/linux/dmar.h
include/linux/elfcore.h
include/linux/eventfd.h
include/linux/ext3_fs_i.h
include/linux/falloc.h
include/linux/fb.h
include/linux/firewire.h
include/linux/fs.h
include/linux/fsnotify_backend.h
include/linux/fuse.h
include/linux/hardirq.h
include/linux/hrtimer.h
include/linux/icmpv6.h
include/linux/ide.h
include/linux/if_ether.h
include/linux/ima.h
include/linux/init_task.h
include/linux/input/matrix_keypad.h [new file with mode: 0644]
include/linux/kernel.h
include/linux/kmemleak.h
include/linux/kvm_host.h
include/linux/leds-lp3944.h [new file with mode: 0644]
include/linux/leds.h
include/linux/lguest.h
include/linux/libata.h
include/linux/linkage.h
include/linux/lockdep.h
include/linux/max17040_battery.h [new file with mode: 0644]
include/linux/mm.h
include/linux/mnt_namespace.h
include/linux/netfilter/xt_conntrack.h
include/linux/netfilter/xt_osf.h
include/linux/pci.h
include/linux/pci_hotplug.h
include/linux/pci_ids.h
include/linux/percpu-defs.h
include/linux/perf_counter.h
include/linux/personality.h
include/linux/posix_acl.h
include/linux/quotaops.h
include/linux/reiserfs_acl.h
include/linux/reiserfs_fs_i.h
include/linux/rfkill.h
include/linux/sched.h
include/linux/shmem_fs.h
include/linux/skbuff.h
include/linux/slub_def.h
include/linux/spi/spi.h
include/linux/spi/spidev.h
include/linux/spinlock.h
include/linux/sunrpc/xdr.h
include/linux/syscalls.h
include/linux/sysrq.h
include/linux/timer.h
include/linux/usb.h
include/linux/usb/langwell_otg.h [deleted file]
include/linux/usb/serial.h
include/linux/usb/usbnet.h
include/linux/videodev2.h
include/linux/virtio_net.h
include/media/v4l2-chip-ident.h
include/net/netfilter/nf_conntrack.h
include/net/phonet/pn_dev.h
include/net/protocol.h
include/net/rawv6.h
include/net/sctp/sctp.h
include/net/sock.h
include/net/xfrm.h
include/trace/events/block.h
include/trace/events/ext4.h
include/trace/events/irq.h
include/trace/events/jbd2.h
include/trace/events/kmem.h
include/trace/events/lockdep.h
include/trace/events/sched.h
include/trace/events/skb.h
include/trace/events/workqueue.h
init/main.c
ipc/mqueue.c
kernel/Makefile
kernel/acct.c
kernel/audit.c
kernel/audit.h
kernel/audit_tree.c
kernel/audit_watch.c [new file with mode: 0644]
kernel/auditfilter.c
kernel/auditsc.c
kernel/exit.c
kernel/fork.c
kernel/futex.c
kernel/hrtimer.c
kernel/kmod.c
kernel/module.c
kernel/perf_counter.c
kernel/power/user.c
kernel/ptrace.c
kernel/rcutree.c
kernel/resource.c
kernel/sched.c
kernel/sched_fair.c
kernel/sched_rt.c
kernel/sysctl.c
kernel/time/clockevents.c
kernel/time/timer_stats.c
kernel/timer.c
kernel/trace/blktrace.c
kernel/trace/ftrace.c
kernel/trace/trace.c
kernel/trace/trace_functions.c
kernel/trace/trace_output.c
lib/Kconfig.debug
lib/dma-debug.c
mm/backing-dev.c
mm/bootmem.c
mm/dmapool.c
mm/filemap.c
mm/kmemleak.c
mm/memcontrol.c
mm/memory.c
mm/nommu.c
mm/page-writeback.c
mm/page_alloc.c
mm/percpu.c
mm/shmem.c
mm/shmem_acl.c
mm/slab.c
mm/slob.c
mm/slub.c
mm/vmscan.c
net/9p/trans_fd.c
net/appletalk/ddp.c
net/atm/common.c
net/ax25/ax25_in.c
net/bridge/br.c
net/core/datagram.c
net/core/dev.c
net/core/netpoll.c
net/core/sock.c
net/dccp/ipv6.c
net/dccp/output.c
net/dccp/proto.c
net/decnet/af_decnet.c
net/dsa/mv88e6xxx.c
net/ieee802154/netlink.c
net/ipv4/arp.c
net/ipv4/fib_trie.c
net/ipv4/ip_gre.c
net/ipv4/ip_input.c
net/ipv4/ip_output.c
net/ipv4/netfilter/nf_nat_helper.c
net/ipv4/route.c
net/ipv4/tcp.c
net/ipv4/tcp_minisocks.c
net/ipv4/tcp_output.c
net/ipv4/xfrm4_policy.c
net/ipv6/addrconf.c
net/ipv6/af_inet6.c
net/ipv6/ah6.c
net/ipv6/esp6.c
net/ipv6/icmp.c
net/ipv6/ip6_input.c
net/ipv6/ip6_output.c
net/ipv6/ip6_tunnel.c
net/ipv6/ipcomp6.c
net/ipv6/mip6.c
net/ipv6/raw.c
net/ipv6/route.c
net/ipv6/sit.c
net/ipv6/tcp_ipv6.c
net/ipv6/tunnel6.c
net/ipv6/udp.c
net/ipv6/udp_impl.h
net/ipv6/udplite.c
net/ipv6/xfrm6_policy.c
net/ipv6/xfrm6_tunnel.c
net/ipx/af_ipx.c
net/irda/af_irda.c
net/irda/ircomm/ircomm_lmp.c
net/irda/irnet/irnet.h
net/irda/irnet/irnet_ppp.c
net/iucv/af_iucv.c
net/mac80211/mesh.c
net/mac80211/mesh_hwmp.c
net/mac80211/rc80211_minstrel.c
net/netfilter/nf_conntrack_core.c
net/netfilter/nf_conntrack_expect.c
net/netfilter/nf_conntrack_extend.c
net/netfilter/nf_conntrack_proto_tcp.c
net/netfilter/nf_log.c
net/netfilter/xt_NFQUEUE.c
net/netfilter/xt_cluster.c
net/netfilter/xt_conntrack.c
net/netfilter/xt_quota.c
net/netfilter/xt_rateest.c
net/phonet/pn_dev.c
net/phonet/pn_netlink.c
net/rxrpc/af_rxrpc.c
net/sctp/ipv6.c
net/sctp/output.c
net/sctp/socket.c
net/sunrpc/clnt.c
net/sunrpc/sched.c
net/sunrpc/sunrpc_syms.c
net/sunrpc/svc_xprt.c
net/unix/af_unix.c
net/wanrouter/wanmain.c
net/wireless/nl80211.c
net/wireless/scan.c
net/x25/af_x25.c
net/xfrm/xfrm_algo.c
net/xfrm/xfrm_state.c
samples/trace_events/trace-events-sample.h
scripts/.gitignore
scripts/dtc/.gitignore [new file with mode: 0644]
scripts/kernel-doc
scripts/package/builddeb
scripts/pnmtologo.c
security/integrity/ima/ima_main.c
security/integrity/ima/ima_queue.c
sound/arm/pxa2xx-pcm-lib.c
sound/isa/cmi8330.c
sound/oss/kahlua.c
sound/oss/mpu401.c
sound/pci/atiixp.c
sound/pci/atiixp_modem.c
sound/pci/au88x0/au8810.c
sound/pci/au88x0/au8820.c
sound/pci/au88x0/au8830.c
sound/pci/ca0106/ca0106_main.c
sound/pci/cmipci.c
sound/pci/cs4281.c
sound/pci/cs46xx/cs46xx.c
sound/pci/emu10k1/emu10k1.c
sound/pci/emu10k1/emu10k1x.c
sound/pci/emu10k1/p16v.c
sound/pci/ens1370.c
sound/pci/es1938.c
sound/pci/hda/hda_beep.c
sound/pci/hda/hda_codec.c
sound/pci/hda/hda_intel.c
sound/pci/hda/patch_analog.c
sound/pci/hda/patch_ca0110.c
sound/pci/hda/patch_realtek.c
sound/pci/hda/patch_sigmatel.c
sound/pci/hda/patch_via.c
sound/pci/ice1712/ice1712.c
sound/pci/ice1712/ice1724.c
sound/pci/intel8x0.c
sound/pci/intel8x0m.c
sound/pci/lx6464es/lx6464es.c
sound/pci/mixart/mixart.c
sound/pci/nm256/nm256.c
sound/pci/oxygen/oxygen_mixer.c
sound/pci/oxygen/virtuoso.c
sound/pci/riptide/riptide.c
sound/pci/rme32.c
sound/pci/rme96.c
sound/pci/sonicvibes.c
sound/pci/via82xx.c
sound/pci/via82xx_modem.c
sound/pci/ymfpci/ymfpci.c
sound/soc/codecs/wm8753.c
sound/soc/codecs/wm8988.c
sound/soc/fsl/Kconfig
sound/soc/fsl/mpc5200_dma.c
sound/soc/fsl/mpc5200_dma.h
sound/soc/fsl/mpc5200_psc_ac97.c
sound/soc/omap/omap-pcm.c
sound/soc/pxa/pxa2xx-i2s.c
sound/sound_core.c
sound/usb/caiaq/device.c
sound/usb/usbaudio.c
sound/usb/usx2y/us122l.c
sound/usb/usx2y/usbusx2y.c
sound/usb/usx2y/usbusx2yaudio.c
tools/perf/CREDITS [new file with mode: 0644]
tools/perf/Documentation/perf-report.txt
tools/perf/Documentation/perf-stat.txt
tools/perf/Makefile
tools/perf/builtin-annotate.c
tools/perf/builtin-help.c
tools/perf/builtin-list.c
tools/perf/builtin-record.c
tools/perf/builtin-report.c
tools/perf/builtin-stat.c
tools/perf/builtin-top.c
tools/perf/perf.c
tools/perf/perf.h
tools/perf/util/alias.c
tools/perf/util/cache.h
tools/perf/util/callchain.c [new file with mode: 0644]
tools/perf/util/callchain.h [new file with mode: 0644]
tools/perf/util/color.c
tools/perf/util/color.h
tools/perf/util/config.c
tools/perf/util/exec_cmd.c
tools/perf/util/header.c [new file with mode: 0644]
tools/perf/util/header.h [new file with mode: 0644]
tools/perf/util/help.c
tools/perf/util/help.h
tools/perf/util/include/asm/system.h [new file with mode: 0644]
tools/perf/util/include/linux/kernel.h [new file with mode: 0644]
tools/perf/util/include/linux/list.h [new file with mode: 0644]
tools/perf/util/include/linux/module.h [new file with mode: 0644]
tools/perf/util/include/linux/poison.h [new file with mode: 0644]
tools/perf/util/include/linux/prefetch.h [new file with mode: 0644]
tools/perf/util/include/linux/rbtree.h [new file with mode: 0644]
tools/perf/util/list.h [deleted file]
tools/perf/util/module.c [new file with mode: 0644]
tools/perf/util/module.h [new file with mode: 0644]
tools/perf/util/pager.c
tools/perf/util/parse-events.c
tools/perf/util/parse-options.c
tools/perf/util/parse-options.h
tools/perf/util/quote.c
tools/perf/util/quote.h
tools/perf/util/rbtree.c [deleted file]
tools/perf/util/rbtree.h [deleted file]
tools/perf/util/run-command.c
tools/perf/util/run-command.h
tools/perf/util/strbuf.c
tools/perf/util/strbuf.h
tools/perf/util/string.h
tools/perf/util/strlist.c [new file with mode: 0644]
tools/perf/util/strlist.h [new file with mode: 0644]
tools/perf/util/symbol.c
tools/perf/util/symbol.h
tools/perf/util/types.h [moved from tools/perf/types.h with 100% similarity]
tools/perf/util/util.h
tools/perf/util/wrapper.c
virt/kvm/kvm_main.c

index cecb3b040cc17d22acdb9268e130a459e771608a..b93fb7eff94286c7a15d475fa581dac32a89b0db 100644 (file)
@@ -27,6 +27,7 @@
 *.gz
 *.lzma
 *.patch
+*.gcno
 
 #
 # Top-level generic files
index e36986663570d6be1577365645c25b11e866c138..f3f37f141dbdb4a00ab621e07a9c1fa361a1f782 100644 (file)
@@ -184,8 +184,6 @@ usage should require reading the full document.
 !Finclude/net/mac80211.h ieee80211_ctstoself_get
 !Finclude/net/mac80211.h ieee80211_ctstoself_duration
 !Finclude/net/mac80211.h ieee80211_generic_frame_duration
-!Finclude/net/mac80211.h ieee80211_get_hdrlen_from_skb
-!Finclude/net/mac80211.h ieee80211_hdrlen
 !Finclude/net/mac80211.h ieee80211_wake_queue
 !Finclude/net/mac80211.h ieee80211_stop_queue
 !Finclude/net/mac80211.h ieee80211_wake_queues
index e8ca040ba2cff4bb5b938939f75c1bb97f0610af..2d735b0ae383b625c87f37ed2603ec829adf6746 100644 (file)
@@ -50,7 +50,7 @@ encouraged them to allow separation of the data and integrity metadata
 scatter-gather lists.
 
 The controller will interleave the buffers on write and split them on
-read.  This means that the Linux can DMA the data buffers to and from
+read.  This means that Linux can DMA the data buffers to and from
 host memory without changes to the page cache.
 
 Also, the 16-bit CRC checksum mandated by both the SCSI and SATA specs
@@ -66,7 +66,7 @@ software RAID5).
 
 The IP checksum is weaker than the CRC in terms of detecting bit
 errors.  However, the strength is really in the separation of the data
-buffers and the integrity metadata.  These two distinct buffers much
+buffers and the integrity metadata.  These two distinct buffers must
 match up for an I/O to complete.
 
 The separation of the data and integrity metadata buffers as well as
index f9ca389dddf49a7f1bc80c7e724b4a2ffa7e1ba4..1d7e9784439adee55d9d7e983f90e2006b7ef954 100644 (file)
@@ -777,6 +777,18 @@ in cpuset directories:
 # /bin/echo 1-4 > cpus         -> set cpus list to cpus 1,2,3,4
 # /bin/echo 1,2,3,4 > cpus     -> set cpus list to cpus 1,2,3,4
 
+To add a CPU to a cpuset, write the new list of CPUs including the
+CPU to be added. To add 6 to the above cpuset:
+
+# /bin/echo 1-4,6 > cpus       -> set cpus list to cpus 1,2,3,4,6
+
+Similarly to remove a CPU from a cpuset, write the new list of CPUs
+without the CPU to be removed.
+
+To remove all the CPUs:
+
+# /bin/echo "" > cpus          -> clear cpus list
+
 2.3 Setting flags
 -----------------
 
diff --git a/Documentation/device-mapper/dm-log.txt b/Documentation/device-mapper/dm-log.txt
new file mode 100644 (file)
index 0000000..994dd75
--- /dev/null
@@ -0,0 +1,54 @@
+Device-Mapper Logging
+=====================
+The device-mapper logging code is used by some of the device-mapper
+RAID targets to track regions of the disk that are not consistent.
+A region (or portion of the address space) of the disk may be
+inconsistent because a RAID stripe is currently being operated on or
+a machine died while the region was being altered.  In the case of
+mirrors, a region would be considered dirty/inconsistent while you
+are writing to it because the writes need to be replicated for all
+the legs of the mirror and may not reach the legs at the same time.
+Once all writes are complete, the region is considered clean again.
+
+There is a generic logging interface that the device-mapper RAID
+implementations use to perform logging operations (see
+dm_dirty_log_type in include/linux/dm-dirty-log.h).  Various different
+logging implementations are available and provide different
+capabilities.  The list includes:
+
+Type           Files
+====           =====
+disk           drivers/md/dm-log.c
+core           drivers/md/dm-log.c
+userspace      drivers/md/dm-log-userspace* include/linux/dm-log-userspace.h
+
+The "disk" log type
+-------------------
+This log implementation commits the log state to disk.  This way, the
+logging state survives reboots/crashes.
+
+The "core" log type
+-------------------
+This log implementation keeps the log state in memory.  The log state
+will not survive a reboot or crash, but there may be a small boost in
+performance.  This method can also be used if no storage device is
+available for storing log state.
+
+The "userspace" log type
+------------------------
+This log type simply provides a way to export the log API to userspace,
+so log implementations can be done there.  This is done by forwarding most
+logging requests to userspace, where a daemon receives and processes the
+request.
+
+The structure used for communication between kernel and userspace are
+located in include/linux/dm-log-userspace.h.  Due to the frequency,
+diversity, and 2-way communication nature of the exchanges between
+kernel and userspace, 'connector' is used as the interface for
+communication.
+
+There are currently two userspace log implementations that leverage this
+framework - "clustered_disk" and "clustered_core".  These implementations
+provide a cluster-coherent log for shared-storage.  Device-mapper mirroring
+can be used in a shared-storage environment when the cluster log implementations
+are employed.
diff --git a/Documentation/device-mapper/dm-queue-length.txt b/Documentation/device-mapper/dm-queue-length.txt
new file mode 100644 (file)
index 0000000..f4db256
--- /dev/null
@@ -0,0 +1,39 @@
+dm-queue-length
+===============
+
+dm-queue-length is a path selector module for device-mapper targets,
+which selects a path with the least number of in-flight I/Os.
+The path selector name is 'queue-length'.
+
+Table parameters for each path: [<repeat_count>]
+       <repeat_count>: The number of I/Os to dispatch using the selected
+                       path before switching to the next path.
+                       If not given, internal default is used. To check
+                       the default value, see the activated table.
+
+Status for each path: <status> <fail-count> <in-flight>
+       <status>: 'A' if the path is active, 'F' if the path is failed.
+       <fail-count>: The number of path failures.
+       <in-flight>: The number of in-flight I/Os on the path.
+
+
+Algorithm
+=========
+
+dm-queue-length increments/decrements 'in-flight' when an I/O is
+dispatched/completed respectively.
+dm-queue-length selects a path with the minimum 'in-flight'.
+
+
+Examples
+========
+In case that 2 paths (sda and sdb) are used with repeat_count == 128.
+
+# echo "0 10 multipath 0 0 1 1 queue-length 0 2 1 8:0 128 8:16 128" \
+  dmsetup create test
+#
+# dmsetup table
+test: 0 10 multipath 0 0 1 1 queue-length 0 2 1 8:0 128 8:16 128
+#
+# dmsetup status
+test: 0 10 multipath 2 0 0 0 1 1 E 0 2 1 8:0 A 0 0 8:16 A 0 0
diff --git a/Documentation/device-mapper/dm-service-time.txt b/Documentation/device-mapper/dm-service-time.txt
new file mode 100644 (file)
index 0000000..7d00668
--- /dev/null
@@ -0,0 +1,91 @@
+dm-service-time
+===============
+
+dm-service-time is a path selector module for device-mapper targets,
+which selects a path with the shortest estimated service time for
+the incoming I/O.
+
+The service time for each path is estimated by dividing the total size
+of in-flight I/Os on a path with the performance value of the path.
+The performance value is a relative throughput value among all paths
+in a path-group, and it can be specified as a table argument.
+
+The path selector name is 'service-time'.
+
+Table parameters for each path: [<repeat_count> [<relative_throughput>]]
+       <repeat_count>: The number of I/Os to dispatch using the selected
+                       path before switching to the next path.
+                       If not given, internal default is used.  To check
+                       the default value, see the activated table.
+       <relative_throughput>: The relative throughput value of the path
+                       among all paths in the path-group.
+                       The valid range is 0-100.
+                       If not given, minimum value '1' is used.
+                       If '0' is given, the path isn't selected while
+                       other paths having a positive value are available.
+
+Status for each path: <status> <fail-count> <in-flight-size> \
+                     <relative_throughput>
+       <status>: 'A' if the path is active, 'F' if the path is failed.
+       <fail-count>: The number of path failures.
+       <in-flight-size>: The size of in-flight I/Os on the path.
+       <relative_throughput>: The relative throughput value of the path
+                       among all paths in the path-group.
+
+
+Algorithm
+=========
+
+dm-service-time adds the I/O size to 'in-flight-size' when the I/O is
+dispatched and substracts when completed.
+Basically, dm-service-time selects a path having minimum service time
+which is calculated by:
+
+       ('in-flight-size' + 'size-of-incoming-io') / 'relative_throughput'
+
+However, some optimizations below are used to reduce the calculation
+as much as possible.
+
+       1. If the paths have the same 'relative_throughput', skip
+          the division and just compare the 'in-flight-size'.
+
+       2. If the paths have the same 'in-flight-size', skip the division
+          and just compare the 'relative_throughput'.
+
+       3. If some paths have non-zero 'relative_throughput' and others
+          have zero 'relative_throughput', ignore those paths with zero
+          'relative_throughput'.
+
+If such optimizations can't be applied, calculate service time, and
+compare service time.
+If calculated service time is equal, the path having maximum
+'relative_throughput' may be better.  So compare 'relative_throughput'
+then.
+
+
+Examples
+========
+In case that 2 paths (sda and sdb) are used with repeat_count == 128
+and sda has an average throughput 1GB/s and sdb has 4GB/s,
+'relative_throughput' value may be '1' for sda and '4' for sdb.
+
+# echo "0 10 multipath 0 0 1 1 service-time 0 2 2 8:0 128 1 8:16 128 4" \
+  dmsetup create test
+#
+# dmsetup table
+test: 0 10 multipath 0 0 1 1 service-time 0 2 2 8:0 128 1 8:16 128 4
+#
+# dmsetup status
+test: 0 10 multipath 2 0 0 0 1 1 E 0 2 2 8:0 A 0 0 1 8:16 A 0 0 4
+
+
+Or '2' for sda and '8' for sdb would be also true.
+
+# echo "0 10 multipath 0 0 1 1 service-time 0 2 2 8:0 128 2 8:16 128 8" \
+  dmsetup create test
+#
+# dmsetup table
+test: 0 10 multipath 0 0 1 1 service-time 0 2 2 8:0 128 2 8:16 128 8
+#
+# dmsetup status
+test: 0 10 multipath 2 0 0 0 1 1 E 0 2 2 8:0 A 0 0 2 8:16 A 0 0 8
index 82132169d47a837fc55ea9d53555abc29b2c7b5d..60120fb3b9618181a9e58f855cdef3ecdc5d0649 100644 (file)
@@ -207,8 +207,8 @@ Attributes
 ~~~~~~~~~~
 struct driver_attribute {
         struct attribute        attr;
-        ssize_t (*show)(struct device_driver *, char * buf, size_t count, loff_t off);
-        ssize_t (*store)(struct device_driver *, const char * buf, size_t count, loff_t off);
+        ssize_t (*show)(struct device_driver *driver, char *buf);
+        ssize_t (*store)(struct device_driver *, const char * buf, size_t count);
 };
 
 Device drivers can export attributes via their sysfs directories. 
index a52adfc9a57fe4d7b8cfbbecfa525df6d91906e1..3d1b0ab70c8ef3ed498eb00da7c68b5371d55ce6 100644 (file)
@@ -25,7 +25,7 @@ use IO::Handle;
                "tda10046lifeview", "av7110", "dec2000t", "dec2540t",
                "dec3000s", "vp7041", "dibusb", "nxt2002", "nxt2004",
                "or51211", "or51132_qam", "or51132_vsb", "bluebird",
-               "opera1", "cx231xx", "cx18", "cx23885", "pvrusb2" );
+               "opera1", "cx231xx", "cx18", "cx23885", "pvrusb2", "mpc718" );
 
 # Check args
 syntax() if (scalar(@ARGV) != 1);
@@ -381,6 +381,57 @@ sub cx18 {
     $allfiles;
 }
 
+sub mpc718 {
+    my $archive = 'Yuan MPC718 TV Tuner Card 2.13.10.1016.zip';
+    my $url = "ftp://ftp.work.acer-euro.com/desktop/aspire_idea510/vista/Drivers/$archive";
+    my $fwfile = "dvb-cx18-mpc718-mt352.fw";
+    my $tmpdir = tempdir(DIR => "/tmp", CLEANUP => 1);
+
+    checkstandard();
+    wgetfile($archive, $url);
+    unzip($archive, $tmpdir);
+
+    my $sourcefile = "$tmpdir/Yuan MPC718 TV Tuner Card 2.13.10.1016/mpc718_32bit/yuanrap.sys";
+    my $found = 0;
+
+    open IN, '<', $sourcefile or die "Couldn't open $sourcefile to extract $fwfile data\n";
+    binmode IN;
+    open OUT, '>', $fwfile;
+    binmode OUT;
+    {
+       # Block scope because we change the line terminator variable $/
+       my $prevlen = 0;
+       my $currlen;
+
+       # Buried in the data segment are 3 runs of almost identical
+       # register-value pairs that end in 0x5d 0x01 which is a "TUNER GO"
+       # command for the MT352.
+       # Pull out the middle run (because it's easy) of register-value
+       # pairs to make the "firmware" file.
+
+       local $/ = "\x5d\x01"; # MT352 "TUNER GO"
+
+       while (<IN>) {
+           $currlen = length($_);
+           if ($prevlen == $currlen && $currlen <= 64) {
+               chop; chop; # Get rid of "TUNER GO"
+               s/^\0\0//;  # get rid of leading 00 00 if it's there
+               printf OUT "$_";
+               $found = 1;
+               last;
+           }
+           $prevlen = $currlen;
+       }
+    }
+    close OUT;
+    close IN;
+    if (!$found) {
+       unlink $fwfile;
+       die "Couldn't find valid register-value sequence in $sourcefile for $fwfile\n";
+    }
+    $fwfile;
+}
+
 sub cx23885 {
     my $url = "http://linuxtv.org/downloads/firmware/";
 
index f8cd450be9aa83a4a88cee408f79378ef575ce18..09e031c558875139c72874b1ab78f322ed34d25f 100644 (file)
@@ -458,3 +458,13 @@ Why:       Remove the old legacy 32bit machine check code. This has been
        but the old version has been kept around for easier testing. Note this
        doesn't impact the old P5 and WinChip machine check handlers.
 Who:   Andi Kleen <andi@firstfloor.org>
+
+----------------------------
+
+What:  lock_policy_rwsem_* and unlock_policy_rwsem_* will not be
+       exported interface anymore.
+When:  2.6.33
+Why:   cpu_policy_rwsem has a new cleaner definition making it local to
+       cpufreq core and contained inside cpufreq.c. Other dependent
+       drivers should not use it in order to safely avoid lockdep issues.
+Who:   Venkatesh Pallipadi <venkatesh.pallipadi@intel.com>
index 229d7b7c50a350053170e5fba11ac9a0168c0e70..18b9d0ca0630e281bb20dc5c5991e4b6f06b4643 100644 (file)
@@ -109,27 +109,28 @@ prototypes:
 
 locking rules:
        All may block.
-                       BKL     s_lock  s_umount
-alloc_inode:           no      no      no
-destroy_inode:         no
-dirty_inode:           no                              (must not sleep)
-write_inode:           no
-drop_inode:            no                              !!!inode_lock!!!
-delete_inode:          no
-put_super:             yes     yes     no
-write_super:           no      yes     read
-sync_fs:               no      no      read
-freeze_fs:             ?
-unfreeze_fs:           ?
-statfs:                        no      no      no
-remount_fs:            yes     yes     maybe           (see below)
-clear_inode:           no
-umount_begin:          yes     no      no
-show_options:          no                              (vfsmount->sem)
-quota_read:            no      no      no              (see below)
-quota_write:           no      no      no              (see below)
-
-->remount_fs() will have the s_umount lock if it's already mounted.
+       None have BKL
+                       s_umount
+alloc_inode:
+destroy_inode:
+dirty_inode:                           (must not sleep)
+write_inode:
+drop_inode:                            !!!inode_lock!!!
+delete_inode:
+put_super:             write
+write_super:           read
+sync_fs:               read
+freeze_fs:             read
+unfreeze_fs:           read
+statfs:                        no
+remount_fs:            maybe           (see below)
+clear_inode:
+umount_begin:          no
+show_options:          no              (namespace_sem)
+quota_read:            no              (see below)
+quota_write:           no              (see below)
+
+->remount_fs() will have the s_umount exclusive lock if it's already mounted.
 When called from get_sb_single, it does NOT have the s_umount lock.
 ->quota_read() and ->quota_write() functions are both guaranteed to
 be the only ones operating on the quota file by the quota code (via
index e716aadb3a337006865cfdfd8e53511adb20e787..40ec633527600be750ef15ec4f8706c8bcae0f01 100644 (file)
@@ -188,13 +188,18 @@ Solution: Exclude affected source files from profiling by specifying
           GCOV_PROFILE := n or GCOV_PROFILE_basename.o := n in the
           corresponding Makefile.
 
+Problem:  Files copied from sysfs appear empty or incomplete.
+Cause:    Due to the way seq_file works, some tools such as cp or tar
+          may not correctly copy files from sysfs.
+Solution: Use 'cat' to read .gcda files and 'cp -d' to copy links.
+          Alternatively use the mechanism shown in Appendix B.
+
 
 Appendix A: gather_on_build.sh
 ==============================
 
 Sample script to gather coverage meta files on the build machine
 (see 6a):
-
 #!/bin/bash
 
 KSRC=$1
@@ -226,7 +231,7 @@ Appendix B: gather_on_test.sh
 Sample script to gather coverage data files on the test machine
 (see 6b):
 
-#!/bin/bash
+#!/bin/bash -e
 
 DEST=$1
 GCDA=/sys/kernel/debug/gcov
@@ -236,11 +241,13 @@ if [ -z "$DEST" ] ; then
   exit 1
 fi
 
-find $GCDA -name '*.gcno' -o -name '*.gcda' | tar cfz $DEST -T -
+TEMPDIR=$(mktemp -d)
+echo Collecting data..
+find $GCDA -type d -exec mkdir -p $TEMPDIR/\{\} \;
+find $GCDA -name '*.gcda' -exec sh -c 'cat < $0 > '$TEMPDIR'/$0' {} \;
+find $GCDA -name '*.gcno' -exec sh -c 'cp -d $0 '$TEMPDIR'/$0' {} \;
+tar czf $DEST -C $TEMPDIR sys
+rm -rf $TEMPDIR
 
-if [ $? -eq 0 ] ; then
-  echo "$DEST successfully created, copy to build system and unpack with:"
-  echo "  tar xfz $DEST"
-else
-  echo "Could not create file $DEST"
-fi
+echo "$DEST successfully created, copy to build system and unpack with:"
+echo "  tar xfz $DEST"
index 2582e7aea29fa5391c933c836df08c6e268b8cd0..81cdb7d5e3801a604c3da0686838559068c25403 100644 (file)
@@ -229,14 +229,6 @@ and is between 256 and 4096 characters. It is defined in the file
                        to assume that this machine's pmtimer latches its value
                        and always returns good values.
 
-       acpi.power_nocheck=     [HW,ACPI]
-                       Format: 1/0 enable/disable the check of power state.
-                       On some bogus BIOS the _PSC object/_STA object of
-                       power resource can't return the correct device power
-                       state. In such case it is unneccessary to check its
-                       power state again in power transition.
-                       1 : disable the power state check
-
        acpi_sci=       [HW,ACPI] ACPI System Control Interrupt trigger mode
                        Format: { level | edge | high | low }
 
@@ -1728,8 +1720,8 @@ and is between 256 and 4096 characters. It is defined in the file
        oprofile.cpu_type=      Force an oprofile cpu type
                        This might be useful if you have an older oprofile
                        userland or if you want common events.
-                       Format: { archperfmon }
-                       archperfmon: [X86] Force use of architectural
+                       Format: { arch_perfmon }
+                       arch_perfmon: [X86] Force use of architectural
                                perfmon on Intel CPUs instead of the
                                CPU specific event set.
 
@@ -1863,7 +1855,7 @@ and is between 256 and 4096 characters. It is defined in the file
                                IRQ routing is enabled.
                noacpi          [X86] Do not use ACPI for IRQ routing
                                or for PCI scanning.
-               nocrs           [X86] Don't use _CRS for PCI resource
+               use_crs         [X86] Use _CRS for PCI resource
                                allocation.
                routeirq        Do IRQ routing for all PCI devices.
                                This is normally done in pci_enable_device(),
@@ -1923,6 +1915,12 @@ and is between 256 and 4096 characters. It is defined in the file
                        Format: { 0 | 1 }
                        See arch/parisc/kernel/pdc_chassis.c
 
+       percpu_alloc=   [X86] Select which percpu first chunk allocator to use.
+                       Allowed values are one of "lpage", "embed" and "4k".
+                       See comments in arch/x86/kernel/setup_percpu.c for
+                       details on each allocator.  This parameter is primarily
+                       for debugging and performance comparison.
+
        pf.             [PARIDE]
                        See Documentation/blockdev/paride.txt.
 
index 0112da3b9ab87f731006993c76e1a7fdc4eddcaa..89068030b01bbdb34392df6bf4fd8782d928ac57 100644 (file)
@@ -16,13 +16,17 @@ Usage
 -----
 
 CONFIG_DEBUG_KMEMLEAK in "Kernel hacking" has to be enabled. A kernel
-thread scans the memory every 10 minutes (by default) and prints any new
-unreferenced objects found. To trigger an intermediate scan and display
-all the possible memory leaks:
+thread scans the memory every 10 minutes (by default) and prints the
+number of new unreferenced objects found. To display the details of all
+the possible memory leaks:
 
   # mount -t debugfs nodev /sys/kernel/debug/
   # cat /sys/kernel/debug/kmemleak
 
+To trigger an intermediate memory scan:
+
+  # echo scan > /sys/kernel/debug/kmemleak
+
 Note that the orphan objects are listed in the order they were allocated
 and one object at the beginning of the list may cause other subsequent
 objects to be reported as orphan.
@@ -31,16 +35,21 @@ Memory scanning parameters can be modified at run-time by writing to the
 /sys/kernel/debug/kmemleak file. The following parameters are supported:
 
   off          - disable kmemleak (irreversible)
-  stack=on     - enable the task stacks scanning
+  stack=on     - enable the task stacks scanning (default)
   stack=off    - disable the tasks stacks scanning
-  scan=on      - start the automatic memory scanning thread
+  scan=on      - start the automatic memory scanning thread (default)
   scan=off     - stop the automatic memory scanning thread
-  scan=<secs>  - set the automatic memory scanning period in seconds (0
-                 to disable it)
+  scan=<secs>  - set the automatic memory scanning period in seconds
+                 (default 600, 0 to stop the automatic scanning)
+  scan         - trigger a memory scan
 
 Kmemleak can also be disabled at boot-time by passing "kmemleak=off" on
 the kernel command line.
 
+Memory may be allocated or freed before kmemleak is initialised and
+these actions are stored in an early log buffer. The size of this buffer
+is configured via the CONFIG_DEBUG_KMEMLEAK_EARLY_LOG_SIZE option.
+
 Basic Algorithm
 ---------------
 
index 78e354b42f6785cd07a0e12b56b482fde4b8d10b..f2296ecedb89d41e6afec1d3ea239256cb4fe768 100644 (file)
@@ -920,7 +920,7 @@ The available commands are:
        echo '<LED number> off' >/proc/acpi/ibm/led
        echo '<LED number> blink' >/proc/acpi/ibm/led
 
-The <LED number> range is 0 to 7. The set of LEDs that can be
+The <LED number> range is 0 to 15. The set of LEDs that can be
 controlled varies from model to model. Here is the common ThinkPad
 mapping:
 
@@ -932,6 +932,11 @@ mapping:
        5 - UltraBase battery slot
        6 - (unknown)
        7 - standby
+       8 - dock status 1
+       9 - dock status 2
+       10, 11 - (unknown)
+       12 - thinkvantage
+       13, 14, 15 - (unknown)
 
 All of the above can be turned on and off and can be made to blink.
 
@@ -940,10 +945,12 @@ sysfs notes:
 The ThinkPad LED sysfs interface is described in detail by the LED class
 documentation, in Documentation/leds-class.txt.
 
-The leds are named (in LED ID order, from 0 to 7):
+The LEDs are named (in LED ID order, from 0 to 12):
 "tpacpi::power", "tpacpi:orange:batt", "tpacpi:green:batt",
 "tpacpi::dock_active", "tpacpi::bay_active", "tpacpi::dock_batt",
-"tpacpi::unknown_led", "tpacpi::standby".
+"tpacpi::unknown_led", "tpacpi::standby", "tpacpi::dock_status1",
+"tpacpi::dock_status2", "tpacpi::unknown_led2", "tpacpi::unknown_led3",
+"tpacpi::thinkvantage".
 
 Due to limitations in the sysfs LED class, if the status of the LED
 indicators cannot be read due to an error, thinkpad-acpi will report it as
@@ -958,6 +965,12 @@ ThinkPad indicator LED should blink in hardware accelerated mode, use the
 "timer" trigger, and leave the delay_on and delay_off parameters set to
 zero (to request hardware acceleration autodetection).
 
+LEDs that are known not to exist in a given ThinkPad model are not
+made available through the sysfs interface.  If you have a dock and you
+notice there are LEDs listed for your ThinkPad that do not exist (and
+are not in the dock), or if you notice that there are missing LEDs,
+a report to ibm-acpi-devel@lists.sourceforge.net is appreciated.
+
 
 ACPI sounds -- /proc/acpi/ibm/beep
 ----------------------------------
@@ -1156,17 +1169,19 @@ may not be distinct.  Later Lenovo models that implement the ACPI
 display backlight brightness control methods have 16 levels, ranging
 from 0 to 15.
 
-There are two interfaces to the firmware for direct brightness control,
-EC and UCMS (or CMOS).  To select which one should be used, use the
-brightness_mode module parameter: brightness_mode=1 selects EC mode,
-brightness_mode=2 selects UCMS mode, brightness_mode=3 selects EC
-mode with NVRAM backing (so that brightness changes are remembered
-across shutdown/reboot).
+For IBM ThinkPads, there are two interfaces to the firmware for direct
+brightness control, EC and UCMS (or CMOS).  To select which one should be
+used, use the brightness_mode module parameter: brightness_mode=1 selects
+EC mode, brightness_mode=2 selects UCMS mode, brightness_mode=3 selects EC
+mode with NVRAM backing (so that brightness changes are remembered across
+shutdown/reboot).
 
 The driver tries to select which interface to use from a table of
 defaults for each ThinkPad model.  If it makes a wrong choice, please
 report this as a bug, so that we can fix it.
 
+Lenovo ThinkPads only support brightness_mode=2 (UCMS).
+
 When display backlight brightness controls are available through the
 standard ACPI interface, it is best to use it instead of this direct
 ThinkPad-specific interface.  The driver will disable its native
@@ -1254,7 +1269,7 @@ Fan control and monitoring: fan speed, fan enable/disable
 
 procfs: /proc/acpi/ibm/fan
 sysfs device attributes: (hwmon "thinkpad") fan1_input, pwm1,
-                         pwm1_enable
+                         pwm1_enable, fan2_input
 sysfs hwmon driver attributes: fan_watchdog
 
 NOTE NOTE NOTE: fan control operations are disabled by default for
@@ -1267,6 +1282,9 @@ from the hardware registers of the embedded controller.  This is known
 to work on later R, T, X and Z series ThinkPads but may show a bogus
 value on other models.
 
+Some Lenovo ThinkPads support a secondary fan.  This fan cannot be
+controlled separately, it shares the main fan control.
+
 Fan levels:
 
 Most ThinkPad fans work in "levels" at the firmware interface.  Level 0
@@ -1397,6 +1415,11 @@ hwmon device attribute fan1_input:
        which can take up to two minutes.  May return rubbish on older
        ThinkPads.
 
+hwmon device attribute fan2_input:
+       Fan tachometer reading, in RPM, for the secondary fan.
+       Available only on some ThinkPads.  If the secondary fan is
+       not installed, will always read 0.
+
 hwmon driver attribute fan_watchdog:
        Fan safety watchdog timer interval, in seconds.  Minimum is
        1 second, maximum is 120 seconds.  0 disables the watchdog.
@@ -1555,3 +1578,7 @@ Sysfs interface changelog:
 0x020300:      hotkey enable/disable support removed, attributes
                hotkey_bios_enabled and hotkey_enable deprecated and
                marked for removal.
+
+0x020400:      Marker for 16 LEDs support.  Also, LEDs that are known
+               to not exist in a given model are not registered with
+               the LED sysfs class anymore.
diff --git a/Documentation/leds-lp3944.txt b/Documentation/leds-lp3944.txt
new file mode 100644 (file)
index 0000000..c6eda18
--- /dev/null
@@ -0,0 +1,50 @@
+Kernel driver lp3944
+====================
+
+  * National Semiconductor LP3944 Fun-light Chip
+    Prefix: 'lp3944'
+    Addresses scanned: None (see the Notes section below)
+    Datasheet: Publicly available at the National Semiconductor website
+               http://www.national.com/pf/LP/LP3944.html
+
+Authors:
+        Antonio Ospite <ospite@studenti.unina.it>
+
+
+Description
+-----------
+The LP3944 is a helper chip that can drive up to 8 leds, with two programmable
+DIM modes; it could even be used as a gpio expander but this driver assumes it
+is used as a led controller.
+
+The DIM modes are used to set _blink_ patterns for leds, the pattern is
+specified supplying two parameters:
+  - period: from 0s to 1.6s
+  - duty cycle: percentage of the period the led is on, from 0 to 100
+
+Setting a led in DIM0 or DIM1 mode makes it blink according to the pattern.
+See the datasheet for details.
+
+LP3944 can be found on Motorola A910 smartphone, where it drives the rgb
+leds, the camera flash light and the lcds power.
+
+
+Notes
+-----
+The chip is used mainly in embedded contexts, so this driver expects it is
+registered using the i2c_board_info mechanism.
+
+To register the chip at address 0x60 on adapter 0, set the platform data
+according to include/linux/leds-lp3944.h, set the i2c board info:
+
+       static struct i2c_board_info __initdata a910_i2c_board_info[] = {
+               {
+                       I2C_BOARD_INFO("lp3944", 0x60),
+                       .platform_data = &a910_lp3944_leds,
+               },
+       };
+
+and register it in the platform init function
+
+       i2c_register_board_info(0, a910_i2c_board_info,
+                       ARRAY_SIZE(a910_i2c_board_info));
index 8d999d862d0e646ffb9c7949898d3987fc2004a4..79f533f38c6112d64bed9398c44d31cf3b552f6b 100644 (file)
@@ -1238,1122 +1238,7 @@ descriptions for the SOC devices for which new nodes have been
 defined; this list will expand as more and more SOC-containing
 platforms are moved over to use the flattened-device-tree model.
 
-   a) PHY nodes
-
-   Required properties:
-
-    - device_type : Should be "ethernet-phy"
-    - interrupts : <a b> where a is the interrupt number and b is a
-      field that represents an encoding of the sense and level
-      information for the interrupt.  This should be encoded based on
-      the information in section 2) depending on the type of interrupt
-      controller you have.
-    - interrupt-parent : the phandle for the interrupt controller that
-      services interrupts for this device.
-    - reg : The ID number for the phy, usually a small integer
-    - linux,phandle :  phandle for this node; likely referenced by an
-      ethernet controller node.
-
-
-   Example:
-
-       ethernet-phy@0 {
-               linux,phandle = <2452000>
-               interrupt-parent = <40000>;
-               interrupts = <35 1>;
-               reg = <0>;
-               device_type = "ethernet-phy";
-       };
-
-
-   b) Interrupt controllers
-
-   Some SOC devices contain interrupt controllers that are different
-   from the standard Open PIC specification.  The SOC device nodes for
-   these types of controllers should be specified just like a standard
-   OpenPIC controller.  Sense and level information should be encoded
-   as specified in section 2) of this chapter for each device that
-   specifies an interrupt.
-
-   Example :
-
-       pic@40000 {
-               linux,phandle = <40000>;
-               interrupt-controller;
-               #address-cells = <0>;
-               reg = <40000 40000>;
-               compatible = "chrp,open-pic";
-               device_type = "open-pic";
-       };
-
-    c) 4xx/Axon EMAC ethernet nodes
-
-    The EMAC ethernet controller in IBM and AMCC 4xx chips, and also
-    the Axon bridge.  To operate this needs to interact with a ths
-    special McMAL DMA controller, and sometimes an RGMII or ZMII
-    interface.  In addition to the nodes and properties described
-    below, the node for the OPB bus on which the EMAC sits must have a
-    correct clock-frequency property.
-
-      i) The EMAC node itself
-
-    Required properties:
-    - device_type       : "network"
-
-    - compatible        : compatible list, contains 2 entries, first is
-                         "ibm,emac-CHIP" where CHIP is the host ASIC (440gx,
-                         405gp, Axon) and second is either "ibm,emac" or
-                         "ibm,emac4".  For Axon, thus, we have: "ibm,emac-axon",
-                         "ibm,emac4"
-    - interrupts        : <interrupt mapping for EMAC IRQ and WOL IRQ>
-    - interrupt-parent  : optional, if needed for interrupt mapping
-    - reg               : <registers mapping>
-    - local-mac-address : 6 bytes, MAC address
-    - mal-device        : phandle of the associated McMAL node
-    - mal-tx-channel    : 1 cell, index of the tx channel on McMAL associated
-                         with this EMAC
-    - mal-rx-channel    : 1 cell, index of the rx channel on McMAL associated
-                         with this EMAC
-    - cell-index        : 1 cell, hardware index of the EMAC cell on a given
-                         ASIC (typically 0x0 and 0x1 for EMAC0 and EMAC1 on
-                         each Axon chip)
-    - max-frame-size    : 1 cell, maximum frame size supported in bytes
-    - rx-fifo-size      : 1 cell, Rx fifo size in bytes for 10 and 100 Mb/sec
-                         operations.
-                         For Axon, 2048
-    - tx-fifo-size      : 1 cell, Tx fifo size in bytes for 10 and 100 Mb/sec
-                         operations.
-                         For Axon, 2048.
-    - fifo-entry-size   : 1 cell, size of a fifo entry (used to calculate
-                         thresholds).
-                         For Axon, 0x00000010
-    - mal-burst-size    : 1 cell, MAL burst size (used to calculate thresholds)
-                         in bytes.
-                         For Axon, 0x00000100 (I think ...)
-    - phy-mode          : string, mode of operations of the PHY interface.
-                         Supported values are: "mii", "rmii", "smii", "rgmii",
-                         "tbi", "gmii", rtbi", "sgmii".
-                         For Axon on CAB, it is "rgmii"
-    - mdio-device       : 1 cell, required iff using shared MDIO registers
-                         (440EP).  phandle of the EMAC to use to drive the
-                         MDIO lines for the PHY used by this EMAC.
-    - zmii-device       : 1 cell, required iff connected to a ZMII.  phandle of
-                         the ZMII device node
-    - zmii-channel      : 1 cell, required iff connected to a ZMII.  Which ZMII
-                         channel or 0xffffffff if ZMII is only used for MDIO.
-    - rgmii-device      : 1 cell, required iff connected to an RGMII. phandle
-                         of the RGMII device node.
-                         For Axon: phandle of plb5/plb4/opb/rgmii
-    - rgmii-channel     : 1 cell, required iff connected to an RGMII.  Which
-                         RGMII channel is used by this EMAC.
-                         Fox Axon: present, whatever value is appropriate for each
-                         EMAC, that is the content of the current (bogus) "phy-port"
-                         property.
-
-    Optional properties:
-    - phy-address       : 1 cell, optional, MDIO address of the PHY. If absent,
-                         a search is performed.
-    - phy-map           : 1 cell, optional, bitmap of addresses to probe the PHY
-                         for, used if phy-address is absent. bit 0x00000001 is
-                         MDIO address 0.
-                         For Axon it can be absent, though my current driver
-                         doesn't handle phy-address yet so for now, keep
-                         0x00ffffff in it.
-    - rx-fifo-size-gige : 1 cell, Rx fifo size in bytes for 1000 Mb/sec
-                         operations (if absent the value is the same as
-                         rx-fifo-size).  For Axon, either absent or 2048.
-    - tx-fifo-size-gige : 1 cell, Tx fifo size in bytes for 1000 Mb/sec
-                         operations (if absent the value is the same as
-                         tx-fifo-size). For Axon, either absent or 2048.
-    - tah-device        : 1 cell, optional. If connected to a TAH engine for
-                         offload, phandle of the TAH device node.
-    - tah-channel       : 1 cell, optional. If appropriate, channel used on the
-                         TAH engine.
-
-    Example:
-
-       EMAC0: ethernet@40000800 {
-               device_type = "network";
-               compatible = "ibm,emac-440gp", "ibm,emac";
-               interrupt-parent = <&UIC1>;
-               interrupts = <1c 4 1d 4>;
-               reg = <40000800 70>;
-               local-mac-address = [00 04 AC E3 1B 1E];
-               mal-device = <&MAL0>;
-               mal-tx-channel = <0 1>;
-               mal-rx-channel = <0>;
-               cell-index = <0>;
-               max-frame-size = <5dc>;
-               rx-fifo-size = <1000>;
-               tx-fifo-size = <800>;
-               phy-mode = "rmii";
-               phy-map = <00000001>;
-               zmii-device = <&ZMII0>;
-               zmii-channel = <0>;
-       };
-
-      ii) McMAL node
-
-    Required properties:
-    - device_type        : "dma-controller"
-    - compatible         : compatible list, containing 2 entries, first is
-                          "ibm,mcmal-CHIP" where CHIP is the host ASIC (like
-                          emac) and the second is either "ibm,mcmal" or
-                          "ibm,mcmal2".
-                          For Axon, "ibm,mcmal-axon","ibm,mcmal2"
-    - interrupts         : <interrupt mapping for the MAL interrupts sources:
-                           5 sources: tx_eob, rx_eob, serr, txde, rxde>.
-                           For Axon: This is _different_ from the current
-                          firmware.  We use the "delayed" interrupts for txeob
-                          and rxeob. Thus we end up with mapping those 5 MPIC
-                          interrupts, all level positive sensitive: 10, 11, 32,
-                          33, 34 (in decimal)
-    - dcr-reg            : < DCR registers range >
-    - dcr-parent         : if needed for dcr-reg
-    - num-tx-chans       : 1 cell, number of Tx channels
-    - num-rx-chans       : 1 cell, number of Rx channels
-
-      iii) ZMII node
-
-    Required properties:
-    - compatible         : compatible list, containing 2 entries, first is
-                          "ibm,zmii-CHIP" where CHIP is the host ASIC (like
-                          EMAC) and the second is "ibm,zmii".
-                          For Axon, there is no ZMII node.
-    - reg                : <registers mapping>
-
-      iv) RGMII node
-
-    Required properties:
-    - compatible         : compatible list, containing 2 entries, first is
-                          "ibm,rgmii-CHIP" where CHIP is the host ASIC (like
-                          EMAC) and the second is "ibm,rgmii".
-                           For Axon, "ibm,rgmii-axon","ibm,rgmii"
-    - reg                : <registers mapping>
-    - revision           : as provided by the RGMII new version register if
-                          available.
-                          For Axon: 0x0000012a
-
-   d) Xilinx IP cores
-
-   The Xilinx EDK toolchain ships with a set of IP cores (devices) for use
-   in Xilinx Spartan and Virtex FPGAs.  The devices cover the whole range
-   of standard device types (network, serial, etc.) and miscellaneous
-   devices (gpio, LCD, spi, etc).  Also, since these devices are
-   implemented within the fpga fabric every instance of the device can be
-   synthesised with different options that change the behaviour.
-
-   Each IP-core has a set of parameters which the FPGA designer can use to
-   control how the core is synthesized.  Historically, the EDK tool would
-   extract the device parameters relevant to device drivers and copy them
-   into an 'xparameters.h' in the form of #define symbols.  This tells the
-   device drivers how the IP cores are configured, but it requres the kernel
-   to be recompiled every time the FPGA bitstream is resynthesized.
-
-   The new approach is to export the parameters into the device tree and
-   generate a new device tree each time the FPGA bitstream changes.  The
-   parameters which used to be exported as #defines will now become
-   properties of the device node.  In general, device nodes for IP-cores
-   will take the following form:
-
-       (name): (generic-name)@(base-address) {
-               compatible = "xlnx,(ip-core-name)-(HW_VER)"
-                            [, (list of compatible devices), ...];
-               reg = <(baseaddr) (size)>;
-               interrupt-parent = <&interrupt-controller-phandle>;
-               interrupts = < ... >;
-               xlnx,(parameter1) = "(string-value)";
-               xlnx,(parameter2) = <(int-value)>;
-       };
-
-       (generic-name):   an open firmware-style name that describes the
-                       generic class of device.  Preferably, this is one word, such
-                       as 'serial' or 'ethernet'.
-       (ip-core-name): the name of the ip block (given after the BEGIN
-                       directive in system.mhs).  Should be in lowercase
-                       and all underscores '_' converted to dashes '-'.
-       (name):         is derived from the "PARAMETER INSTANCE" value.
-       (parameter#):   C_* parameters from system.mhs.  The C_ prefix is
-                       dropped from the parameter name, the name is converted
-                       to lowercase and all underscore '_' characters are
-                       converted to dashes '-'.
-       (baseaddr):     the baseaddr parameter value (often named C_BASEADDR).
-       (HW_VER):       from the HW_VER parameter.
-       (size):         the address range size (often C_HIGHADDR - C_BASEADDR + 1).
-
-   Typically, the compatible list will include the exact IP core version
-   followed by an older IP core version which implements the same
-   interface or any other device with the same interface.
-
-   'reg', 'interrupt-parent' and 'interrupts' are all optional properties.
-
-   For example, the following block from system.mhs:
-
-       BEGIN opb_uartlite
-               PARAMETER INSTANCE = opb_uartlite_0
-               PARAMETER HW_VER = 1.00.b
-               PARAMETER C_BAUDRATE = 115200
-               PARAMETER C_DATA_BITS = 8
-               PARAMETER C_ODD_PARITY = 0
-               PARAMETER C_USE_PARITY = 0
-               PARAMETER C_CLK_FREQ = 50000000
-               PARAMETER C_BASEADDR = 0xEC100000
-               PARAMETER C_HIGHADDR = 0xEC10FFFF
-               BUS_INTERFACE SOPB = opb_7
-               PORT OPB_Clk = CLK_50MHz
-               PORT Interrupt = opb_uartlite_0_Interrupt
-               PORT RX = opb_uartlite_0_RX
-               PORT TX = opb_uartlite_0_TX
-               PORT OPB_Rst = sys_bus_reset_0
-       END
-
-   becomes the following device tree node:
-
-       opb_uartlite_0: serial@ec100000 {
-               device_type = "serial";
-               compatible = "xlnx,opb-uartlite-1.00.b";
-               reg = <ec100000 10000>;
-               interrupt-parent = <&opb_intc_0>;
-               interrupts = <1 0>; // got this from the opb_intc parameters
-               current-speed = <d#115200>;     // standard serial device prop
-               clock-frequency = <d#50000000>; // standard serial device prop
-               xlnx,data-bits = <8>;
-               xlnx,odd-parity = <0>;
-               xlnx,use-parity = <0>;
-       };
-
-   Some IP cores actually implement 2 or more logical devices.  In
-   this case, the device should still describe the whole IP core with
-   a single node and add a child node for each logical device.  The
-   ranges property can be used to translate from parent IP-core to the
-   registers of each device.  In addition, the parent node should be
-   compatible with the bus type 'xlnx,compound', and should contain
-   #address-cells and #size-cells, as with any other bus.  (Note: this
-   makes the assumption that both logical devices have the same bus
-   binding.  If this is not true, then separate nodes should be used
-   for each logical device).  The 'cell-index' property can be used to
-   enumerate logical devices within an IP core.  For example, the
-   following is the system.mhs entry for the dual ps2 controller found
-   on the ml403 reference design.
-
-       BEGIN opb_ps2_dual_ref
-               PARAMETER INSTANCE = opb_ps2_dual_ref_0
-               PARAMETER HW_VER = 1.00.a
-               PARAMETER C_BASEADDR = 0xA9000000
-               PARAMETER C_HIGHADDR = 0xA9001FFF
-               BUS_INTERFACE SOPB = opb_v20_0
-               PORT Sys_Intr1 = ps2_1_intr
-               PORT Sys_Intr2 = ps2_2_intr
-               PORT Clkin1 = ps2_clk_rx_1
-               PORT Clkin2 = ps2_clk_rx_2
-               PORT Clkpd1 = ps2_clk_tx_1
-               PORT Clkpd2 = ps2_clk_tx_2
-               PORT Rx1 = ps2_d_rx_1
-               PORT Rx2 = ps2_d_rx_2
-               PORT Txpd1 = ps2_d_tx_1
-               PORT Txpd2 = ps2_d_tx_2
-       END
-
-   It would result in the following device tree nodes:
-
-       opb_ps2_dual_ref_0: opb-ps2-dual-ref@a9000000 {
-               #address-cells = <1>;
-               #size-cells = <1>;
-               compatible = "xlnx,compound";
-               ranges = <0 a9000000 2000>;
-               // If this device had extra parameters, then they would
-               // go here.
-               ps2@0 {
-                       compatible = "xlnx,opb-ps2-dual-ref-1.00.a";
-                       reg = <0 40>;
-                       interrupt-parent = <&opb_intc_0>;
-                       interrupts = <3 0>;
-                       cell-index = <0>;
-               };
-               ps2@1000 {
-                       compatible = "xlnx,opb-ps2-dual-ref-1.00.a";
-                       reg = <1000 40>;
-                       interrupt-parent = <&opb_intc_0>;
-                       interrupts = <3 0>;
-                       cell-index = <0>;
-               };
-       };
-
-   Also, the system.mhs file defines bus attachments from the processor
-   to the devices.  The device tree structure should reflect the bus
-   attachments.  Again an example; this system.mhs fragment:
-
-       BEGIN ppc405_virtex4
-               PARAMETER INSTANCE = ppc405_0
-               PARAMETER HW_VER = 1.01.a
-               BUS_INTERFACE DPLB = plb_v34_0
-               BUS_INTERFACE IPLB = plb_v34_0
-       END
-
-       BEGIN opb_intc
-               PARAMETER INSTANCE = opb_intc_0
-               PARAMETER HW_VER = 1.00.c
-               PARAMETER C_BASEADDR = 0xD1000FC0
-               PARAMETER C_HIGHADDR = 0xD1000FDF
-               BUS_INTERFACE SOPB = opb_v20_0
-       END
-
-       BEGIN opb_uart16550
-               PARAMETER INSTANCE = opb_uart16550_0
-               PARAMETER HW_VER = 1.00.d
-               PARAMETER C_BASEADDR = 0xa0000000
-               PARAMETER C_HIGHADDR = 0xa0001FFF
-               BUS_INTERFACE SOPB = opb_v20_0
-       END
-
-       BEGIN plb_v34
-               PARAMETER INSTANCE = plb_v34_0
-               PARAMETER HW_VER = 1.02.a
-       END
-
-       BEGIN plb_bram_if_cntlr
-               PARAMETER INSTANCE = plb_bram_if_cntlr_0
-               PARAMETER HW_VER = 1.00.b
-               PARAMETER C_BASEADDR = 0xFFFF0000
-               PARAMETER C_HIGHADDR = 0xFFFFFFFF
-               BUS_INTERFACE SPLB = plb_v34_0
-       END
-
-       BEGIN plb2opb_bridge
-               PARAMETER INSTANCE = plb2opb_bridge_0
-               PARAMETER HW_VER = 1.01.a
-               PARAMETER C_RNG0_BASEADDR = 0x20000000
-               PARAMETER C_RNG0_HIGHADDR = 0x3FFFFFFF
-               PARAMETER C_RNG1_BASEADDR = 0x60000000
-               PARAMETER C_RNG1_HIGHADDR = 0x7FFFFFFF
-               PARAMETER C_RNG2_BASEADDR = 0x80000000
-               PARAMETER C_RNG2_HIGHADDR = 0xBFFFFFFF
-               PARAMETER C_RNG3_BASEADDR = 0xC0000000
-               PARAMETER C_RNG3_HIGHADDR = 0xDFFFFFFF
-               BUS_INTERFACE SPLB = plb_v34_0
-               BUS_INTERFACE MOPB = opb_v20_0
-       END
-
-   Gives this device tree (some properties removed for clarity):
-
-       plb@0 {
-               #address-cells = <1>;
-               #size-cells = <1>;
-               compatible = "xlnx,plb-v34-1.02.a";
-               device_type = "ibm,plb";
-               ranges; // 1:1 translation
-
-               plb_bram_if_cntrl_0: bram@ffff0000 {
-                       reg = <ffff0000 10000>;
-               }
-
-               opb@20000000 {
-                       #address-cells = <1>;
-                       #size-cells = <1>;
-                       ranges = <20000000 20000000 20000000
-                                 60000000 60000000 20000000
-                                 80000000 80000000 40000000
-                                 c0000000 c0000000 20000000>;
-
-                       opb_uart16550_0: serial@a0000000 {
-                               reg = <a00000000 2000>;
-                       };
-
-                       opb_intc_0: interrupt-controller@d1000fc0 {
-                               reg = <d1000fc0 20>;
-                       };
-               };
-       };
-
-   That covers the general approach to binding xilinx IP cores into the
-   device tree.  The following are bindings for specific devices:
-
-      i) Xilinx ML300 Framebuffer
-
-      Simple framebuffer device from the ML300 reference design (also on the
-      ML403 reference design as well as others).
-
-      Optional properties:
-       - resolution = <xres yres> : pixel resolution of framebuffer.  Some
-                                    implementations use a different resolution.
-                                    Default is <d#640 d#480>
-       - virt-resolution = <xvirt yvirt> : Size of framebuffer in memory.
-                                           Default is <d#1024 d#480>.
-       - rotate-display (empty) : rotate display 180 degrees.
-
-      ii) Xilinx SystemACE
-
-      The Xilinx SystemACE device is used to program FPGAs from an FPGA
-      bitstream stored on a CF card.  It can also be used as a generic CF
-      interface device.
-
-      Optional properties:
-       - 8-bit (empty) : Set this property for SystemACE in 8 bit mode
-
-      iii) Xilinx EMAC and Xilinx TEMAC
-
-      Xilinx Ethernet devices.  In addition to general xilinx properties
-      listed above, nodes for these devices should include a phy-handle
-      property, and may include other common network device properties
-      like local-mac-address.
-
-      iv) Xilinx Uartlite
-
-      Xilinx uartlite devices are simple fixed speed serial ports.
-
-      Required properties:
-       - current-speed : Baud rate of uartlite
-
-      v) Xilinx hwicap
-
-               Xilinx hwicap devices provide access to the configuration logic
-               of the FPGA through the Internal Configuration Access Port
-               (ICAP).  The ICAP enables partial reconfiguration of the FPGA,
-               readback of the configuration information, and some control over
-               'warm boots' of the FPGA fabric.
-
-               Required properties:
-               - xlnx,family : The family of the FPGA, necessary since the
-                      capabilities of the underlying ICAP hardware
-                      differ between different families.  May be
-                      'virtex2p', 'virtex4', or 'virtex5'.
-
-      vi) Xilinx Uart 16550
-
-      Xilinx UART 16550 devices are very similar to the NS16550 but with
-      different register spacing and an offset from the base address.
-
-      Required properties:
-       - clock-frequency : Frequency of the clock input
-       - reg-offset : A value of 3 is required
-       - reg-shift : A value of 2 is required
-
-    e) USB EHCI controllers
-
-    Required properties:
-      - compatible : should be "usb-ehci".
-      - reg : should contain at least address and length of the standard EHCI
-        register set for the device. Optional platform-dependent registers
-        (debug-port or other) can be also specified here, but only after
-        definition of standard EHCI registers.
-      - interrupts : one EHCI interrupt should be described here.
-    If device registers are implemented in big endian mode, the device
-    node should have "big-endian-regs" property.
-    If controller implementation operates with big endian descriptors,
-    "big-endian-desc" property should be specified.
-    If both big endian registers and descriptors are used by the controller
-    implementation, "big-endian" property can be specified instead of having
-    both "big-endian-regs" and "big-endian-desc".
-
-     Example (Sequoia 440EPx):
-           ehci@e0000300 {
-                  compatible = "ibm,usb-ehci-440epx", "usb-ehci";
-                  interrupt-parent = <&UIC0>;
-                  interrupts = <1a 4>;
-                  reg = <0 e0000300 90 0 e0000390 70>;
-                  big-endian;
-          };
-
-   f) MDIO on GPIOs
-
-   Currently defined compatibles:
-   - virtual,gpio-mdio
-
-   MDC and MDIO lines connected to GPIO controllers are listed in the
-   gpios property as described in section VIII.1 in the following order:
-
-   MDC, MDIO.
-
-   Example:
-
-       mdio {
-               compatible = "virtual,mdio-gpio";
-               #address-cells = <1>;
-               #size-cells = <0>;
-               gpios = <&qe_pio_a 11
-                        &qe_pio_c 6>;
-       };
-
-    g) SPI (Serial Peripheral Interface) busses
-
-    SPI busses can be described with a node for the SPI master device
-    and a set of child nodes for each SPI slave on the bus.  For this
-    discussion, it is assumed that the system's SPI controller is in
-    SPI master mode.  This binding does not describe SPI controllers
-    in slave mode.
-
-    The SPI master node requires the following properties:
-    - #address-cells  - number of cells required to define a chip select
-                       address on the SPI bus.
-    - #size-cells     - should be zero.
-    - compatible      - name of SPI bus controller following generic names
-                       recommended practice.
-    No other properties are required in the SPI bus node.  It is assumed
-    that a driver for an SPI bus device will understand that it is an SPI bus.
-    However, the binding does not attempt to define the specific method for
-    assigning chip select numbers.  Since SPI chip select configuration is
-    flexible and non-standardized, it is left out of this binding with the
-    assumption that board specific platform code will be used to manage
-    chip selects.  Individual drivers can define additional properties to
-    support describing the chip select layout.
-
-    SPI slave nodes must be children of the SPI master node and can
-    contain the following properties.
-    - reg             - (required) chip select address of device.
-    - compatible      - (required) name of SPI device following generic names
-                       recommended practice
-    - spi-max-frequency - (required) Maximum SPI clocking speed of device in Hz
-    - spi-cpol        - (optional) Empty property indicating device requires
-                       inverse clock polarity (CPOL) mode
-    - spi-cpha        - (optional) Empty property indicating device requires
-                       shifted clock phase (CPHA) mode
-    - spi-cs-high     - (optional) Empty property indicating device requires
-                       chip select active high
-
-    SPI example for an MPC5200 SPI bus:
-               spi@f00 {
-                       #address-cells = <1>;
-                       #size-cells = <0>;
-                       compatible = "fsl,mpc5200b-spi","fsl,mpc5200-spi";
-                       reg = <0xf00 0x20>;
-                       interrupts = <2 13 0 2 14 0>;
-                       interrupt-parent = <&mpc5200_pic>;
-
-                       ethernet-switch@0 {
-                               compatible = "micrel,ks8995m";
-                               spi-max-frequency = <1000000>;
-                               reg = <0>;
-                       };
-
-                       codec@1 {
-                               compatible = "ti,tlv320aic26";
-                               spi-max-frequency = <100000>;
-                               reg = <1>;
-                       };
-               };
-
-VII - Marvell Discovery mv64[345]6x System Controller chips
-===========================================================
-
-The Marvell mv64[345]60 series of system controller chips contain
-many of the peripherals needed to implement a complete computer
-system.  In this section, we define device tree nodes to describe
-the system controller chip itself and each of the peripherals
-which it contains.  Compatible string values for each node are
-prefixed with the string "marvell,", for Marvell Technology Group Ltd.
-
-1) The /system-controller node
-
-  This node is used to represent the system-controller and must be
-  present when the system uses a system controller chip. The top-level
-  system-controller node contains information that is global to all
-  devices within the system controller chip. The node name begins
-  with "system-controller" followed by the unit address, which is
-  the base address of the memory-mapped register set for the system
-  controller chip.
-
-  Required properties:
-
-    - ranges : Describes the translation of system controller addresses
-      for memory mapped registers.
-    - clock-frequency: Contains the main clock frequency for the system
-      controller chip.
-    - reg : This property defines the address and size of the
-      memory-mapped registers contained within the system controller
-      chip.  The address specified in the "reg" property should match
-      the unit address of the system-controller node.
-    - #address-cells : Address representation for system controller
-      devices.  This field represents the number of cells needed to
-      represent the address of the memory-mapped registers of devices
-      within the system controller chip.
-    - #size-cells : Size representation for for the memory-mapped
-      registers within the system controller chip.
-    - #interrupt-cells : Defines the width of cells used to represent
-      interrupts.
-
-  Optional properties:
-
-    - model : The specific model of the system controller chip.  Such
-      as, "mv64360", "mv64460", or "mv64560".
-    - compatible : A string identifying the compatibility identifiers
-      of the system controller chip.
-
-  The system-controller node contains child nodes for each system
-  controller device that the platform uses.  Nodes should not be created
-  for devices which exist on the system controller chip but are not used
-
-  Example Marvell Discovery mv64360 system-controller node:
-
-    system-controller@f1000000 { /* Marvell Discovery mv64360 */
-           #address-cells = <1>;
-           #size-cells = <1>;
-           model = "mv64360";                      /* Default */
-           compatible = "marvell,mv64360";
-           clock-frequency = <133333333>;
-           reg = <0xf1000000 0x10000>;
-           virtual-reg = <0xf1000000>;
-           ranges = <0x88000000 0x88000000 0x1000000 /* PCI 0 I/O Space */
-                   0x80000000 0x80000000 0x8000000 /* PCI 0 MEM Space */
-                   0xa0000000 0xa0000000 0x4000000 /* User FLASH */
-                   0x00000000 0xf1000000 0x0010000 /* Bridge's regs */
-                   0xf2000000 0xf2000000 0x0040000>;/* Integrated SRAM */
-
-           [ child node definitions... ]
-    }
-
-2) Child nodes of /system-controller
-
-   a) Marvell Discovery MDIO bus
-
-   The MDIO is a bus to which the PHY devices are connected.  For each
-   device that exists on this bus, a child node should be created.  See
-   the definition of the PHY node below for an example of how to define
-   a PHY.
-
-   Required properties:
-     - #address-cells : Should be <1>
-     - #size-cells : Should be <0>
-     - device_type : Should be "mdio"
-     - compatible : Should be "marvell,mv64360-mdio"
-
-   Example:
-
-     mdio {
-            #address-cells = <1>;
-            #size-cells = <0>;
-            device_type = "mdio";
-            compatible = "marvell,mv64360-mdio";
-
-            ethernet-phy@0 {
-                    ......
-            };
-     };
-
-
-   b) Marvell Discovery ethernet controller
-
-   The Discover ethernet controller is described with two levels
-   of nodes.  The first level describes an ethernet silicon block
-   and the second level describes up to 3 ethernet nodes within
-   that block.  The reason for the multiple levels is that the
-   registers for the node are interleaved within a single set
-   of registers.  The "ethernet-block" level describes the
-   shared register set, and the "ethernet" nodes describe ethernet
-   port-specific properties.
-
-   Ethernet block node
-
-   Required properties:
-     - #address-cells : <1>
-     - #size-cells : <0>
-     - compatible : "marvell,mv64360-eth-block"
-     - reg : Offset and length of the register set for this block
-
-   Example Discovery Ethernet block node:
-     ethernet-block@2000 {
-            #address-cells = <1>;
-            #size-cells = <0>;
-            compatible = "marvell,mv64360-eth-block";
-            reg = <0x2000 0x2000>;
-            ethernet@0 {
-                    .......
-            };
-     };
-
-   Ethernet port node
-
-   Required properties:
-     - device_type : Should be "network".
-     - compatible : Should be "marvell,mv64360-eth".
-     - reg : Should be <0>, <1>, or <2>, according to which registers
-       within the silicon block the device uses.
-     - interrupts : <a> where a is the interrupt number for the port.
-     - interrupt-parent : the phandle for the interrupt controller
-       that services interrupts for this device.
-     - phy : the phandle for the PHY connected to this ethernet
-       controller.
-     - local-mac-address : 6 bytes, MAC address
-
-   Example Discovery Ethernet port node:
-     ethernet@0 {
-            device_type = "network";
-            compatible = "marvell,mv64360-eth";
-            reg = <0>;
-            interrupts = <32>;
-            interrupt-parent = <&PIC>;
-            phy = <&PHY0>;
-            local-mac-address = [ 00 00 00 00 00 00 ];
-     };
-
-
-
-   c) Marvell Discovery PHY nodes
-
-   Required properties:
-     - device_type : Should be "ethernet-phy"
-     - interrupts : <a> where a is the interrupt number for this phy.
-     - interrupt-parent : the phandle for the interrupt controller that
-       services interrupts for this device.
-     - reg : The ID number for the phy, usually a small integer
-
-   Example Discovery PHY node:
-     ethernet-phy@1 {
-            device_type = "ethernet-phy";
-            compatible = "broadcom,bcm5421";
-            interrupts = <76>;      /* GPP 12 */
-            interrupt-parent = <&PIC>;
-            reg = <1>;
-     };
-
-
-   d) Marvell Discovery SDMA nodes
-
-   Represent DMA hardware associated with the MPSC (multiprotocol
-   serial controllers).
-
-   Required properties:
-     - compatible : "marvell,mv64360-sdma"
-     - reg : Offset and length of the register set for this device
-     - interrupts : <a> where a is the interrupt number for the DMA
-       device.
-     - interrupt-parent : the phandle for the interrupt controller
-       that services interrupts for this device.
-
-   Example Discovery SDMA node:
-     sdma@4000 {
-            compatible = "marvell,mv64360-sdma";
-            reg = <0x4000 0xc18>;
-            virtual-reg = <0xf1004000>;
-            interrupts = <36>;
-            interrupt-parent = <&PIC>;
-     };
-
-
-   e) Marvell Discovery BRG nodes
-
-   Represent baud rate generator hardware associated with the MPSC
-   (multiprotocol serial controllers).
-
-   Required properties:
-     - compatible : "marvell,mv64360-brg"
-     - reg : Offset and length of the register set for this device
-     - clock-src : A value from 0 to 15 which selects the clock
-       source for the baud rate generator.  This value corresponds
-       to the CLKS value in the BRGx configuration register.  See
-       the mv64x60 User's Manual.
-     - clock-frequence : The frequency (in Hz) of the baud rate
-       generator's input clock.
-     - current-speed : The current speed setting (presumably by
-       firmware) of the baud rate generator.
-
-   Example Discovery BRG node:
-     brg@b200 {
-            compatible = "marvell,mv64360-brg";
-            reg = <0xb200 0x8>;
-            clock-src = <8>;
-            clock-frequency = <133333333>;
-            current-speed = <9600>;
-     };
-
-
-   f) Marvell Discovery CUNIT nodes
-
-   Represent the Serial Communications Unit device hardware.
-
-   Required properties:
-     - reg : Offset and length of the register set for this device
-
-   Example Discovery CUNIT node:
-     cunit@f200 {
-            reg = <0xf200 0x200>;
-     };
-
-
-   g) Marvell Discovery MPSCROUTING nodes
-
-   Represent the Discovery's MPSC routing hardware
-
-   Required properties:
-     - reg : Offset and length of the register set for this device
-
-   Example Discovery CUNIT node:
-     mpscrouting@b500 {
-            reg = <0xb400 0xc>;
-     };
-
-
-   h) Marvell Discovery MPSCINTR nodes
-
-   Represent the Discovery's MPSC DMA interrupt hardware registers
-   (SDMA cause and mask registers).
-
-   Required properties:
-     - reg : Offset and length of the register set for this device
-
-   Example Discovery MPSCINTR node:
-     mpsintr@b800 {
-            reg = <0xb800 0x100>;
-     };
-
-
-   i) Marvell Discovery MPSC nodes
-
-   Represent the Discovery's MPSC (Multiprotocol Serial Controller)
-   serial port.
-
-   Required properties:
-     - device_type : "serial"
-     - compatible : "marvell,mv64360-mpsc"
-     - reg : Offset and length of the register set for this device
-     - sdma : the phandle for the SDMA node used by this port
-     - brg : the phandle for the BRG node used by this port
-     - cunit : the phandle for the CUNIT node used by this port
-     - mpscrouting : the phandle for the MPSCROUTING node used by this port
-     - mpscintr : the phandle for the MPSCINTR node used by this port
-     - cell-index : the hardware index of this cell in the MPSC core
-     - max_idle : value needed for MPSC CHR3 (Maximum Frame Length)
-       register
-     - interrupts : <a> where a is the interrupt number for the MPSC.
-     - interrupt-parent : the phandle for the interrupt controller
-       that services interrupts for this device.
-
-   Example Discovery MPSCINTR node:
-     mpsc@8000 {
-            device_type = "serial";
-            compatible = "marvell,mv64360-mpsc";
-            reg = <0x8000 0x38>;
-            virtual-reg = <0xf1008000>;
-            sdma = <&SDMA0>;
-            brg = <&BRG0>;
-            cunit = <&CUNIT>;
-            mpscrouting = <&MPSCROUTING>;
-            mpscintr = <&MPSCINTR>;
-            cell-index = <0>;
-            max_idle = <40>;
-            interrupts = <40>;
-            interrupt-parent = <&PIC>;
-     };
-
-
-   j) Marvell Discovery Watch Dog Timer nodes
-
-   Represent the Discovery's watchdog timer hardware
-
-   Required properties:
-     - compatible : "marvell,mv64360-wdt"
-     - reg : Offset and length of the register set for this device
-
-   Example Discovery Watch Dog Timer node:
-     wdt@b410 {
-            compatible = "marvell,mv64360-wdt";
-            reg = <0xb410 0x8>;
-     };
-
-
-   k) Marvell Discovery I2C nodes
-
-   Represent the Discovery's I2C hardware
-
-   Required properties:
-     - device_type : "i2c"
-     - compatible : "marvell,mv64360-i2c"
-     - reg : Offset and length of the register set for this device
-     - interrupts : <a> where a is the interrupt number for the I2C.
-     - interrupt-parent : the phandle for the interrupt controller
-       that services interrupts for this device.
-
-   Example Discovery I2C node:
-            compatible = "marvell,mv64360-i2c";
-            reg = <0xc000 0x20>;
-            virtual-reg = <0xf100c000>;
-            interrupts = <37>;
-            interrupt-parent = <&PIC>;
-     };
-
-
-   l) Marvell Discovery PIC (Programmable Interrupt Controller) nodes
-
-   Represent the Discovery's PIC hardware
-
-   Required properties:
-     - #interrupt-cells : <1>
-     - #address-cells : <0>
-     - compatible : "marvell,mv64360-pic"
-     - reg : Offset and length of the register set for this device
-     - interrupt-controller
-
-   Example Discovery PIC node:
-     pic {
-            #interrupt-cells = <1>;
-            #address-cells = <0>;
-            compatible = "marvell,mv64360-pic";
-            reg = <0x0 0x88>;
-            interrupt-controller;
-     };
-
-
-   m) Marvell Discovery MPP (Multipurpose Pins) multiplexing nodes
-
-   Represent the Discovery's MPP hardware
-
-   Required properties:
-     - compatible : "marvell,mv64360-mpp"
-     - reg : Offset and length of the register set for this device
-
-   Example Discovery MPP node:
-     mpp@f000 {
-            compatible = "marvell,mv64360-mpp";
-            reg = <0xf000 0x10>;
-     };
-
-
-   n) Marvell Discovery GPP (General Purpose Pins) nodes
-
-   Represent the Discovery's GPP hardware
-
-   Required properties:
-     - compatible : "marvell,mv64360-gpp"
-     - reg : Offset and length of the register set for this device
-
-   Example Discovery GPP node:
-     gpp@f000 {
-            compatible = "marvell,mv64360-gpp";
-            reg = <0xf100 0x20>;
-     };
-
-
-   o) Marvell Discovery PCI host bridge node
-
-   Represents the Discovery's PCI host bridge device.  The properties
-   for this node conform to Rev 2.1 of the PCI Bus Binding to IEEE
-   1275-1994.  A typical value for the compatible property is
-   "marvell,mv64360-pci".
-
-   Example Discovery PCI host bridge node
-     pci@80000000 {
-            #address-cells = <3>;
-            #size-cells = <2>;
-            #interrupt-cells = <1>;
-            device_type = "pci";
-            compatible = "marvell,mv64360-pci";
-            reg = <0xcf8 0x8>;
-            ranges = <0x01000000 0x0        0x0
-                            0x88000000 0x0 0x01000000
-                      0x02000000 0x0 0x80000000
-                            0x80000000 0x0 0x08000000>;
-            bus-range = <0 255>;
-            clock-frequency = <66000000>;
-            interrupt-parent = <&PIC>;
-            interrupt-map-mask = <0xf800 0x0 0x0 0x7>;
-            interrupt-map = <
-                    /* IDSEL 0x0a */
-                    0x5000 0 0 1 &PIC 80
-                    0x5000 0 0 2 &PIC 81
-                    0x5000 0 0 3 &PIC 91
-                    0x5000 0 0 4 &PIC 93
-
-                    /* IDSEL 0x0b */
-                    0x5800 0 0 1 &PIC 91
-                    0x5800 0 0 2 &PIC 93
-                    0x5800 0 0 3 &PIC 80
-                    0x5800 0 0 4 &PIC 81
-
-                    /* IDSEL 0x0c */
-                    0x6000 0 0 1 &PIC 91
-                    0x6000 0 0 2 &PIC 93
-                    0x6000 0 0 3 &PIC 80
-                    0x6000 0 0 4 &PIC 81
-
-                    /* IDSEL 0x0d */
-                    0x6800 0 0 1 &PIC 93
-                    0x6800 0 0 2 &PIC 80
-                    0x6800 0 0 3 &PIC 81
-                    0x6800 0 0 4 &PIC 91
-            >;
-     };
-
-
-   p) Marvell Discovery CPU Error nodes
-
-   Represent the Discovery's CPU error handler device.
-
-   Required properties:
-     - compatible : "marvell,mv64360-cpu-error"
-     - reg : Offset and length of the register set for this device
-     - interrupts : the interrupt number for this device
-     - interrupt-parent : the phandle for the interrupt controller
-       that services interrupts for this device.
-
-   Example Discovery CPU Error node:
-     cpu-error@0070 {
-            compatible = "marvell,mv64360-cpu-error";
-            reg = <0x70 0x10 0x128 0x28>;
-            interrupts = <3>;
-            interrupt-parent = <&PIC>;
-     };
-
-
-   q) Marvell Discovery SRAM Controller nodes
-
-   Represent the Discovery's SRAM controller device.
-
-   Required properties:
-     - compatible : "marvell,mv64360-sram-ctrl"
-     - reg : Offset and length of the register set for this device
-     - interrupts : the interrupt number for this device
-     - interrupt-parent : the phandle for the interrupt controller
-       that services interrupts for this device.
-
-   Example Discovery SRAM Controller node:
-     sram-ctrl@0380 {
-            compatible = "marvell,mv64360-sram-ctrl";
-            reg = <0x380 0x80>;
-            interrupts = <13>;
-            interrupt-parent = <&PIC>;
-     };
-
-
-   r) Marvell Discovery PCI Error Handler nodes
-
-   Represent the Discovery's PCI error handler device.
-
-   Required properties:
-     - compatible : "marvell,mv64360-pci-error"
-     - reg : Offset and length of the register set for this device
-     - interrupts : the interrupt number for this device
-     - interrupt-parent : the phandle for the interrupt controller
-       that services interrupts for this device.
-
-   Example Discovery PCI Error Handler node:
-     pci-error@1d40 {
-            compatible = "marvell,mv64360-pci-error";
-            reg = <0x1d40 0x40 0xc28 0x4>;
-            interrupts = <12>;
-            interrupt-parent = <&PIC>;
-     };
-
-
-   s) Marvell Discovery Memory Controller nodes
-
-   Represent the Discovery's memory controller device.
-
-   Required properties:
-     - compatible : "marvell,mv64360-mem-ctrl"
-     - reg : Offset and length of the register set for this device
-     - interrupts : the interrupt number for this device
-     - interrupt-parent : the phandle for the interrupt controller
-       that services interrupts for this device.
-
-   Example Discovery Memory Controller node:
-     mem-ctrl@1400 {
-            compatible = "marvell,mv64360-mem-ctrl";
-            reg = <0x1400 0x60>;
-            interrupts = <17>;
-            interrupt-parent = <&PIC>;
-     };
-
-
-VIII - Specifying interrupt information for devices
+VII - Specifying interrupt information for devices
 ===================================================
 
 The device tree represents the busses and devices of a hardware
@@ -2439,56 +1324,7 @@ encodings listed below:
        2 =  high to low edge sensitive type enabled
        3 =  low to high edge sensitive type enabled
 
-IX - Specifying GPIO information for devices
-============================================
-
-1) gpios property
------------------
-
-Nodes that makes use of GPIOs should define them using `gpios' property,
-format of which is: <&gpio-controller1-phandle gpio1-specifier
-                    &gpio-controller2-phandle gpio2-specifier
-                    0 /* holes are permitted, means no GPIO 3 */
-                    &gpio-controller4-phandle gpio4-specifier
-                    ...>;
-
-Note that gpio-specifier length is controller dependent.
-
-gpio-specifier may encode: bank, pin position inside the bank,
-whether pin is open-drain and whether pin is logically inverted.
-
-Example of the node using GPIOs:
-
-       node {
-               gpios = <&qe_pio_e 18 0>;
-       };
-
-In this example gpio-specifier is "18 0" and encodes GPIO pin number,
-and empty GPIO flags as accepted by the "qe_pio_e" gpio-controller.
-
-2) gpio-controller nodes
-------------------------
-
-Every GPIO controller node must have #gpio-cells property defined,
-this information will be used to translate gpio-specifiers.
-
-Example of two SOC GPIO banks defined as gpio-controller nodes:
-
-       qe_pio_a: gpio-controller@1400 {
-               #gpio-cells = <2>;
-               compatible = "fsl,qe-pario-bank-a", "fsl,qe-pario-bank";
-               reg = <0x1400 0x18>;
-               gpio-controller;
-       };
-
-       qe_pio_e: gpio-controller@1460 {
-               #gpio-cells = <2>;
-               compatible = "fsl,qe-pario-bank-e", "fsl,qe-pario-bank";
-               reg = <0x1460 0x18>;
-               gpio-controller;
-       };
-
-X - Specifying Device Power Management Information (sleep property)
+VIII - Specifying Device Power Management Information (sleep property)
 ===================================================================
 
 Devices on SOCs often have mechanisms for placing devices into low-power
diff --git a/Documentation/powerpc/dts-bindings/4xx/emac.txt b/Documentation/powerpc/dts-bindings/4xx/emac.txt
new file mode 100644 (file)
index 0000000..2161334
--- /dev/null
@@ -0,0 +1,148 @@
+    4xx/Axon EMAC ethernet nodes
+
+    The EMAC ethernet controller in IBM and AMCC 4xx chips, and also
+    the Axon bridge.  To operate this needs to interact with a ths
+    special McMAL DMA controller, and sometimes an RGMII or ZMII
+    interface.  In addition to the nodes and properties described
+    below, the node for the OPB bus on which the EMAC sits must have a
+    correct clock-frequency property.
+
+      i) The EMAC node itself
+
+    Required properties:
+    - device_type       : "network"
+
+    - compatible        : compatible list, contains 2 entries, first is
+                         "ibm,emac-CHIP" where CHIP is the host ASIC (440gx,
+                         405gp, Axon) and second is either "ibm,emac" or
+                         "ibm,emac4".  For Axon, thus, we have: "ibm,emac-axon",
+                         "ibm,emac4"
+    - interrupts        : <interrupt mapping for EMAC IRQ and WOL IRQ>
+    - interrupt-parent  : optional, if needed for interrupt mapping
+    - reg               : <registers mapping>
+    - local-mac-address : 6 bytes, MAC address
+    - mal-device        : phandle of the associated McMAL node
+    - mal-tx-channel    : 1 cell, index of the tx channel on McMAL associated
+                         with this EMAC
+    - mal-rx-channel    : 1 cell, index of the rx channel on McMAL associated
+                         with this EMAC
+    - cell-index        : 1 cell, hardware index of the EMAC cell on a given
+                         ASIC (typically 0x0 and 0x1 for EMAC0 and EMAC1 on
+                         each Axon chip)
+    - max-frame-size    : 1 cell, maximum frame size supported in bytes
+    - rx-fifo-size      : 1 cell, Rx fifo size in bytes for 10 and 100 Mb/sec
+                         operations.
+                         For Axon, 2048
+    - tx-fifo-size      : 1 cell, Tx fifo size in bytes for 10 and 100 Mb/sec
+                         operations.
+                         For Axon, 2048.
+    - fifo-entry-size   : 1 cell, size of a fifo entry (used to calculate
+                         thresholds).
+                         For Axon, 0x00000010
+    - mal-burst-size    : 1 cell, MAL burst size (used to calculate thresholds)
+                         in bytes.
+                         For Axon, 0x00000100 (I think ...)
+    - phy-mode          : string, mode of operations of the PHY interface.
+                         Supported values are: "mii", "rmii", "smii", "rgmii",
+                         "tbi", "gmii", rtbi", "sgmii".
+                         For Axon on CAB, it is "rgmii"
+    - mdio-device       : 1 cell, required iff using shared MDIO registers
+                         (440EP).  phandle of the EMAC to use to drive the
+                         MDIO lines for the PHY used by this EMAC.
+    - zmii-device       : 1 cell, required iff connected to a ZMII.  phandle of
+                         the ZMII device node
+    - zmii-channel      : 1 cell, required iff connected to a ZMII.  Which ZMII
+                         channel or 0xffffffff if ZMII is only used for MDIO.
+    - rgmii-device      : 1 cell, required iff connected to an RGMII. phandle
+                         of the RGMII device node.
+                         For Axon: phandle of plb5/plb4/opb/rgmii
+    - rgmii-channel     : 1 cell, required iff connected to an RGMII.  Which
+                         RGMII channel is used by this EMAC.
+                         Fox Axon: present, whatever value is appropriate for each
+                         EMAC, that is the content of the current (bogus) "phy-port"
+                         property.
+
+    Optional properties:
+    - phy-address       : 1 cell, optional, MDIO address of the PHY. If absent,
+                         a search is performed.
+    - phy-map           : 1 cell, optional, bitmap of addresses to probe the PHY
+                         for, used if phy-address is absent. bit 0x00000001 is
+                         MDIO address 0.
+                         For Axon it can be absent, though my current driver
+                         doesn't handle phy-address yet so for now, keep
+                         0x00ffffff in it.
+    - rx-fifo-size-gige : 1 cell, Rx fifo size in bytes for 1000 Mb/sec
+                         operations (if absent the value is the same as
+                         rx-fifo-size).  For Axon, either absent or 2048.
+    - tx-fifo-size-gige : 1 cell, Tx fifo size in bytes for 1000 Mb/sec
+                         operations (if absent the value is the same as
+                         tx-fifo-size). For Axon, either absent or 2048.
+    - tah-device        : 1 cell, optional. If connected to a TAH engine for
+                         offload, phandle of the TAH device node.
+    - tah-channel       : 1 cell, optional. If appropriate, channel used on the
+                         TAH engine.
+
+    Example:
+
+       EMAC0: ethernet@40000800 {
+               device_type = "network";
+               compatible = "ibm,emac-440gp", "ibm,emac";
+               interrupt-parent = <&UIC1>;
+               interrupts = <1c 4 1d 4>;
+               reg = <40000800 70>;
+               local-mac-address = [00 04 AC E3 1B 1E];
+               mal-device = <&MAL0>;
+               mal-tx-channel = <0 1>;
+               mal-rx-channel = <0>;
+               cell-index = <0>;
+               max-frame-size = <5dc>;
+               rx-fifo-size = <1000>;
+               tx-fifo-size = <800>;
+               phy-mode = "rmii";
+               phy-map = <00000001>;
+               zmii-device = <&ZMII0>;
+               zmii-channel = <0>;
+       };
+
+      ii) McMAL node
+
+    Required properties:
+    - device_type        : "dma-controller"
+    - compatible         : compatible list, containing 2 entries, first is
+                          "ibm,mcmal-CHIP" where CHIP is the host ASIC (like
+                          emac) and the second is either "ibm,mcmal" or
+                          "ibm,mcmal2".
+                          For Axon, "ibm,mcmal-axon","ibm,mcmal2"
+    - interrupts         : <interrupt mapping for the MAL interrupts sources:
+                           5 sources: tx_eob, rx_eob, serr, txde, rxde>.
+                           For Axon: This is _different_ from the current
+                          firmware.  We use the "delayed" interrupts for txeob
+                          and rxeob. Thus we end up with mapping those 5 MPIC
+                          interrupts, all level positive sensitive: 10, 11, 32,
+                          33, 34 (in decimal)
+    - dcr-reg            : < DCR registers range >
+    - dcr-parent         : if needed for dcr-reg
+    - num-tx-chans       : 1 cell, number of Tx channels
+    - num-rx-chans       : 1 cell, number of Rx channels
+
+      iii) ZMII node
+
+    Required properties:
+    - compatible         : compatible list, containing 2 entries, first is
+                          "ibm,zmii-CHIP" where CHIP is the host ASIC (like
+                          EMAC) and the second is "ibm,zmii".
+                          For Axon, there is no ZMII node.
+    - reg                : <registers mapping>
+
+      iv) RGMII node
+
+    Required properties:
+    - compatible         : compatible list, containing 2 entries, first is
+                          "ibm,rgmii-CHIP" where CHIP is the host ASIC (like
+                          EMAC) and the second is "ibm,rgmii".
+                           For Axon, "ibm,rgmii-axon","ibm,rgmii"
+    - reg                : <registers mapping>
+    - revision           : as provided by the RGMII new version register if
+                          available.
+                          For Axon: 0x0000012a
+
diff --git a/Documentation/powerpc/dts-bindings/gpio/gpio.txt b/Documentation/powerpc/dts-bindings/gpio/gpio.txt
new file mode 100644 (file)
index 0000000..edaa84d
--- /dev/null
@@ -0,0 +1,50 @@
+Specifying GPIO information for devices
+============================================
+
+1) gpios property
+-----------------
+
+Nodes that makes use of GPIOs should define them using `gpios' property,
+format of which is: <&gpio-controller1-phandle gpio1-specifier
+                    &gpio-controller2-phandle gpio2-specifier
+                    0 /* holes are permitted, means no GPIO 3 */
+                    &gpio-controller4-phandle gpio4-specifier
+                    ...>;
+
+Note that gpio-specifier length is controller dependent.
+
+gpio-specifier may encode: bank, pin position inside the bank,
+whether pin is open-drain and whether pin is logically inverted.
+
+Example of the node using GPIOs:
+
+       node {
+               gpios = <&qe_pio_e 18 0>;
+       };
+
+In this example gpio-specifier is "18 0" and encodes GPIO pin number,
+and empty GPIO flags as accepted by the "qe_pio_e" gpio-controller.
+
+2) gpio-controller nodes
+------------------------
+
+Every GPIO controller node must have #gpio-cells property defined,
+this information will be used to translate gpio-specifiers.
+
+Example of two SOC GPIO banks defined as gpio-controller nodes:
+
+       qe_pio_a: gpio-controller@1400 {
+               #gpio-cells = <2>;
+               compatible = "fsl,qe-pario-bank-a", "fsl,qe-pario-bank";
+               reg = <0x1400 0x18>;
+               gpio-controller;
+       };
+
+       qe_pio_e: gpio-controller@1460 {
+               #gpio-cells = <2>;
+               compatible = "fsl,qe-pario-bank-e", "fsl,qe-pario-bank";
+               reg = <0x1460 0x18>;
+               gpio-controller;
+       };
+
+
index 4fe14deedc0a3e5aa3988288873c5e4f9a2ee01c..064db928c3c12cc3d6141664e57d25e7050520ed 100644 (file)
@@ -16,10 +16,17 @@ LED sub-node properties:
   string defining the trigger assigned to the LED.  Current triggers are:
     "backlight" - LED will act as a back-light, controlled by the framebuffer
                  system
-    "default-on" - LED will turn on
+    "default-on" - LED will turn on, but see "default-state" below
     "heartbeat" - LED "double" flashes at a load average based rate
     "ide-disk" - LED indicates disk activity
     "timer" - LED flashes at a fixed, configurable rate
+- default-state:  (optional) The initial state of the LED.  Valid
+  values are "on", "off", and "keep".  If the LED is already on or off
+  and the default-state property is set the to same value, then no
+  glitch should be produced where the LED momentarily turns off (or
+  on).  The "keep" setting will keep the LED at whatever its current
+  state is, without producing a glitch.  The default is off if this
+  property is not present.
 
 Examples:
 
@@ -30,14 +37,22 @@ leds {
                gpios = <&mcu_pio 0 1>; /* Active low */
                linux,default-trigger = "ide-disk";
        };
+
+       fault {
+               gpios = <&mcu_pio 1 0>;
+               /* Keep LED on if BIOS detected hardware fault */
+               default-state = "keep";
+       };
 };
 
 run-control {
        compatible = "gpio-leds";
        red {
                gpios = <&mpc8572 6 0>;
+               default-state = "off";
        };
        green {
                gpios = <&mpc8572 7 0>;
+               default-state = "on";
        };
 }
diff --git a/Documentation/powerpc/dts-bindings/gpio/mdio.txt b/Documentation/powerpc/dts-bindings/gpio/mdio.txt
new file mode 100644 (file)
index 0000000..bc95495
--- /dev/null
@@ -0,0 +1,19 @@
+MDIO on GPIOs
+
+Currently defined compatibles:
+- virtual,gpio-mdio
+
+MDC and MDIO lines connected to GPIO controllers are listed in the
+gpios property as described in section VIII.1 in the following order:
+
+MDC, MDIO.
+
+Example:
+
+mdio {
+       compatible = "virtual,mdio-gpio";
+       #address-cells = <1>;
+       #size-cells = <0>;
+       gpios = <&qe_pio_a 11
+                &qe_pio_c 6>;
+};
diff --git a/Documentation/powerpc/dts-bindings/marvell.txt b/Documentation/powerpc/dts-bindings/marvell.txt
new file mode 100644 (file)
index 0000000..3708a2f
--- /dev/null
@@ -0,0 +1,521 @@
+Marvell Discovery mv64[345]6x System Controller chips
+===========================================================
+
+The Marvell mv64[345]60 series of system controller chips contain
+many of the peripherals needed to implement a complete computer
+system.  In this section, we define device tree nodes to describe
+the system controller chip itself and each of the peripherals
+which it contains.  Compatible string values for each node are
+prefixed with the string "marvell,", for Marvell Technology Group Ltd.
+
+1) The /system-controller node
+
+  This node is used to represent the system-controller and must be
+  present when the system uses a system controller chip. The top-level
+  system-controller node contains information that is global to all
+  devices within the system controller chip. The node name begins
+  with "system-controller" followed by the unit address, which is
+  the base address of the memory-mapped register set for the system
+  controller chip.
+
+  Required properties:
+
+    - ranges : Describes the translation of system controller addresses
+      for memory mapped registers.
+    - clock-frequency: Contains the main clock frequency for the system
+      controller chip.
+    - reg : This property defines the address and size of the
+      memory-mapped registers contained within the system controller
+      chip.  The address specified in the "reg" property should match
+      the unit address of the system-controller node.
+    - #address-cells : Address representation for system controller
+      devices.  This field represents the number of cells needed to
+      represent the address of the memory-mapped registers of devices
+      within the system controller chip.
+    - #size-cells : Size representation for for the memory-mapped
+      registers within the system controller chip.
+    - #interrupt-cells : Defines the width of cells used to represent
+      interrupts.
+
+  Optional properties:
+
+    - model : The specific model of the system controller chip.  Such
+      as, "mv64360", "mv64460", or "mv64560".
+    - compatible : A string identifying the compatibility identifiers
+      of the system controller chip.
+
+  The system-controller node contains child nodes for each system
+  controller device that the platform uses.  Nodes should not be created
+  for devices which exist on the system controller chip but are not used
+
+  Example Marvell Discovery mv64360 system-controller node:
+
+    system-controller@f1000000 { /* Marvell Discovery mv64360 */
+           #address-cells = <1>;
+           #size-cells = <1>;
+           model = "mv64360";                      /* Default */
+           compatible = "marvell,mv64360";
+           clock-frequency = <133333333>;
+           reg = <0xf1000000 0x10000>;
+           virtual-reg = <0xf1000000>;
+           ranges = <0x88000000 0x88000000 0x1000000 /* PCI 0 I/O Space */
+                   0x80000000 0x80000000 0x8000000 /* PCI 0 MEM Space */
+                   0xa0000000 0xa0000000 0x4000000 /* User FLASH */
+                   0x00000000 0xf1000000 0x0010000 /* Bridge's regs */
+                   0xf2000000 0xf2000000 0x0040000>;/* Integrated SRAM */
+
+           [ child node definitions... ]
+    }
+
+2) Child nodes of /system-controller
+
+   a) Marvell Discovery MDIO bus
+
+   The MDIO is a bus to which the PHY devices are connected.  For each
+   device that exists on this bus, a child node should be created.  See
+   the definition of the PHY node below for an example of how to define
+   a PHY.
+
+   Required properties:
+     - #address-cells : Should be <1>
+     - #size-cells : Should be <0>
+     - device_type : Should be "mdio"
+     - compatible : Should be "marvell,mv64360-mdio"
+
+   Example:
+
+     mdio {
+            #address-cells = <1>;
+            #size-cells = <0>;
+            device_type = "mdio";
+            compatible = "marvell,mv64360-mdio";
+
+            ethernet-phy@0 {
+                    ......
+            };
+     };
+
+
+   b) Marvell Discovery ethernet controller
+
+   The Discover ethernet controller is described with two levels
+   of nodes.  The first level describes an ethernet silicon block
+   and the second level describes up to 3 ethernet nodes within
+   that block.  The reason for the multiple levels is that the
+   registers for the node are interleaved within a single set
+   of registers.  The "ethernet-block" level describes the
+   shared register set, and the "ethernet" nodes describe ethernet
+   port-specific properties.
+
+   Ethernet block node
+
+   Required properties:
+     - #address-cells : <1>
+     - #size-cells : <0>
+     - compatible : "marvell,mv64360-eth-block"
+     - reg : Offset and length of the register set for this block
+
+   Example Discovery Ethernet block node:
+     ethernet-block@2000 {
+            #address-cells = <1>;
+            #size-cells = <0>;
+            compatible = "marvell,mv64360-eth-block";
+            reg = <0x2000 0x2000>;
+            ethernet@0 {
+                    .......
+            };
+     };
+
+   Ethernet port node
+
+   Required properties:
+     - device_type : Should be "network".
+     - compatible : Should be "marvell,mv64360-eth".
+     - reg : Should be <0>, <1>, or <2>, according to which registers
+       within the silicon block the device uses.
+     - interrupts : <a> where a is the interrupt number for the port.
+     - interrupt-parent : the phandle for the interrupt controller
+       that services interrupts for this device.
+     - phy : the phandle for the PHY connected to this ethernet
+       controller.
+     - local-mac-address : 6 bytes, MAC address
+
+   Example Discovery Ethernet port node:
+     ethernet@0 {
+            device_type = "network";
+            compatible = "marvell,mv64360-eth";
+            reg = <0>;
+            interrupts = <32>;
+            interrupt-parent = <&PIC>;
+            phy = <&PHY0>;
+            local-mac-address = [ 00 00 00 00 00 00 ];
+     };
+
+
+
+   c) Marvell Discovery PHY nodes
+
+   Required properties:
+     - device_type : Should be "ethernet-phy"
+     - interrupts : <a> where a is the interrupt number for this phy.
+     - interrupt-parent : the phandle for the interrupt controller that
+       services interrupts for this device.
+     - reg : The ID number for the phy, usually a small integer
+
+   Example Discovery PHY node:
+     ethernet-phy@1 {
+            device_type = "ethernet-phy";
+            compatible = "broadcom,bcm5421";
+            interrupts = <76>;      /* GPP 12 */
+            interrupt-parent = <&PIC>;
+            reg = <1>;
+     };
+
+
+   d) Marvell Discovery SDMA nodes
+
+   Represent DMA hardware associated with the MPSC (multiprotocol
+   serial controllers).
+
+   Required properties:
+     - compatible : "marvell,mv64360-sdma"
+     - reg : Offset and length of the register set for this device
+     - interrupts : <a> where a is the interrupt number for the DMA
+       device.
+     - interrupt-parent : the phandle for the interrupt controller
+       that services interrupts for this device.
+
+   Example Discovery SDMA node:
+     sdma@4000 {
+            compatible = "marvell,mv64360-sdma";
+            reg = <0x4000 0xc18>;
+            virtual-reg = <0xf1004000>;
+            interrupts = <36>;
+            interrupt-parent = <&PIC>;
+     };
+
+
+   e) Marvell Discovery BRG nodes
+
+   Represent baud rate generator hardware associated with the MPSC
+   (multiprotocol serial controllers).
+
+   Required properties:
+     - compatible : "marvell,mv64360-brg"
+     - reg : Offset and length of the register set for this device
+     - clock-src : A value from 0 to 15 which selects the clock
+       source for the baud rate generator.  This value corresponds
+       to the CLKS value in the BRGx configuration register.  See
+       the mv64x60 User's Manual.
+     - clock-frequence : The frequency (in Hz) of the baud rate
+       generator's input clock.
+     - current-speed : The current speed setting (presumably by
+       firmware) of the baud rate generator.
+
+   Example Discovery BRG node:
+     brg@b200 {
+            compatible = "marvell,mv64360-brg";
+            reg = <0xb200 0x8>;
+            clock-src = <8>;
+            clock-frequency = <133333333>;
+            current-speed = <9600>;
+     };
+
+
+   f) Marvell Discovery CUNIT nodes
+
+   Represent the Serial Communications Unit device hardware.
+
+   Required properties:
+     - reg : Offset and length of the register set for this device
+
+   Example Discovery CUNIT node:
+     cunit@f200 {
+            reg = <0xf200 0x200>;
+     };
+
+
+   g) Marvell Discovery MPSCROUTING nodes
+
+   Represent the Discovery's MPSC routing hardware
+
+   Required properties:
+     - reg : Offset and length of the register set for this device
+
+   Example Discovery CUNIT node:
+     mpscrouting@b500 {
+            reg = <0xb400 0xc>;
+     };
+
+
+   h) Marvell Discovery MPSCINTR nodes
+
+   Represent the Discovery's MPSC DMA interrupt hardware registers
+   (SDMA cause and mask registers).
+
+   Required properties:
+     - reg : Offset and length of the register set for this device
+
+   Example Discovery MPSCINTR node:
+     mpsintr@b800 {
+            reg = <0xb800 0x100>;
+     };
+
+
+   i) Marvell Discovery MPSC nodes
+
+   Represent the Discovery's MPSC (Multiprotocol Serial Controller)
+   serial port.
+
+   Required properties:
+     - device_type : "serial"
+     - compatible : "marvell,mv64360-mpsc"
+     - reg : Offset and length of the register set for this device
+     - sdma : the phandle for the SDMA node used by this port
+     - brg : the phandle for the BRG node used by this port
+     - cunit : the phandle for the CUNIT node used by this port
+     - mpscrouting : the phandle for the MPSCROUTING node used by this port
+     - mpscintr : the phandle for the MPSCINTR node used by this port
+     - cell-index : the hardware index of this cell in the MPSC core
+     - max_idle : value needed for MPSC CHR3 (Maximum Frame Length)
+       register
+     - interrupts : <a> where a is the interrupt number for the MPSC.
+     - interrupt-parent : the phandle for the interrupt controller
+       that services interrupts for this device.
+
+   Example Discovery MPSCINTR node:
+     mpsc@8000 {
+            device_type = "serial";
+            compatible = "marvell,mv64360-mpsc";
+            reg = <0x8000 0x38>;
+            virtual-reg = <0xf1008000>;
+            sdma = <&SDMA0>;
+            brg = <&BRG0>;
+            cunit = <&CUNIT>;
+            mpscrouting = <&MPSCROUTING>;
+            mpscintr = <&MPSCINTR>;
+            cell-index = <0>;
+            max_idle = <40>;
+            interrupts = <40>;
+            interrupt-parent = <&PIC>;
+     };
+
+
+   j) Marvell Discovery Watch Dog Timer nodes
+
+   Represent the Discovery's watchdog timer hardware
+
+   Required properties:
+     - compatible : "marvell,mv64360-wdt"
+     - reg : Offset and length of the register set for this device
+
+   Example Discovery Watch Dog Timer node:
+     wdt@b410 {
+            compatible = "marvell,mv64360-wdt";
+            reg = <0xb410 0x8>;
+     };
+
+
+   k) Marvell Discovery I2C nodes
+
+   Represent the Discovery's I2C hardware
+
+   Required properties:
+     - device_type : "i2c"
+     - compatible : "marvell,mv64360-i2c"
+     - reg : Offset and length of the register set for this device
+     - interrupts : <a> where a is the interrupt number for the I2C.
+     - interrupt-parent : the phandle for the interrupt controller
+       that services interrupts for this device.
+
+   Example Discovery I2C node:
+            compatible = "marvell,mv64360-i2c";
+            reg = <0xc000 0x20>;
+            virtual-reg = <0xf100c000>;
+            interrupts = <37>;
+            interrupt-parent = <&PIC>;
+     };
+
+
+   l) Marvell Discovery PIC (Programmable Interrupt Controller) nodes
+
+   Represent the Discovery's PIC hardware
+
+   Required properties:
+     - #interrupt-cells : <1>
+     - #address-cells : <0>
+     - compatible : "marvell,mv64360-pic"
+     - reg : Offset and length of the register set for this device
+     - interrupt-controller
+
+   Example Discovery PIC node:
+     pic {
+            #interrupt-cells = <1>;
+            #address-cells = <0>;
+            compatible = "marvell,mv64360-pic";
+            reg = <0x0 0x88>;
+            interrupt-controller;
+     };
+
+
+   m) Marvell Discovery MPP (Multipurpose Pins) multiplexing nodes
+
+   Represent the Discovery's MPP hardware
+
+   Required properties:
+     - compatible : "marvell,mv64360-mpp"
+     - reg : Offset and length of the register set for this device
+
+   Example Discovery MPP node:
+     mpp@f000 {
+            compatible = "marvell,mv64360-mpp";
+            reg = <0xf000 0x10>;
+     };
+
+
+   n) Marvell Discovery GPP (General Purpose Pins) nodes
+
+   Represent the Discovery's GPP hardware
+
+   Required properties:
+     - compatible : "marvell,mv64360-gpp"
+     - reg : Offset and length of the register set for this device
+
+   Example Discovery GPP node:
+     gpp@f000 {
+            compatible = "marvell,mv64360-gpp";
+            reg = <0xf100 0x20>;
+     };
+
+
+   o) Marvell Discovery PCI host bridge node
+
+   Represents the Discovery's PCI host bridge device.  The properties
+   for this node conform to Rev 2.1 of the PCI Bus Binding to IEEE
+   1275-1994.  A typical value for the compatible property is
+   "marvell,mv64360-pci".
+
+   Example Discovery PCI host bridge node
+     pci@80000000 {
+            #address-cells = <3>;
+            #size-cells = <2>;
+            #interrupt-cells = <1>;
+            device_type = "pci";
+            compatible = "marvell,mv64360-pci";
+            reg = <0xcf8 0x8>;
+            ranges = <0x01000000 0x0        0x0
+                            0x88000000 0x0 0x01000000
+                      0x02000000 0x0 0x80000000
+                            0x80000000 0x0 0x08000000>;
+            bus-range = <0 255>;
+            clock-frequency = <66000000>;
+            interrupt-parent = <&PIC>;
+            interrupt-map-mask = <0xf800 0x0 0x0 0x7>;
+            interrupt-map = <
+                    /* IDSEL 0x0a */
+                    0x5000 0 0 1 &PIC 80
+                    0x5000 0 0 2 &PIC 81
+                    0x5000 0 0 3 &PIC 91
+                    0x5000 0 0 4 &PIC 93
+
+                    /* IDSEL 0x0b */
+                    0x5800 0 0 1 &PIC 91
+                    0x5800 0 0 2 &PIC 93
+                    0x5800 0 0 3 &PIC 80
+                    0x5800 0 0 4 &PIC 81
+
+                    /* IDSEL 0x0c */
+                    0x6000 0 0 1 &PIC 91
+                    0x6000 0 0 2 &PIC 93
+                    0x6000 0 0 3 &PIC 80
+                    0x6000 0 0 4 &PIC 81
+
+                    /* IDSEL 0x0d */
+                    0x6800 0 0 1 &PIC 93
+                    0x6800 0 0 2 &PIC 80
+                    0x6800 0 0 3 &PIC 81
+                    0x6800 0 0 4 &PIC 91
+            >;
+     };
+
+
+   p) Marvell Discovery CPU Error nodes
+
+   Represent the Discovery's CPU error handler device.
+
+   Required properties:
+     - compatible : "marvell,mv64360-cpu-error"
+     - reg : Offset and length of the register set for this device
+     - interrupts : the interrupt number for this device
+     - interrupt-parent : the phandle for the interrupt controller
+       that services interrupts for this device.
+
+   Example Discovery CPU Error node:
+     cpu-error@0070 {
+            compatible = "marvell,mv64360-cpu-error";
+            reg = <0x70 0x10 0x128 0x28>;
+            interrupts = <3>;
+            interrupt-parent = <&PIC>;
+     };
+
+
+   q) Marvell Discovery SRAM Controller nodes
+
+   Represent the Discovery's SRAM controller device.
+
+   Required properties:
+     - compatible : "marvell,mv64360-sram-ctrl"
+     - reg : Offset and length of the register set for this device
+     - interrupts : the interrupt number for this device
+     - interrupt-parent : the phandle for the interrupt controller
+       that services interrupts for this device.
+
+   Example Discovery SRAM Controller node:
+     sram-ctrl@0380 {
+            compatible = "marvell,mv64360-sram-ctrl";
+            reg = <0x380 0x80>;
+            interrupts = <13>;
+            interrupt-parent = <&PIC>;
+     };
+
+
+   r) Marvell Discovery PCI Error Handler nodes
+
+   Represent the Discovery's PCI error handler device.
+
+   Required properties:
+     - compatible : "marvell,mv64360-pci-error"
+     - reg : Offset and length of the register set for this device
+     - interrupts : the interrupt number for this device
+     - interrupt-parent : the phandle for the interrupt controller
+       that services interrupts for this device.
+
+   Example Discovery PCI Error Handler node:
+     pci-error@1d40 {
+            compatible = "marvell,mv64360-pci-error";
+            reg = <0x1d40 0x40 0xc28 0x4>;
+            interrupts = <12>;
+            interrupt-parent = <&PIC>;
+     };
+
+
+   s) Marvell Discovery Memory Controller nodes
+
+   Represent the Discovery's memory controller device.
+
+   Required properties:
+     - compatible : "marvell,mv64360-mem-ctrl"
+     - reg : Offset and length of the register set for this device
+     - interrupts : the interrupt number for this device
+     - interrupt-parent : the phandle for the interrupt controller
+       that services interrupts for this device.
+
+   Example Discovery Memory Controller node:
+     mem-ctrl@1400 {
+            compatible = "marvell,mv64360-mem-ctrl";
+            reg = <0x1400 0x60>;
+            interrupts = <17>;
+            interrupt-parent = <&PIC>;
+     };
+
+
diff --git a/Documentation/powerpc/dts-bindings/phy.txt b/Documentation/powerpc/dts-bindings/phy.txt
new file mode 100644 (file)
index 0000000..bb8c742
--- /dev/null
@@ -0,0 +1,25 @@
+PHY nodes
+
+Required properties:
+
+ - device_type : Should be "ethernet-phy"
+ - interrupts : <a b> where a is the interrupt number and b is a
+   field that represents an encoding of the sense and level
+   information for the interrupt.  This should be encoded based on
+   the information in section 2) depending on the type of interrupt
+   controller you have.
+ - interrupt-parent : the phandle for the interrupt controller that
+   services interrupts for this device.
+ - reg : The ID number for the phy, usually a small integer
+ - linux,phandle :  phandle for this node; likely referenced by an
+   ethernet controller node.
+
+Example:
+
+ethernet-phy@0 {
+       linux,phandle = <2452000>
+       interrupt-parent = <40000>;
+       interrupts = <35 1>;
+       reg = <0>;
+       device_type = "ethernet-phy";
+};
diff --git a/Documentation/powerpc/dts-bindings/spi-bus.txt b/Documentation/powerpc/dts-bindings/spi-bus.txt
new file mode 100644 (file)
index 0000000..e782add
--- /dev/null
@@ -0,0 +1,57 @@
+SPI (Serial Peripheral Interface) busses
+
+SPI busses can be described with a node for the SPI master device
+and a set of child nodes for each SPI slave on the bus.  For this
+discussion, it is assumed that the system's SPI controller is in
+SPI master mode.  This binding does not describe SPI controllers
+in slave mode.
+
+The SPI master node requires the following properties:
+- #address-cells  - number of cells required to define a chip select
+               address on the SPI bus.
+- #size-cells     - should be zero.
+- compatible      - name of SPI bus controller following generic names
+               recommended practice.
+No other properties are required in the SPI bus node.  It is assumed
+that a driver for an SPI bus device will understand that it is an SPI bus.
+However, the binding does not attempt to define the specific method for
+assigning chip select numbers.  Since SPI chip select configuration is
+flexible and non-standardized, it is left out of this binding with the
+assumption that board specific platform code will be used to manage
+chip selects.  Individual drivers can define additional properties to
+support describing the chip select layout.
+
+SPI slave nodes must be children of the SPI master node and can
+contain the following properties.
+- reg             - (required) chip select address of device.
+- compatible      - (required) name of SPI device following generic names
+               recommended practice
+- spi-max-frequency - (required) Maximum SPI clocking speed of device in Hz
+- spi-cpol        - (optional) Empty property indicating device requires
+               inverse clock polarity (CPOL) mode
+- spi-cpha        - (optional) Empty property indicating device requires
+               shifted clock phase (CPHA) mode
+- spi-cs-high     - (optional) Empty property indicating device requires
+               chip select active high
+
+SPI example for an MPC5200 SPI bus:
+       spi@f00 {
+               #address-cells = <1>;
+               #size-cells = <0>;
+               compatible = "fsl,mpc5200b-spi","fsl,mpc5200-spi";
+               reg = <0xf00 0x20>;
+               interrupts = <2 13 0 2 14 0>;
+               interrupt-parent = <&mpc5200_pic>;
+
+               ethernet-switch@0 {
+                       compatible = "micrel,ks8995m";
+                       spi-max-frequency = <1000000>;
+                       reg = <0>;
+               };
+
+               codec@1 {
+                       compatible = "ti,tlv320aic26";
+                       spi-max-frequency = <100000>;
+                       reg = <1>;
+               };
+       };
diff --git a/Documentation/powerpc/dts-bindings/usb-ehci.txt b/Documentation/powerpc/dts-bindings/usb-ehci.txt
new file mode 100644 (file)
index 0000000..fa18612
--- /dev/null
@@ -0,0 +1,25 @@
+USB EHCI controllers
+
+Required properties:
+  - compatible : should be "usb-ehci".
+  - reg : should contain at least address and length of the standard EHCI
+    register set for the device. Optional platform-dependent registers
+    (debug-port or other) can be also specified here, but only after
+    definition of standard EHCI registers.
+  - interrupts : one EHCI interrupt should be described here.
+If device registers are implemented in big endian mode, the device
+node should have "big-endian-regs" property.
+If controller implementation operates with big endian descriptors,
+"big-endian-desc" property should be specified.
+If both big endian registers and descriptors are used by the controller
+implementation, "big-endian" property can be specified instead of having
+both "big-endian-regs" and "big-endian-desc".
+
+Example (Sequoia 440EPx):
+    ehci@e0000300 {
+          compatible = "ibm,usb-ehci-440epx", "usb-ehci";
+          interrupt-parent = <&UIC0>;
+          interrupts = <1a 4>;
+          reg = <0 e0000300 90 0 e0000390 70>;
+          big-endian;
+   };
diff --git a/Documentation/powerpc/dts-bindings/xilinx.txt b/Documentation/powerpc/dts-bindings/xilinx.txt
new file mode 100644 (file)
index 0000000..80339fe
--- /dev/null
@@ -0,0 +1,295 @@
+   d) Xilinx IP cores
+
+   The Xilinx EDK toolchain ships with a set of IP cores (devices) for use
+   in Xilinx Spartan and Virtex FPGAs.  The devices cover the whole range
+   of standard device types (network, serial, etc.) and miscellaneous
+   devices (gpio, LCD, spi, etc).  Also, since these devices are
+   implemented within the fpga fabric every instance of the device can be
+   synthesised with different options that change the behaviour.
+
+   Each IP-core has a set of parameters which the FPGA designer can use to
+   control how the core is synthesized.  Historically, the EDK tool would
+   extract the device parameters relevant to device drivers and copy them
+   into an 'xparameters.h' in the form of #define symbols.  This tells the
+   device drivers how the IP cores are configured, but it requres the kernel
+   to be recompiled every time the FPGA bitstream is resynthesized.
+
+   The new approach is to export the parameters into the device tree and
+   generate a new device tree each time the FPGA bitstream changes.  The
+   parameters which used to be exported as #defines will now become
+   properties of the device node.  In general, device nodes for IP-cores
+   will take the following form:
+
+       (name): (generic-name)@(base-address) {
+               compatible = "xlnx,(ip-core-name)-(HW_VER)"
+                            [, (list of compatible devices), ...];
+               reg = <(baseaddr) (size)>;
+               interrupt-parent = <&interrupt-controller-phandle>;
+               interrupts = < ... >;
+               xlnx,(parameter1) = "(string-value)";
+               xlnx,(parameter2) = <(int-value)>;
+       };
+
+       (generic-name):   an open firmware-style name that describes the
+                       generic class of device.  Preferably, this is one word, such
+                       as 'serial' or 'ethernet'.
+       (ip-core-name): the name of the ip block (given after the BEGIN
+                       directive in system.mhs).  Should be in lowercase
+                       and all underscores '_' converted to dashes '-'.
+       (name):         is derived from the "PARAMETER INSTANCE" value.
+       (parameter#):   C_* parameters from system.mhs.  The C_ prefix is
+                       dropped from the parameter name, the name is converted
+                       to lowercase and all underscore '_' characters are
+                       converted to dashes '-'.
+       (baseaddr):     the baseaddr parameter value (often named C_BASEADDR).
+       (HW_VER):       from the HW_VER parameter.
+       (size):         the address range size (often C_HIGHADDR - C_BASEADDR + 1).
+
+   Typically, the compatible list will include the exact IP core version
+   followed by an older IP core version which implements the same
+   interface or any other device with the same interface.
+
+   'reg', 'interrupt-parent' and 'interrupts' are all optional properties.
+
+   For example, the following block from system.mhs:
+
+       BEGIN opb_uartlite
+               PARAMETER INSTANCE = opb_uartlite_0
+               PARAMETER HW_VER = 1.00.b
+               PARAMETER C_BAUDRATE = 115200
+               PARAMETER C_DATA_BITS = 8
+               PARAMETER C_ODD_PARITY = 0
+               PARAMETER C_USE_PARITY = 0
+               PARAMETER C_CLK_FREQ = 50000000
+               PARAMETER C_BASEADDR = 0xEC100000
+               PARAMETER C_HIGHADDR = 0xEC10FFFF
+               BUS_INTERFACE SOPB = opb_7
+               PORT OPB_Clk = CLK_50MHz
+               PORT Interrupt = opb_uartlite_0_Interrupt
+               PORT RX = opb_uartlite_0_RX
+               PORT TX = opb_uartlite_0_TX
+               PORT OPB_Rst = sys_bus_reset_0
+       END
+
+   becomes the following device tree node:
+
+       opb_uartlite_0: serial@ec100000 {
+               device_type = "serial";
+               compatible = "xlnx,opb-uartlite-1.00.b";
+               reg = <ec100000 10000>;
+               interrupt-parent = <&opb_intc_0>;
+               interrupts = <1 0>; // got this from the opb_intc parameters
+               current-speed = <d#115200>;     // standard serial device prop
+               clock-frequency = <d#50000000>; // standard serial device prop
+               xlnx,data-bits = <8>;
+               xlnx,odd-parity = <0>;
+               xlnx,use-parity = <0>;
+       };
+
+   Some IP cores actually implement 2 or more logical devices.  In
+   this case, the device should still describe the whole IP core with
+   a single node and add a child node for each logical device.  The
+   ranges property can be used to translate from parent IP-core to the
+   registers of each device.  In addition, the parent node should be
+   compatible with the bus type 'xlnx,compound', and should contain
+   #address-cells and #size-cells, as with any other bus.  (Note: this
+   makes the assumption that both logical devices have the same bus
+   binding.  If this is not true, then separate nodes should be used
+   for each logical device).  The 'cell-index' property can be used to
+   enumerate logical devices within an IP core.  For example, the
+   following is the system.mhs entry for the dual ps2 controller found
+   on the ml403 reference design.
+
+       BEGIN opb_ps2_dual_ref
+               PARAMETER INSTANCE = opb_ps2_dual_ref_0
+               PARAMETER HW_VER = 1.00.a
+               PARAMETER C_BASEADDR = 0xA9000000
+               PARAMETER C_HIGHADDR = 0xA9001FFF
+               BUS_INTERFACE SOPB = opb_v20_0
+               PORT Sys_Intr1 = ps2_1_intr
+               PORT Sys_Intr2 = ps2_2_intr
+               PORT Clkin1 = ps2_clk_rx_1
+               PORT Clkin2 = ps2_clk_rx_2
+               PORT Clkpd1 = ps2_clk_tx_1
+               PORT Clkpd2 = ps2_clk_tx_2
+               PORT Rx1 = ps2_d_rx_1
+               PORT Rx2 = ps2_d_rx_2
+               PORT Txpd1 = ps2_d_tx_1
+               PORT Txpd2 = ps2_d_tx_2
+       END
+
+   It would result in the following device tree nodes:
+
+       opb_ps2_dual_ref_0: opb-ps2-dual-ref@a9000000 {
+               #address-cells = <1>;
+               #size-cells = <1>;
+               compatible = "xlnx,compound";
+               ranges = <0 a9000000 2000>;
+               // If this device had extra parameters, then they would
+               // go here.
+               ps2@0 {
+                       compatible = "xlnx,opb-ps2-dual-ref-1.00.a";
+                       reg = <0 40>;
+                       interrupt-parent = <&opb_intc_0>;
+                       interrupts = <3 0>;
+                       cell-index = <0>;
+               };
+               ps2@1000 {
+                       compatible = "xlnx,opb-ps2-dual-ref-1.00.a";
+                       reg = <1000 40>;
+                       interrupt-parent = <&opb_intc_0>;
+                       interrupts = <3 0>;
+                       cell-index = <0>;
+               };
+       };
+
+   Also, the system.mhs file defines bus attachments from the processor
+   to the devices.  The device tree structure should reflect the bus
+   attachments.  Again an example; this system.mhs fragment:
+
+       BEGIN ppc405_virtex4
+               PARAMETER INSTANCE = ppc405_0
+               PARAMETER HW_VER = 1.01.a
+               BUS_INTERFACE DPLB = plb_v34_0
+               BUS_INTERFACE IPLB = plb_v34_0
+       END
+
+       BEGIN opb_intc
+               PARAMETER INSTANCE = opb_intc_0
+               PARAMETER HW_VER = 1.00.c
+               PARAMETER C_BASEADDR = 0xD1000FC0
+               PARAMETER C_HIGHADDR = 0xD1000FDF
+               BUS_INTERFACE SOPB = opb_v20_0
+       END
+
+       BEGIN opb_uart16550
+               PARAMETER INSTANCE = opb_uart16550_0
+               PARAMETER HW_VER = 1.00.d
+               PARAMETER C_BASEADDR = 0xa0000000
+               PARAMETER C_HIGHADDR = 0xa0001FFF
+               BUS_INTERFACE SOPB = opb_v20_0
+       END
+
+       BEGIN plb_v34
+               PARAMETER INSTANCE = plb_v34_0
+               PARAMETER HW_VER = 1.02.a
+       END
+
+       BEGIN plb_bram_if_cntlr
+               PARAMETER INSTANCE = plb_bram_if_cntlr_0
+               PARAMETER HW_VER = 1.00.b
+               PARAMETER C_BASEADDR = 0xFFFF0000
+               PARAMETER C_HIGHADDR = 0xFFFFFFFF
+               BUS_INTERFACE SPLB = plb_v34_0
+       END
+
+       BEGIN plb2opb_bridge
+               PARAMETER INSTANCE = plb2opb_bridge_0
+               PARAMETER HW_VER = 1.01.a
+               PARAMETER C_RNG0_BASEADDR = 0x20000000
+               PARAMETER C_RNG0_HIGHADDR = 0x3FFFFFFF
+               PARAMETER C_RNG1_BASEADDR = 0x60000000
+               PARAMETER C_RNG1_HIGHADDR = 0x7FFFFFFF
+               PARAMETER C_RNG2_BASEADDR = 0x80000000
+               PARAMETER C_RNG2_HIGHADDR = 0xBFFFFFFF
+               PARAMETER C_RNG3_BASEADDR = 0xC0000000
+               PARAMETER C_RNG3_HIGHADDR = 0xDFFFFFFF
+               BUS_INTERFACE SPLB = plb_v34_0
+               BUS_INTERFACE MOPB = opb_v20_0
+       END
+
+   Gives this device tree (some properties removed for clarity):
+
+       plb@0 {
+               #address-cells = <1>;
+               #size-cells = <1>;
+               compatible = "xlnx,plb-v34-1.02.a";
+               device_type = "ibm,plb";
+               ranges; // 1:1 translation
+
+               plb_bram_if_cntrl_0: bram@ffff0000 {
+                       reg = <ffff0000 10000>;
+               }
+
+               opb@20000000 {
+                       #address-cells = <1>;
+                       #size-cells = <1>;
+                       ranges = <20000000 20000000 20000000
+                                 60000000 60000000 20000000
+                                 80000000 80000000 40000000
+                                 c0000000 c0000000 20000000>;
+
+                       opb_uart16550_0: serial@a0000000 {
+                               reg = <a00000000 2000>;
+                       };
+
+                       opb_intc_0: interrupt-controller@d1000fc0 {
+                               reg = <d1000fc0 20>;
+                       };
+               };
+       };
+
+   That covers the general approach to binding xilinx IP cores into the
+   device tree.  The following are bindings for specific devices:
+
+      i) Xilinx ML300 Framebuffer
+
+      Simple framebuffer device from the ML300 reference design (also on the
+      ML403 reference design as well as others).
+
+      Optional properties:
+       - resolution = <xres yres> : pixel resolution of framebuffer.  Some
+                                    implementations use a different resolution.
+                                    Default is <d#640 d#480>
+       - virt-resolution = <xvirt yvirt> : Size of framebuffer in memory.
+                                           Default is <d#1024 d#480>.
+       - rotate-display (empty) : rotate display 180 degrees.
+
+      ii) Xilinx SystemACE
+
+      The Xilinx SystemACE device is used to program FPGAs from an FPGA
+      bitstream stored on a CF card.  It can also be used as a generic CF
+      interface device.
+
+      Optional properties:
+       - 8-bit (empty) : Set this property for SystemACE in 8 bit mode
+
+      iii) Xilinx EMAC and Xilinx TEMAC
+
+      Xilinx Ethernet devices.  In addition to general xilinx properties
+      listed above, nodes for these devices should include a phy-handle
+      property, and may include other common network device properties
+      like local-mac-address.
+
+      iv) Xilinx Uartlite
+
+      Xilinx uartlite devices are simple fixed speed serial ports.
+
+      Required properties:
+       - current-speed : Baud rate of uartlite
+
+      v) Xilinx hwicap
+
+               Xilinx hwicap devices provide access to the configuration logic
+               of the FPGA through the Internal Configuration Access Port
+               (ICAP).  The ICAP enables partial reconfiguration of the FPGA,
+               readback of the configuration information, and some control over
+               'warm boots' of the FPGA fabric.
+
+               Required properties:
+               - xlnx,family : The family of the FPGA, necessary since the
+                      capabilities of the underlying ICAP hardware
+                      differ between different families.  May be
+                      'virtex2p', 'virtex4', or 'virtex5'.
+
+      vi) Xilinx Uart 16550
+
+      Xilinx UART 16550 devices are very similar to the NS16550 but with
+      different register spacing and an offset from the base address.
+
+      Required properties:
+       - clock-frequency : Frequency of the clock input
+       - reg-offset : A value of 3 is required
+       - reg-shift : A value of 2 is required
+
+
index 1df7f9cdab0576227671703c6fec1fc780ec596b..86eabe6c3419fd4f26aba47a090ecc1caff9a1fd 100644 (file)
@@ -73,7 +73,7 @@ The remaining CPU time will be used for user input and other tasks. Because
 realtime tasks have explicitly allocated the CPU time they need to perform
 their tasks, buffer underruns in the graphics or audio can be eliminated.
 
-NOTE: the above example is not fully implemented as of yet (2.6.25). We still
+NOTE: the above example is not fully implemented yet. We still
 lack an EDF scheduler to make non-uniform periods usable.
 
 
@@ -140,14 +140,15 @@ The other option is:
 
 .o CONFIG_CGROUP_SCHED (aka "Basis for grouping tasks" = "Control groups")
 
-This uses the /cgroup virtual file system and "/cgroup/<cgroup>/cpu.rt_runtime_us"
-to control the CPU time reserved for each control group instead.
+This uses the /cgroup virtual file system and
+"/cgroup/<cgroup>/cpu.rt_runtime_us" to control the CPU time reserved for each
+control group instead.
 
 For more information on working with control groups, you should read
 Documentation/cgroups/cgroups.txt as well.
 
-Group settings are checked against the following limits in order to keep the configuration
-schedulable:
+Group settings are checked against the following limits in order to keep the
+configuration schedulable:
 
    \Sum_{i} runtime_{i} / global_period <= global_runtime / global_period
 
@@ -189,7 +190,7 @@ Implementing SCHED_EDF might take a while to complete. Priority Inheritance is
 the biggest challenge as the current linux PI infrastructure is geared towards
 the limited static priority levels 0-99. With deadline scheduling you need to
 do deadline inheritance (since priority is inversely proportional to the
-deadline delta (deadline - now).
+deadline delta (deadline - now)).
 
 This means the whole PI machinery will have to be reworked - and that is one of
 the most complex pieces of code we have.
index 0d8d23581c44ebd304b11fcc784e04ca2ad4000b..939a3dd5814817d222ff64c8ce4489a16f8d9930 100644 (file)
@@ -240,6 +240,7 @@ AD1986A
   laptop-automute 2-channel with EAPD and HP-automute (Lenovo N100)
   ultra                2-channel with EAPD (Samsung Ultra tablet PC)
   samsung      2-channel with EAPD (Samsung R65)
+  samsung-p50  2-channel with HP-automute (Samsung P50)
 
 AD1988/AD1988B/AD1989A/AD1989B
 ==============================
index cf0e3ce0d52682171688c07974e90fce66036d5f..c1a5aad3c75a905d470725fc5795775227c4a4fd 100644 (file)
@@ -99,11 +99,13 @@ void parse_opts(int argc, char *argv[])
                        { "lsb",     0, 0, 'L' },
                        { "cs-high", 0, 0, 'C' },
                        { "3wire",   0, 0, '3' },
+                       { "no-cs",   0, 0, 'N' },
+                       { "ready",   0, 0, 'R' },
                        { NULL, 0, 0, 0 },
                };
                int c;
 
-               c = getopt_long(argc, argv, "D:s:d:b:lHOLC3", lopts, NULL);
+               c = getopt_long(argc, argv, "D:s:d:b:lHOLC3NR", lopts, NULL);
 
                if (c == -1)
                        break;
@@ -139,6 +141,12 @@ void parse_opts(int argc, char *argv[])
                case '3':
                        mode |= SPI_3WIRE;
                        break;
+               case 'N':
+                       mode |= SPI_NO_CS;
+                       break;
+               case 'R':
+                       mode |= SPI_READY;
+                       break;
                default:
                        print_usage(argv[0]);
                        break;
index 873630e7e53eb5859b1cd722c0818865d895cd20..014d255231fc7cea3eb73378788e0ddae551eb88 100644 (file)
@@ -66,3 +66,4 @@
  68 -> Terratec AV350                           (em2860)        [0ccd:0084]
  69 -> KWorld ATSC 315U HDTV TV Box             (em2882)        [eb1a:a313]
  70 -> Evga inDtube                             (em2882)
+ 71 -> Silvercrest Webcam 1.3mpix               (em2820/em2840)
index dbe3377754af5ab0d36c5665a3a118e02fc5621f..f37b46d348614be9fc5a0b54a8c303617e979d56 100644 (file)
@@ -2,3 +2,5 @@
        - this file
 mtrr.txt
        - how to use x86 Memory Type Range Registers to increase performance
+exception-tables.txt
+       - why and how Linux kernel uses exception tables on x86
similarity index 75%
rename from Documentation/exception.txt
rename to Documentation/x86/exception-tables.txt
index 2d5aded64247343e1cfa13ded99c3a1e0204517a..32901aa36f0a99f7c087aa7c510bbceb0ec14a89 100644 (file)
-     Kernel level exception handling in Linux 2.1.8
+     Kernel level exception handling in Linux
   Commentary by Joerg Pommnitz <joerg@raleigh.ibm.com>
 
-When a process runs in kernel mode, it often has to access user 
-mode memory whose address has been passed by an untrusted program. 
+When a process runs in kernel mode, it often has to access user
+mode memory whose address has been passed by an untrusted program.
 To protect itself the kernel has to verify this address.
 
-In older versions of Linux this was done with the 
-int verify_area(int type, const void * addr, unsigned long size) 
+In older versions of Linux this was done with the
+int verify_area(int type, const void * addr, unsigned long size)
 function (which has since been replaced by access_ok()).
 
-This function verified that the memory area starting at address 
+This function verified that the memory area starting at address
 'addr' and of size 'size' was accessible for the operation specified
-in type (read or write). To do this, verify_read had to look up the 
-virtual memory area (vma) that contained the address addr. In the 
-normal case (correctly working program), this test was successful. 
+in type (read or write). To do this, verify_read had to look up the
+virtual memory area (vma) that contained the address addr. In the
+normal case (correctly working program), this test was successful.
 It only failed for a few buggy programs. In some kernel profiling
 tests, this normally unneeded verification used up a considerable
 amount of time.
 
-To overcome this situation, Linus decided to let the virtual memory 
+To overcome this situation, Linus decided to let the virtual memory
 hardware present in every Linux-capable CPU handle this test.
 
 How does this work?
 
-Whenever the kernel tries to access an address that is currently not 
-accessible, the CPU generates a page fault exception and calls the 
-page fault handler 
+Whenever the kernel tries to access an address that is currently not
+accessible, the CPU generates a page fault exception and calls the
+page fault handler
 
 void do_page_fault(struct pt_regs *regs, unsigned long error_code)
 
-in arch/i386/mm/fault.c. The parameters on the stack are set up by 
-the low level assembly glue in arch/i386/kernel/entry.S. The parameter
-regs is a pointer to the saved registers on the stack, error_code 
+in arch/x86/mm/fault.c. The parameters on the stack are set up by
+the low level assembly glue in arch/x86/kernel/entry_32.S. The parameter
+regs is a pointer to the saved registers on the stack, error_code
 contains a reason code for the exception.
 
-do_page_fault first obtains the unaccessible address from the CPU 
-control register CR2. If the address is within the virtual address 
-space of the process, the fault probably occurred, because the page 
-was not swapped in, write protected or something similar. However, 
-we are interested in the other case: the address is not valid, there 
-is no vma that contains this address. In this case, the kernel jumps 
-to the bad_area label. 
-
-There it uses the address of the instruction that caused the exception 
-(i.e. regs->eip) to find an address where the execution can continue 
-(fixup). If this search is successful, the fault handler modifies the 
-return address (again regs->eip) and returns. The execution will 
+do_page_fault first obtains the unaccessible address from the CPU
+control register CR2. If the address is within the virtual address
+space of the process, the fault probably occurred, because the page
+was not swapped in, write protected or something similar. However,
+we are interested in the other case: the address is not valid, there
+is no vma that contains this address. In this case, the kernel jumps
+to the bad_area label.
+
+There it uses the address of the instruction that caused the exception
+(i.e. regs->eip) to find an address where the execution can continue
+(fixup). If this search is successful, the fault handler modifies the
+return address (again regs->eip) and returns. The execution will
 continue at the address in fixup.
 
 Where does fixup point to?
 
-Since we jump to the contents of fixup, fixup obviously points 
-to executable code. This code is hidden inside the user access macros. 
-I have picked the get_user macro defined in include/asm/uaccess.h as an
-example. The definition is somewhat hard to follow, so let's peek at 
+Since we jump to the contents of fixup, fixup obviously points
+to executable code. This code is hidden inside the user access macros.
+I have picked the get_user macro defined in arch/x86/include/asm/uaccess.h
+as an example. The definition is somewhat hard to follow, so let's peek at
 the code generated by the preprocessor and the compiler. I selected
-the get_user call in drivers/char/console.c for a detailed examination.
+the get_user call in drivers/char/sysrq.c for a detailed examination.
 
-The original code in console.c line 1405:
+The original code in sysrq.c line 587:
         get_user(c, buf);
 
 The preprocessor output (edited to become somewhat readable):
 
 (
-  {        
-    long __gu_err = - 14 , __gu_val = 0;        
-    const __typeof__(*( (  buf ) )) *__gu_addr = ((buf));        
-    if (((((0 + current_set[0])->tss.segment) == 0x18 )  || 
-       (((sizeof(*(buf))) <= 0xC0000000UL) && 
-       ((unsigned long)(__gu_addr ) <= 0xC0000000UL - (sizeof(*(buf)))))))        
+  {
+    long __gu_err = - 14 , __gu_val = 0;
+    const __typeof__(*( (  buf ) )) *__gu_addr = ((buf));
+    if (((((0 + current_set[0])->tss.segment) == 0x18 )  ||
+       (((sizeof(*(buf))) <= 0xC0000000UL) &&
+       ((unsigned long)(__gu_addr ) <= 0xC0000000UL - (sizeof(*(buf)))))))
       do {
-        __gu_err  = 0;        
-        switch ((sizeof(*(buf)))) {        
-          case 1: 
-            __asm__ __volatile__(        
-              "1:      mov" "b" " %2,%" "b" "1\n"        
-              "2:\n"        
-              ".section .fixup,\"ax\"\n"        
-              "3:      movl %3,%0\n"        
-              "        xor" "b" " %" "b" "1,%" "b" "1\n"        
-              "        jmp 2b\n"        
-              ".section __ex_table,\"a\"\n"        
-              "        .align 4\n"        
-              "        .long 1b,3b\n"        
+        __gu_err  = 0;
+        switch ((sizeof(*(buf)))) {
+          case 1:
+            __asm__ __volatile__(
+              "1:      mov" "b" " %2,%" "b" "1\n"
+              "2:\n"
+              ".section .fixup,\"ax\"\n"
+              "3:      movl %3,%0\n"
+              "        xor" "b" " %" "b" "1,%" "b" "1\n"
+              "        jmp 2b\n"
+              ".section __ex_table,\"a\"\n"
+              "        .align 4\n"
+              "        .long 1b,3b\n"
               ".text"        : "=r"(__gu_err), "=q" (__gu_val): "m"((*(struct __large_struct *)
-                            (   __gu_addr   )) ), "i"(- 14 ), "0"(  __gu_err  )) ; 
-              break;        
-          case 2: 
+                            (   __gu_addr   )) ), "i"(- 14 ), "0"(  __gu_err  )) ;
+              break;
+          case 2:
             __asm__ __volatile__(
-              "1:      mov" "w" " %2,%" "w" "1\n"        
-              "2:\n"        
-              ".section .fixup,\"ax\"\n"        
-              "3:      movl %3,%0\n"        
-              "        xor" "w" " %" "w" "1,%" "w" "1\n"        
-              "        jmp 2b\n"        
-              ".section __ex_table,\"a\"\n"        
-              "        .align 4\n"        
-              "        .long 1b,3b\n"        
+              "1:      mov" "w" " %2,%" "w" "1\n"
+              "2:\n"
+              ".section .fixup,\"ax\"\n"
+              "3:      movl %3,%0\n"
+              "        xor" "w" " %" "w" "1,%" "w" "1\n"
+              "        jmp 2b\n"
+              ".section __ex_table,\"a\"\n"
+              "        .align 4\n"
+              "        .long 1b,3b\n"
               ".text"        : "=r"(__gu_err), "=r" (__gu_val) : "m"((*(struct __large_struct *)
-                            (   __gu_addr   )) ), "i"(- 14 ), "0"(  __gu_err  )); 
-              break;        
-          case 4: 
-            __asm__ __volatile__(        
-              "1:      mov" "l" " %2,%" "" "1\n"        
-              "2:\n"        
-              ".section .fixup,\"ax\"\n"        
-              "3:      movl %3,%0\n"        
-              "        xor" "l" " %" "" "1,%" "" "1\n"        
-              "        jmp 2b\n"        
-              ".section __ex_table,\"a\"\n"        
-              "        .align 4\n"        "        .long 1b,3b\n"        
+                            (   __gu_addr   )) ), "i"(- 14 ), "0"(  __gu_err  ));
+              break;
+          case 4:
+            __asm__ __volatile__(
+              "1:      mov" "l" " %2,%" "" "1\n"
+              "2:\n"
+              ".section .fixup,\"ax\"\n"
+              "3:      movl %3,%0\n"
+              "        xor" "l" " %" "" "1,%" "" "1\n"
+              "        jmp 2b\n"
+              ".section __ex_table,\"a\"\n"
+              "        .align 4\n"        "        .long 1b,3b\n"
               ".text"        : "=r"(__gu_err), "=r" (__gu_val) : "m"((*(struct __large_struct *)
-                            (   __gu_addr   )) ), "i"(- 14 ), "0"(__gu_err)); 
-              break;        
-          default: 
-            (__gu_val) = __get_user_bad();        
-        }        
-      } while (0) ;        
-    ((c)) = (__typeof__(*((buf))))__gu_val;        
+                            (   __gu_addr   )) ), "i"(- 14 ), "0"(__gu_err));
+              break;
+          default:
+            (__gu_val) = __get_user_bad();
+        }
+      } while (0) ;
+    ((c)) = (__typeof__(*((buf))))__gu_val;
     __gu_err;
   }
 );
@@ -127,12 +127,12 @@ see what code gcc generates:
 
  >         xorl %edx,%edx
  >         movl current_set,%eax
- >         cmpl $24,788(%eax)        
- >         je .L1424        
+ >         cmpl $24,788(%eax)
+ >         je .L1424
  >         cmpl $-1073741825,64(%esp)
- >         ja .L1423                
+ >         ja .L1423
  > .L1424:
- >         movl %edx,%eax                        
+ >         movl %edx,%eax
  >         movl 64(%esp),%ebx
  > #APP
  > 1:      movb (%ebx),%dl                /* this is the actual user access */
@@ -149,17 +149,17 @@ see what code gcc generates:
  > .L1423:
  >         movzbl %dl,%esi
 
-The optimizer does a good job and gives us something we can actually 
-understand. Can we? The actual user access is quite obvious. Thanks 
-to the unified address space we can just access the address in user 
+The optimizer does a good job and gives us something we can actually
+understand. Can we? The actual user access is quite obvious. Thanks
+to the unified address space we can just access the address in user
 memory. But what does the .section stuff do?????
 
 To understand this we have to look at the final kernel:
 
  > objdump --section-headers vmlinux
- > 
+ >
  > vmlinux:     file format elf32-i386
- > 
+ >
  > Sections:
  > Idx Name          Size      VMA       LMA       File off  Algn
  >   0 .text         00098f40  c0100000  c0100000  00001000  2**4
@@ -198,18 +198,18 @@ final kernel executable:
 
 The whole user memory access is reduced to 10 x86 machine instructions.
 The instructions bracketed in the .section directives are no longer
-in the normal execution path. They are located in a different section 
+in the normal execution path. They are located in a different section
 of the executable file:
 
  > objdump --disassemble --section=.fixup vmlinux
- > 
+ >
  > c0199ff5 <.fixup+10b5> movl   $0xfffffff2,%eax
  > c0199ffa <.fixup+10ba> xorb   %dl,%dl
  > c0199ffc <.fixup+10bc> jmp    c017e7a7 <do_con_write+e3>
 
 And finally:
  > objdump --full-contents --section=__ex_table vmlinux
- > 
+ >
  >  c01aa7c4 93c017c0 e09f19c0 97c017c0 99c017c0  ................
  >  c01aa7d4 f6c217c0 e99f19c0 a5e717c0 f59f19c0  ................
  >  c01aa7e4 080a18c0 01a019c0 0a0a18c0 04a019c0  ................
@@ -235,8 +235,8 @@ sections in the ELF object file. So the instructions
 ended up in the .fixup section of the object file and the addresses
         .long 1b,3b
 ended up in the __ex_table section of the object file. 1b and 3b
-are local labels. The local label 1b (1b stands for next label 1 
-backward) is the address of the instruction that might fault, i.e. 
+are local labels. The local label 1b (1b stands for next label 1
+backward) is the address of the instruction that might fault, i.e.
 in our case the address of the label 1 is c017e7a5:
 the original assembly code: > 1:      movb (%ebx),%dl
 and linked in vmlinux     : > c017e7a5 <do_con_write+e1> movb   (%ebx),%dl
@@ -254,7 +254,7 @@ The assembly code
 becomes the value pair
  >  c01aa7d4 c017c2f6 c0199fe9 c017e7a5 c0199ff5  ................
                                ^this is ^this is
-                               1b       3b 
+                               1b       3b
 c017e7a5,c0199ff5 in the exception table of the kernel.
 
 So, what actually happens if a fault from kernel mode with no suitable
@@ -266,9 +266,9 @@ vma occurs?
 3.) CPU calls do_page_fault
 4.) do page fault calls search_exception_table (regs->eip == c017e7a5);
 5.) search_exception_table looks up the address c017e7a5 in the
-    exception table (i.e. the contents of the ELF section __ex_table) 
+    exception table (i.e. the contents of the ELF section __ex_table)
     and returns the address of the associated fault handle code c0199ff5.
-6.) do_page_fault modifies its own return address to point to the fault 
+6.) do_page_fault modifies its own return address to point to the fault
     handle code and returns.
 7.) execution continues in the fault handling code.
 8.) 8a) EAX becomes -EFAULT (== -14)
index 303129ab4b7509bff0ed0ce3960d5c6b7bc53ff9..18c3f0c41c95a034d98efda6cc4f7db905325a4a 100644 (file)
@@ -230,6 +230,13 @@ L: linux-acenic@sunsite.dk
 S:     Maintained
 F:     drivers/net/acenic*
 
+ACER ASPIRE ONE TEMPERATURE AND FAN DRIVER
+P: Peter Feuerer
+M: peter@piie.net
+W: http://piie.net/?section=acerhdf
+S: Maintained
+F: drivers/platform/x86/acerhdf.c
+
 ACER WMI LAPTOP EXTRAS
 P:     Carlos Corbacho
 M:     carlos@strangeworlds.co.uk
@@ -860,12 +867,22 @@ M:        alex@shark-linux.de
 W:     http://www.shark-linux.de/shark.html
 S:     Maintained
 
+ARM/SAMSUNG ARM ARCHITECTURES
+P:     Ben Dooks
+M:     ben-linux@fluff.org
+L:     linux-arm-kernel@lists.arm.linux.org.uk (subscribers-only)
+W:     http://www.fluff.org/ben/linux/
+S:     Maintained
+F:     arch/arm/plat-s3c/
+F:     arch/arm/plat-s3c24xx/
+
 ARM/S3C2410 ARM ARCHITECTURE
 P:     Ben Dooks
 M:     ben-linux@fluff.org
 L:     linux-arm-kernel@lists.arm.linux.org.uk (subscribers-only)
 W:     http://www.fluff.org/ben/linux/
 S:     Maintained
+F:     arch/arm/mach-s3c2410/
 
 ARM/S3C2440 ARM ARCHITECTURE
 P:     Ben Dooks
@@ -873,6 +890,39 @@ M: ben-linux@fluff.org
 L:     linux-arm-kernel@lists.arm.linux.org.uk (subscribers-only)
 W:     http://www.fluff.org/ben/linux/
 S:     Maintained
+F:     arch/arm/mach-s3c2440/
+
+ARM/S3C2442 ARM ARCHITECTURE
+P:     Ben Dooks
+M:     ben-linux@fluff.org
+L:     linux-arm-kernel@lists.arm.linux.org.uk (subscribers-only)
+W:     http://www.fluff.org/ben/linux/
+S:     Maintained
+F:     arch/arm/mach-s3c2442/
+
+ARM/S3C2443 ARM ARCHITECTURE
+P:     Ben Dooks
+M:     ben-linux@fluff.org
+L:     linux-arm-kernel@lists.arm.linux.org.uk (subscribers-only)
+W:     http://www.fluff.org/ben/linux/
+S:     Maintained
+F:     arch/arm/mach-s3c2443/
+
+ARM/S3C6400 ARM ARCHITECTURE
+P:     Ben Dooks
+M:     ben-linux@fluff.org
+L:     linux-arm-kernel@lists.arm.linux.org.uk (subscribers-only)
+W:     http://www.fluff.org/ben/linux/
+S:     Maintained
+F:     arch/arm/mach-s3c6400/
+
+ARM/S3C6410 ARM ARCHITECTURE
+P:     Ben Dooks
+M:     ben-linux@fluff.org
+L:     linux-arm-kernel@lists.arm.linux.org.uk (subscribers-only)
+W:     http://www.fluff.org/ben/linux/
+S:     Maintained
+F:     arch/arm/mach-s3c6410/
 
 ARM/TECHNOLOGIC SYSTEMS TS7250 MACHINE SUPPORT
 P:     Lennert Buytenhek
@@ -913,8 +963,7 @@ M:  corentincj@iksaif.net
 P:     Karol Kozimor
 M:     sziwan@users.sourceforge.net
 L:     acpi4asus-user@lists.sourceforge.net
-W:     http://sourceforge.net/projects/acpi4asus
-W:     http://xf.iksaif.net/acpi4asus
+W:     http://acpi4asus.sf.net
 S:     Maintained
 F:     arch/x86/kernel/acpi/boot.c
 F:     drivers/platform/x86/asus_acpi.c
@@ -930,8 +979,7 @@ ASUS LAPTOP EXTRAS DRIVER
 P:     Corentin Chary
 M:     corentincj@iksaif.net
 L:     acpi4asus-user@lists.sourceforge.net
-W:     http://sourceforge.net/projects/acpi4asus
-W:     http://xf.iksaif.net/acpi4asus
+W:     http://acpi4asus.sf.net
 S:     Maintained
 F:     drivers/platform/x86/asus-laptop.c
 
@@ -1636,7 +1684,7 @@ P:        Mikael Starvik
 M:     starvik@axis.com
 P:     Jesper Nilsson
 M:     jesper.nilsson@axis.com
-L:     dev-etrax@axis.com
+L:     linux-cris-kernel@axis.com
 W:     http://developer.axis.com
 S:     Maintained
 F:     arch/cris/
@@ -2082,9 +2130,9 @@ F:        drivers/edac/i5400_edac.c
 
 EDAC-I82975X
 P:     Ranganathan Desikan
-M:     rdesikan@jetzbroadband.com
+M:     ravi@jetztechnologies.com
 P:     Arvind R.
-M:     arvind@acarlab.com
+M:     arvind@jetztechnologies.com
 L:     bluesmoke-devel@lists.sourceforge.net (moderated for non-subscribers)
 W:     bluesmoke.sourceforge.net
 S:     Maintained
@@ -2110,7 +2158,7 @@ EEEPC LAPTOP EXTRAS DRIVER
 P:     Corentin Chary
 M:     corentincj@iksaif.net
 L:     acpi4asus-user@lists.sourceforge.net
-W:     http://sourceforge.net/projects/acpi4asus
+W:     http://acpi4asus.sf.net
 S:     Maintained
 F:     drivers/platform/x86/eeepc-laptop.c
 
@@ -2803,7 +2851,9 @@ S:        Maintained
 
 IA64 (Itanium) PLATFORM
 P:     Tony Luck
+P:     Fenghua Yu
 M:     tony.luck@intel.com
+M:     fenghua.yu@intel.com
 L:     linux-ia64@vger.kernel.org
 W:     http://www.ia64-linux.org/
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/aegl/linux-2.6.git
@@ -2881,7 +2931,7 @@ P:        Dmitry Eremin-Solenikov
 M:     dbaryshkov@gmail.com
 P:     Sergey Lapin
 M:     slapin@ossfans.org
-L:     linux-zigbee-devel@lists.sourceforge.net
+L:     linux-zigbee-devel@lists.sourceforge.net (moderated for non-subscribers)
 W:     http://apps.sourceforge.net/trac/linux-zigbee
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/lowpan/lowpan.git
 S:     Maintained
@@ -3237,11 +3287,11 @@ F:      include/linux/ivtv*
 
 JFS FILESYSTEM
 P:     Dave Kleikamp
-M:     shaggy@austin.ibm.com
+M:     shaggy@linux.vnet.ibm.com
 L:     jfs-discussion@lists.sourceforge.net
 W:     http://jfs.sourceforge.net/
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/shaggy/jfs-2.6.git
-S:     Supported
+S:     Maintained
 F:     Documentation/filesystems/jfs.txt
 F:     fs/jfs/
 
@@ -4357,7 +4407,7 @@ W:        http://www.nongnu.org/orinoco/
 S:     Maintained
 F:     drivers/net/wireless/orinoco/
 
-OSD LIBRARY
+OSD LIBRARY and FILESYSTEM
 P:     Boaz Harrosh
 M:     bharrosh@panasas.com
 P:     Benny Halevy
@@ -4366,6 +4416,9 @@ L:        osd-dev@open-osd.org
 W:     http://open-osd.org
 T:     git git://git.open-osd.org/open-osd.git
 S:     Maintained
+F:     drivers/scsi/osd/
+F:     drivers/include/scsi/osd_*
+F:     fs/exofs/
 
 P54 WIRELESS DRIVER
 P:     Michael Wu
@@ -5528,8 +5581,8 @@ F:        drivers/staging/
 
 STARFIRE/DURALAN NETWORK DRIVER
 P:     Ion Badulescu
-M:     ionut@cs.columbia.edu
-S:     Maintained
+M:     ionut@badula.org
+S:     Odd Fixes
 F:     drivers/net/starfire*
 
 STARMODE RADIO IP (STRIP) PROTOCOL DRIVER
@@ -5663,6 +5716,13 @@ F:       drivers/misc/tifm*
 F:     drivers/mmc/host/tifm_sd.c
 F:     include/linux/tifm.h
 
+TI TWL4030 SERIES SOC CODEC DRIVER
+P:     Peter Ujfalusi
+M:     peter.ujfalusi@nokia.com
+L:     alsa-devel@alsa-project.org (moderated for non-subscribers)
+S:     Maintained
+F:     sound/soc/codecs/twl4030*
+
 TIPC NETWORK LAYER
 P:     Per Liden
 M:     per.liden@ericsson.com
@@ -5746,17 +5806,17 @@ P:      Jiri Kosina
 M:     trivial@kernel.org
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/jikos/trivial.git
 S:     Maintained
-F:     drivers/char/tty_*
-F:     drivers/serial/serial_core.c
-F:     include/linux/serial_core.h
-F:     include/linux/serial.h
-F:     include/linux/tty.h
 
 TTY LAYER
 P:     Alan Cox
 M:     alan@lxorguk.ukuu.org.uk
 S:     Maintained
 T:     stgit http://zeniv.linux.org.uk/~alan/ttydev/
+F:     drivers/char/tty_*
+F:     drivers/serial/serial_core.c
+F:     include/linux/serial_core.h
+F:     include/linux/serial.h
+F:     include/linux/tty.h
 
 TULIP NETWORK DRIVERS
 P:     Grant Grundler
@@ -5794,7 +5854,7 @@ UBI FILE SYSTEM (UBIFS)
 P:     Artem Bityutskiy
 M:     dedekind@infradead.org
 P:     Adrian Hunter
-M:     ext-adrian.hunter@nokia.com
+M:     adrian.hunter@nokia.com
 L:     linux-mtd@lists.infradead.org
 T:     git git://git.infradead.org/ubifs-2.6.git
 W:     http://www.linux-mtd.infradead.org/doc/ubifs.html
index 46e1c9d03d515c4a32945b189584a1f652e87c1c..79957b338770d30d9dd9d72abf3ad9e9e3620cd4 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -1,7 +1,7 @@
 VERSION = 2
 PATCHLEVEL = 6
-SUBLEVEL = 30
-EXTRAVERSION =
+SUBLEVEL = 31
+EXTRAVERSION = -rc3
 NAME = Man-Eating Seals of Antiquity
 
 # *DOCUMENTATION*
@@ -140,15 +140,13 @@ _all: modules
 endif
 
 srctree                := $(if $(KBUILD_SRC),$(KBUILD_SRC),$(CURDIR))
-TOPDIR         := $(srctree)
-# FIXME - TOPDIR is obsolete, use srctree/objtree
 objtree                := $(CURDIR)
 src            := $(srctree)
 obj            := $(objtree)
 
 VPATH          := $(srctree)$(if $(KBUILD_EXTMOD),:$(KBUILD_EXTMOD))
 
-export srctree objtree VPATH TOPDIR
+export srctree objtree VPATH
 
 
 # SUBARCH tells the usermode build what the underlying arch is.  That is set
@@ -344,7 +342,9 @@ KBUILD_CPPFLAGS := -D__KERNEL__
 
 KBUILD_CFLAGS   := -Wall -Wundef -Wstrict-prototypes -Wno-trigraphs \
                   -fno-strict-aliasing -fno-common \
-                  -Werror-implicit-function-declaration
+                  -Werror-implicit-function-declaration \
+                  -Wno-format-security \
+                  -fno-delete-null-pointer-checks
 KBUILD_AFLAGS   := -D__ASSEMBLY__
 
 # Read KERNELRELEASE from include/config/kernel.release (if it exists)
@@ -566,7 +566,7 @@ KBUILD_CFLAGS += $(call cc-option,-Wdeclaration-after-statement,)
 KBUILD_CFLAGS += $(call cc-option,-Wno-pointer-sign,)
 
 # disable invalid "can't wrap" optimizations for signed / pointers
-KBUILD_CFLAGS  += $(call cc-option,-fwrapv)
+KBUILD_CFLAGS  += $(call cc-option,-fno-strict-overflow)
 
 # revert to pre-gcc-4.4 behaviour of .eh_frame
 KBUILD_CFLAGS  += $(call cc-option,-fno-dwarf2-cfi-asm)
index 06c5c7a4afd3f6617440cdbcf669d70d591a0d44..b663f1f10b6a1011c7645580300951b977029acd 100644 (file)
@@ -30,7 +30,7 @@ extern unsigned long __per_cpu_offset[NR_CPUS];
 
 #ifndef MODULE
 #define SHIFT_PERCPU_PTR(var, offset) RELOC_HIDE(&per_cpu_var(var), (offset))
-#define PER_CPU_ATTRIBUTES
+#define PER_CPU_DEF_ATTRIBUTES
 #else
 /*
  * To calculate addresses of locally defined variables, GCC uses 32-bit
@@ -49,7 +49,7 @@ extern unsigned long __per_cpu_offset[NR_CPUS];
                : "=&r"(__ptr), "=&r"(tmp_gp));         \
        (typeof(&per_cpu_var(var)))(__ptr + (offset)); })
 
-#define PER_CPU_ATTRIBUTES     __used
+#define PER_CPU_DEF_ATTRIBUTES __used
 
 #endif /* MODULE */
 
@@ -71,7 +71,7 @@ extern unsigned long __per_cpu_offset[NR_CPUS];
 #define __get_cpu_var(var)             per_cpu_var(var)
 #define __raw_get_cpu_var(var)         per_cpu_var(var)
 
-#define PER_CPU_ATTRIBUTES
+#define PER_CPU_DEF_ATTRIBUTES
 
 #endif /* SMP */
 
index d069526bd7673f9ead6eb33e825782ea690e2fb0..60c83abfde7027832e0e7609ac7e032accb66386 100644 (file)
@@ -37,6 +37,7 @@ struct thread_info {
        .task           = &tsk,                 \
        .exec_domain    = &default_exec_domain, \
        .addr_limit     = KERNEL_DS,            \
+       .preempt_count  = INIT_PREEMPT_COUNT,   \
        .restart_block = {                      \
                .fn = do_no_restart_syscall,    \
        },                                      \
index 1e9ad52c460ec293aa70f9cbc5bb3094adc08d74..e072041d19f8ba97f15ee6922ee5955e4db36930 100644 (file)
@@ -8,7 +8,6 @@
 #include <linux/sched.h>
 #include <linux/mm.h>
 #include <linux/smp.h>
-#include <linux/smp_lock.h>
 #include <linux/errno.h>
 #include <linux/ptrace.h>
 #include <linux/user.h>
index a71fd941ade7cdd82610b62a1109a6dc04615907..a89e4734b8f0b6a966b7dd2bba0d1af32896b467 100644 (file)
@@ -99,14 +99,6 @@ config DEBUG_CLPS711X_UART2
          output to the second serial port on these devices.  Saying N will
          cause the debug messages to appear on the first serial port.
 
-config DEBUG_S3C_PORT
-       depends on DEBUG_LL && PLAT_S3C
-       bool "Kernel low-level debugging messages via S3C UART"
-       help
-         Say Y here if you want debug print routines to go to one of the
-         S3C internal UARTs. The chosen UART must have been configured
-         before it is used.
-
 config DEBUG_S3C_UART
        depends on PLAT_S3C
        int "S3C UART to use for low-level debug"
index 8e74c66f239db6bec52dd8f88ffa1a8c44603b55..605a8462f17263cb2547d16dcdd1e73f37d3034a 100644 (file)
 #
 # Automatically generated make config: don't edit
-# Linux kernel version: 2.6.13-rc2
-# Sun Aug 14 19:26:59 2005
+# Linux kernel version: 2.6.30-rc8
+# Wed Jun  3 13:52:33 2009
 #
 CONFIG_ARM=y
+CONFIG_SYS_SUPPORTS_APM_EMULATION=y
+CONFIG_GENERIC_GPIO=y
+CONFIG_GENERIC_TIME=y
+CONFIG_GENERIC_CLOCKEVENTS=y
 CONFIG_MMU=y
-CONFIG_UID16=y
+# CONFIG_NO_IOPORT is not set
+CONFIG_GENERIC_HARDIRQS=y
+CONFIG_STACKTRACE_SUPPORT=y
+CONFIG_HAVE_LATENCYTOP_SUPPORT=y
+CONFIG_LOCKDEP_SUPPORT=y
+CONFIG_TRACE_IRQFLAGS_SUPPORT=y
+CONFIG_HARDIRQS_SW_RESEND=y
+CONFIG_GENERIC_IRQ_PROBE=y
 CONFIG_RWSEM_GENERIC_SPINLOCK=y
+# CONFIG_ARCH_HAS_ILOG2_U32 is not set
+# CONFIG_ARCH_HAS_ILOG2_U64 is not set
+CONFIG_GENERIC_HWEIGHT=y
 CONFIG_GENERIC_CALIBRATE_DELAY=y
+CONFIG_GENERIC_HARDIRQS_NO__DO_IRQ=y
+CONFIG_VECTORS_BASE=0xffff0000
+CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
 
 #
-# Code maturity level options
+# General setup
 #
-# CONFIG_EXPERIMENTAL is not set
-CONFIG_CLEAN_COMPILE=y
+CONFIG_EXPERIMENTAL=y
 CONFIG_BROKEN_ON_SMP=y
+CONFIG_LOCK_KERNEL=y
 CONFIG_INIT_ENV_ARG_LIMIT=32
-
-#
-# General setup
-#
 CONFIG_LOCALVERSION=""
+CONFIG_LOCALVERSION_AUTO=y
 # CONFIG_SWAP is not set
-# CONFIG_SYSVIPC is not set
-# CONFIG_BSD_PROCESS_ACCT is not set
+CONFIG_SYSVIPC=y
+CONFIG_SYSVIPC_SYSCTL=y
+CONFIG_POSIX_MQUEUE=y
+CONFIG_POSIX_MQUEUE_SYSCTL=y
+CONFIG_BSD_PROCESS_ACCT=y
+# CONFIG_BSD_PROCESS_ACCT_V3 is not set
+# CONFIG_TASKSTATS is not set
+CONFIG_AUDIT=y
+
+#
+# RCU Subsystem
+#
+CONFIG_CLASSIC_RCU=y
+# CONFIG_TREE_RCU is not set
+# CONFIG_PREEMPT_RCU is not set
+# CONFIG_TREE_RCU_TRACE is not set
+# CONFIG_PREEMPT_RCU_TRACE is not set
+CONFIG_IKCONFIG=y
+CONFIG_IKCONFIG_PROC=y
+CONFIG_LOG_BUF_SHIFT=17
+# CONFIG_GROUP_SCHED is not set
+# CONFIG_CGROUPS is not set
+# CONFIG_SYSFS_DEPRECATED_V2 is not set
+# CONFIG_RELAY is not set
+CONFIG_NAMESPACES=y
+# CONFIG_UTS_NS is not set
+# CONFIG_IPC_NS is not set
+# CONFIG_USER_NS is not set
+# CONFIG_PID_NS is not set
+# CONFIG_NET_NS is not set
+CONFIG_BLK_DEV_INITRD=y
+CONFIG_INITRAMFS_SOURCE=""
+CONFIG_RD_GZIP=y
+CONFIG_RD_BZIP2=y
+CONFIG_RD_LZMA=y
+CONFIG_CC_OPTIMIZE_FOR_SIZE=y
 CONFIG_SYSCTL=y
-# CONFIG_AUDIT is not set
-CONFIG_HOTPLUG=y
-# CONFIG_KOBJECT_UEVENT is not set
-# CONFIG_IKCONFIG is not set
+CONFIG_ANON_INODES=y
 # CONFIG_EMBEDDED is not set
+CONFIG_UID16=y
+CONFIG_SYSCTL_SYSCALL=y
 CONFIG_KALLSYMS=y
 # CONFIG_KALLSYMS_ALL is not set
-# CONFIG_KALLSYMS_EXTRA_PASS is not set
+CONFIG_KALLSYMS_EXTRA_PASS=y
+# CONFIG_STRIP_ASM_SYMS is not set
+CONFIG_HOTPLUG=y
 CONFIG_PRINTK=y
 CONFIG_BUG=y
+CONFIG_ELF_CORE=y
 CONFIG_BASE_FULL=y
 CONFIG_FUTEX=y
 CONFIG_EPOLL=y
-CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+CONFIG_SIGNALFD=y
+CONFIG_TIMERFD=y
+CONFIG_EVENTFD=y
 CONFIG_SHMEM=y
-CONFIG_CC_ALIGN_FUNCTIONS=0
-CONFIG_CC_ALIGN_LABELS=0
-CONFIG_CC_ALIGN_LOOPS=0
-CONFIG_CC_ALIGN_JUMPS=0
-# CONFIG_TINY_SHMEM is not set
+CONFIG_AIO=y
+CONFIG_VM_EVENT_COUNTERS=y
+CONFIG_SLUB_DEBUG=y
+CONFIG_COMPAT_BRK=y
+# CONFIG_SLAB is not set
+CONFIG_SLUB=y
+# CONFIG_SLOB is not set
+# CONFIG_PROFILING is not set
+CONFIG_TRACEPOINTS=y
+CONFIG_MARKERS=y
+CONFIG_HAVE_OPROFILE=y
+# CONFIG_KPROBES is not set
+CONFIG_HAVE_KPROBES=y
+CONFIG_HAVE_KRETPROBES=y
+CONFIG_HAVE_CLK=y
+# CONFIG_SLOW_WORK is not set
+CONFIG_HAVE_GENERIC_DMA_COHERENT=y
+CONFIG_SLABINFO=y
+CONFIG_RT_MUTEXES=y
 CONFIG_BASE_SMALL=0
+CONFIG_MODULES=y
+# CONFIG_MODULE_FORCE_LOAD is not set
+CONFIG_MODULE_UNLOAD=y
+# CONFIG_MODULE_FORCE_UNLOAD is not set
+CONFIG_MODVERSIONS=y
+CONFIG_MODULE_SRCVERSION_ALL=y
+CONFIG_BLOCK=y
+# CONFIG_LBD is not set
+# CONFIG_BLK_DEV_BSG is not set
+# CONFIG_BLK_DEV_INTEGRITY is not set
 
 #
-# Loadable module support
+# IO Schedulers
 #
-CONFIG_MODULES=y
-CONFIG_MODULE_UNLOAD=y
-CONFIG_OBSOLETE_MODPARM=y
-# CONFIG_MODULE_SRCVERSION_ALL is not set
-CONFIG_KMOD=y
+CONFIG_IOSCHED_NOOP=y
+# CONFIG_IOSCHED_AS is not set
+# CONFIG_IOSCHED_DEADLINE is not set
+CONFIG_IOSCHED_CFQ=y
+# CONFIG_DEFAULT_AS is not set
+# CONFIG_DEFAULT_DEADLINE is not set
+CONFIG_DEFAULT_CFQ=y
+# CONFIG_DEFAULT_NOOP is not set
+CONFIG_DEFAULT_IOSCHED="cfq"
+# CONFIG_FREEZER is not set
 
 #
 # System Type
 #
-# CONFIG_ARCH_CLPS7500 is not set
+# CONFIG_ARCH_AAEC2000 is not set
+# CONFIG_ARCH_INTEGRATOR is not set
+# CONFIG_ARCH_REALVIEW is not set
+# CONFIG_ARCH_VERSATILE is not set
+CONFIG_ARCH_AT91=y
 # CONFIG_ARCH_CLPS711X is not set
-# CONFIG_ARCH_CO285 is not set
 # CONFIG_ARCH_EBSA110 is not set
+# CONFIG_ARCH_EP93XX is not set
+# CONFIG_ARCH_GEMINI is not set
 # CONFIG_ARCH_FOOTBRIDGE is not set
-# CONFIG_ARCH_INTEGRATOR is not set
-# CONFIG_ARCH_IOP3XX is not set
-# CONFIG_ARCH_IXP4XX is not set
+# CONFIG_ARCH_NETX is not set
+# CONFIG_ARCH_H720X is not set
+# CONFIG_ARCH_IMX is not set
+# CONFIG_ARCH_IOP13XX is not set
+# CONFIG_ARCH_IOP32X is not set
+# CONFIG_ARCH_IOP33X is not set
+# CONFIG_ARCH_IXP23XX is not set
 # CONFIG_ARCH_IXP2000 is not set
+# CONFIG_ARCH_IXP4XX is not set
 # CONFIG_ARCH_L7200 is not set
+# CONFIG_ARCH_KIRKWOOD is not set
+# CONFIG_ARCH_KS8695 is not set
+# CONFIG_ARCH_NS9XXX is not set
+# CONFIG_ARCH_LOKI is not set
+# CONFIG_ARCH_MV78XX0 is not set
+# CONFIG_ARCH_MXC is not set
+# CONFIG_ARCH_ORION5X is not set
+# CONFIG_ARCH_PNX4008 is not set
 # CONFIG_ARCH_PXA is not set
+# CONFIG_ARCH_MMP is not set
 # CONFIG_ARCH_RPC is not set
 # CONFIG_ARCH_SA1100 is not set
 # CONFIG_ARCH_S3C2410 is not set
+# CONFIG_ARCH_S3C64XX is not set
 # CONFIG_ARCH_SHARK is not set
 # CONFIG_ARCH_LH7A40X is not set
+# CONFIG_ARCH_DAVINCI is not set
 # CONFIG_ARCH_OMAP is not set
-# CONFIG_ARCH_VERSATILE is not set
-# CONFIG_ARCH_IMX is not set
-# CONFIG_ARCH_H720X is not set
-# CONFIG_ARCH_AAEC2000 is not set
-CONFIG_ARCH_AT91=y
+# CONFIG_ARCH_MSM is not set
+# CONFIG_ARCH_W90X900 is not set
+
+#
+# Atmel AT91 System-on-Chip
+#
 CONFIG_ARCH_AT91RM9200=y
+# CONFIG_ARCH_AT91SAM9260 is not set
+# CONFIG_ARCH_AT91SAM9261 is not set
+# CONFIG_ARCH_AT91SAM9263 is not set
+# CONFIG_ARCH_AT91SAM9RL is not set
+# CONFIG_ARCH_AT91SAM9G20 is not set
+# CONFIG_ARCH_AT91CAP9 is not set
+# CONFIG_ARCH_AT91X40 is not set
+CONFIG_AT91_PMC_UNIT=y
 
 #
-# AT91RM9200 Implementations
+# AT91RM9200 Board Type
 #
+# CONFIG_MACH_ONEARM is not set
 # CONFIG_ARCH_AT91RM9200DK is not set
 # CONFIG_MACH_AT91RM9200EK is not set
 # CONFIG_MACH_CSB337 is not set
 # CONFIG_MACH_CSB637 is not set
 # CONFIG_MACH_CARMEVA is not set
+# CONFIG_MACH_ATEB9200 is not set
 CONFIG_MACH_KB9200=y
+# CONFIG_MACH_PICOTUX2XX is not set
+# CONFIG_MACH_KAFA is not set
+# CONFIG_MACH_ECBAT91 is not set
+# CONFIG_MACH_YL9200 is not set
+
+#
+# AT91 Board Options
+#
+
+#
+# AT91 Feature Selections
+#
+CONFIG_AT91_PROGRAMMABLE_CLOCKS=y
+CONFIG_AT91_TIMER_HZ=128
+CONFIG_AT91_EARLY_DBGU=y
+# CONFIG_AT91_EARLY_USART0 is not set
+# CONFIG_AT91_EARLY_USART1 is not set
+# CONFIG_AT91_EARLY_USART2 is not set
+# CONFIG_AT91_EARLY_USART3 is not set
+# CONFIG_AT91_EARLY_USART4 is not set
+# CONFIG_AT91_EARLY_USART5 is not set
 
 #
 # Processor Type
 #
 CONFIG_CPU_32=y
 CONFIG_CPU_ARM920T=y
-CONFIG_CPU_32v4=y
+CONFIG_CPU_32v4T=y
 CONFIG_CPU_ABRT_EV4T=y
+CONFIG_CPU_PABRT_NOIFAR=y
 CONFIG_CPU_CACHE_V4WT=y
 CONFIG_CPU_CACHE_VIVT=y
 CONFIG_CPU_COPY_V4WB=y
 CONFIG_CPU_TLB_V4WBI=y
+CONFIG_CPU_CP15=y
+CONFIG_CPU_CP15_MMU=y
 
 #
 # Processor Features
@@ -112,23 +249,48 @@ CONFIG_ARM_THUMB=y
 # CONFIG_CPU_ICACHE_DISABLE is not set
 # CONFIG_CPU_DCACHE_DISABLE is not set
 # CONFIG_CPU_DCACHE_WRITETHROUGH is not set
+# CONFIG_OUTER_CACHE is not set
 
 #
 # Bus support
 #
-CONFIG_ISA_DMA_API=y
-
-#
-# PCCARD (PCMCIA/CardBus) support
-#
+# CONFIG_PCI_SYSCALL is not set
+# CONFIG_ARCH_SUPPORTS_MSI is not set
 # CONFIG_PCCARD is not set
 
 #
 # Kernel Features
 #
-# CONFIG_ARCH_DISCONTIGMEM_ENABLE is not set
+CONFIG_TICK_ONESHOT=y
+CONFIG_NO_HZ=y
+CONFIG_HIGH_RES_TIMERS=y
+CONFIG_GENERIC_CLOCKEVENTS_BUILD=y
+CONFIG_VMSPLIT_3G=y
+# CONFIG_VMSPLIT_2G is not set
+# CONFIG_VMSPLIT_1G is not set
+CONFIG_PAGE_OFFSET=0xC0000000
+CONFIG_PREEMPT=y
+CONFIG_HZ=128
+CONFIG_AEABI=y
+CONFIG_OABI_COMPAT=y
+# CONFIG_ARCH_HAS_HOLES_MEMORYMODEL is not set
+# CONFIG_ARCH_SPARSEMEM_DEFAULT is not set
+# CONFIG_ARCH_SELECT_MEMORY_MODEL is not set
+# CONFIG_HIGHMEM is not set
+CONFIG_SELECT_MEMORY_MODEL=y
+CONFIG_FLATMEM_MANUAL=y
+# CONFIG_DISCONTIGMEM_MANUAL is not set
+# CONFIG_SPARSEMEM_MANUAL is not set
 CONFIG_FLATMEM=y
 CONFIG_FLAT_NODE_MEM_MAP=y
+CONFIG_PAGEFLAGS_EXTENDED=y
+CONFIG_SPLIT_PTLOCK_CPUS=4096
+# CONFIG_PHYS_ADDR_T_64BIT is not set
+CONFIG_ZONE_DMA_FLAG=0
+CONFIG_VIRT_TO_BUS=y
+CONFIG_UNEVICTABLE_LRU=y
+CONFIG_HAVE_MLOCK=y
+CONFIG_HAVE_MLOCKED_PAGE_BIT=y
 # CONFIG_LEDS is not set
 CONFIG_ALIGNMENT_TRAP=y
 
@@ -137,8 +299,16 @@ CONFIG_ALIGNMENT_TRAP=y
 #
 CONFIG_ZBOOT_ROM_TEXT=0x10000000
 CONFIG_ZBOOT_ROM_BSS=0x20040000
-CONFIG_ZBOOT_ROM=y
-CONFIG_CMDLINE="console=ttyS0,115200 root=/dev/ram rw initrd=0x20210000,654933"
+# CONFIG_ZBOOT_ROM is not set
+CONFIG_CMDLINE="noinitrd root=/dev/mtdblock0 rootfstype=jffs2 mem=64M"
+# CONFIG_XIP_KERNEL is not set
+CONFIG_KEXEC=y
+CONFIG_ATAGS_PROC=y
+
+#
+# CPU Power Management
+#
+# CONFIG_CPU_IDLE is not set
 
 #
 # Floating point emulation
@@ -149,74 +319,251 @@ CONFIG_CMDLINE="console=ttyS0,115200 root=/dev/ram rw initrd=0x20210000,654933"
 #
 CONFIG_FPE_NWFPE=y
 # CONFIG_FPE_NWFPE_XP is not set
+# CONFIG_FPE_FASTFPE is not set
 
 #
 # Userspace binary formats
 #
 CONFIG_BINFMT_ELF=y
-CONFIG_BINFMT_AOUT=y
+# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set
+CONFIG_HAVE_AOUT=y
+# CONFIG_BINFMT_AOUT is not set
 CONFIG_BINFMT_MISC=y
-# CONFIG_ARTHUR is not set
 
 #
 # Power management options
 #
 # CONFIG_PM is not set
+CONFIG_ARCH_SUSPEND_POSSIBLE=y
+CONFIG_NET=y
 
 #
-# Device Drivers
+# Networking options
 #
+CONFIG_PACKET=y
+# CONFIG_PACKET_MMAP is not set
+CONFIG_UNIX=y
+# CONFIG_NET_KEY is not set
+CONFIG_INET=y
+# CONFIG_IP_MULTICAST is not set
+# CONFIG_IP_ADVANCED_ROUTER is not set
+CONFIG_IP_FIB_HASH=y
+CONFIG_IP_PNP=y
+CONFIG_IP_PNP_DHCP=y
+CONFIG_IP_PNP_BOOTP=y
+# CONFIG_IP_PNP_RARP is not set
+# CONFIG_NET_IPIP is not set
+# CONFIG_NET_IPGRE is not set
+# CONFIG_ARPD is not set
+# CONFIG_SYN_COOKIES is not set
+# CONFIG_INET_AH is not set
+# CONFIG_INET_ESP is not set
+# CONFIG_INET_IPCOMP is not set
+# CONFIG_INET_XFRM_TUNNEL is not set
+# CONFIG_INET_TUNNEL is not set
+# CONFIG_INET_XFRM_MODE_TRANSPORT is not set
+# CONFIG_INET_XFRM_MODE_TUNNEL is not set
+# CONFIG_INET_XFRM_MODE_BEET is not set
+# CONFIG_INET_LRO is not set
+# CONFIG_INET_DIAG is not set
+# CONFIG_TCP_CONG_ADVANCED is not set
+CONFIG_TCP_CONG_CUBIC=y
+CONFIG_DEFAULT_TCP_CONG="cubic"
+# CONFIG_TCP_MD5SIG is not set
+# CONFIG_IPV6 is not set
+# CONFIG_NETWORK_SECMARK is not set
+# CONFIG_NETFILTER is not set
+# CONFIG_IP_DCCP is not set
+# CONFIG_IP_SCTP is not set
+# CONFIG_TIPC is not set
+# CONFIG_ATM is not set
+# CONFIG_BRIDGE is not set
+# CONFIG_NET_DSA is not set
+# CONFIG_VLAN_8021Q is not set
+# CONFIG_DECNET is not set
+# CONFIG_LLC2 is not set
+# CONFIG_IPX is not set
+# CONFIG_ATALK is not set
+# CONFIG_X25 is not set
+# CONFIG_LAPB is not set
+# CONFIG_ECONET is not set
+# CONFIG_WAN_ROUTER is not set
+# CONFIG_PHONET is not set
+# CONFIG_NET_SCHED is not set
+# CONFIG_DCB is not set
 
 #
-# Generic Driver Options
+# Network testing
 #
-CONFIG_STANDALONE=y
-CONFIG_PREVENT_FIRMWARE_BUILD=y
-# CONFIG_FW_LOADER is not set
-CONFIG_DEBUG_DRIVER=y
+# CONFIG_NET_PKTGEN is not set
+# CONFIG_NET_DROP_MONITOR is not set
+# CONFIG_HAMRADIO is not set
+# CONFIG_CAN is not set
+# CONFIG_IRDA is not set
+# CONFIG_BT is not set
+# CONFIG_AF_RXRPC is not set
+# CONFIG_WIRELESS is not set
+# CONFIG_WIMAX is not set
+# CONFIG_RFKILL is not set
+# CONFIG_NET_9P is not set
 
 #
-# Memory Technology Devices (MTD)
+# Device Drivers
 #
-# CONFIG_MTD is not set
 
 #
-# Parallel port support
+# Generic Driver Options
 #
+CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
+CONFIG_STANDALONE=y
+CONFIG_PREVENT_FIRMWARE_BUILD=y
+CONFIG_FW_LOADER=y
+# CONFIG_FIRMWARE_IN_KERNEL is not set
+CONFIG_EXTRA_FIRMWARE=""
+# CONFIG_DEBUG_DRIVER is not set
+# CONFIG_DEBUG_DEVRES is not set
+# CONFIG_SYS_HYPERVISOR is not set
+# CONFIG_CONNECTOR is not set
+CONFIG_MTD=y
+# CONFIG_MTD_DEBUG is not set
+CONFIG_MTD_CONCAT=y
+CONFIG_MTD_PARTITIONS=y
+# CONFIG_MTD_TESTS is not set
+# CONFIG_MTD_REDBOOT_PARTS is not set
+CONFIG_MTD_CMDLINE_PARTS=y
+# CONFIG_MTD_AFS_PARTS is not set
+# CONFIG_MTD_AR7_PARTS is not set
+
+#
+# User Modules And Translation Layers
+#
+CONFIG_MTD_CHAR=y
+CONFIG_MTD_BLKDEVS=y
+CONFIG_MTD_BLOCK=y
+# CONFIG_FTL is not set
+# CONFIG_NFTL is not set
+# CONFIG_INFTL is not set
+# CONFIG_RFD_FTL is not set
+# CONFIG_SSFDC is not set
+# CONFIG_MTD_OOPS is not set
+
+#
+# RAM/ROM/Flash chip drivers
+#
+CONFIG_MTD_CFI=y
+# CONFIG_MTD_JEDECPROBE is not set
+CONFIG_MTD_GEN_PROBE=y
+# CONFIG_MTD_CFI_ADV_OPTIONS is not set
+CONFIG_MTD_MAP_BANK_WIDTH_1=y
+CONFIG_MTD_MAP_BANK_WIDTH_2=y
+CONFIG_MTD_MAP_BANK_WIDTH_4=y
+# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set
+CONFIG_MTD_CFI_I1=y
+CONFIG_MTD_CFI_I2=y
+# CONFIG_MTD_CFI_I4 is not set
+# CONFIG_MTD_CFI_I8 is not set
+CONFIG_MTD_CFI_INTELEXT=y
+# CONFIG_MTD_CFI_AMDSTD is not set
+# CONFIG_MTD_CFI_STAA is not set
+CONFIG_MTD_CFI_UTIL=y
+# CONFIG_MTD_RAM is not set
+# CONFIG_MTD_ROM is not set
+# CONFIG_MTD_ABSENT is not set
+
+#
+# Mapping drivers for chip access
+#
+CONFIG_MTD_COMPLEX_MAPPINGS=y
+CONFIG_MTD_PHYSMAP=y
+# CONFIG_MTD_PHYSMAP_COMPAT is not set
+# CONFIG_MTD_ARM_INTEGRATOR is not set
+# CONFIG_MTD_PLATRAM is not set
+
+#
+# Self-contained MTD device drivers
+#
+# CONFIG_MTD_SLRAM is not set
+# CONFIG_MTD_PHRAM is not set
+# CONFIG_MTD_MTDRAM is not set
+# CONFIG_MTD_BLOCK2MTD is not set
+
+#
+# Disk-On-Chip Device Drivers
+#
+# CONFIG_MTD_DOC2000 is not set
+# CONFIG_MTD_DOC2001 is not set
+# CONFIG_MTD_DOC2001PLUS is not set
+CONFIG_MTD_NAND=y
+# CONFIG_MTD_NAND_VERIFY_WRITE is not set
+# CONFIG_MTD_NAND_ECC_SMC is not set
+# CONFIG_MTD_NAND_MUSEUM_IDS is not set
+# CONFIG_MTD_NAND_GPIO is not set
+CONFIG_MTD_NAND_IDS=y
+# CONFIG_MTD_NAND_DISKONCHIP is not set
+CONFIG_MTD_NAND_ATMEL=y
+# CONFIG_MTD_NAND_ATMEL_ECC_HW is not set
+CONFIG_MTD_NAND_ATMEL_ECC_SOFT=y
+# CONFIG_MTD_NAND_ATMEL_ECC_NONE is not set
+# CONFIG_MTD_NAND_NANDSIM is not set
+# CONFIG_MTD_NAND_PLATFORM is not set
+# CONFIG_MTD_ALAUDA is not set
+# CONFIG_MTD_ONENAND is not set
+
+#
+# LPDDR flash memory drivers
+#
+# CONFIG_MTD_LPDDR is not set
+
+#
+# UBI - Unsorted block images
+#
+CONFIG_MTD_UBI=y
+CONFIG_MTD_UBI_WL_THRESHOLD=4096
+CONFIG_MTD_UBI_BEB_RESERVE=1
+CONFIG_MTD_UBI_GLUEBI=y
+
+#
+# UBI debugging options
+#
+# CONFIG_MTD_UBI_DEBUG is not set
 # CONFIG_PARPORT is not set
-
-#
-# Plug and Play support
-#
-
-#
-# Block devices
-#
+CONFIG_BLK_DEV=y
 # CONFIG_BLK_DEV_COW_COMMON is not set
 CONFIG_BLK_DEV_LOOP=y
 # CONFIG_BLK_DEV_CRYPTOLOOP is not set
-CONFIG_BLK_DEV_NBD=y
+# CONFIG_BLK_DEV_NBD is not set
 # CONFIG_BLK_DEV_UB is not set
 CONFIG_BLK_DEV_RAM=y
 CONFIG_BLK_DEV_RAM_COUNT=16
-CONFIG_BLK_DEV_RAM_SIZE=4096
-CONFIG_BLK_DEV_INITRD=y
-CONFIG_INITRAMFS_SOURCE=""
+CONFIG_BLK_DEV_RAM_SIZE=16384
+# CONFIG_BLK_DEV_XIP is not set
 # CONFIG_CDROM_PKTCDVD is not set
+# CONFIG_ATA_OVER_ETH is not set
+CONFIG_MISC_DEVICES=y
+CONFIG_ATMEL_TCLIB=y
+CONFIG_ATMEL_TCB_CLKSRC=y
+CONFIG_ATMEL_TCB_CLKSRC_BLOCK=0
+CONFIG_ATMEL_SSC=y
+# CONFIG_ENCLOSURE_SERVICES is not set
+# CONFIG_C2PORT is not set
 
 #
-# IO Schedulers
+# EEPROM support
 #
-CONFIG_IOSCHED_NOOP=y
-CONFIG_IOSCHED_AS=y
-CONFIG_IOSCHED_DEADLINE=y
-CONFIG_IOSCHED_CFQ=y
-# CONFIG_ATA_OVER_ETH is not set
+# CONFIG_EEPROM_93CX6 is not set
+CONFIG_HAVE_IDE=y
+# CONFIG_IDE is not set
 
 #
 # SCSI device support
 #
+# CONFIG_RAID_ATTRS is not set
 CONFIG_SCSI=y
+CONFIG_SCSI_DMA=y
+# CONFIG_SCSI_TGT is not set
+# CONFIG_SCSI_NETLINK is not set
 CONFIG_SCSI_PROC_FS=y
 
 #
@@ -232,145 +579,87 @@ CONFIG_CHR_DEV_SG=y
 #
 # Some SCSI devices (e.g. CD jukebox) support multiple LUNs
 #
-# CONFIG_SCSI_MULTI_LUN is not set
-# CONFIG_SCSI_CONSTANTS is not set
-# CONFIG_SCSI_LOGGING is not set
+CONFIG_SCSI_MULTI_LUN=y
+CONFIG_SCSI_CONSTANTS=y
+CONFIG_SCSI_LOGGING=y
+# CONFIG_SCSI_SCAN_ASYNC is not set
+CONFIG_SCSI_WAIT_SCAN=m
 
 #
-# SCSI Transport Attributes
+# SCSI Transports
 #
-# CONFIG_SCSI_SPI_ATTRS is not set
+CONFIG_SCSI_SPI_ATTRS=m
 # CONFIG_SCSI_FC_ATTRS is not set
 # CONFIG_SCSI_ISCSI_ATTRS is not set
-
-#
-# SCSI low-level drivers
-#
-# CONFIG_SCSI_SATA is not set
-# CONFIG_SCSI_DEBUG is not set
-
-#
-# Multi-device support (RAID and LVM)
-#
+# CONFIG_SCSI_SAS_LIBSAS is not set
+# CONFIG_SCSI_SRP_ATTRS is not set
+# CONFIG_SCSI_LOWLEVEL is not set
+# CONFIG_SCSI_DH is not set
+# CONFIG_SCSI_OSD_INITIATOR is not set
+# CONFIG_ATA is not set
 # CONFIG_MD is not set
-
-#
-# Fusion MPT device support
-#
-# CONFIG_FUSION is not set
-
-#
-# IEEE 1394 (FireWire) support
-#
-
-#
-# I2O device support
-#
-
-#
-# Networking support
-#
-CONFIG_NET=y
-
-#
-# Networking options
-#
-CONFIG_PACKET=y
-# CONFIG_PACKET_MMAP is not set
-CONFIG_UNIX=y
-# CONFIG_NET_KEY is not set
-CONFIG_INET=y
-CONFIG_IP_MULTICAST=y
-# CONFIG_IP_ADVANCED_ROUTER is not set
-CONFIG_IP_FIB_HASH=y
-CONFIG_IP_PNP=y
-CONFIG_IP_PNP_DHCP=y
-# CONFIG_IP_PNP_BOOTP is not set
-# CONFIG_IP_PNP_RARP is not set
-# CONFIG_NET_IPIP is not set
-# CONFIG_NET_IPGRE is not set
-# CONFIG_IP_MROUTE is not set
-# CONFIG_SYN_COOKIES is not set
-# CONFIG_INET_AH is not set
-# CONFIG_INET_ESP is not set
-# CONFIG_INET_IPCOMP is not set
-# CONFIG_INET_TUNNEL is not set
-# CONFIG_IP_TCPDIAG is not set
-# CONFIG_IP_TCPDIAG_IPV6 is not set
-# CONFIG_TCP_CONG_ADVANCED is not set
-CONFIG_TCP_CONG_BIC=y
-# CONFIG_IPV6 is not set
-# CONFIG_NETFILTER is not set
-# CONFIG_BRIDGE is not set
-# CONFIG_VLAN_8021Q is not set
-# CONFIG_DECNET is not set
-# CONFIG_LLC2 is not set
-# CONFIG_IPX is not set
-# CONFIG_ATALK is not set
-
-#
-# QoS and/or fair queueing
-#
-# CONFIG_NET_SCHED is not set
-# CONFIG_NET_CLS_ROUTE is not set
-
-#
-# Network testing
-#
-# CONFIG_NET_PKTGEN is not set
-# CONFIG_NETPOLL is not set
-# CONFIG_NET_POLL_CONTROLLER is not set
-# CONFIG_HAMRADIO is not set
-# CONFIG_IRDA is not set
-# CONFIG_BT is not set
 CONFIG_NETDEVICES=y
+CONFIG_COMPAT_NET_DEV_OPS=y
 # CONFIG_DUMMY is not set
 # CONFIG_BONDING is not set
+# CONFIG_MACVLAN is not set
 # CONFIG_EQUALIZER is not set
 # CONFIG_TUN is not set
-
-#
-# Ethernet (10 or 100Mbit)
-#
+# CONFIG_VETH is not set
+# CONFIG_PHYLIB is not set
 CONFIG_NET_ETHERNET=y
 CONFIG_MII=y
 CONFIG_ARM_AT91_ETHER=y
+# CONFIG_AX88796 is not set
 # CONFIG_SMC91X is not set
 # CONFIG_DM9000 is not set
+# CONFIG_ETHOC is not set
+# CONFIG_SMC911X is not set
+# CONFIG_SMSC911X is not set
+# CONFIG_DNET is not set
+# CONFIG_IBM_NEW_EMAC_ZMII is not set
+# CONFIG_IBM_NEW_EMAC_RGMII is not set
+# CONFIG_IBM_NEW_EMAC_TAH is not set
+# CONFIG_IBM_NEW_EMAC_EMAC4 is not set
+# CONFIG_IBM_NEW_EMAC_NO_FLOW_CTRL is not set
+# CONFIG_IBM_NEW_EMAC_MAL_CLR_ICINTSTAT is not set
+# CONFIG_IBM_NEW_EMAC_MAL_COMMON_ERR is not set
+# CONFIG_B44 is not set
+# CONFIG_NETDEV_1000 is not set
+# CONFIG_NETDEV_10000 is not set
 
 #
-# Ethernet (1000 Mbit)
-#
-
-#
-# Ethernet (10000 Mbit)
-#
-
-#
-# Token Ring devices
+# Wireless LAN
 #
+# CONFIG_WLAN_PRE80211 is not set
+# CONFIG_WLAN_80211 is not set
 
 #
-# Wireless LAN (non-hamradio)
+# Enable WiMAX (Networking options) to see the WiMAX drivers
 #
-# CONFIG_NET_RADIO is not set
 
 #
-# Wan interfaces
+# USB Network Adapters
 #
+# CONFIG_USB_CATC is not set
+# CONFIG_USB_KAWETH is not set
+# CONFIG_USB_PEGASUS is not set
+# CONFIG_USB_RTL8150 is not set
+# CONFIG_USB_USBNET is not set
 # CONFIG_WAN is not set
 # CONFIG_PPP is not set
 # CONFIG_SLIP is not set
-
-#
-# ISDN subsystem
-#
+# CONFIG_NETCONSOLE is not set
+# CONFIG_NETPOLL is not set
+# CONFIG_NET_POLL_CONTROLLER is not set
 # CONFIG_ISDN is not set
 
 #
 # Input device support
 #
 CONFIG_INPUT=y
+# CONFIG_INPUT_FF_MEMLESS is not set
+# CONFIG_INPUT_POLLDEV is not set
 
 #
 # Userland interfaces
@@ -380,7 +669,6 @@ CONFIG_INPUT_MOUSEDEV=y
 CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024
 CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
 # CONFIG_INPUT_JOYDEV is not set
-# CONFIG_INPUT_TSDEV is not set
 # CONFIG_INPUT_EVDEV is not set
 # CONFIG_INPUT_EVBUG is not set
 
@@ -390,23 +678,25 @@ CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
 # CONFIG_INPUT_KEYBOARD is not set
 # CONFIG_INPUT_MOUSE is not set
 # CONFIG_INPUT_JOYSTICK is not set
+# CONFIG_INPUT_TABLET is not set
 # CONFIG_INPUT_TOUCHSCREEN is not set
 # CONFIG_INPUT_MISC is not set
 
 #
 # Hardware I/O ports
 #
-CONFIG_SERIO=y
-# CONFIG_SERIO_SERPORT is not set
-# CONFIG_SERIO_RAW is not set
+# CONFIG_SERIO is not set
 # CONFIG_GAMEPORT is not set
 
 #
 # Character devices
 #
 CONFIG_VT=y
+CONFIG_CONSOLE_TRANSLATIONS=y
 CONFIG_VT_CONSOLE=y
 CONFIG_HW_CONSOLE=y
+# CONFIG_VT_HW_CONSOLE_BINDING is not set
+CONFIG_DEVKMEM=y
 # CONFIG_SERIAL_NONSTANDARD is not set
 
 #
@@ -419,215 +709,362 @@ CONFIG_HW_CONSOLE=y
 #
 CONFIG_SERIAL_ATMEL=y
 CONFIG_SERIAL_ATMEL_CONSOLE=y
+CONFIG_SERIAL_ATMEL_PDC=y
+# CONFIG_SERIAL_ATMEL_TTYAT is not set
 CONFIG_SERIAL_CORE=y
 CONFIG_SERIAL_CORE_CONSOLE=y
 CONFIG_UNIX98_PTYS=y
-CONFIG_LEGACY_PTYS=y
-CONFIG_LEGACY_PTY_COUNT=256
+# CONFIG_DEVPTS_MULTIPLE_INSTANCES is not set
+# CONFIG_LEGACY_PTYS is not set
+# CONFIG_IPMI_HANDLER is not set
+# CONFIG_HW_RANDOM is not set
+# CONFIG_R3964 is not set
+# CONFIG_RAW_DRIVER is not set
+# CONFIG_TCG_TPM is not set
+# CONFIG_I2C is not set
+# CONFIG_SPI is not set
+CONFIG_ARCH_REQUIRE_GPIOLIB=y
+CONFIG_GPIOLIB=y
+# CONFIG_DEBUG_GPIO is not set
+# CONFIG_GPIO_SYSFS is not set
 
 #
-# IPMI
+# Memory mapped GPIO expanders:
 #
-# CONFIG_IPMI_HANDLER is not set
 
 #
-# Watchdog Cards
+# I2C GPIO expanders:
 #
-# CONFIG_WATCHDOG is not set
-# CONFIG_NVRAM is not set
-# CONFIG_RTC is not set
-# CONFIG_AT91RM9200_RTC is not set
-# CONFIG_DTLK is not set
-# CONFIG_R3964 is not set
 
 #
-# Ftape, the floppy tape device driver
+# PCI GPIO expanders:
 #
-# CONFIG_RAW_DRIVER is not set
 
 #
-# TPM devices
+# SPI GPIO expanders:
 #
-# CONFIG_AT91_SPI is not set
+# CONFIG_W1 is not set
+# CONFIG_POWER_SUPPLY is not set
+# CONFIG_HWMON is not set
+# CONFIG_THERMAL is not set
+# CONFIG_THERMAL_HWMON is not set
+CONFIG_WATCHDOG=y
+# CONFIG_WATCHDOG_NOWAYOUT is not set
 
 #
-# I2C support
+# Watchdog Device Drivers
 #
-# CONFIG_I2C is not set
+# CONFIG_SOFT_WATCHDOG is not set
+CONFIG_AT91RM9200_WATCHDOG=y
+
+#
+# USB-based Watchdog Cards
+#
+# CONFIG_USBPCWATCHDOG is not set
+CONFIG_SSB_POSSIBLE=y
 
 #
-# Misc devices
+# Sonics Silicon Backplane
 #
+# CONFIG_SSB is not set
+
+#
+# Multifunction device drivers
+#
+# CONFIG_MFD_CORE is not set
+# CONFIG_MFD_SM501 is not set
+# CONFIG_MFD_ASIC3 is not set
+# CONFIG_HTC_EGPIO is not set
+# CONFIG_HTC_PASIC3 is not set
+# CONFIG_MFD_TMIO is not set
+# CONFIG_MFD_T7L66XB is not set
+# CONFIG_MFD_TC6387XB is not set
+# CONFIG_MFD_TC6393XB is not set
 
 #
 # Multimedia devices
 #
+
+#
+# Multimedia core support
+#
 # CONFIG_VIDEO_DEV is not set
+# CONFIG_DVB_CORE is not set
+# CONFIG_VIDEO_MEDIA is not set
 
 #
-# Digital Video Broadcasting Devices
+# Multimedia drivers
 #
-# CONFIG_DVB is not set
+# CONFIG_DAB is not set
 
 #
 # Graphics support
 #
-# CONFIG_FB is not set
+# CONFIG_VGASTATE is not set
+# CONFIG_VIDEO_OUTPUT_CONTROL is not set
+CONFIG_FB=y
+# CONFIG_FIRMWARE_EDID is not set
+# CONFIG_FB_DDC is not set
+# CONFIG_FB_BOOT_VESA_SUPPORT is not set
+# CONFIG_FB_CFB_FILLRECT is not set
+# CONFIG_FB_CFB_COPYAREA is not set
+# CONFIG_FB_CFB_IMAGEBLIT is not set
+# CONFIG_FB_CFB_REV_PIXELS_IN_BYTE is not set
+# CONFIG_FB_SYS_FILLRECT is not set
+# CONFIG_FB_SYS_COPYAREA is not set
+# CONFIG_FB_SYS_IMAGEBLIT is not set
+# CONFIG_FB_FOREIGN_ENDIAN is not set
+# CONFIG_FB_SYS_FOPS is not set
+# CONFIG_FB_SVGALIB is not set
+# CONFIG_FB_MACMODES is not set
+# CONFIG_FB_BACKLIGHT is not set
+CONFIG_FB_MODE_HELPERS=y
+CONFIG_FB_TILEBLITTING=y
+
+#
+# Frame buffer hardware drivers
+#
+# CONFIG_FB_S1D13XXX is not set
+# CONFIG_FB_VIRTUAL is not set
+# CONFIG_FB_METRONOME is not set
+# CONFIG_FB_MB862XX is not set
+# CONFIG_FB_BROADSHEET is not set
+CONFIG_BACKLIGHT_LCD_SUPPORT=y
+# CONFIG_LCD_CLASS_DEVICE is not set
+CONFIG_BACKLIGHT_CLASS_DEVICE=y
+# CONFIG_BACKLIGHT_GENERIC is not set
+
+#
+# Display device support
+#
+# CONFIG_DISPLAY_SUPPORT is not set
 
 #
 # Console display driver support
 #
 # CONFIG_VGA_CONSOLE is not set
 CONFIG_DUMMY_CONSOLE=y
-
-#
-# Sound
-#
+CONFIG_FRAMEBUFFER_CONSOLE=y
+# CONFIG_FRAMEBUFFER_CONSOLE_DETECT_PRIMARY is not set
+# CONFIG_FRAMEBUFFER_CONSOLE_ROTATION is not set
+CONFIG_FONTS=y
+# CONFIG_FONT_8x8 is not set
+# CONFIG_FONT_8x16 is not set
+# CONFIG_FONT_6x11 is not set
+# CONFIG_FONT_7x14 is not set
+# CONFIG_FONT_PEARL_8x8 is not set
+# CONFIG_FONT_ACORN_8x8 is not set
+CONFIG_FONT_MINI_4x6=y
+# CONFIG_FONT_SUN8x16 is not set
+# CONFIG_FONT_SUN12x22 is not set
+# CONFIG_FONT_10x18 is not set
+# CONFIG_LOGO is not set
 # CONFIG_SOUND is not set
-
-#
-# USB support
-#
+# CONFIG_HID_SUPPORT is not set
+CONFIG_USB_SUPPORT=y
 CONFIG_USB_ARCH_HAS_HCD=y
 CONFIG_USB_ARCH_HAS_OHCI=y
+# CONFIG_USB_ARCH_HAS_EHCI is not set
 CONFIG_USB=y
-CONFIG_USB_DEBUG=y
+# CONFIG_USB_DEBUG is not set
+# CONFIG_USB_ANNOUNCE_NEW_DEVICES is not set
 
 #
 # Miscellaneous USB options
 #
 CONFIG_USB_DEVICEFS=y
+CONFIG_USB_DEVICE_CLASS=y
+# CONFIG_USB_DYNAMIC_MINORS is not set
+# CONFIG_USB_OTG is not set
+# CONFIG_USB_MON is not set
+# CONFIG_USB_WUSB is not set
+# CONFIG_USB_WUSB_CBAF is not set
 
 #
 # USB Host Controller Drivers
 #
+# CONFIG_USB_C67X00_HCD is not set
+# CONFIG_USB_OXU210HP_HCD is not set
 # CONFIG_USB_ISP116X_HCD is not set
+# CONFIG_USB_ISP1760_HCD is not set
 CONFIG_USB_OHCI_HCD=y
-# CONFIG_USB_OHCI_BIG_ENDIAN is not set
+# CONFIG_USB_OHCI_BIG_ENDIAN_DESC is not set
+# CONFIG_USB_OHCI_BIG_ENDIAN_MMIO is not set
 CONFIG_USB_OHCI_LITTLE_ENDIAN=y
 # CONFIG_USB_SL811_HCD is not set
+# CONFIG_USB_R8A66597_HCD is not set
+# CONFIG_USB_HWA_HCD is not set
+# CONFIG_USB_MUSB_HDRC is not set
 
 #
 # USB Device Class drivers
 #
-# CONFIG_USB_BLUETOOTH_TTY is not set
 # CONFIG_USB_ACM is not set
 # CONFIG_USB_PRINTER is not set
+# CONFIG_USB_WDM is not set
+# CONFIG_USB_TMC is not set
 
 #
-# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support' may also be needed; see USB_STORAGE Help for more information
+# NOTE: USB_STORAGE depends on SCSI but BLK_DEV_SD may
 #
-CONFIG_USB_STORAGE=y
-CONFIG_USB_STORAGE_DEBUG=y
-# CONFIG_USB_STORAGE_FREECOM is not set
-# CONFIG_USB_STORAGE_DPCM is not set
-
-#
-# USB Input Devices
-#
-# CONFIG_USB_HID is not set
 
 #
-# USB HID Boot Protocol drivers
+# also be needed; see USB_STORAGE Help for more info
 #
-# CONFIG_USB_KBD is not set
-# CONFIG_USB_MOUSE is not set
-# CONFIG_USB_AIPTEK is not set
-# CONFIG_USB_WACOM is not set
-# CONFIG_USB_ACECAD is not set
-# CONFIG_USB_KBTAB is not set
-# CONFIG_USB_POWERMATE is not set
-# CONFIG_USB_MTOUCH is not set
-# CONFIG_USB_ITMTOUCH is not set
-# CONFIG_USB_EGALAX is not set
-# CONFIG_USB_XPAD is not set
-# CONFIG_USB_ATI_REMOTE is not set
+CONFIG_USB_STORAGE=y
+# CONFIG_USB_STORAGE_DEBUG is not set
+# CONFIG_USB_STORAGE_DATAFAB is not set
+# CONFIG_USB_STORAGE_FREECOM is not set
+# CONFIG_USB_STORAGE_ISD200 is not set
+# CONFIG_USB_STORAGE_USBAT is not set
+# CONFIG_USB_STORAGE_SDDR09 is not set
+# CONFIG_USB_STORAGE_SDDR55 is not set
+# CONFIG_USB_STORAGE_JUMPSHOT is not set
+# CONFIG_USB_STORAGE_ALAUDA is not set
+# CONFIG_USB_STORAGE_ONETOUCH is not set
+# CONFIG_USB_STORAGE_KARMA is not set
+# CONFIG_USB_STORAGE_CYPRESS_ATACB is not set
+CONFIG_USB_LIBUSUAL=y
 
 #
 # USB Imaging devices
 #
+# CONFIG_USB_MDC800 is not set
 # CONFIG_USB_MICROTEK is not set
 
 #
-# USB Multimedia devices
+# USB port drivers
 #
-# CONFIG_USB_DABUSB is not set
+# CONFIG_USB_SERIAL is not set
 
 #
-# Video4Linux support is needed for USB Multimedia device support
+# USB Miscellaneous drivers
 #
+# CONFIG_USB_EMI62 is not set
+# CONFIG_USB_EMI26 is not set
+# CONFIG_USB_ADUTUX is not set
+# CONFIG_USB_SEVSEG is not set
+# CONFIG_USB_RIO500 is not set
+# CONFIG_USB_LEGOTOWER is not set
+# CONFIG_USB_LCD is not set
+# CONFIG_USB_BERRY_CHARGE is not set
+# CONFIG_USB_LED is not set
+# CONFIG_USB_CYPRESS_CY7C63 is not set
+# CONFIG_USB_CYTHERM is not set
+# CONFIG_USB_IDMOUSE is not set
+# CONFIG_USB_FTDI_ELAN is not set
+# CONFIG_USB_APPLEDISPLAY is not set
+# CONFIG_USB_LD is not set
+# CONFIG_USB_TRANCEVIBRATOR is not set
+# CONFIG_USB_IOWARRIOR is not set
+# CONFIG_USB_TEST is not set
+# CONFIG_USB_ISIGHTFW is not set
+# CONFIG_USB_VST is not set
+# CONFIG_USB_GADGET is not set
 
 #
-# USB Network Adapters
+# OTG and related infrastructure
 #
-# CONFIG_USB_KAWETH is not set
-# CONFIG_USB_PEGASUS is not set
-# CONFIG_USB_USBNET is not set
-# CONFIG_USB_MON is not set
+# CONFIG_USB_GPIO_VBUS is not set
+# CONFIG_NOP_USB_XCEIV is not set
+CONFIG_MMC=y
+# CONFIG_MMC_DEBUG is not set
+# CONFIG_MMC_UNSAFE_RESUME is not set
 
 #
-# USB port drivers
+# MMC/SD/SDIO Card Drivers
 #
+CONFIG_MMC_BLOCK=y
+CONFIG_MMC_BLOCK_BOUNCE=y
+# CONFIG_SDIO_UART is not set
+# CONFIG_MMC_TEST is not set
 
 #
-# USB Serial Converter support
+# MMC/SD/SDIO Host Controller Drivers
 #
-# CONFIG_USB_SERIAL is not set
+# CONFIG_MMC_SDHCI is not set
+CONFIG_MMC_AT91=y
+# CONFIG_MEMSTICK is not set
+# CONFIG_ACCESSIBILITY is not set
+# CONFIG_NEW_LEDS is not set
+CONFIG_RTC_LIB=y
+CONFIG_RTC_CLASS=y
+CONFIG_RTC_HCTOSYS=y
+CONFIG_RTC_HCTOSYS_DEVICE="rtc0"
+# CONFIG_RTC_DEBUG is not set
 
 #
-# USB Miscellaneous drivers
+# RTC interfaces
 #
-# CONFIG_USB_EMI62 is not set
-# CONFIG_USB_EMI26 is not set
-# CONFIG_USB_LCD is not set
-# CONFIG_USB_LED is not set
-# CONFIG_USB_CYTHERM is not set
-# CONFIG_USB_PHIDGETKIT is not set
-# CONFIG_USB_PHIDGETSERVO is not set
-# CONFIG_USB_IDMOUSE is not set
+CONFIG_RTC_INTF_SYSFS=y
+CONFIG_RTC_INTF_PROC=y
+CONFIG_RTC_INTF_DEV=y
+# CONFIG_RTC_INTF_DEV_UIE_EMUL is not set
+# CONFIG_RTC_DRV_TEST is not set
 
 #
-# USB DSL modem support
+# SPI RTC drivers
 #
 
 #
-# USB Gadget Support
+# Platform RTC drivers
 #
-# CONFIG_USB_GADGET is not set
+# CONFIG_RTC_DRV_CMOS is not set
+# CONFIG_RTC_DRV_DS1286 is not set
+# CONFIG_RTC_DRV_DS1511 is not set
+# CONFIG_RTC_DRV_DS1553 is not set
+# CONFIG_RTC_DRV_DS1742 is not set
+# CONFIG_RTC_DRV_STK17TA8 is not set
+# CONFIG_RTC_DRV_M48T86 is not set
+# CONFIG_RTC_DRV_M48T35 is not set
+# CONFIG_RTC_DRV_M48T59 is not set
+# CONFIG_RTC_DRV_BQ4802 is not set
+# CONFIG_RTC_DRV_V3020 is not set
 
 #
-# MMC/SD Card support
+# on-CPU RTC drivers
 #
-# CONFIG_MMC is not set
+CONFIG_RTC_DRV_AT91RM9200=y
+# CONFIG_DMADEVICES is not set
+# CONFIG_AUXDISPLAY is not set
+# CONFIG_REGULATOR is not set
+# CONFIG_UIO is not set
+# CONFIG_STAGING is not set
 
 #
 # File systems
 #
 CONFIG_EXT2_FS=y
-CONFIG_EXT2_FS_XATTR=y
-# CONFIG_EXT2_FS_POSIX_ACL is not set
-# CONFIG_EXT2_FS_SECURITY is not set
+# CONFIG_EXT2_FS_XATTR is not set
 # CONFIG_EXT2_FS_XIP is not set
 CONFIG_EXT3_FS=y
+# CONFIG_EXT3_DEFAULTS_TO_ORDERED is not set
 CONFIG_EXT3_FS_XATTR=y
 # CONFIG_EXT3_FS_POSIX_ACL is not set
 # CONFIG_EXT3_FS_SECURITY is not set
+# CONFIG_EXT4_FS is not set
 CONFIG_JBD=y
 # CONFIG_JBD_DEBUG is not set
 CONFIG_FS_MBCACHE=y
 # CONFIG_REISERFS_FS is not set
 # CONFIG_JFS_FS is not set
+# CONFIG_FS_POSIX_ACL is not set
+CONFIG_FILE_LOCKING=y
+# CONFIG_XFS_FS is not set
+# CONFIG_OCFS2_FS is not set
+# CONFIG_BTRFS_FS is not set
+# CONFIG_DNOTIFY is not set
+CONFIG_INOTIFY=y
+CONFIG_INOTIFY_USER=y
+# CONFIG_QUOTA is not set
+# CONFIG_AUTOFS_FS is not set
+# CONFIG_AUTOFS4_FS is not set
+# CONFIG_FUSE_FS is not set
 
 #
-# XFS support
+# Caches
 #
-# CONFIG_XFS_FS is not set
-# CONFIG_MINIX_FS is not set
-# CONFIG_ROMFS_FS is not set
-# CONFIG_QUOTA is not set
-CONFIG_DNOTIFY=y
-CONFIG_AUTOFS_FS=y
-CONFIG_AUTOFS4_FS=y
+# CONFIG_FSCACHE is not set
 
 #
 # CD-ROM/DVD Filesystems
@@ -639,7 +1076,7 @@ CONFIG_AUTOFS4_FS=y
 # DOS/FAT/NT Filesystems
 #
 CONFIG_FAT_FS=y
-CONFIG_MSDOS_FS=y
+# CONFIG_MSDOS_FS is not set
 CONFIG_VFAT_FS=y
 CONFIG_FAT_DEFAULT_CODEPAGE=437
 CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1"
@@ -649,53 +1086,70 @@ CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1"
 # Pseudo filesystems
 #
 CONFIG_PROC_FS=y
+CONFIG_PROC_SYSCTL=y
+CONFIG_PROC_PAGE_MONITOR=y
 CONFIG_SYSFS=y
-CONFIG_DEVPTS_FS_XATTR=y
-# CONFIG_DEVPTS_FS_SECURITY is not set
 CONFIG_TMPFS=y
-# CONFIG_TMPFS_XATTR is not set
+# CONFIG_TMPFS_POSIX_ACL is not set
 # CONFIG_HUGETLB_PAGE is not set
-CONFIG_RAMFS=y
-
-#
-# Miscellaneous filesystems
-#
+CONFIG_CONFIGFS_FS=y
+CONFIG_MISC_FILESYSTEMS=y
+# CONFIG_ADFS_FS is not set
+# CONFIG_AFFS_FS is not set
+# CONFIG_HFS_FS is not set
 # CONFIG_HFSPLUS_FS is not set
+# CONFIG_BEFS_FS is not set
+# CONFIG_BFS_FS is not set
+# CONFIG_EFS_FS is not set
+CONFIG_JFFS2_FS=y
+CONFIG_JFFS2_FS_DEBUG=0
+CONFIG_JFFS2_FS_WRITEBUFFER=y
+# CONFIG_JFFS2_FS_WBUF_VERIFY is not set
+# CONFIG_JFFS2_SUMMARY is not set
+# CONFIG_JFFS2_FS_XATTR is not set
+# CONFIG_JFFS2_COMPRESSION_OPTIONS is not set
+CONFIG_JFFS2_ZLIB=y
+# CONFIG_JFFS2_LZO is not set
+CONFIG_JFFS2_RTIME=y
+# CONFIG_JFFS2_RUBIN is not set
+# CONFIG_UBIFS_FS is not set
 # CONFIG_CRAMFS is not set
+# CONFIG_SQUASHFS is not set
 # CONFIG_VXFS_FS is not set
+# CONFIG_MINIX_FS is not set
+# CONFIG_OMFS_FS is not set
 # CONFIG_HPFS_FS is not set
 # CONFIG_QNX4FS_FS is not set
+# CONFIG_ROMFS_FS is not set
 # CONFIG_SYSV_FS is not set
 # CONFIG_UFS_FS is not set
-
-#
-# Network File Systems
-#
+# CONFIG_NILFS2_FS is not set
+CONFIG_NETWORK_FILESYSTEMS=y
 CONFIG_NFS_FS=y
 CONFIG_NFS_V3=y
 # CONFIG_NFS_V3_ACL is not set
-# CONFIG_NFSD is not set
+# CONFIG_NFS_V4 is not set
 CONFIG_ROOT_NFS=y
+# CONFIG_NFSD is not set
 CONFIG_LOCKD=y
 CONFIG_LOCKD_V4=y
 CONFIG_NFS_COMMON=y
 CONFIG_SUNRPC=y
+# CONFIG_RPCSEC_GSS_KRB5 is not set
+# CONFIG_RPCSEC_GSS_SPKM3 is not set
 # CONFIG_SMB_FS is not set
 # CONFIG_CIFS is not set
 # CONFIG_NCP_FS is not set
 # CONFIG_CODA_FS is not set
+# CONFIG_AFS_FS is not set
 
 #
 # Partition Types
 #
 # CONFIG_PARTITION_ADVANCED is not set
 CONFIG_MSDOS_PARTITION=y
-
-#
-# Native Language Support
-#
 CONFIG_NLS=y
-CONFIG_NLS_DEFAULT="utf8"
+CONFIG_NLS_DEFAULT="iso8859-1"
 CONFIG_NLS_CODEPAGE_437=y
 # CONFIG_NLS_CODEPAGE_737 is not set
 # CONFIG_NLS_CODEPAGE_775 is not set
@@ -719,7 +1173,7 @@ CONFIG_NLS_CODEPAGE_437=y
 # CONFIG_NLS_ISO8859_8 is not set
 # CONFIG_NLS_CODEPAGE_1250 is not set
 # CONFIG_NLS_CODEPAGE_1251 is not set
-CONFIG_NLS_ASCII=y
+# CONFIG_NLS_ASCII is not set
 # CONFIG_NLS_ISO8859_1 is not set
 # CONFIG_NLS_ISO8859_2 is not set
 # CONFIG_NLS_ISO8859_3 is not set
@@ -733,47 +1187,119 @@ CONFIG_NLS_ASCII=y
 # CONFIG_NLS_ISO8859_15 is not set
 # CONFIG_NLS_KOI8_R is not set
 # CONFIG_NLS_KOI8_U is not set
-# CONFIG_NLS_UTF8 is not set
+CONFIG_NLS_UTF8=y
+# CONFIG_DLM is not set
 
 #
 # Kernel hacking
 #
 # CONFIG_PRINTK_TIME is not set
+CONFIG_ENABLE_WARN_DEPRECATED=y
+CONFIG_ENABLE_MUST_CHECK=y
+CONFIG_FRAME_WARN=1024
+CONFIG_MAGIC_SYSRQ=y
+# CONFIG_UNUSED_SYMBOLS is not set
+CONFIG_DEBUG_FS=y
+# CONFIG_HEADERS_CHECK is not set
 CONFIG_DEBUG_KERNEL=y
-# CONFIG_MAGIC_SYSRQ is not set
-CONFIG_LOG_BUF_SHIFT=14
+# CONFIG_DEBUG_SHIRQ is not set
+CONFIG_DETECT_SOFTLOCKUP=y
+# CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC is not set
+CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC_VALUE=0
+CONFIG_DETECT_HUNG_TASK=y
+# CONFIG_BOOTPARAM_HUNG_TASK_PANIC is not set
+CONFIG_BOOTPARAM_HUNG_TASK_PANIC_VALUE=0
+# CONFIG_SCHED_DEBUG is not set
 # CONFIG_SCHEDSTATS is not set
-# CONFIG_DEBUG_SLAB is not set
+# CONFIG_TIMER_STATS is not set
+# CONFIG_DEBUG_OBJECTS is not set
+# CONFIG_SLUB_DEBUG_ON is not set
+# CONFIG_SLUB_STATS is not set
+# CONFIG_DEBUG_PREEMPT is not set
+# CONFIG_DEBUG_RT_MUTEXES is not set
+# CONFIG_RT_MUTEX_TESTER is not set
 # CONFIG_DEBUG_SPINLOCK is not set
+# CONFIG_DEBUG_MUTEXES is not set
+# CONFIG_DEBUG_LOCK_ALLOC is not set
+# CONFIG_PROVE_LOCKING is not set
+# CONFIG_LOCK_STAT is not set
 # CONFIG_DEBUG_SPINLOCK_SLEEP is not set
+# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set
 # CONFIG_DEBUG_KOBJECT is not set
 CONFIG_DEBUG_BUGVERBOSE=y
 # CONFIG_DEBUG_INFO is not set
-# CONFIG_DEBUG_FS is not set
-CONFIG_FRAME_POINTER=y
-CONFIG_DEBUG_USER=y
-CONFIG_DEBUG_ERRORS=y
-CONFIG_DEBUG_LL=y
-# CONFIG_DEBUG_ICEDCC is not set
+# CONFIG_DEBUG_VM is not set
+# CONFIG_DEBUG_WRITECOUNT is not set
+CONFIG_DEBUG_MEMORY_INIT=y
+# CONFIG_DEBUG_LIST is not set
+# CONFIG_DEBUG_SG is not set
+# CONFIG_DEBUG_NOTIFIERS is not set
+# CONFIG_BOOT_PRINTK_DELAY is not set
+# CONFIG_RCU_TORTURE_TEST is not set
+# CONFIG_RCU_CPU_STALL_DETECTOR is not set
+# CONFIG_BACKTRACE_SELF_TEST is not set
+# CONFIG_DEBUG_BLOCK_EXT_DEVT is not set
+# CONFIG_FAULT_INJECTION is not set
+# CONFIG_LATENCYTOP is not set
+# CONFIG_SYSCTL_SYSCALL_CHECK is not set
+# CONFIG_PAGE_POISONING is not set
+CONFIG_HAVE_FUNCTION_TRACER=y
+CONFIG_TRACING_SUPPORT=y
+
+#
+# Tracers
+#
+# CONFIG_FUNCTION_TRACER is not set
+# CONFIG_IRQSOFF_TRACER is not set
+# CONFIG_PREEMPT_TRACER is not set
+# CONFIG_SCHED_TRACER is not set
+# CONFIG_CONTEXT_SWITCH_TRACER is not set
+# CONFIG_EVENT_TRACER is not set
+# CONFIG_BOOT_TRACER is not set
+# CONFIG_TRACE_BRANCH_PROFILING is not set
+# CONFIG_STACK_TRACER is not set
+# CONFIG_KMEMTRACE is not set
+# CONFIG_WORKQUEUE_TRACER is not set
+# CONFIG_BLK_DEV_IO_TRACE is not set
+# CONFIG_DYNAMIC_DEBUG is not set
+# CONFIG_SAMPLES is not set
+CONFIG_HAVE_ARCH_KGDB=y
+# CONFIG_KGDB is not set
+CONFIG_ARM_UNWIND=y
+# CONFIG_DEBUG_USER is not set
+# CONFIG_DEBUG_ERRORS is not set
+# CONFIG_DEBUG_STACK_USAGE is not set
+# CONFIG_DEBUG_LL is not set
 
 #
 # Security options
 #
 # CONFIG_KEYS is not set
 # CONFIG_SECURITY is not set
-
-#
-# Cryptographic options
-#
+# CONFIG_SECURITYFS is not set
+# CONFIG_SECURITY_FILE_CAPABILITIES is not set
 # CONFIG_CRYPTO is not set
-
-#
-# Hardware crypto devices
-#
+# CONFIG_BINARY_PRINTF is not set
 
 #
 # Library routines
 #
+CONFIG_BITREVERSE=y
+CONFIG_GENERIC_FIND_LAST_BIT=y
 # CONFIG_CRC_CCITT is not set
+# CONFIG_CRC16 is not set
+# CONFIG_CRC_T10DIF is not set
+# CONFIG_CRC_ITU_T is not set
 CONFIG_CRC32=y
+# CONFIG_CRC7 is not set
 # CONFIG_LIBCRC32C is not set
+CONFIG_AUDIT_GENERIC=y
+CONFIG_ZLIB_INFLATE=y
+CONFIG_ZLIB_DEFLATE=y
+CONFIG_DECOMPRESS_GZIP=y
+CONFIG_DECOMPRESS_BZIP2=y
+CONFIG_DECOMPRESS_LZMA=y
+CONFIG_HAS_IOMEM=y
+CONFIG_HAS_IOPORT=y
+CONFIG_HAS_DMA=y
+CONFIG_NLATTR=y
index 2d58b8fe59bedb90791403301c2ffe4384e421f8..b49810461e41f7e90b57c9cb8de2ff833cbe2d49 100644 (file)
@@ -260,6 +260,7 @@ CONFIG_MACH_NEXCODER_2440=y
 CONFIG_SMDK2440_CPU2440=y
 CONFIG_MACH_AT2440EVB=y
 CONFIG_CPU_S3C2442=y
+CONFIG_MACH_MINI2440=y
 
 #
 # S3C2442 Machines
@@ -2298,7 +2299,6 @@ CONFIG_DEBUG_ERRORS=y
 # CONFIG_DEBUG_STACK_USAGE is not set
 CONFIG_DEBUG_LL=y
 # CONFIG_DEBUG_ICEDCC is not set
-CONFIG_DEBUG_S3C_PORT=y
 CONFIG_DEBUG_S3C_UART=0
 
 #
index 2e8fa50e9a09a190d89c01d38b41e5733dcc2715..32860609e057764caa9c1b1f34331717c4dfb734 100644 (file)
@@ -816,7 +816,6 @@ CONFIG_DEBUG_ERRORS=y
 # CONFIG_DEBUG_STACK_USAGE is not set
 CONFIG_DEBUG_LL=y
 # CONFIG_DEBUG_ICEDCC is not set
-CONFIG_DEBUG_S3C_PORT=y
 CONFIG_DEBUG_S3C_UART=0
 
 #
index 07dfb98df4f0798da3b02a9497c0a32b081ff3be..9d32faef05f6e1b183f5d5fc23f4728413aa2b88 100644 (file)
@@ -857,7 +857,6 @@ CONFIG_DEBUG_ERRORS=y
 # CONFIG_DEBUG_STACK_USAGE is not set
 CONFIG_DEBUG_LL=y
 # CONFIG_DEBUG_ICEDCC is not set
-# CONFIG_DEBUG_S3C_PORT is not set
 CONFIG_DEBUG_S3C_UART=0
 
 #
index 2d827e1211470f85c603bd5498dfd3f27511535d..4762d900129841d637604195ecb8aaf4effcd218 100644 (file)
@@ -1,7 +1,7 @@
 #
 # Automatically generated make config: don't edit
-# Linux kernel version: 2.6.30-rc6
-# Mon Jun  1 09:18:22 2009
+# Linux kernel version: 2.6.31-rc1
+# Thu Jul  2 00:16:59 2009
 #
 CONFIG_ARM=y
 CONFIG_SYS_SUPPORTS_APM_EMULATION=y
@@ -9,7 +9,7 @@ CONFIG_GENERIC_GPIO=y
 CONFIG_GENERIC_TIME=y
 CONFIG_GENERIC_CLOCKEVENTS=y
 CONFIG_MMU=y
-# CONFIG_NO_IOPORT is not set
+CONFIG_HAVE_TCM=y
 CONFIG_GENERIC_HARDIRQS=y
 CONFIG_STACKTRACE_SUPPORT=y
 CONFIG_HAVE_LATENCYTOP_SUPPORT=y
@@ -18,13 +18,12 @@ CONFIG_TRACE_IRQFLAGS_SUPPORT=y
 CONFIG_HARDIRQS_SW_RESEND=y
 CONFIG_GENERIC_IRQ_PROBE=y
 CONFIG_RWSEM_GENERIC_SPINLOCK=y
-# CONFIG_ARCH_HAS_ILOG2_U32 is not set
-# CONFIG_ARCH_HAS_ILOG2_U64 is not set
 CONFIG_GENERIC_HWEIGHT=y
 CONFIG_GENERIC_CALIBRATE_DELAY=y
 CONFIG_GENERIC_HARDIRQS_NO__DO_IRQ=y
 CONFIG_VECTORS_BASE=0xffff0000
 CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+CONFIG_CONSTRUCTORS=y
 
 #
 # General setup
@@ -68,7 +67,6 @@ CONFIG_SYSCTL_SYSCALL=y
 CONFIG_KALLSYMS=y
 # CONFIG_KALLSYMS_ALL is not set
 # CONFIG_KALLSYMS_EXTRA_PASS is not set
-# CONFIG_STRIP_ASM_SYMS is not set
 CONFIG_HOTPLUG=y
 CONFIG_PRINTK=y
 CONFIG_BUG=y
@@ -81,8 +79,13 @@ CONFIG_TIMERFD=y
 CONFIG_EVENTFD=y
 CONFIG_SHMEM=y
 # CONFIG_AIO is not set
+
+#
+# Performance Counters
+#
 # CONFIG_VM_EVENT_COUNTERS is not set
 CONFIG_SLUB_DEBUG=y
+# CONFIG_STRIP_ASM_SYMS is not set
 CONFIG_COMPAT_BRK=y
 # CONFIG_SLAB is not set
 CONFIG_SLUB=y
@@ -94,6 +97,10 @@ CONFIG_HAVE_OPROFILE=y
 CONFIG_HAVE_KPROBES=y
 CONFIG_HAVE_KRETPROBES=y
 CONFIG_HAVE_CLK=y
+
+#
+# GCOV-based kernel profiling
+#
 # CONFIG_SLOW_WORK is not set
 CONFIG_HAVE_GENERIC_DMA_COHERENT=y
 CONFIG_SLABINFO=y
@@ -106,7 +113,7 @@ CONFIG_MODULE_UNLOAD=y
 # CONFIG_MODVERSIONS is not set
 # CONFIG_MODULE_SRCVERSION_ALL is not set
 CONFIG_BLOCK=y
-# CONFIG_LBD is not set
+CONFIG_LBDAF=y
 # CONFIG_BLK_DEV_BSG is not set
 # CONFIG_BLK_DEV_INTEGRITY is not set
 
@@ -138,9 +145,9 @@ CONFIG_DEFAULT_IOSCHED="deadline"
 # CONFIG_ARCH_EP93XX is not set
 # CONFIG_ARCH_FOOTBRIDGE is not set
 # CONFIG_ARCH_MXC is not set
+# CONFIG_ARCH_STMP3XXX is not set
 # CONFIG_ARCH_NETX is not set
 # CONFIG_ARCH_H720X is not set
-# CONFIG_ARCH_IMX is not set
 # CONFIG_ARCH_IOP13XX is not set
 # CONFIG_ARCH_IOP32X is not set
 # CONFIG_ARCH_IOP33X is not set
@@ -216,8 +223,8 @@ CONFIG_ARM_THUMB=y
 # CONFIG_CPU_DCACHE_DISABLE is not set
 # CONFIG_CPU_DCACHE_WRITETHROUGH is not set
 # CONFIG_CPU_CACHE_ROUND_ROBIN is not set
-# CONFIG_OUTER_CACHE is not set
 CONFIG_ARM_VIC=y
+CONFIG_ARM_VIC_NR=2
 CONFIG_COMMON_CLKDEV=y
 
 #
@@ -243,7 +250,6 @@ CONFIG_PREEMPT=y
 CONFIG_HZ=100
 CONFIG_AEABI=y
 CONFIG_OABI_COMPAT=y
-CONFIG_ARCH_FLATMEM_HAS_HOLES=y
 # CONFIG_ARCH_SPARSEMEM_DEFAULT is not set
 # CONFIG_ARCH_SELECT_MEMORY_MODEL is not set
 # CONFIG_HIGHMEM is not set
@@ -258,17 +264,18 @@ CONFIG_SPLIT_PTLOCK_CPUS=4096
 # CONFIG_PHYS_ADDR_T_64BIT is not set
 CONFIG_ZONE_DMA_FLAG=0
 CONFIG_VIRT_TO_BUS=y
-CONFIG_UNEVICTABLE_LRU=y
 CONFIG_HAVE_MLOCK=y
 CONFIG_HAVE_MLOCKED_PAGE_BIT=y
+CONFIG_DEFAULT_MMAP_MIN_ADDR=4096
 CONFIG_ALIGNMENT_TRAP=y
+# CONFIG_UACCESS_WITH_MEMCPY is not set
 
 #
 # Boot options
 #
 CONFIG_ZBOOT_ROM_TEXT=0x0
 CONFIG_ZBOOT_ROM_BSS=0x0
-CONFIG_CMDLINE="root=/dev/mtdblock2 rw rootfstype=yaffs2 console=ttyAMA0,115200n8 ab3100.force=0,0x48 mtdparts=u300nand:128k@0x0(bootrecords)ro,8064k@128k(free)ro,253952k@8192k(platform) lpj=515072"
+CONFIG_CMDLINE="root=/dev/ram0 rw rootfstype=rootfs console=ttyAMA0,115200n8 lpj=515072"
 # CONFIG_XIP_KERNEL is not set
 # CONFIG_KEXEC is not set
 
@@ -359,6 +366,7 @@ CONFIG_DEFAULT_TCP_CONG="cubic"
 # CONFIG_ECONET is not set
 # CONFIG_WAN_ROUTER is not set
 # CONFIG_PHONET is not set
+# CONFIG_IEEE802154 is not set
 # CONFIG_NET_SCHED is not set
 # CONFIG_DCB is not set
 
@@ -497,6 +505,7 @@ CONFIG_MISC_DEVICES=y
 # CONFIG_EEPROM_AT24 is not set
 # CONFIG_EEPROM_AT25 is not set
 # CONFIG_EEPROM_LEGACY is not set
+# CONFIG_EEPROM_MAX6875 is not set
 # CONFIG_EEPROM_93CX6 is not set
 CONFIG_HAVE_IDE=y
 # CONFIG_IDE is not set
@@ -538,6 +547,7 @@ CONFIG_INPUT_KEYBOARD=y
 # CONFIG_KEYBOARD_XTKBD is not set
 # CONFIG_KEYBOARD_NEWTON is not set
 # CONFIG_KEYBOARD_STOWAWAY is not set
+# CONFIG_KEYBOARD_LM8323 is not set
 # CONFIG_KEYBOARD_GPIO is not set
 # CONFIG_INPUT_MOUSE is not set
 # CONFIG_INPUT_JOYSTICK is not set
@@ -597,9 +607,11 @@ CONFIG_I2C_HELPER_AUTO=y
 #
 # I2C system bus drivers (mostly embedded / system-on-chip)
 #
+# CONFIG_I2C_DESIGNWARE is not set
 # CONFIG_I2C_GPIO is not set
 # CONFIG_I2C_OCORES is not set
 # CONFIG_I2C_SIMTEC is not set
+CONFIG_I2C_STU300=y
 
 #
 # External I2C/SMBus adapter drivers
@@ -620,7 +632,6 @@ CONFIG_I2C_HELPER_AUTO=y
 # CONFIG_SENSORS_PCF8574 is not set
 # CONFIG_PCF8575 is not set
 # CONFIG_SENSORS_PCA9539 is not set
-# CONFIG_SENSORS_MAX6875 is not set
 # CONFIG_SENSORS_TSL2550 is not set
 # CONFIG_I2C_DEBUG_CORE is not set
 # CONFIG_I2C_DEBUG_ALGO is not set
@@ -635,6 +646,7 @@ CONFIG_SPI_MASTER=y
 #
 # CONFIG_SPI_BITBANG is not set
 # CONFIG_SPI_GPIO is not set
+CONFIG_SPI_PL022=y
 
 #
 # SPI Protocol Masters
@@ -647,6 +659,7 @@ CONFIG_POWER_SUPPLY=y
 # CONFIG_PDA_POWER is not set
 # CONFIG_BATTERY_DS2760 is not set
 # CONFIG_BATTERY_BQ27x00 is not set
+# CONFIG_BATTERY_MAX17040 is not set
 # CONFIG_HWMON is not set
 # CONFIG_THERMAL is not set
 # CONFIG_THERMAL_HWMON is not set
@@ -657,6 +670,7 @@ CONFIG_WATCHDOG=y
 # Watchdog Device Drivers
 #
 # CONFIG_SOFT_WATCHDOG is not set
+CONFIG_COH901327_WATCHDOG=y
 CONFIG_SSB_POSSIBLE=y
 
 #
@@ -678,22 +692,9 @@ CONFIG_SSB_POSSIBLE=y
 # CONFIG_MFD_WM8400 is not set
 # CONFIG_MFD_WM8350_I2C is not set
 # CONFIG_MFD_PCF50633 is not set
-
-#
-# Multimedia devices
-#
-
-#
-# Multimedia core support
-#
-# CONFIG_VIDEO_DEV is not set
-# CONFIG_DVB_CORE is not set
-# CONFIG_VIDEO_MEDIA is not set
-
-#
-# Multimedia drivers
-#
-# CONFIG_DAB is not set
+CONFIG_AB3100_CORE=y
+# CONFIG_EZX_PCAP is not set
+# CONFIG_MEDIA_SUPPORT is not set
 
 #
 # Graphics support
@@ -760,6 +761,11 @@ CONFIG_SND_JACK=y
 # CONFIG_SND_VERBOSE_PROCFS is not set
 # CONFIG_SND_VERBOSE_PRINTK is not set
 # CONFIG_SND_DEBUG is not set
+# CONFIG_SND_RAWMIDI_SEQ is not set
+# CONFIG_SND_OPL3_LIB_SEQ is not set
+# CONFIG_SND_OPL4_LIB_SEQ is not set
+# CONFIG_SND_SBAWE_SEQ is not set
+# CONFIG_SND_EMU10K1_SEQ is not set
 # CONFIG_SND_DRIVERS is not set
 # CONFIG_SND_ARM is not set
 # CONFIG_SND_SPI is not set
@@ -770,7 +776,7 @@ CONFIG_SND_SOC_I2C_AND_SPI=y
 # CONFIG_HID_SUPPORT is not set
 # CONFIG_USB_SUPPORT is not set
 CONFIG_MMC=y
-# CONFIG_MMC_DEBUG is not set
+CONFIG_MMC_DEBUG=y
 # CONFIG_MMC_UNSAFE_RESUME is not set
 
 #
@@ -797,7 +803,7 @@ CONFIG_LEDS_CLASS=y
 #
 # CONFIG_LEDS_PCA9532 is not set
 # CONFIG_LEDS_GPIO is not set
-# CONFIG_LEDS_LP5521 is not set
+# CONFIG_LEDS_LP3944 is not set
 # CONFIG_LEDS_PCA955X is not set
 # CONFIG_LEDS_DAC124S085 is not set
 # CONFIG_LEDS_BD2802 is not set
@@ -845,6 +851,7 @@ CONFIG_RTC_INTF_DEV=y
 # CONFIG_RTC_DRV_S35390A is not set
 # CONFIG_RTC_DRV_FM3130 is not set
 # CONFIG_RTC_DRV_RX8581 is not set
+# CONFIG_RTC_DRV_RX8025 is not set
 
 #
 # SPI RTC drivers
@@ -887,7 +894,10 @@ CONFIG_REGULATOR=y
 # CONFIG_REGULATOR_DEBUG is not set
 # CONFIG_REGULATOR_FIXED_VOLTAGE is not set
 # CONFIG_REGULATOR_VIRTUAL_CONSUMER is not set
+# CONFIG_REGULATOR_USERSPACE_CONSUMER is not set
 # CONFIG_REGULATOR_BQ24022 is not set
+# CONFIG_REGULATOR_MAX1586 is not set
+# CONFIG_REGULATOR_LP3971 is not set
 # CONFIG_UIO is not set
 # CONFIG_STAGING is not set
 
@@ -900,16 +910,20 @@ CONFIG_REGULATOR=y
 # CONFIG_REISERFS_FS is not set
 # CONFIG_JFS_FS is not set
 # CONFIG_FS_POSIX_ACL is not set
-CONFIG_FILE_LOCKING=y
 # CONFIG_XFS_FS is not set
+# CONFIG_GFS2_FS is not set
 # CONFIG_OCFS2_FS is not set
 # CONFIG_BTRFS_FS is not set
+CONFIG_FILE_LOCKING=y
+CONFIG_FSNOTIFY=y
 # CONFIG_DNOTIFY is not set
 # CONFIG_INOTIFY is not set
+CONFIG_INOTIFY_USER=y
 # CONFIG_QUOTA is not set
 # CONFIG_AUTOFS_FS is not set
 # CONFIG_AUTOFS4_FS is not set
 CONFIG_FUSE_FS=y
+# CONFIG_CUSE is not set
 
 #
 # Caches
@@ -1033,6 +1047,7 @@ CONFIG_TIMER_STATS=y
 # CONFIG_DEBUG_OBJECTS is not set
 # CONFIG_SLUB_DEBUG_ON is not set
 # CONFIG_SLUB_STATS is not set
+# CONFIG_DEBUG_KMEMLEAK is not set
 # CONFIG_DEBUG_PREEMPT is not set
 # CONFIG_DEBUG_RT_MUTEXES is not set
 # CONFIG_RT_MUTEX_TESTER is not set
@@ -1063,18 +1078,16 @@ CONFIG_DEBUG_INFO=y
 # CONFIG_PAGE_POISONING is not set
 CONFIG_HAVE_FUNCTION_TRACER=y
 CONFIG_TRACING_SUPPORT=y
-
-#
-# Tracers
-#
+CONFIG_FTRACE=y
 # CONFIG_FUNCTION_TRACER is not set
 # CONFIG_IRQSOFF_TRACER is not set
 # CONFIG_PREEMPT_TRACER is not set
 # CONFIG_SCHED_TRACER is not set
-# CONFIG_CONTEXT_SWITCH_TRACER is not set
-# CONFIG_EVENT_TRACER is not set
+# CONFIG_ENABLE_DEFAULT_TRACERS is not set
 # CONFIG_BOOT_TRACER is not set
-# CONFIG_TRACE_BRANCH_PROFILING is not set
+CONFIG_BRANCH_PROFILE_NONE=y
+# CONFIG_PROFILE_ANNOTATED_BRANCHES is not set
+# CONFIG_PROFILE_ALL_BRANCHES is not set
 # CONFIG_STACK_TRACER is not set
 # CONFIG_KMEMTRACE is not set
 # CONFIG_WORKQUEUE_TRACER is not set
@@ -1109,6 +1122,7 @@ CONFIG_GENERIC_FIND_LAST_BIT=y
 # CONFIG_CRC32 is not set
 # CONFIG_CRC7 is not set
 # CONFIG_LIBCRC32C is not set
+CONFIG_GENERIC_ALLOCATOR=y
 CONFIG_HAS_IOMEM=y
 CONFIG_HAS_IOPORT=y
 CONFIG_HAS_DMA=y
index be962c1349c4aa17a65f4cd364fd6221f1ea83bc..9c746af1bf6e150ae19acebe961b0a0c116b5d45 100644 (file)
@@ -12,7 +12,7 @@
 
 /* PAGE_SHIFT determines the page size */
 #define PAGE_SHIFT             12
-#define PAGE_SIZE              (1UL << PAGE_SHIFT)
+#define PAGE_SIZE              (_AC(1,UL) << PAGE_SHIFT)
 #define PAGE_MASK              (~(PAGE_SIZE-1))
 
 #ifndef __ASSEMBLY__
index 1cd2d6416bda447da0a64276ab2d302ff785cd19..c433c6c73112a70f379d954cdfb1ec07d19c86f3 100644 (file)
@@ -285,15 +285,6 @@ extern struct page *empty_zero_page;
 #define pte_young(pte)         (pte_val(pte) & L_PTE_YOUNG)
 #define pte_special(pte)       (0)
 
-/*
- * The following only works if pte_present() is not true.
- */
-#define pte_file(pte)          (pte_val(pte) & L_PTE_FILE)
-#define pte_to_pgoff(x)                (pte_val(x) >> 2)
-#define pgoff_to_pte(x)                __pte(((x) << 2) | L_PTE_FILE)
-
-#define PTE_FILE_MAX_BITS      30
-
 #define PTE_BIT_FUNC(fn,op) \
 static inline pte_t pte_##fn(pte_t pte) { pte_val(pte) op; return pte; }
 
@@ -384,16 +375,50 @@ static inline pte_t pte_modify(pte_t pte, pgprot_t newprot)
 
 extern pgd_t swapper_pg_dir[PTRS_PER_PGD];
 
-/* Encode and decode a swap entry.
+/*
+ * Encode and decode a swap entry.  Swap entries are stored in the Linux
+ * page tables as follows:
  *
- * We support up to 32GB of swap on 4k machines
+ *   3 3 2 2 2 2 2 2 2 2 2 2 1 1 1 1 1 1 1 1 1 1
+ *   1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0
+ *   <--------------- offset --------------------> <--- type --> 0 0
+ *
+ * This gives us up to 127 swap files and 32GB per swap file.  Note that
+ * the offset field is always non-zero.
  */
-#define __swp_type(x)          (((x).val >> 2) & 0x7f)
-#define __swp_offset(x)                ((x).val >> 9)
-#define __swp_entry(type,offset) ((swp_entry_t) { ((type) << 2) | ((offset) << 9) })
+#define __SWP_TYPE_SHIFT       2
+#define __SWP_TYPE_BITS                7
+#define __SWP_TYPE_MASK                ((1 << __SWP_TYPE_BITS) - 1)
+#define __SWP_OFFSET_SHIFT     (__SWP_TYPE_BITS + __SWP_TYPE_SHIFT)
+
+#define __swp_type(x)          (((x).val >> __SWP_TYPE_SHIFT) & __SWP_TYPE_MASK)
+#define __swp_offset(x)                ((x).val >> __SWP_OFFSET_SHIFT)
+#define __swp_entry(type,offset) ((swp_entry_t) { ((type) << __SWP_TYPE_SHIFT) | ((offset) << __SWP_OFFSET_SHIFT) })
+
 #define __pte_to_swp_entry(pte)        ((swp_entry_t) { pte_val(pte) })
 #define __swp_entry_to_pte(swp)        ((pte_t) { (swp).val })
 
+/*
+ * It is an error for the kernel to have more swap files than we can
+ * encode in the PTEs.  This ensures that we know when MAX_SWAPFILES
+ * is increased beyond what we presently support.
+ */
+#define MAX_SWAPFILES_CHECK() BUILD_BUG_ON(MAX_SWAPFILES_SHIFT > __SWP_TYPE_BITS)
+
+/*
+ * Encode and decode a file entry.  File entries are stored in the Linux
+ * page tables as follows:
+ *
+ *   3 3 2 2 2 2 2 2 2 2 2 2 1 1 1 1 1 1 1 1 1 1
+ *   1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0
+ *   <------------------------ offset -------------------------> 1 0
+ */
+#define pte_file(pte)          (pte_val(pte) & L_PTE_FILE)
+#define pte_to_pgoff(x)                (pte_val(x) >> 2)
+#define pgoff_to_pte(x)                __pte(((x) << 2) | L_PTE_FILE)
+
+#define PTE_FILE_MAX_BITS      30
+
 /* Needs to be defined here and not in linux/mm.h, as it is arch dependent */
 /* FIXME: this is not correct */
 #define kern_addr_valid(addr)  (1)
index 4f8848260ee2b85b4256b9762aeb7ce68e29ef38..73394e50cbca26e4198349de503fd18554f331d6 100644 (file)
@@ -73,7 +73,7 @@ struct thread_info {
        .task           = &tsk,                                         \
        .exec_domain    = &default_exec_domain,                         \
        .flags          = 0,                                            \
-       .preempt_count  = 1,                                            \
+       .preempt_count  = INIT_PREEMPT_COUNT,                           \
        .addr_limit     = KERNEL_DS,                                    \
        .cpu_domain     = domain_val(DOMAIN_USER, DOMAIN_MANAGER) |     \
                          domain_val(DOMAIN_KERNEL, DOMAIN_MANAGER) |   \
index 096f600dc8d84e25603f9269cbfebeab634ac4d6..b7c3490eaa24adb04bc7e7b2f971f5980f245221 100644 (file)
@@ -98,17 +98,6 @@ unlock:
        return 0;
 }
 
-/* Handle bad interrupts */
-static struct irq_desc bad_irq_desc = {
-       .handle_irq = handle_bad_irq,
-       .lock = __SPIN_LOCK_UNLOCKED(bad_irq_desc.lock),
-};
-
-#ifdef CONFIG_CPUMASK_OFFSTACK
-/* We are not allocating bad_irq_desc.affinity or .pending_mask */
-#error "ARM architecture does not support CONFIG_CPUMASK_OFFSTACK."
-#endif
-
 /*
  * do_IRQ handles all hardware IRQ's.  Decoded IRQs should not
  * come via this function.  Instead, they should provide their
@@ -124,10 +113,13 @@ asmlinkage void __exception asm_do_IRQ(unsigned int irq, struct pt_regs *regs)
         * Some hardware gives randomly wrong interrupts.  Rather
         * than crashing, do something sensible.
         */
-       if (irq >= NR_IRQS)
-               handle_bad_irq(irq, &bad_irq_desc);
-       else
+       if (unlikely(irq >= NR_IRQS)) {
+               if (printk_ratelimit())
+                       printk(KERN_WARNING "Bad IRQ%u\n", irq);
+               ack_bad_irq(irq);
+       } else {
                generic_handle_irq(irq);
+       }
 
        /* AT91 specific workaround */
        irq_finish(irq);
@@ -165,10 +157,6 @@ void __init init_IRQ(void)
        for (irq = 0; irq < NR_IRQS; irq++)
                irq_desc[irq].status |= IRQ_NOREQUEST | IRQ_NOPROBE;
 
-#ifdef CONFIG_SMP
-       cpumask_setall(bad_irq_desc.affinity);
-       bad_irq_desc.node = smp_processor_id();
-#endif
        init_arch_irq();
 }
 
index 4340bf3d2c84a8feae21eea058283f143640a698..69371028a2025a7f7b2f52fb32cdabadeae728e7 100644 (file)
@@ -6,6 +6,7 @@
 #include <asm-generic/vmlinux.lds.h>
 #include <asm/thread_info.h>
 #include <asm/memory.h>
+#include <asm/page.h>
        
 OUTPUT_ARCH(arm)
 ENTRY(stext)
@@ -63,7 +64,7 @@ SECTIONS
                        usr/built-in.o(.init.ramfs)
                __initramfs_end = .;
 #endif
-               . = ALIGN(4096);
+               . = ALIGN(PAGE_SIZE);
                __per_cpu_load = .;
                __per_cpu_start = .;
                        *(.data.percpu.page_aligned)
@@ -73,7 +74,7 @@ SECTIONS
 #ifndef CONFIG_XIP_KERNEL
                __init_begin = _stext;
                INIT_DATA
-               . = ALIGN(4096);
+               . = ALIGN(PAGE_SIZE);
                __init_end = .;
 #endif
        }
@@ -118,7 +119,7 @@ SECTIONS
                *(.got)                 /* Global offset table          */
        }
 
-       RODATA
+       RO_DATA(PAGE_SIZE)
 
        _etext = .;                     /* End of text and rodata section */
 
@@ -158,17 +159,17 @@ SECTIONS
                *(.data.init_task)
 
 #ifdef CONFIG_XIP_KERNEL
-               . = ALIGN(4096);
+               . = ALIGN(PAGE_SIZE);
                __init_begin = .;
                INIT_DATA
-               . = ALIGN(4096);
+               . = ALIGN(PAGE_SIZE);
                __init_end = .;
 #endif
 
-               . = ALIGN(4096);
+               . = ALIGN(PAGE_SIZE);
                __nosave_begin = .;
                *(.data.nosave)
-               . = ALIGN(4096);
+               . = ALIGN(PAGE_SIZE);
                __nosave_end = .;
 
                /*
index cc270beadd5d67bea4389fd6eed8113177bb3135..a55398ed1211d932266ac4ebace286ffe53490df 100644 (file)
@@ -24,6 +24,8 @@
 #include <linux/platform_device.h>
 #include <linux/spi/spi.h>
 #include <linux/spi/at73c213.h>
+#include <linux/gpio_keys.h>
+#include <linux/input.h>
 #include <linux/clk.h>
 
 #include <mach/hardware.h>
@@ -218,6 +220,56 @@ static struct gpio_led ek_leds[] = {
        }
 };
 
+
+/*
+ * GPIO Buttons
+ */
+#if defined(CONFIG_KEYBOARD_GPIO) || defined(CONFIG_KEYBOARD_GPIO_MODULE)
+static struct gpio_keys_button ek_buttons[] = {
+       {
+               .gpio           = AT91_PIN_PA30,
+               .code           = BTN_3,
+               .desc           = "Button 3",
+               .active_low     = 1,
+               .wakeup         = 1,
+       },
+       {
+               .gpio           = AT91_PIN_PA31,
+               .code           = BTN_4,
+               .desc           = "Button 4",
+               .active_low     = 1,
+               .wakeup         = 1,
+       }
+};
+
+static struct gpio_keys_platform_data ek_button_data = {
+       .buttons        = ek_buttons,
+       .nbuttons       = ARRAY_SIZE(ek_buttons),
+};
+
+static struct platform_device ek_button_device = {
+       .name           = "gpio-keys",
+       .id             = -1,
+       .num_resources  = 0,
+       .dev            = {
+               .platform_data  = &ek_button_data,
+       }
+};
+
+static void __init ek_add_device_buttons(void)
+{
+       at91_set_gpio_input(AT91_PIN_PA30, 1);  /* btn3 */
+       at91_set_deglitch(AT91_PIN_PA30, 1);
+       at91_set_gpio_input(AT91_PIN_PA31, 1);  /* btn4 */
+       at91_set_deglitch(AT91_PIN_PA31, 1);
+
+       platform_device_register(&ek_button_device);
+}
+#else
+static void __init ek_add_device_buttons(void) {}
+#endif
+
+
 static struct i2c_board_info __initdata ek_i2c_devices[] = {
        {
                I2C_BOARD_INFO("24c512", 0x50),
@@ -245,6 +297,8 @@ static void __init ek_board_init(void)
        at91_add_device_i2c(ek_i2c_devices, ARRAY_SIZE(ek_i2c_devices));
        /* LEDs */
        at91_gpio_leds(ek_leds, ARRAY_SIZE(ek_leds));
+       /* Push Buttons */
+       ek_add_device_buttons();
        /* PCK0 provides MCLK to the WM8731 */
        at91_set_B_periph(AT91_PIN_PC1, 0);
        /* SSC (for WM8731) */
index 35e12a49d1a684372f736fe374abed15763cd6bd..f6b5672cabd6377e6fdb8cc9b9531c565c72042a 100644 (file)
@@ -186,19 +186,21 @@ static struct fb_monspecs at91fb_default_monspecs = {
 static void at91_lcdc_power_control(int on)
 {
        if (on)
-               at91_set_gpio_value(AT91_PIN_PA30, 0);  /* power up */
+               at91_set_gpio_value(AT91_PIN_PC1, 0);   /* power up */
        else
-               at91_set_gpio_value(AT91_PIN_PA30, 1);  /* power down */
+               at91_set_gpio_value(AT91_PIN_PC1, 1);   /* power down */
 }
 
 /* Driver datas */
 static struct atmel_lcdfb_info __initdata ek_lcdc_data = {
+       .lcdcon_is_backlight            = true,
        .default_bpp                    = 16,
        .default_dmacon                 = ATMEL_LCDC_DMAEN,
        .default_lcdcon2                = AT91SAM9RL_DEFAULT_LCDCON2,
        .default_monspecs               = &at91fb_default_monspecs,
        .atmel_lcdfb_power_control      = at91_lcdc_power_control,
        .guard_time                     = 1,
+       .lcd_wiring_mode                = ATMEL_LCDC_WIRING_RGB,
 };
 
 #else
index e70fc7c66bbb63d0b8b28d59d3e404ac9263a5f7..ed2a48a9ce74b51634514b0d2e4eee8ec1802c49 100644 (file)
@@ -36,7 +36,6 @@
 #include <mach/hwa742.h>
 #include <mach/lcd_mipid.h>
 #include <mach/mmc.h>
-#include <mach/usb.h>
 #include <mach/clock.h>
 
 #define ADS7846_PENDOWN_GPIO   15
@@ -205,9 +204,11 @@ static int nokia770_mmc_get_cover_state(struct device *dev, int slot)
 static struct omap_mmc_platform_data nokia770_mmc2_data = {
        .nr_slots                       = 1,
        .dma_mask                       = 0xffffffff,
+       .max_freq                       = 12000000,
        .slots[0]       = {
                .set_power              = nokia770_mmc_set_power,
                .get_cover_state        = nokia770_mmc_get_cover_state,
+               .ocr_mask               = MMC_VDD_32_33|MMC_VDD_33_34,
                .name                   = "mmcblk",
        },
 };
index 0af4d6c85b4763cad50a8af100b1a0045f47c90d..6810b4aeb02cd8d8e7d34de769772b3f8c81b3e4 100644 (file)
@@ -203,5 +203,5 @@ module_exit(omap1_mbox_exit);
 
 MODULE_LICENSE("GPL v2");
 MODULE_DESCRIPTION("omap mailbox: omap1 architecture specific functions");
-MODULE_AUTHOR("Hiroshi DOYU" <Hiroshi.DOYU@nokia.com>);
+MODULE_AUTHOR("Hiroshi DOYU <Hiroshi.DOYU@nokia.com>");
 MODULE_ALIAS("platform:omap1-mailbox");
index da93b86234ed47d7ef1546d55e98072c0abc913d..9a0bf6744a057518971f22d6d808c0f4c7af152b 100644 (file)
@@ -362,6 +362,7 @@ static struct omap_onenand_platform_data board_onenand_data = {
        .gpio_irq       = 65,
        .parts          = onenand_partitions,
        .nr_parts       = ARRAY_SIZE(onenand_partitions),
+       .flags          = ONENAND_SYNC_READWRITE,
 };
 
 static void __init board_onenand_init(void)
index 2fd22f9c5f0e785e694075efbccca830f52b397e..54fec53a48e7a8e4d5cabe7fade86e184f72df92 100644 (file)
@@ -31,6 +31,8 @@ static struct platform_device gpmc_onenand_device = {
 static int omap2_onenand_set_async_mode(int cs, void __iomem *onenand_base)
 {
        struct gpmc_timings t;
+       u32 reg;
+       int err;
 
        const int t_cer = 15;
        const int t_avdp = 12;
@@ -43,6 +45,11 @@ static int omap2_onenand_set_async_mode(int cs, void __iomem *onenand_base)
        const int t_wpl = 40;
        const int t_wph = 30;
 
+       /* Ensure sync read and sync write are disabled */
+       reg = readw(onenand_base + ONENAND_REG_SYS_CFG1);
+       reg &= ~ONENAND_SYS_CFG1_SYNC_READ & ~ONENAND_SYS_CFG1_SYNC_WRITE;
+       writew(reg, onenand_base + ONENAND_REG_SYS_CFG1);
+
        memset(&t, 0, sizeof(t));
        t.sync_clk = 0;
        t.cs_on = 0;
@@ -74,7 +81,16 @@ static int omap2_onenand_set_async_mode(int cs, void __iomem *onenand_base)
                          GPMC_CONFIG1_DEVICESIZE_16 |
                          GPMC_CONFIG1_MUXADDDATA);
 
-       return gpmc_cs_set_timings(cs, &t);
+       err = gpmc_cs_set_timings(cs, &t);
+       if (err)
+               return err;
+
+       /* Ensure sync read and sync write are disabled */
+       reg = readw(onenand_base + ONENAND_REG_SYS_CFG1);
+       reg &= ~ONENAND_SYS_CFG1_SYNC_READ & ~ONENAND_SYS_CFG1_SYNC_WRITE;
+       writew(reg, onenand_base + ONENAND_REG_SYS_CFG1);
+
+       return 0;
 }
 
 static void set_onenand_cfg(void __iomem *onenand_base, int latency,
@@ -124,7 +140,8 @@ static int omap2_onenand_set_sync_mode(struct omap_onenand_platform_data *cfg,
        } else if (cfg->flags & ONENAND_SYNC_READWRITE) {
                sync_read = 1;
                sync_write = 1;
-       }
+       } else
+               return omap2_onenand_set_async_mode(cs, onenand_base);
 
        if (!freq) {
                /* Very first call freq is not known */
index 458990e20c60db3a7f97d5b74ee33cee71496c78..a98201cc265cc08f5189b04fac3cb178212e0038 100644 (file)
@@ -48,6 +48,28 @@ int omap_chip_is(struct omap_chip_id oci)
 }
 EXPORT_SYMBOL(omap_chip_is);
 
+int omap_type(void)
+{
+       u32 val = 0;
+
+       if (cpu_is_omap24xx())
+               val = omap_ctrl_readl(OMAP24XX_CONTROL_STATUS);
+       else if (cpu_is_omap34xx())
+               val = omap_ctrl_readl(OMAP343X_CONTROL_STATUS);
+       else {
+               pr_err("Cannot detect omap type!\n");
+               goto out;
+       }
+
+       val &= OMAP2_DEVICETYPE_MASK;
+       val >>= 8;
+
+out:
+       return val;
+}
+EXPORT_SYMBOL(omap_type);
+
+
 /*----------------------------------------------------------------------------*/
 
 #define OMAP_TAP_IDCODE                0x0204
index fd5b8a5925cc5abaa3193066a26f9f35af1e53e4..6f71f3730c97789d461880912de06abc5861fa58 100644 (file)
@@ -282,12 +282,12 @@ static int __devinit omap2_mbox_probe(struct platform_device *pdev)
                return -ENOMEM;
 
        /* DSP or IVA2 IRQ */
-       mbox_dsp_info.irq = platform_get_irq(pdev, 0);
-       if (mbox_dsp_info.irq < 0) {
+       ret = platform_get_irq(pdev, 0);
+       if (ret < 0) {
                dev_err(&pdev->dev, "invalid irq resource\n");
-               ret = -ENODEV;
                goto err_dsp;
        }
+       mbox_dsp_info.irq = ret;
 
        ret = omap_mbox_register(&pdev->dev, &mbox_dsp_info);
        if (ret)
index 9756a878fd90263c5ddd4fcfd7a1d6dc60228c77..1541fd4c8d0fd0b28bacf30eca96853f7da04a3d 100644 (file)
@@ -263,8 +263,19 @@ static int twl_mmc1_set_power(struct device *dev, int slot, int power_on,
 static int twl_mmc23_set_power(struct device *dev, int slot, int power_on, int vdd)
 {
        int ret = 0;
-       struct twl_mmc_controller *c = &hsmmc[1];
+       struct twl_mmc_controller *c = NULL;
        struct omap_mmc_platform_data *mmc = dev->platform_data;
+       int i;
+
+       for (i = 1; i < ARRAY_SIZE(hsmmc); i++) {
+               if (mmc == hsmmc[i].mmc) {
+                       c = &hsmmc[i];
+                       break;
+               }
+       }
+
+       if (c == NULL)
+               return -ENODEV;
 
        /* If we don't see a Vcc regulator, assume it's a fixed
         * voltage always-on regulator.
index 6a5bc3021bdb6218a5ffb31a0229b797f3994797..ec71a69657867edcbc7ffb79a2eda78d36f73bf3 100644 (file)
@@ -48,8 +48,6 @@
 #include <plat/mci.h>
 #include <plat/udc.h>
 
-#include <plat/regs-serial.h>
-
 #include <linux/mtd/mtd.h>
 #include <linux/mtd/nand.h>
 #include <linux/mtd/nand_ecc.h>
@@ -275,6 +273,7 @@ static struct s3c2410_nand_set mini2440_nand_sets[] __initdata = {
                .nr_chips       = 1,
                .nr_partitions  = ARRAY_SIZE(mini2440_default_nand_part),
                .partitions     = mini2440_default_nand_part,
+               .flash_bbt      = 1, /* we use u-boot to create a BBT */
        },
 };
 
index e23b581aa0e169dff61e4b58c4c8c73370277f5e..0fb385bd9cd9c44eaa164cfe14d6721063eab8d3 100644 (file)
@@ -433,8 +433,7 @@ static struct s3c2410_nand_set gta02_nand_sets[] = {
                 */
                .name           = "neo1973-nand",
                .nr_chips       = 1,
-               .use_bbt        = 1,
-               .force_soft_ecc = 1,
+               .flash_bbt      = 1,
        },
 };
 
index 5cd04d6751b30166c1d3a1146725ddfa3a840e34..111f7ea32b384bd6e492d1cb1c0cf9635632c035 100644 (file)
@@ -24,6 +24,7 @@
 #include <linux/init.h>
 #include <linux/timer.h>
 #include <linux/io.h>
+#include <linux/seq_file.h>
 
 #include <asm/clkdev.h>
 #include <mach/hardware.h>
@@ -702,6 +703,7 @@ static struct clk amba_clk = {
        .rate       = 52000000, /* this varies! */
        .hw_ctrld   = true,
        .reset      = false,
+       .lock       = __SPIN_LOCK_UNLOCKED(amba_clk.lock),
 };
 
 /*
@@ -720,6 +722,7 @@ static struct clk cpu_clk = {
        .set_rate   = clk_set_rate_cpuclk,
        .get_rate   = clk_get_rate_cpuclk,
        .round_rate = clk_round_rate_cpuclk,
+       .lock       = __SPIN_LOCK_UNLOCKED(cpu_clk.lock),
 };
 
 static struct clk nandif_clk = {
@@ -732,6 +735,7 @@ static struct clk nandif_clk = {
        .clk_val    = U300_SYSCON_SBCER_NANDIF_CLK_EN,
        .enable     = syscon_clk_enable,
        .disable    = syscon_clk_disable,
+       .lock       = __SPIN_LOCK_UNLOCKED(nandif_clk.lock),
 };
 
 static struct clk semi_clk = {
@@ -744,6 +748,7 @@ static struct clk semi_clk = {
        .clk_val    = U300_SYSCON_SBCER_SEMI_CLK_EN,
        .enable     = syscon_clk_enable,
        .disable    = syscon_clk_disable,
+       .lock       = __SPIN_LOCK_UNLOCKED(semi_clk.lock),
 };
 
 #ifdef CONFIG_MACH_U300_BS335
@@ -758,6 +763,7 @@ static struct clk isp_clk = {
        .clk_val    = U300_SYSCON_SBCER_ISP_CLK_EN,
        .enable     = syscon_clk_enable,
        .disable    = syscon_clk_disable,
+       .lock       = __SPIN_LOCK_UNLOCKED(isp_clk.lock),
 };
 
 static struct clk cds_clk = {
@@ -771,6 +777,7 @@ static struct clk cds_clk = {
        .clk_val    = U300_SYSCON_SBCER_CDS_CLK_EN,
        .enable     = syscon_clk_enable,
        .disable    = syscon_clk_disable,
+       .lock       = __SPIN_LOCK_UNLOCKED(cds_clk.lock),
 };
 #endif
 
@@ -785,6 +792,7 @@ static struct clk dma_clk = {
        .clk_val    = U300_SYSCON_SBCER_DMAC_CLK_EN,
        .enable     = syscon_clk_enable,
        .disable    = syscon_clk_disable,
+       .lock       = __SPIN_LOCK_UNLOCKED(dma_clk.lock),
 };
 
 static struct clk aaif_clk = {
@@ -798,6 +806,7 @@ static struct clk aaif_clk = {
        .clk_val    = U300_SYSCON_SBCER_AAIF_CLK_EN,
        .enable     = syscon_clk_enable,
        .disable    = syscon_clk_disable,
+       .lock       = __SPIN_LOCK_UNLOCKED(aaif_clk.lock),
 };
 
 static struct clk apex_clk = {
@@ -811,6 +820,7 @@ static struct clk apex_clk = {
        .clk_val    = U300_SYSCON_SBCER_APEX_CLK_EN,
        .enable     = syscon_clk_enable,
        .disable    = syscon_clk_disable,
+       .lock       = __SPIN_LOCK_UNLOCKED(apex_clk.lock),
 };
 
 static struct clk video_enc_clk = {
@@ -825,6 +835,7 @@ static struct clk video_enc_clk = {
        .clk_val    = U300_SYSCON_SBCER_VIDEO_ENC_CLK_EN,
        .enable     = syscon_clk_enable,
        .disable    = syscon_clk_disable,
+       .lock       = __SPIN_LOCK_UNLOCKED(video_enc_clk.lock),
 };
 
 static struct clk xgam_clk = {
@@ -839,6 +850,7 @@ static struct clk xgam_clk = {
        .get_rate   = clk_get_rate_xgamclk,
        .enable     = syscon_clk_enable,
        .disable    = syscon_clk_disable,
+       .lock       = __SPIN_LOCK_UNLOCKED(xgam_clk.lock),
 };
 
 /* This clock is used to activate the video encoder */
@@ -854,6 +866,7 @@ static struct clk ahb_clk = {
        .enable     = syscon_clk_enable,
        .disable    = syscon_clk_disable,
        .get_rate   = clk_get_rate_ahb_clk,
+       .lock       = __SPIN_LOCK_UNLOCKED(ahb_clk.lock),
 };
 
 
@@ -871,6 +884,7 @@ static struct clk ahb_subsys_clk = {
        .enable     = syscon_clk_enable,
        .disable    = syscon_clk_disable,
        .get_rate   = clk_get_rate_ahb_clk,
+       .lock       = __SPIN_LOCK_UNLOCKED(ahb_subsys_clk.lock),
 };
 
 static struct clk intcon_clk = {
@@ -882,6 +896,8 @@ static struct clk intcon_clk = {
        .res_reg    = U300_SYSCON_VBASE + U300_SYSCON_RRR,
        .res_mask   = U300_SYSCON_RRR_INTCON_RESET_EN,
        /* INTCON can be reset but not clock-gated */
+       .lock       = __SPIN_LOCK_UNLOCKED(intcon_clk.lock),
+
 };
 
 static struct clk mspro_clk = {
@@ -895,6 +911,7 @@ static struct clk mspro_clk = {
        .clk_val    = U300_SYSCON_SBCER_MSPRO_CLK_EN,
        .enable     = syscon_clk_enable,
        .disable    = syscon_clk_disable,
+       .lock       = __SPIN_LOCK_UNLOCKED(mspro_clk.lock),
 };
 
 static struct clk emif_clk = {
@@ -909,6 +926,7 @@ static struct clk emif_clk = {
        .enable     = syscon_clk_enable,
        .disable    = syscon_clk_disable,
        .get_rate   = clk_get_rate_emif_clk,
+       .lock       = __SPIN_LOCK_UNLOCKED(emif_clk.lock),
 };
 
 
@@ -926,6 +944,7 @@ static struct clk fast_clk = {
        .clk_val    = U300_SYSCON_SBCER_FAST_BRIDGE_CLK_EN,
        .enable     = syscon_clk_enable,
        .disable    = syscon_clk_disable,
+       .lock       = __SPIN_LOCK_UNLOCKED(fast_clk.lock),
 };
 
 static struct clk mmcsd_clk = {
@@ -942,6 +961,7 @@ static struct clk mmcsd_clk = {
        .round_rate = clk_round_rate_mclk,
        .disable    = syscon_clk_disable,
        .enable     = syscon_clk_enable,
+       .lock       = __SPIN_LOCK_UNLOCKED(mmcsd_clk.lock),
 };
 
 static struct clk i2s0_clk = {
@@ -956,6 +976,7 @@ static struct clk i2s0_clk = {
        .enable     = syscon_clk_enable,
        .disable    = syscon_clk_disable,
        .get_rate   = clk_get_rate_i2s_i2c_spi,
+       .lock       = __SPIN_LOCK_UNLOCKED(i2s0_clk.lock),
 };
 
 static struct clk i2s1_clk = {
@@ -970,6 +991,7 @@ static struct clk i2s1_clk = {
        .enable     = syscon_clk_enable,
        .disable    = syscon_clk_disable,
        .get_rate   = clk_get_rate_i2s_i2c_spi,
+       .lock       = __SPIN_LOCK_UNLOCKED(i2s1_clk.lock),
 };
 
 static struct clk i2c0_clk = {
@@ -984,6 +1006,7 @@ static struct clk i2c0_clk = {
        .enable     = syscon_clk_enable,
        .disable    = syscon_clk_disable,
        .get_rate   = clk_get_rate_i2s_i2c_spi,
+       .lock       = __SPIN_LOCK_UNLOCKED(i2c0_clk.lock),
 };
 
 static struct clk i2c1_clk = {
@@ -998,6 +1021,7 @@ static struct clk i2c1_clk = {
        .enable     = syscon_clk_enable,
        .disable    = syscon_clk_disable,
        .get_rate   = clk_get_rate_i2s_i2c_spi,
+       .lock       = __SPIN_LOCK_UNLOCKED(i2c1_clk.lock),
 };
 
 static struct clk spi_clk = {
@@ -1012,6 +1036,7 @@ static struct clk spi_clk = {
        .enable     = syscon_clk_enable,
        .disable    = syscon_clk_disable,
        .get_rate   = clk_get_rate_i2s_i2c_spi,
+       .lock       = __SPIN_LOCK_UNLOCKED(spi_clk.lock),
 };
 
 #ifdef CONFIG_MACH_U300_BS335
@@ -1026,6 +1051,7 @@ static struct clk uart1_clk = {
        .clk_val    = U300_SYSCON_SBCER_UART1_CLK_EN,
        .enable     = syscon_clk_enable,
        .disable    = syscon_clk_disable,
+       .lock       = __SPIN_LOCK_UNLOCKED(uart1_clk.lock),
 };
 #endif
 
@@ -1044,6 +1070,7 @@ static struct clk slow_clk = {
        .clk_val    = U300_SYSCON_SBCER_SLOW_BRIDGE_CLK_EN,
        .enable     = syscon_clk_enable,
        .disable    = syscon_clk_disable,
+       .lock       = __SPIN_LOCK_UNLOCKED(slow_clk.lock),
 };
 
 /* TODO: implement SYSCON clock? */
@@ -1055,6 +1082,7 @@ static struct clk wdog_clk = {
        .rate       = 32768,
        .reset      = false,
        /* This is always on, cannot be enabled/disabled or reset */
+       .lock       = __SPIN_LOCK_UNLOCKED(wdog_clk.lock),
 };
 
 /* This one is hardwired to PLL13 */
@@ -1069,6 +1097,7 @@ static struct clk uart_clk = {
        .clk_val    = U300_SYSCON_SBCER_UART_CLK_EN,
        .enable     = syscon_clk_enable,
        .disable    = syscon_clk_disable,
+       .lock       = __SPIN_LOCK_UNLOCKED(uart_clk.lock),
 };
 
 static struct clk keypad_clk = {
@@ -1082,6 +1111,7 @@ static struct clk keypad_clk = {
        .clk_val    = U300_SYSCON_SBCER_KEYPAD_CLK_EN,
        .enable     = syscon_clk_enable,
        .disable    = syscon_clk_disable,
+       .lock       = __SPIN_LOCK_UNLOCKED(keypad_clk.lock),
 };
 
 static struct clk gpio_clk = {
@@ -1095,6 +1125,7 @@ static struct clk gpio_clk = {
        .clk_val    = U300_SYSCON_SBCER_GPIO_CLK_EN,
        .enable     = syscon_clk_enable,
        .disable    = syscon_clk_disable,
+       .lock       = __SPIN_LOCK_UNLOCKED(gpio_clk.lock),
 };
 
 static struct clk rtc_clk = {
@@ -1106,6 +1137,7 @@ static struct clk rtc_clk = {
        .res_reg    = U300_SYSCON_VBASE + U300_SYSCON_RSR,
        .res_mask   = U300_SYSCON_RSR_RTC_RESET_EN,
        /* This clock is always on, cannot be enabled/disabled */
+       .lock       = __SPIN_LOCK_UNLOCKED(rtc_clk.lock),
 };
 
 static struct clk bustr_clk = {
@@ -1119,6 +1151,7 @@ static struct clk bustr_clk = {
        .clk_val    = U300_SYSCON_SBCER_BTR_CLK_EN,
        .enable     = syscon_clk_enable,
        .disable    = syscon_clk_disable,
+       .lock       = __SPIN_LOCK_UNLOCKED(bustr_clk.lock),
 };
 
 static struct clk evhist_clk = {
@@ -1132,6 +1165,7 @@ static struct clk evhist_clk = {
        .clk_val    = U300_SYSCON_SBCER_EH_CLK_EN,
        .enable     = syscon_clk_enable,
        .disable    = syscon_clk_disable,
+       .lock       = __SPIN_LOCK_UNLOCKED(evhist_clk.lock),
 };
 
 static struct clk timer_clk = {
@@ -1145,6 +1179,7 @@ static struct clk timer_clk = {
        .clk_val    = U300_SYSCON_SBCER_ACC_TMR_CLK_EN,
        .enable     = syscon_clk_enable,
        .disable    = syscon_clk_disable,
+       .lock       = __SPIN_LOCK_UNLOCKED(timer_clk.lock),
 };
 
 static struct clk app_timer_clk = {
@@ -1158,6 +1193,7 @@ static struct clk app_timer_clk = {
        .clk_val    = U300_SYSCON_SBCER_APP_TMR_CLK_EN,
        .enable     = syscon_clk_enable,
        .disable    = syscon_clk_disable,
+       .lock       = __SPIN_LOCK_UNLOCKED(app_timer_clk.lock),
 };
 
 #ifdef CONFIG_MACH_U300_BS335
@@ -1172,6 +1208,7 @@ static struct clk ppm_clk = {
        .clk_val    = U300_SYSCON_SBCER_PPM_CLK_EN,
        .enable     = syscon_clk_enable,
        .disable    = syscon_clk_disable,
+       .lock       = __SPIN_LOCK_UNLOCKED(ppm_clk.lock),
 };
 #endif
 
@@ -1187,53 +1224,53 @@ static struct clk ppm_clk = {
  */
 static struct clk_lookup lookups[] = {
        /* Connected directly to the AMBA bus */
-       DEF_LOOKUP("amba", &amba_clk),
-       DEF_LOOKUP("cpu", &cpu_clk),
-       DEF_LOOKUP("nandif", &nandif_clk),
-       DEF_LOOKUP("semi", &semi_clk),
+       DEF_LOOKUP("amba",      &amba_clk),
+       DEF_LOOKUP("cpu",       &cpu_clk),
+       DEF_LOOKUP("fsmc",      &nandif_clk),
+       DEF_LOOKUP("semi",      &semi_clk),
 #ifdef CONFIG_MACH_U300_BS335
-       DEF_LOOKUP("isp", &isp_clk),
-       DEF_LOOKUP("cds", &cds_clk),
+       DEF_LOOKUP("isp",       &isp_clk),
+       DEF_LOOKUP("cds",       &cds_clk),
 #endif
-       DEF_LOOKUP("dma", &dma_clk),
-       DEF_LOOKUP("aaif", &aaif_clk),
-       DEF_LOOKUP("apex", &apex_clk),
+       DEF_LOOKUP("dma",       &dma_clk),
+       DEF_LOOKUP("msl",       &aaif_clk),
+       DEF_LOOKUP("apex",      &apex_clk),
        DEF_LOOKUP("video_enc", &video_enc_clk),
-       DEF_LOOKUP("xgam", &xgam_clk),
-       DEF_LOOKUP("ahb", &ahb_clk),
+       DEF_LOOKUP("xgam",      &xgam_clk),
+       DEF_LOOKUP("ahb",       &ahb_clk),
        /* AHB bridge clocks */
-       DEF_LOOKUP("ahb", &ahb_subsys_clk),
-       DEF_LOOKUP("intcon", &intcon_clk),
-       DEF_LOOKUP("mspro", &mspro_clk),
-       DEF_LOOKUP("pl172", &emif_clk),
+       DEF_LOOKUP("ahb_subsys", &ahb_subsys_clk),
+       DEF_LOOKUP("intcon",    &intcon_clk),
+       DEF_LOOKUP("mspro",     &mspro_clk),
+       DEF_LOOKUP("pl172",     &emif_clk),
        /* FAST bridge clocks */
-       DEF_LOOKUP("fast", &fast_clk),
-       DEF_LOOKUP("mmci", &mmcsd_clk),
+       DEF_LOOKUP("fast",      &fast_clk),
+       DEF_LOOKUP("mmci",      &mmcsd_clk),
        /*
         * The .0 and .1 identifiers on these comes from the platform device
         * .id field and are assigned when the platform devices are registered.
         */
-       DEF_LOOKUP("i2s.0", &i2s0_clk),
-       DEF_LOOKUP("i2s.1", &i2s1_clk),
-       DEF_LOOKUP("stddci2c.0", &i2c0_clk),
-       DEF_LOOKUP("stddci2c.1", &i2c1_clk),
-       DEF_LOOKUP("pl022", &spi_clk),
+       DEF_LOOKUP("i2s.0",     &i2s0_clk),
+       DEF_LOOKUP("i2s.1",     &i2s1_clk),
+       DEF_LOOKUP("stu300.0",  &i2c0_clk),
+       DEF_LOOKUP("stu300.1",  &i2c1_clk),
+       DEF_LOOKUP("pl022",     &spi_clk),
 #ifdef CONFIG_MACH_U300_BS335
-       DEF_LOOKUP("uart1", &uart1_clk),
+       DEF_LOOKUP("uart1",     &uart1_clk),
 #endif
        /* SLOW bridge clocks */
-       DEF_LOOKUP("slow", &slow_clk),
-       DEF_LOOKUP("wdog", &wdog_clk),
-       DEF_LOOKUP("uart0", &uart_clk),
-       DEF_LOOKUP("apptimer", &app_timer_clk),
-       DEF_LOOKUP("keypad", &keypad_clk),
+       DEF_LOOKUP("slow",      &slow_clk),
+       DEF_LOOKUP("coh901327_wdog",      &wdog_clk),
+       DEF_LOOKUP("uart0",     &uart_clk),
+       DEF_LOOKUP("apptimer",  &app_timer_clk),
+       DEF_LOOKUP("coh901461-keypad",    &keypad_clk),
        DEF_LOOKUP("u300-gpio", &gpio_clk),
-       DEF_LOOKUP("rtc0", &rtc_clk),
-       DEF_LOOKUP("bustr", &bustr_clk),
-       DEF_LOOKUP("evhist", &evhist_clk),
-       DEF_LOOKUP("timer", &timer_clk),
+       DEF_LOOKUP("rtc-coh901331",      &rtc_clk),
+       DEF_LOOKUP("bustr",     &bustr_clk),
+       DEF_LOOKUP("evhist",    &evhist_clk),
+       DEF_LOOKUP("timer",     &timer_clk),
 #ifdef CONFIG_MACH_U300_BS335
-       DEF_LOOKUP("ppm", &ppm_clk),
+       DEF_LOOKUP("ppm",       &ppm_clk),
 #endif
 };
 
@@ -1427,16 +1464,20 @@ static const struct file_operations u300_clocks_operations = {
        .release        = single_release,
 };
 
-static void init_clk_read_procfs(void)
+static int __init init_clk_read_debugfs(void)
 {
        /* Expose a simple debugfs interface to view all clocks */
        (void) debugfs_create_file("u300_clocks", S_IFREG | S_IRUGO,
-                                  NULL, NULL, &u300_clocks_operations);
-}
-#else
-static inline void init_clk_read_procfs(void)
-{
+                                  NULL, NULL,
+                                  &u300_clocks_operations);
+       return 0;
 }
+/*
+ * This needs to come in after the core_initcall() for the
+ * overall clocks, because debugfs is not available until
+ * the subsystems come up.
+ */
+module_init(init_clk_read_debugfs);
 #endif
 
 static int __init u300_clock_init(void)
@@ -1462,8 +1503,6 @@ static int __init u300_clock_init(void)
 
        clk_register();
 
-       init_clk_read_procfs();
-
        /*
         * Some of these may be on when we boot the system so make sure they
         * are turned OFF.
index 195e48edd8c2ce951cb8ac5b3272e962785d6bae..ac5c80062b704b791d0d9af9be34e7484f8d4311 100644 (file)
@@ -27,6 +27,7 @@ EXPORT_SYMBOL(__cpuc_flush_kern_all);
 EXPORT_SYMBOL(__cpuc_flush_user_all);
 EXPORT_SYMBOL(__cpuc_flush_user_range);
 EXPORT_SYMBOL(__cpuc_coherent_kern_range);
+EXPORT_SYMBOL(__cpuc_flush_dcache_page);
 EXPORT_SYMBOL(dmac_inv_range);  /* because of flush_ioremap_region() */
 #else
 EXPORT_SYMBOL(cpu_cache);
index def14ec265b369f7929ea5bd841f4e97a6ac5b38..7677a4a1cef26f0df05e5db328cf7134bd27e0ee 100644 (file)
@@ -2457,6 +2457,19 @@ static int __init omap_init_dma(void)
                setup_irq(irq, &omap24xx_dma_irq);
        }
 
+       /* Enable smartidle idlemodes and autoidle */
+       if (cpu_is_omap34xx()) {
+               u32 v = dma_read(OCP_SYSCONFIG);
+               v &= ~(DMA_SYSCONFIG_MIDLEMODE_MASK |
+                               DMA_SYSCONFIG_SIDLEMODE_MASK |
+                               DMA_SYSCONFIG_AUTOIDLE);
+               v |= (DMA_SYSCONFIG_MIDLEMODE(DMA_IDLEMODE_SMARTIDLE) |
+                       DMA_SYSCONFIG_SIDLEMODE(DMA_IDLEMODE_SMARTIDLE) |
+                       DMA_SYSCONFIG_AUTOIDLE);
+               dma_write(v , OCP_SYSCONFIG);
+       }
+
+
        /* FIXME: Update LCD DMA to work on 24xx */
        if (cpu_class_is_omap1()) {
                r = request_irq(INT_DMA_LCD, lcd_dma_irq_handler, 0,
index 7fd89ba8d3b5939684ab6999a12fc19c5430b31e..26b387c1242393e9bd5450a6751d1ed9a2f3e54c 100644 (file)
@@ -1585,6 +1585,7 @@ static int __init _omap_gpio_init(void)
                        __raw_writel(0x00000000, bank->base + OMAP24XX_GPIO_IRQENABLE1);
                        __raw_writel(0xffffffff, bank->base + OMAP24XX_GPIO_IRQSTATUS1);
                        __raw_writew(0x0015, bank->base + OMAP24XX_GPIO_SYSCONFIG);
+                       __raw_writel(0x00000000, bank->base + OMAP24XX_GPIO_DEBOUNCE_EN);
 
                        /* Initialize interface clock ungated, module enabled */
                        __raw_writel(0, bank->base + OMAP24XX_GPIO_CTRL);
index fc60c4ebcc28af1d0d1fa80d583b7f35cf00feaf..285eaa3a82750bf986bb5ebe331f86b1e55177fe 100644 (file)
 #ifndef __ASM_ARCH_OMAP_CPU_H
 #define __ASM_ARCH_OMAP_CPU_H
 
+/*
+ * Omap device type i.e. EMU/HS/TST/GP/BAD
+ */
+#define OMAP2_DEVICE_TYPE_TEST         0
+#define OMAP2_DEVICE_TYPE_EMU          1
+#define OMAP2_DEVICE_TYPE_SEC          2
+#define OMAP2_DEVICE_TYPE_GP           3
+#define OMAP2_DEVICE_TYPE_BAD          4
+
+int omap_type(void);
+
 struct omap_chip_id {
        u8 oc;
        u8 type;
@@ -424,17 +435,6 @@ IS_OMAP_TYPE(3430, 0x3430)
 
 
 int omap_chip_is(struct omap_chip_id oci);
-int omap_type(void);
-
-/*
- * Macro to detect device type i.e. EMU/HS/TST/GP/BAD
- */
-#define OMAP2_DEVICE_TYPE_TEST         0
-#define OMAP2_DEVICE_TYPE_EMU          1
-#define OMAP2_DEVICE_TYPE_SEC          2
-#define OMAP2_DEVICE_TYPE_GP           3
-#define OMAP2_DEVICE_TYPE_BAD          4
-
 void omap2_check_revision(void);
 
 #endif    /* defined(CONFIG_ARCH_OMAP2) || defined(CONFIG_ARCH_OMAP3) */
index 8c1eae88737e9e6a0ca24d85a5b51c63050c156a..7b939cc01962034fd8003964be7bcc33d4e1a535 100644 (file)
 #define DMA_THREAD_FIFO_25             (0x02 << 14)
 #define DMA_THREAD_FIFO_50             (0x03 << 14)
 
+/* DMA4_OCP_SYSCONFIG bits */
+#define DMA_SYSCONFIG_MIDLEMODE_MASK           (3 << 12)
+#define DMA_SYSCONFIG_CLOCKACTIVITY_MASK       (3 << 8)
+#define DMA_SYSCONFIG_EMUFREE                  (1 << 5)
+#define DMA_SYSCONFIG_SIDLEMODE_MASK           (3 << 3)
+#define DMA_SYSCONFIG_SOFTRESET                        (1 << 2)
+#define DMA_SYSCONFIG_AUTOIDLE                 (1 << 0)
+
+#define DMA_SYSCONFIG_MIDLEMODE(n)             ((n) << 12)
+#define DMA_SYSCONFIG_SIDLEMODE(n)             ((n) << 3)
+
+#define DMA_IDLEMODE_SMARTIDLE                 0x2
+#define DMA_IDLEMODE_NO_IDLE                   0x1
+#define DMA_IDLEMODE_FORCE_IDLE                        0x0
+
 /* Chaining modes*/
 #ifndef CONFIG_ARCH_OMAP1
 #define OMAP_DMA_STATIC_CHAIN          0x1
index 3b28147205691a05df715d71a31d5e33fef858eb..73f483d56ca6a0180ea64d896f0979cf80318419 100644 (file)
 #define OMAP2_IO_ADDRESS(pa)   IOMEM(__OMAP2_IO_ADDRESS(pa))
 
 #ifdef __ASSEMBLER__
-#define IOMEM(x)               x
+#define IOMEM(x)               (x)
 #else
 #define IOMEM(x)               ((void __force __iomem *)(x))
 
index 4cf449fa2cb54a8013cd8df951ab00af2c439905..4a03013990135c6c4faa2ee134a55c16feb26470 100644 (file)
@@ -298,7 +298,7 @@ void flush_iotlb_page(struct iommu *obj, u32 da)
                if ((start <= da) && (da < start + bytes)) {
                        dev_dbg(obj->dev, "%s: %08x<=%08x(%x)\n",
                                __func__, start, da, bytes);
-
+                       iotlb_load_cr(obj, &cr);
                        iommu_write_reg(obj, 1, MMU_FLUSH_ENTRY);
                }
        }
index 65006df3f1b750832b3832c3fb1ac62aa84b6a94..4ea73804d21e2ffcfbc4f5e314c9c27250e9d814 100644 (file)
@@ -133,7 +133,12 @@ void __init omap_detect_sram(void)
                        if (cpu_is_omap34xx()) {
                                omap_sram_base = OMAP3_SRAM_PUB_VA;
                                omap_sram_start = OMAP3_SRAM_PUB_PA;
-                               omap_sram_size = 0x8000; /* 32K */
+                               if ((omap_type() == OMAP2_DEVICE_TYPE_EMU) ||
+                                   (omap_type() == OMAP2_DEVICE_TYPE_SEC)) {
+                                       omap_sram_size = 0x7000; /* 28K */
+                               } else {
+                                       omap_sram_size = 0x8000; /* 32K */
+                               }
                        } else {
                                omap_sram_base = OMAP2_SRAM_PUB_VA;
                                omap_sram_start = OMAP2_SRAM_PUB_PA;
index 74bb7cb5da49571766c568ec3ad5ad90a4d434a4..0761766b183325cc3f5f0a7565445bc3ff94705a 100644 (file)
@@ -34,7 +34,7 @@ obj-$(CONFIG_S3C_DEV_HSMMC)   += dev-hsmmc.o
 obj-$(CONFIG_S3C_DEV_HSMMC1)   += dev-hsmmc1.o
 obj-y                          += dev-i2c0.o
 obj-$(CONFIG_S3C_DEV_I2C1)     += dev-i2c1.o
-obj-$(CONFIG_SND_S3C24XX_SOC)  += dev-audio.o
+obj-$(CONFIG_SND_S3C64XX_SOC_I2S)      += dev-audio.o
 obj-$(CONFIG_S3C_DEV_FB)       += dev-fb.o
 obj-$(CONFIG_S3C_DEV_USB_HOST) += dev-usb.o
 obj-$(CONFIG_S3C_DEV_USB_HSOTG)        += dev-usb-hsotg.o
index b5b9c4d46e9a3b7e04745062d3086eb6d1947337..2e170827e0b078cd62db84541a7c23ebbf274672 100644 (file)
@@ -37,6 +37,7 @@ extern struct platform_device s3c_device_i2c1;
 extern struct platform_device s3c_device_rtc;
 extern struct platform_device s3c_device_adc;
 extern struct platform_device s3c_device_sdi;
+extern struct platform_device s3c_device_iis;
 extern struct platform_device s3c_device_hwmon;
 extern struct platform_device s3c_device_hsmmc0;
 extern struct platform_device s3c_device_hsmmc1;
index 636cb12711df8e98de68cce12d0196d10529da94..579a165c282708276c3511eb8f6734b3f3cc588a 100644 (file)
@@ -29,7 +29,7 @@ obj-$(CONFIG_PM_SIMTEC)               += pm-simtec.o
 obj-$(CONFIG_PM)               += pm.o
 obj-$(CONFIG_PM)               += irq-pm.o
 obj-$(CONFIG_PM)               += sleep.o
-obj-$(CONFIG_HAVE_PWM)         += pwm.o
+obj-$(CONFIG_S3C24XX_PWM)      += pwm.o
 obj-$(CONFIG_S3C2410_CLOCK)    += s3c2410-clock.o
 obj-$(CONFIG_S3C2410_DMA)      += dma.o
 obj-$(CONFIG_S3C24XX_ADC)      += adc.o
index 9edf7894eedd663fd5a2ad652515ce08c437f09d..da7a61728c18eacbe8acbbd5e4f8c36cf66ecc23 100644 (file)
@@ -12,8 +12,7 @@
 */
 
 #include <linux/kernel.h>
-
-#include <mach/hardware.h>
+#include <linux/gpio.h>
 
 #include <mach/spi.h>
 #include <mach/regs-gpio.h>
index f34d0fc69ad81228add93dcd4db889aa4c44230c..86b9edc674133e4b85fcbe628fdf36ef4a0efa76 100644 (file)
@@ -12,8 +12,7 @@
 */
 
 #include <linux/kernel.h>
-
-#include <mach/hardware.h>
+#include <linux/gpio.h>
 
 #include <mach/spi.h>
 #include <mach/regs-gpio.h>
index 4442f8d2d4239a09470e04583aa9f168583246d9..fc42de5ca209ac5e9de0cfca9c1f35561f740be2 100644 (file)
@@ -40,7 +40,7 @@ struct thread_info {
        .exec_domain    = &default_exec_domain,                         \
        .flags          = 0,                                            \
        .cpu            = 0,                                            \
-       .preempt_count  = 1,                                            \
+       .preempt_count  = INIT_PREEMPT_COUNT,                           \
        .restart_block  = {                                             \
                .fn     = do_no_restart_syscall                         \
        }                                                               \
index 6e3d491184eab1d079b83a6cdaf33139f1365c1f..b91b2044af9c9660210bb9efd5f11ab60a08dcbc 100644 (file)
@@ -32,22 +32,25 @@ void NORET_TYPE die(const char *str, struct pt_regs *regs, long err)
        spin_lock_irq(&die_lock);
        bust_spinlocks(1);
 
-       printk(KERN_ALERT "Oops: %s, sig: %ld [#%d]\n" KERN_EMERG,
+       printk(KERN_ALERT "Oops: %s, sig: %ld [#%d]\n",
               str, err, ++die_counter);
+
+       printk(KERN_EMERG);
+
 #ifdef CONFIG_PREEMPT
-       printk("PREEMPT ");
+       printk(KERN_CONT "PREEMPT ");
 #endif
 #ifdef CONFIG_FRAME_POINTER
-       printk("FRAME_POINTER ");
+       printk(KERN_CONT "FRAME_POINTER ");
 #endif
        if (current_cpu_data.features & AVR32_FEATURE_OCD) {
                unsigned long did = ocd_read(DID);
-               printk("chip: 0x%03lx:0x%04lx rev %lu\n",
+               printk(KERN_CONT "chip: 0x%03lx:0x%04lx rev %lu\n",
                       (did >> 1) & 0x7ff,
                       (did >> 12) & 0x7fff,
                       (did >> 28) & 0xf);
        } else {
-               printk("cpu: arch %u r%u / core %u r%u\n",
+               printk(KERN_CONT "cpu: arch %u r%u / core %u r%u\n",
                       current_cpu_data.arch_type,
                       current_cpu_data.arch_revision,
                       current_cpu_data.cpu_type,
index 2920087516f2a08175b54ed3086844434db937c9..2bbfdd950afc49c4623d876125b0a71dd7de4903 100644 (file)
@@ -77,7 +77,7 @@ struct thread_info {
        .exec_domain    = &default_exec_domain, \
        .flags          = 0,                    \
        .cpu            = 0,                    \
-       .preempt_count  = 1,                    \
+       .preempt_count  = INIT_PREEMPT_COUNT,   \
        .restart_block  = {                     \
                .fn = do_no_restart_syscall,    \
        },                                      \
index d76618db50df8c4e3f4c06cb44d09906e5b41147..6a387eec6b65e5baa3bcfb247e037748bea6f587 100644 (file)
@@ -31,7 +31,6 @@
 #include <linux/sched.h>
 #include <linux/mm.h>
 #include <linux/smp.h>
-#include <linux/smp_lock.h>
 #include <linux/errno.h>
 #include <linux/ptrace.h>
 #include <linux/user.h>
index 298f023bcc09b91bbb34eb59262dbf60069b59e3..6136c33e919f79b700efcac55623eaf5a53f1911 100644 (file)
@@ -408,13 +408,14 @@ static void __init print_memory_map(char *who)
                        bfin_memmap.map[i].addr + bfin_memmap.map[i].size);
                switch (bfin_memmap.map[i].type) {
                case BFIN_MEMMAP_RAM:
-                               printk("(usable)\n");
-                               break;
+                       printk(KERN_CONT "(usable)\n");
+                       break;
                case BFIN_MEMMAP_RESERVED:
-                               printk("(reserved)\n");
-                               break;
-               default:        printk("type %lu\n", bfin_memmap.map[i].type);
-                               break;
+                       printk(KERN_CONT "(reserved)\n");
+                       break;
+               default:
+                       printk(KERN_CONT "type %lu\n", bfin_memmap.map[i].type);
+                       break;
                }
        }
 }
@@ -614,19 +615,19 @@ static __init void memory_setup(void)
        printk(KERN_INFO "Kernel Managed Memory: %ldMB\n", _ramend >> 20);
 
        printk(KERN_INFO "Memory map:\n"
-               KERN_INFO "  fixedcode = 0x%p-0x%p\n"
-               KERN_INFO "  text      = 0x%p-0x%p\n"
-               KERN_INFO "  rodata    = 0x%p-0x%p\n"
-               KERN_INFO "  bss       = 0x%p-0x%p\n"
-               KERN_INFO "  data      = 0x%p-0x%p\n"
-               KERN_INFO "    stack   = 0x%p-0x%p\n"
-               KERN_INFO "  init      = 0x%p-0x%p\n"
-               KERN_INFO "  available = 0x%p-0x%p\n"
+              "  fixedcode = 0x%p-0x%p\n"
+              "  text      = 0x%p-0x%p\n"
+              "  rodata    = 0x%p-0x%p\n"
+              "  bss       = 0x%p-0x%p\n"
+              "  data      = 0x%p-0x%p\n"
+              "    stack   = 0x%p-0x%p\n"
+              "  init      = 0x%p-0x%p\n"
+              "  available = 0x%p-0x%p\n"
 #ifdef CONFIG_MTD_UCLINUX
-               KERN_INFO "  rootfs    = 0x%p-0x%p\n"
+              "  rootfs    = 0x%p-0x%p\n"
 #endif
 #if DMA_UNCACHED_REGION > 0
-               KERN_INFO "  DMA Zone  = 0x%p-0x%p\n"
+              "  DMA Zone  = 0x%p-0x%p\n"
 #endif
                , (void *)FIXED_CODE_START, (void *)FIXED_CODE_END,
                _stext, _etext,
@@ -859,13 +860,13 @@ void __init setup_arch(char **cmdline_p)
 #endif
        printk(KERN_INFO "Hardware Trace ");
        if (bfin_read_TBUFCTL() & 0x1)
-               printk("Active ");
+               printk(KERN_CONT "Active ");
        else
-               printk("Off ");
+               printk(KERN_CONT "Off ");
        if (bfin_read_TBUFCTL() & 0x2)
-               printk("and Enabled\n");
+               printk(KERN_CONT "and Enabled\n");
        else
-       printk("and Disabled\n");
+               printk(KERN_CONT "and Disabled\n");
 
 #if defined(CONFIG_CHR_DEV_FLASH) || defined(CONFIG_BLK_DEV_FLASH)
        /* we need to initialize the Flashrom device here since we might
index a8f1329c15a48befeb62f31a7b80603b263dda2d..3da60fb13ce46d8a45b5194e152985608c0cbaeb 100644 (file)
@@ -29,7 +29,6 @@
  * 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
  */
 
-#include <linux/smp_lock.h>
 #include <linux/spinlock.h>
 #include <linux/sem.h>
 #include <linux/msg.h>
index 8eeb457ce5d5fc6cc6541a174be1c6989113328a..8a1caf2bb5b9defa94dc1fff7c6803afb3324fad 100644 (file)
@@ -212,7 +212,7 @@ asmlinkage void double_fault_c(struct pt_regs *fp)
        console_verbose();
        oops_in_progress = 1;
 #ifdef CONFIG_DEBUG_VERBOSE
-       printk(KERN_EMERG "\n" KERN_EMERG "Double Fault\n");
+       printk(KERN_EMERG "Double Fault\n");
 #ifdef CONFIG_DEBUG_DOUBLEFAULT_PRINT
        if (((long)fp->seqstat &  SEQSTAT_EXCAUSE) == VEC_UNCOV) {
                unsigned int cpu = smp_processor_id();
@@ -583,15 +583,14 @@ asmlinkage void trap_c(struct pt_regs *fp)
 #ifndef CONFIG_DEBUG_BFIN_NO_KERN_HWTRACE
                if (trapnr == VEC_CPLB_I_M || trapnr == VEC_CPLB_M)
                        verbose_printk(KERN_NOTICE "No trace since you do not have "
-                               "CONFIG_DEBUG_BFIN_NO_KERN_HWTRACE enabled\n"
-                               KERN_NOTICE "\n");
+                              "CONFIG_DEBUG_BFIN_NO_KERN_HWTRACE enabled\n\n");
                else
 #endif
                        dump_bfin_trace_buffer();
 
                if (oops_in_progress) {
                        /* Dump the current kernel stack */
-                       verbose_printk(KERN_NOTICE "\n" KERN_NOTICE "Kernel Stack\n");
+                       verbose_printk(KERN_NOTICE "Kernel Stack\n");
                        show_stack(current, NULL);
                        print_modules();
 #ifndef CONFIG_ACCESS_CHECK
@@ -906,7 +905,7 @@ void show_stack(struct task_struct *task, unsigned long *stack)
 
                        ret_addr = 0;
                        if (!j && i % 8 == 0)
-                               printk("\n" KERN_NOTICE "%p:",addr);
+                               printk(KERN_NOTICE "%p:",addr);
 
                        /* if it is an odd address, or zero, just skip it */
                        if (*addr & 0x1 || !*addr)
@@ -996,9 +995,9 @@ void dump_bfin_process(struct pt_regs *fp)
 
                printk(KERN_NOTICE "CPU = %d\n", current_thread_info()->cpu);
                if (!((unsigned long)current->mm & 0x3) && (unsigned long)current->mm >= FIXED_CODE_START)
-                       verbose_printk(KERN_NOTICE  "TEXT = 0x%p-0x%p        DATA = 0x%p-0x%p\n"
-                               KERN_NOTICE " BSS = 0x%p-0x%p  USER-STACK = 0x%p\n"
-                               KERN_NOTICE "\n",
+                       verbose_printk(KERN_NOTICE
+                               "TEXT = 0x%p-0x%p        DATA = 0x%p-0x%p\n"
+                               " BSS = 0x%p-0x%p  USER-STACK = 0x%p\n\n",
                                (void *)current->mm->start_code,
                                (void *)current->mm->end_code,
                                (void *)current->mm->start_data,
@@ -1009,8 +1008,8 @@ void dump_bfin_process(struct pt_regs *fp)
                else
                        verbose_printk(KERN_NOTICE "invalid mm\n");
        } else
-               verbose_printk(KERN_NOTICE "\n" KERN_NOTICE
-                    "No Valid process in current context\n");
+               verbose_printk(KERN_NOTICE
+                              "No Valid process in current context\n");
 #endif
 }
 
@@ -1028,7 +1027,7 @@ void dump_bfin_mem(struct pt_regs *fp)
             addr < (unsigned short *)((unsigned long)erraddr & ~0xF) + 0x10;
             addr++) {
                if (!((unsigned long)addr & 0xF))
-                       verbose_printk("\n" KERN_NOTICE "0x%p: ", addr);
+                       verbose_printk(KERN_NOTICE "0x%p: ", addr);
 
                if (!get_instruction(&val, addr)) {
                                val = 0;
@@ -1056,9 +1055,9 @@ void dump_bfin_mem(struct pt_regs *fp)
            oops_in_progress)){
                verbose_printk(KERN_NOTICE "Looks like this was a deferred error - sorry\n");
 #ifndef CONFIG_DEBUG_HWERR
-               verbose_printk(KERN_NOTICE "The remaining message may be meaningless\n"
-                       KERN_NOTICE "You should enable CONFIG_DEBUG_HWERR to get a"
-                        " better idea where it came from\n");
+               verbose_printk(KERN_NOTICE
+"The remaining message may be meaningless\n"
+"You should enable CONFIG_DEBUG_HWERR to get a better idea where it came from\n");
 #else
                /* If we are handling only one peripheral interrupt
                 * and current mm and pid are valid, and the last error
@@ -1114,9 +1113,10 @@ void show_regs(struct pt_regs *fp)
 
        verbose_printk(KERN_NOTICE "%s", linux_banner);
 
-       verbose_printk(KERN_NOTICE "\n" KERN_NOTICE "SEQUENCER STATUS:\t\t%s\n", print_tainted());
+       verbose_printk(KERN_NOTICE "\nSEQUENCER STATUS:\t\t%s\n",
+                      print_tainted());
        verbose_printk(KERN_NOTICE " SEQSTAT: %08lx  IPEND: %04lx  SYSCFG: %04lx\n",
-               (long)fp->seqstat, fp->ipend, fp->syscfg);
+                      (long)fp->seqstat, fp->ipend, fp->syscfg);
        if ((fp->seqstat & SEQSTAT_EXCAUSE) == VEC_HWERR) {
                verbose_printk(KERN_NOTICE "  HWERRCAUSE: 0x%lx\n",
                        (fp->seqstat & SEQSTAT_HWERRCAUSE) >> 14);
@@ -1184,7 +1184,7 @@ unlock:
                verbose_printk(KERN_NOTICE "ICPLB_FAULT_ADDR: %s\n", buf);
        }
 
-       verbose_printk(KERN_NOTICE "\n" KERN_NOTICE "PROCESSOR STATE:\n");
+       verbose_printk(KERN_NOTICE "PROCESSOR STATE:\n");
        verbose_printk(KERN_NOTICE " R0 : %08lx    R1 : %08lx    R2 : %08lx    R3 : %08lx\n",
                fp->r0, fp->r1, fp->r2, fp->r3);
        verbose_printk(KERN_NOTICE " R4 : %08lx    R5 : %08lx    R6 : %08lx    R7 : %08lx\n",
index bc5b2935ca53a782c66acf4c371e87e46de39077..c3aade36c330400cb7dceb69051a422bb16ed34a 100644 (file)
@@ -50,8 +50,6 @@ struct thread_info {
 
 /*
  * macros/functions for gaining access to the thread information structure
- *
- * preempt_count needs to be 1 initially, until the scheduler is functional.
  */
 #ifndef __ASSEMBLY__
 #define INIT_THREAD_INFO(tsk)                          \
@@ -60,7 +58,7 @@ struct thread_info {
        .exec_domain    = &default_exec_domain,         \
        .flags          = 0,                            \
        .cpu            = 0,                            \
-       .preempt_count  = 1,                            \
+       .preempt_count  = INIT_PREEMPT_COUNT,           \
        .addr_limit     = KERNEL_DS,                    \
        .restart_block = {                              \
                       .fn = do_no_restart_syscall,     \
index a79fbd87021b02cf03663f7a06d680a58a24ceac..2ad962c7e88ebaddcbc11ed7a3a88f3e2e900385 100644 (file)
@@ -15,7 +15,6 @@
 #include <linux/mm.h>
 #include <linux/fs.h>
 #include <linux/smp.h>
-#include <linux/smp_lock.h>
 #include <linux/sem.h>
 #include <linux/msg.h>
 #include <linux/shm.h>
index 8a5bd7a9c6f533b452b21de81127c476b1826765..b86e19c9b5b0a137c297f5a1a55e1be49b7d250b 100644 (file)
@@ -7,6 +7,7 @@ config FRV
        default y
        select HAVE_IDE
        select HAVE_ARCH_TRACEHOOK
+       select HAVE_PERF_COUNTERS
 
 config ZONE_DMA
        bool
index 0409d981fd39501820618036f8667957ef7f205d..00a57af79afc6b7d6d45fd1046dd96abdf35184b 100644 (file)
@@ -121,10 +121,72 @@ static inline void atomic_dec(atomic_t *v)
 #define atomic_dec_and_test(v)         (atomic_sub_return(1, (v)) == 0)
 #define atomic_inc_and_test(v)         (atomic_add_return(1, (v)) == 0)
 
+/*
+ * 64-bit atomic ops
+ */
+typedef struct {
+       volatile long long counter;
+} atomic64_t;
+
+#define ATOMIC64_INIT(i)       { (i) }
+
+static inline long long atomic64_read(atomic64_t *v)
+{
+       long long counter;
+
+       asm("ldd%I1 %M1,%0"
+           : "=e"(counter)
+           : "m"(v->counter));
+       return counter;
+}
+
+static inline void atomic64_set(atomic64_t *v, long long i)
+{
+       asm volatile("std%I0 %1,%M0"
+                    : "=m"(v->counter)
+                    : "e"(i));
+}
+
+extern long long atomic64_inc_return(atomic64_t *v);
+extern long long atomic64_dec_return(atomic64_t *v);
+extern long long atomic64_add_return(long long i, atomic64_t *v);
+extern long long atomic64_sub_return(long long i, atomic64_t *v);
+
+static inline long long atomic64_add_negative(long long i, atomic64_t *v)
+{
+       return atomic64_add_return(i, v) < 0;
+}
+
+static inline void atomic64_add(long long i, atomic64_t *v)
+{
+       atomic64_add_return(i, v);
+}
+
+static inline void atomic64_sub(long long i, atomic64_t *v)
+{
+       atomic64_sub_return(i, v);
+}
+
+static inline void atomic64_inc(atomic64_t *v)
+{
+       atomic64_inc_return(v);
+}
+
+static inline void atomic64_dec(atomic64_t *v)
+{
+       atomic64_dec_return(v);
+}
+
+#define atomic64_sub_and_test(i,v)     (atomic64_sub_return((i), (v)) == 0)
+#define atomic64_dec_and_test(v)       (atomic64_dec_return((v)) == 0)
+#define atomic64_inc_and_test(v)       (atomic64_inc_return((v)) == 0)
+
 /*****************************************************************************/
 /*
  * exchange value with memory
  */
+extern uint64_t __xchg_64(uint64_t i, volatile void *v);
+
 #ifndef CONFIG_FRV_OUTOFLINE_ATOMIC_OPS
 
 #define xchg(ptr, x)                                                           \
@@ -174,8 +236,10 @@ extern uint32_t __xchg_32(uint32_t i, volatile void *v);
 
 #define tas(ptr) (xchg((ptr), 1))
 
-#define atomic_cmpxchg(v, old, new) (cmpxchg(&((v)->counter), old, new))
-#define atomic_xchg(v, new) (xchg(&((v)->counter), new))
+#define atomic_cmpxchg(v, old, new)    (cmpxchg(&(v)->counter, old, new))
+#define atomic_xchg(v, new)            (xchg(&(v)->counter, new))
+#define atomic64_cmpxchg(v, old, new)  (__cmpxchg_64(old, new, &(v)->counter))
+#define atomic64_xchg(v, new)          (__xchg_64(new, &(v)->counter))
 
 static __inline__ int atomic_add_unless(atomic_t *v, int a, int u)
 {
diff --git a/arch/frv/include/asm/perf_counter.h b/arch/frv/include/asm/perf_counter.h
new file mode 100644 (file)
index 0000000..ccf726e
--- /dev/null
@@ -0,0 +1,17 @@
+/* FRV performance counter support
+ *
+ * Copyright (C) 2009 Red Hat, Inc. All Rights Reserved.
+ * Written by David Howells (dhowells@redhat.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public Licence
+ * as published by the Free Software Foundation; either version
+ * 2 of the Licence, or (at your option) any later version.
+ */
+
+#ifndef _ASM_PERF_COUNTER_H
+#define _ASM_PERF_COUNTER_H
+
+#define PERF_COUNTER_INDEX_OFFSET      0
+
+#endif /* _ASM_PERF_COUNTER_H */
index 7742ec000cc474d018c6378705395ce9e0b43688..efd22d9077ac3be05e0ce45b4d9cd5fa0f1a83ce 100644 (file)
@@ -208,6 +208,8 @@ extern void free_initmem(void);
  * - if (*ptr == test) then orig = *ptr; *ptr = test;
  * - if (*ptr != test) then orig = *ptr;
  */
+extern uint64_t __cmpxchg_64(uint64_t test, uint64_t new, volatile uint64_t *v);
+
 #ifndef CONFIG_FRV_OUTOFLINE_ATOMIC_OPS
 
 #define cmpxchg(ptr, test, new)                                                        \
index e8a5ed7be0212791674996fd16afeb4f38a6b751..e608e056bb5301582b44b13d2bba9d9ccabfc23a 100644 (file)
@@ -56,8 +56,6 @@ struct thread_info {
 
 /*
  * macros/functions for gaining access to the thread information structure
- *
- * preempt_count needs to be 1 initially, until the scheduler is functional.
  */
 #ifndef __ASSEMBLY__
 
@@ -67,7 +65,7 @@ struct thread_info {
        .exec_domain    = &default_exec_domain, \
        .flags          = 0,                    \
        .cpu            = 0,                    \
-       .preempt_count  = 1,                    \
+       .preempt_count  = INIT_PREEMPT_COUNT,   \
        .addr_limit     = KERNEL_DS,            \
        .restart_block = {                      \
                .fn = do_no_restart_syscall,    \
index 96d78d5d2c41969b0b497846faff20a954f552bb..4a8fb427ce0a274a62aeffb989bbb195549d4ee8 100644 (file)
 #define __NR_inotify_init1     332
 #define __NR_preadv            333
 #define __NR_pwritev           334
+#define __NR_rt_tgsigqueueinfo 335
+#define __NR_perf_counter_open 336
 
 #ifdef __KERNEL__
 
-#define NR_syscalls 335
+#define NR_syscalls 337
 
 #define __ARCH_WANT_IPC_PARSE_VERSION
 /* #define __ARCH_WANT_OLD_READDIR */
index 356e0e327a8923f87d366776f06e5b916852bf56..fde1e446b440e7a5027ec597437365350d18fda5 100644 (file)
@@ -1524,5 +1524,7 @@ sys_call_table:
        .long sys_inotify_init1
        .long sys_preadv
        .long sys_pwritev
+       .long sys_rt_tgsigqueueinfo     /* 335 */
+       .long sys_perf_counter_open
 
 syscall_table_size = (. - sys_call_table)
index 0316b3c50efff8814d0ba2b44156ddec40c886c4..a89803b58b9a970c47c0784ca1be398478de6142 100644 (file)
@@ -67,6 +67,10 @@ EXPORT_SYMBOL(atomic_sub_return);
 EXPORT_SYMBOL(__xchg_32);
 EXPORT_SYMBOL(__cmpxchg_32);
 #endif
+EXPORT_SYMBOL(atomic64_add_return);
+EXPORT_SYMBOL(atomic64_sub_return);
+EXPORT_SYMBOL(__xchg_64);
+EXPORT_SYMBOL(__cmpxchg_64);
 
 EXPORT_SYMBOL(__debug_bug_printk);
 EXPORT_SYMBOL(__delay_loops_MHz);
index 08be305c9f446c436a51aa6930d7cb8d2ebb24f6..0a377210c89b3117dec4145769b39998721a3f8a 100644 (file)
@@ -4,5 +4,5 @@
 
 lib-y := \
        __ashldi3.o __lshrdi3.o __muldi3.o __ashrdi3.o __negdi2.o __ucmpdi2.o \
-       checksum.o memcpy.o memset.o atomic-ops.o \
-       outsl_ns.o outsl_sw.o insl_ns.o insl_sw.o cache.o
+       checksum.o memcpy.o memset.o atomic-ops.o atomic64-ops.o \
+       outsl_ns.o outsl_sw.o insl_ns.o insl_sw.o cache.o perf_counter.o
index ee0ac905fb08ac271139ecd12de58e9fc9b61366..5e9e6ab5dd0e89ef2977743b847aa274da6f0890 100644 (file)
@@ -163,11 +163,10 @@ __cmpxchg_32:
        ld.p            @(gr11,gr0),gr8
        orcr            cc7,cc7,cc3
        subcc           gr8,gr9,gr7,icc0
-       bne             icc0,#0,1f
+       bnelr           icc0,#0
        cst.p           gr10,@(gr11,gr0)        ,cc3,#1
        corcc           gr29,gr29,gr0           ,cc3,#1
        beq             icc3,#0,0b
-1:
        bralr
 
        .size           __cmpxchg_32, .-__cmpxchg_32
diff --git a/arch/frv/lib/atomic64-ops.S b/arch/frv/lib/atomic64-ops.S
new file mode 100644 (file)
index 0000000..b6194ee
--- /dev/null
@@ -0,0 +1,162 @@
+/* kernel atomic64 operations
+ *
+ * For an explanation of how atomic ops work in this arch, see:
+ *   Documentation/frv/atomic-ops.txt
+ *
+ * Copyright (C) 2009 Red Hat, Inc. All Rights Reserved.
+ * Written by David Howells (dhowells@redhat.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#include <asm/spr-regs.h>
+
+       .text
+       .balign 4
+
+
+###############################################################################
+#
+# long long atomic64_inc_return(atomic64_t *v)
+#
+###############################################################################
+       .globl          atomic64_inc_return
+        .type          atomic64_inc_return,@function
+atomic64_inc_return:
+       or.p            gr8,gr8,gr10
+0:
+       orcc            gr0,gr0,gr0,icc3                /* set ICC3.Z */
+       ckeq            icc3,cc7
+       ldd.p           @(gr10,gr0),gr8                 /* LDD.P/ORCR must be atomic */
+       orcr            cc7,cc7,cc3                     /* set CC3 to true */
+       addicc          gr9,#1,gr9,icc0
+       addxi           gr8,#0,gr8,icc0
+       cstd.p          gr8,@(gr10,gr0)         ,cc3,#1
+       corcc           gr29,gr29,gr0           ,cc3,#1 /* clear ICC3.Z if store happens */
+       beq             icc3,#0,0b
+       bralr
+
+       .size           atomic64_inc_return, .-atomic64_inc_return
+
+###############################################################################
+#
+# long long atomic64_dec_return(atomic64_t *v)
+#
+###############################################################################
+       .globl          atomic64_dec_return
+        .type          atomic64_dec_return,@function
+atomic64_dec_return:
+       or.p            gr8,gr8,gr10
+0:
+       orcc            gr0,gr0,gr0,icc3                /* set ICC3.Z */
+       ckeq            icc3,cc7
+       ldd.p           @(gr10,gr0),gr8                 /* LDD.P/ORCR must be atomic */
+       orcr            cc7,cc7,cc3                     /* set CC3 to true */
+       subicc          gr9,#1,gr9,icc0
+       subxi           gr8,#0,gr8,icc0
+       cstd.p          gr8,@(gr10,gr0)         ,cc3,#1
+       corcc           gr29,gr29,gr0           ,cc3,#1 /* clear ICC3.Z if store happens */
+       beq             icc3,#0,0b
+       bralr
+
+       .size           atomic64_dec_return, .-atomic64_dec_return
+
+###############################################################################
+#
+# long long atomic64_add_return(long long i, atomic64_t *v)
+#
+###############################################################################
+       .globl          atomic64_add_return
+        .type          atomic64_add_return,@function
+atomic64_add_return:
+       or.p            gr8,gr8,gr4
+       or              gr9,gr9,gr5
+0:
+       orcc            gr0,gr0,gr0,icc3                /* set ICC3.Z */
+       ckeq            icc3,cc7
+       ldd.p           @(gr10,gr0),gr8                 /* LDD.P/ORCR must be atomic */
+       orcr            cc7,cc7,cc3                     /* set CC3 to true */
+       addcc           gr9,gr5,gr9,icc0
+       addx            gr8,gr4,gr8,icc0
+       cstd.p          gr8,@(gr10,gr0)         ,cc3,#1
+       corcc           gr29,gr29,gr0           ,cc3,#1 /* clear ICC3.Z if store happens */
+       beq             icc3,#0,0b
+       bralr
+
+       .size           atomic64_add_return, .-atomic64_add_return
+
+###############################################################################
+#
+# long long atomic64_sub_return(long long i, atomic64_t *v)
+#
+###############################################################################
+       .globl          atomic64_sub_return
+        .type          atomic64_sub_return,@function
+atomic64_sub_return:
+       or.p            gr8,gr8,gr4
+       or              gr9,gr9,gr5
+0:
+       orcc            gr0,gr0,gr0,icc3                /* set ICC3.Z */
+       ckeq            icc3,cc7
+       ldd.p           @(gr10,gr0),gr8                 /* LDD.P/ORCR must be atomic */
+       orcr            cc7,cc7,cc3                     /* set CC3 to true */
+       subcc           gr9,gr5,gr9,icc0
+       subx            gr8,gr4,gr8,icc0
+       cstd.p          gr8,@(gr10,gr0)         ,cc3,#1
+       corcc           gr29,gr29,gr0           ,cc3,#1 /* clear ICC3.Z if store happens */
+       beq             icc3,#0,0b
+       bralr
+
+       .size           atomic64_sub_return, .-atomic64_sub_return
+
+###############################################################################
+#
+# uint64_t __xchg_64(uint64_t i, uint64_t *v)
+#
+###############################################################################
+       .globl          __xchg_64
+        .type          __xchg_64,@function
+__xchg_64:
+       or.p            gr8,gr8,gr4
+       or              gr9,gr9,gr5
+0:
+       orcc            gr0,gr0,gr0,icc3                /* set ICC3.Z */
+       ckeq            icc3,cc7
+       ldd.p           @(gr10,gr0),gr8                 /* LDD.P/ORCR must be atomic */
+       orcr            cc7,cc7,cc3                     /* set CC3 to true */
+       cstd.p          gr4,@(gr10,gr0)         ,cc3,#1
+       corcc           gr29,gr29,gr0           ,cc3,#1 /* clear ICC3.Z if store happens */
+       beq             icc3,#0,0b
+       bralr
+
+       .size           __xchg_64, .-__xchg_64
+
+###############################################################################
+#
+# uint64_t __cmpxchg_64(uint64_t test, uint64_t new, uint64_t *v)
+#
+###############################################################################
+       .globl          __cmpxchg_64
+        .type          __cmpxchg_64,@function
+__cmpxchg_64:
+       or.p            gr8,gr8,gr4
+       or              gr9,gr9,gr5
+0:
+       orcc            gr0,gr0,gr0,icc3                /* set ICC3.Z */
+       ckeq            icc3,cc7
+       ldd.p           @(gr12,gr0),gr8                 /* LDD.P/ORCR must be atomic */
+       orcr            cc7,cc7,cc3
+       subcc           gr8,gr4,gr0,icc0
+       subcc.p         gr9,gr5,gr0,icc1
+       bnelr           icc0,#0
+       bnelr           icc1,#0
+       cstd.p          gr10,@(gr12,gr0)        ,cc3,#1
+       corcc           gr29,gr29,gr0           ,cc3,#1 /* clear ICC3.Z if store happens */
+       beq             icc3,#0,0b
+       bralr
+
+       .size           __cmpxchg_64, .-__cmpxchg_64
+
diff --git a/arch/frv/lib/perf_counter.c b/arch/frv/lib/perf_counter.c
new file mode 100644 (file)
index 0000000..2000fee
--- /dev/null
@@ -0,0 +1,19 @@
+/* Performance counter handling
+ *
+ * Copyright (C) 2009 Red Hat, Inc. All Rights Reserved.
+ * Written by David Howells (dhowells@redhat.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public Licence
+ * as published by the Free Software Foundation; either version
+ * 2 of the Licence, or (at your option) any later version.
+ */
+
+#include <linux/perf_counter.h>
+
+/*
+ * mark the performance counter as pending
+ */
+void set_perf_counter_pending(void)
+{
+}
index 700014d2155fd8d82a4aeadb54c4b3ad682855bb..8bbc8b0ee45db3ad2ddb97f6c6c9be4b5550315f 100644 (file)
@@ -36,7 +36,7 @@ struct thread_info {
        .exec_domain =  &default_exec_domain,   \
        .flags =        0,                      \
        .cpu =          0,                      \
-       .preempt_count = 1,                     \
+       .preempt_count = INIT_PREEMPT_COUNT,    \
        .restart_block  = {                     \
                .fn = do_no_restart_syscall,    \
        },                                      \
index 0c26157cffa55fe0ea1c348fd0a542b11e6c46c3..b6395ad1500a00f7d2a133b3633bed96fd91be2f 100644 (file)
@@ -6,6 +6,8 @@
  *     David Mosberger-Tang <davidm@hpl.hp.com>
  */
 
+#include <linux/types.h>
+
 /* floating point status register: */
 #define FPSR_TRAP_VD   (1 << 0)        /* invalid op trap disabled */
 #define FPSR_TRAP_DD   (1 << 1)        /* denormal trap disabled */
index ae6922626bf49bbecae323b08e58478bcaeb4e07..8ce2e388e37c550573bfc2ca28033a43b7d74d50 100644 (file)
@@ -48,7 +48,7 @@ struct thread_info {
        .flags          = 0,                    \
        .cpu            = 0,                    \
        .addr_limit     = KERNEL_DS,            \
-       .preempt_count  = 0,                    \
+       .preempt_count  = INIT_PREEMPT_COUNT,   \
        .restart_block = {                      \
                .fn = do_no_restart_syscall,    \
        },                                      \
index e425227a418e9b15a40a0dce0d8f09be3061ec90..88afb54501e48feba6c24d6f25c7f5967b308c89 100644 (file)
@@ -33,6 +33,7 @@
 #ifndef _ASM_IA64_XEN_HYPERVISOR_H
 #define _ASM_IA64_XEN_HYPERVISOR_H
 
+#include <linux/err.h>
 #include <xen/interface/xen.h>
 #include <xen/interface/version.h>     /* to compile feature.c */
 #include <xen/features.h>              /* to comiple xen-netfront.c */
index cbe6cee5a550327500d5497d6c445eb471714a12..dbda7bde61129d3403b189f5145618eae9f655e0 100644 (file)
@@ -71,3 +71,15 @@ void arch_acpi_processor_init_pdc(struct acpi_processor *pr)
 }
 
 EXPORT_SYMBOL(arch_acpi_processor_init_pdc);
+
+void arch_acpi_processor_cleanup_pdc(struct acpi_processor *pr)
+{
+       if (pr->pdc) {
+               kfree(pr->pdc->pointer->buffer.pointer);
+               kfree(pr->pdc->pointer);
+               kfree(pr->pdc);
+               pr->pdc = NULL;
+       }
+}
+
+EXPORT_SYMBOL(arch_acpi_processor_cleanup_pdc);
index 086a2aeb0404e6a889d6b10cfe766eca20a568c3..39a3cd0a417326be10680e9d9cb52458e400051f 100644 (file)
@@ -6,6 +6,14 @@ int iommu_detected __read_mostly;
 struct dma_map_ops *dma_ops;
 EXPORT_SYMBOL(dma_ops);
 
+#define PREALLOC_DMA_DEBUG_ENTRIES (1 << 16)
+
+static int __init dma_init(void)
+{
+       dma_debug_init(PREALLOC_DMA_DEBUG_ENTRIES);
+}
+fs_initcall(dma_init);
+
 struct dma_map_ops *dma_get_ops(struct device *dev)
 {
        return dma_ops;
index ebf4e988e78ca7abd8e0397668dfeb5bc1ee47ae..d5764a3d74af2b73176444212e21f7747b35f679 100644 (file)
@@ -65,7 +65,7 @@ static int __init esi_init (void)
        }
 
        if (!esi)
-               return -ENODEV;;
+               return -ENODEV;
 
        systab = __va(esi);
 
index abce2468a40baeefd47bd8d39f5b61e9218b8f9e..f1782705b1f72caaf2cae0ae96ab869b84a8e0f3 100644 (file)
@@ -5603,7 +5603,7 @@ pfm_interrupt_handler(int irq, void *arg)
  * /proc/perfmon interface, for debug only
  */
 
-#define PFM_PROC_SHOW_HEADER   ((void *)nr_cpu_ids+1)
+#define PFM_PROC_SHOW_HEADER   ((void *)(long)nr_cpu_ids+1)
 
 static void *
 pfm_proc_start(struct seq_file *m, loff_t *pos)
index 92c9689b7d9764a80fc72b8a06f2c45b10443387..9daa87fdb0182e63cde61e6c78df1ff6dea41340 100644 (file)
@@ -15,7 +15,6 @@
 #include <linux/mm.h>
 #include <linux/errno.h>
 #include <linux/ptrace.h>
-#include <linux/smp_lock.h>
 #include <linux/user.h>
 #include <linux/security.h>
 #include <linux/audit.h>
index 7053c55b7649337c19f5495c205a0d1584f33caa..e6676fca482876db425b281d476ad06ca64dc873 100644 (file)
@@ -192,7 +192,7 @@ struct salinfo_platform_oemdata_parms {
 static void
 salinfo_work_to_do(struct salinfo_data *data)
 {
-       down_trylock(&data->mutex);
+       (void)(down_trylock(&data->mutex) ?: 0);
        up(&data->mutex);
 }
 
index a85cb611ecd7c8f4782b54724021026188640b96..f1268b8e6f9e69b7818aed279859268aa02d62f1 100644 (file)
  *
  */
 #undef CONFIG_MODULES
+#include <linux/module.h>
+#undef CONFIG_KALLSYMS
+#undef EXPORT_SYMBOL
+#undef EXPORT_SYMBOL_GPL
+#define EXPORT_SYMBOL(sym)
+#define EXPORT_SYMBOL_GPL(sym)
 #include "../../../lib/vsprintf.c"
 #include "../../../lib/ctype.c"
index a8f84da04b49b8baa8daed4f49bdc2e178e240be..bb862fb224f2968df93206e37589612556988f6b 100644 (file)
@@ -130,7 +130,7 @@ static void collect_interruption(struct kvm_vcpu *vcpu)
        if (vdcr & IA64_DCR_PP) {
                vpsr |= IA64_PSR_PP;
        } else {
-               vpsr &= ~IA64_PSR_PP;;
+               vpsr &= ~IA64_PSR_PP;
        }
 
        vcpu_set_psr(vcpu, vpsr);
@@ -594,11 +594,11 @@ static void set_pal_call_data(struct kvm_vcpu *vcpu)
                p->u.pal_data.gr30 = vcpu_get_gr(vcpu, 30);
                break;
        case PAL_BRAND_INFO:
-               p->u.pal_data.gr29 = gr29;;
+               p->u.pal_data.gr29 = gr29;
                p->u.pal_data.gr30 = kvm_trans_pal_call_args(vcpu, gr30);
                break;
        default:
-               p->u.pal_data.gr29 = gr29;;
+               p->u.pal_data.gr29 = gr29;
                p->u.pal_data.gr30 = vcpu_get_gr(vcpu, 30);
        }
        p->u.pal_data.gr28 = gr28;
index a2c6c15e4761871ffe98f5bba8b52b6b70691056..46b02cbcc8748b1ffc90fbe36865bb9c489f65a9 100644 (file)
@@ -406,7 +406,7 @@ void getreg(unsigned long regnum, unsigned long *val,
         * Now look at registers in [0-31] range and init correct UNAT
         */
        addr = (unsigned long)regs;
-       unat = &regs->eml_unat;;
+       unat = &regs->eml_unat;
 
        addr += gr_info[regnum];
 
index 4290a429bf7c9b48f0cd9ff049d60626e23af689..20b3852f7a6ec50d765fe3911fa0b6e6a0ef4859 100644 (file)
@@ -135,7 +135,7 @@ struct thash_data *__vtr_lookup(struct kvm_vcpu *vcpu, u64 va, int type)
        u64 rid;
 
        rid = vcpu_get_rr(vcpu, va);
-       rid = rid & RR_RID_MASK;;
+       rid = rid & RR_RID_MASK;
        if (type == D_TLB) {
                if (vcpu_quick_region_check(vcpu->arch.dtr_regions, va)) {
                        for (trp = (struct thash_data *)&vcpu->arch.dtrs, i = 0;
@@ -518,7 +518,7 @@ struct thash_data *vtlb_lookup(struct kvm_vcpu *v, u64 va, int is_data)
 
        struct thash_cb *hcb = &v->arch.vtlb;
 
-       cch = __vtr_lookup(v, va, is_data);;
+       cch = __vtr_lookup(v, va, is_data);
        if (cch)
                return cch;
 
index 729298f4b23438dfbd299d6019d59889448e19a5..7de76dd352fe4e6350ee0a8bf6d366fe05c66f35 100644 (file)
@@ -537,7 +537,7 @@ pcibios_align_resource (void *data, struct resource *res,
 /*
  * PCI BIOS setup, always defaults to SAL interface
  */
-char * __devinit
+char * __init
 pcibios_setup (char *str)
 {
        return str;
index 76645cf6ac5d1ded06cd4ae24eb7399ecf83075d..25831c47c579bcf3f3059c5bd914dc22e17f6c98 100644 (file)
@@ -435,7 +435,8 @@ void sn_generate_path(struct pci_bus *pci_bus, char *address)
        bricktype = MODULE_GET_BTYPE(moduleid);
        if ((bricktype == L1_BRICKTYPE_191010) ||
            (bricktype == L1_BRICKTYPE_1932))
-                       sprintf(address, "%s^%d", address, geo_slot(geoid));
+                       sprintf(address + strlen(address), "^%d",
+                                               geo_slot(geoid));
 }
 
 void __devinit
index 8589d462df27e366863974619b5cf293e0b9213c..07bb5bd00e2a0660dc3be6c0c0c4514da8ade81b 100644 (file)
@@ -57,8 +57,6 @@ struct thread_info {
 
 /*
  * macros/functions for gaining access to the thread information structure
- *
- * preempt_count needs to be 1 initially, until the scheduler is functional.
  */
 #ifndef __ASSEMBLY__
 
@@ -68,7 +66,7 @@ struct thread_info {
        .exec_domain    = &default_exec_domain, \
        .flags          = 0,                    \
        .cpu            = 0,                    \
-       .preempt_count  = 1,                    \
+       .preempt_count  = INIT_PREEMPT_COUNT,   \
        .addr_limit     = KERNEL_DS,            \
        .restart_block = {                      \
                .fn = do_no_restart_syscall,    \
index bf0abe9e1f73e9bc9f30b1162df1577f75f51907..98b8feb12ed899e6dba32d0532b981057d4f5a6e 100644 (file)
@@ -19,7 +19,6 @@
 #include <linux/mm.h>
 #include <linux/err.h>
 #include <linux/smp.h>
-#include <linux/smp_lock.h>
 #include <linux/errno.h>
 #include <linux/ptrace.h>
 #include <linux/user.h>
index af0fda46e94bc969978a9572221ac2843f23bae2..6ea5c33b3c564ed2d1558840f9642241fcc2e2e8 100644 (file)
@@ -19,6 +19,7 @@ struct thread_info {
 {                                              \
        .task           = &tsk,                 \
        .exec_domain    = &default_exec_domain, \
+       .preempt_count  = INIT_PREEMPT_COUNT,   \
        .restart_block = {                      \
                .fn = do_no_restart_syscall,    \
        },                                      \
index 82529f424ea3d567d0c1a9a2991b9591f7dacd85..c2bde5e24b0b9063d3c984e55dc168a6d9329158 100644 (file)
@@ -49,6 +49,7 @@ struct thread_info {
        .exec_domain    = &default_exec_domain, \
        .flags          = 0,                    \
        .cpu            = 0,                    \
+       .preempt_count  = INIT_PREEMPT_COUNT,   \
        .restart_block  = {                     \
                .fn = do_no_restart_syscall,    \
        },                                      \
index 1e96c6eb631258f75946f9ab84f4ab26f1ab3890..8f8f4abab2ff16419afc8abb35fffdf4c4f63276 100644 (file)
@@ -290,7 +290,7 @@ void dump(struct pt_regs *fp)
        unsigned char   *tp;
        int             i;
 
-       printk(KERN_EMERG "\n" KERN_EMERG "CURRENT PROCESS:\n" KERN_EMERG "\n");
+       printk(KERN_EMERG "\nCURRENT PROCESS:\n\n");
        printk(KERN_EMERG "COMM=%s PID=%d\n", current->comm, current->pid);
 
        if (current->mm) {
@@ -301,8 +301,7 @@ void dump(struct pt_regs *fp)
                        (int) current->mm->end_data,
                        (int) current->mm->end_data,
                        (int) current->mm->brk);
-               printk(KERN_EMERG "USER-STACK=%08x KERNEL-STACK=%08x\n"
-                       KERN_EMERG "\n",
+               printk(KERN_EMERG "USER-STACK=%08x KERNEL-STACK=%08x\n\n",
                        (int) current->mm->start_stack,
                        (int)(((unsigned long) current) + THREAD_SIZE));
        }
@@ -313,35 +312,35 @@ void dump(struct pt_regs *fp)
                fp->d0, fp->d1, fp->d2, fp->d3);
        printk(KERN_EMERG "d4: %08lx    d5: %08lx    a0: %08lx    a1: %08lx\n",
                fp->d4, fp->d5, fp->a0, fp->a1);
-       printk(KERN_EMERG "\n" KERN_EMERG "USP: %08x   TRAPFRAME: %08x\n",
+       printk(KERN_EMERG "\nUSP: %08x   TRAPFRAME: %08x\n",
                (unsigned int) rdusp(), (unsigned int) fp);
 
-       printk(KERN_EMERG "\n" KERN_EMERG "CODE:");
+       printk(KERN_EMERG "\nCODE:");
        tp = ((unsigned char *) fp->pc) - 0x20;
        for (sp = (unsigned long *) tp, i = 0; (i < 0x40);  i += 4) {
                if ((i % 0x10) == 0)
-                       printk("\n" KERN_EMERG "%08x: ", (int) (tp + i));
+                       printk(KERN_EMERG "%08x: ", (int) (tp + i));
                printk("%08x ", (int) *sp++);
        }
-       printk("\n" KERN_EMERG "\n");
+       printk(KERN_EMERG "\n");
 
        printk(KERN_EMERG "KERNEL STACK:");
        tp = ((unsigned char *) fp) - 0x40;
        for (sp = (unsigned long *) tp, i = 0; (i < 0xc0); i += 4) {
                if ((i % 0x10) == 0)
-                       printk("\n" KERN_EMERG "%08x: ", (int) (tp + i));
+                       printk(KERN_EMERG "%08x: ", (int) (tp + i));
                printk("%08x ", (int) *sp++);
        }
-       printk("\n" KERN_EMERG "\n");
+       printk(KERN_EMERG "\n");
 
        printk(KERN_EMERG "USER STACK:");
        tp = (unsigned char *) (rdusp() - 0x10);
        for (sp = (unsigned long *) tp, i = 0; (i < 0x80); i += 4) {
                if ((i % 0x10) == 0)
-                       printk("\n" KERN_EMERG "%08x: ", (int) (tp + i));
+                       printk(KERN_EMERG "%08x: ", (int) (tp + i));
                printk("%08x ", (int) *sp++);
        }
-       printk("\n" KERN_EMERG "\n");
+       printk(KERN_EMERG "\n");
 }
 
 /*
index 51d325343ab58baaa3f5abe3396dbea067ae41c2..3739c8f657d75f12d94c92e2e1665a6f927c2e7d 100644 (file)
@@ -111,7 +111,7 @@ static void print_this_address(unsigned long addr, int i)
        if (i % 5)
                printk(KERN_CONT " [%08lx] ", addr);
        else
-               printk(KERN_CONT "\n" KERN_EMERG " [%08lx] ", addr);
+               printk(KERN_EMERG " [%08lx] ", addr);
        i++;
 #endif
 }
@@ -137,8 +137,8 @@ static void __show_stack(struct task_struct *task, unsigned long *stack)
                if (stack + 1 + i > endstack)
                        break;
                if (i % 8 == 0)
-                       printk("\n" KERN_EMERG "       ");
-               printk(" %08lx", *(stack + i));
+                       printk(KERN_EMERG "       ");
+               printk(KERN_CONT " %08lx", *(stack + i));
        }
        printk("\n");
        i = 0;
index b50b845fdd506d6f6e914038794a854769301bfc..2db722d80d4d19133e8508c046c029a5c2c06cc1 100644 (file)
@@ -53,6 +53,9 @@ config GENERIC_HARDIRQS_NO__DO_IRQ
 config GENERIC_GPIO
        def_bool y
 
+config GENERIC_CSUM
+       def_bool y
+
 config PCI
        def_bool n
 
index 0de612ad7cb2e5b2ca2ef8f98b4616768ab8d6c2..6d2e1d418be74f7dbc3797e82a497b8bcab93bc8 100644 (file)
@@ -1,95 +1,7 @@
-/*
- * Copyright (C) 2006 Atmark Techno, Inc.
- *
- * This file is subject to the terms and conditions of the GNU General Public
- * License. See the file "COPYING" in the main directory of this archive
- * for more details.
- */
-
 #ifndef _ASM_MICROBLAZE_ATOMIC_H
 #define _ASM_MICROBLAZE_ATOMIC_H
 
-#include <linux/types.h>
-#include <linux/compiler.h> /* likely */
-#include <asm/system.h> /* local_irq_XXX and friends */
-
-#define ATOMIC_INIT(i)         { (i) }
-#define atomic_read(v)         ((v)->counter)
-#define atomic_set(v, i)       (((v)->counter) = (i))
-
-#define atomic_inc(v)          (atomic_add_return(1, (v)))
-#define atomic_dec(v)          (atomic_sub_return(1, (v)))
-
-#define atomic_add(i, v)       (atomic_add_return(i, (v)))
-#define atomic_sub(i, v)       (atomic_sub_return(i, (v)))
-
-#define atomic_inc_return(v)   (atomic_add_return(1, (v)))
-#define atomic_dec_return(v)   (atomic_sub_return(1, (v)))
-
-#define atomic_inc_and_test(v) (atomic_add_return(1, (v)) == 0)
-#define atomic_dec_and_test(v) (atomic_sub_return(1, (v)) == 0)
-
-#define atomic_inc_not_zero(v) (atomic_add_unless((v), 1, 0))
-
-#define atomic_sub_and_test(i, v) (atomic_sub_return((i), (v)) == 0)
-
-static inline int atomic_cmpxchg(atomic_t *v, int old, int new)
-{
-       int ret;
-       unsigned long flags;
-
-       local_irq_save(flags);
-       ret = v->counter;
-       if (likely(ret == old))
-               v->counter = new;
-       local_irq_restore(flags);
-
-       return ret;
-}
-
-static inline int atomic_add_unless(atomic_t *v, int a, int u)
-{
-       int c, old;
-
-       c = atomic_read(v);
-       while (c != u && (old = atomic_cmpxchg((v), c, c + a)) != c)
-               c = old;
-       return c != u;
-}
-
-static inline void atomic_clear_mask(unsigned long mask, unsigned long *addr)
-{
-       unsigned long flags;
-
-       local_irq_save(flags);
-       *addr &= ~mask;
-       local_irq_restore(flags);
-}
-
-/**
- * atomic_add_return - add and return
- * @i: integer value to add
- * @v: pointer of type atomic_t
- *
- * Atomically adds @i to @v and returns @i + @v
- */
-static inline int atomic_add_return(int i, atomic_t *v)
-{
-       unsigned long flags;
-       int val;
-
-       local_irq_save(flags);
-       val = v->counter;
-       v->counter = val += i;
-       local_irq_restore(flags);
-
-       return val;
-}
-
-static inline int atomic_sub_return(int i, atomic_t *v)
-{
-       return atomic_add_return(-i, v);
-}
+#include <asm-generic/atomic.h>
 
 /*
  * Atomically test *v and decrement if it is greater than 0.
@@ -109,15 +21,4 @@ static inline int atomic_dec_if_positive(atomic_t *v)
        return res;
 }
 
-#define atomic_add_negative(a, v)      (atomic_add_return((a), (v)) < 0)
-#define atomic_xchg(v, new) (xchg(&((v)->counter), new))
-
-/* Atomic operations are already serializing */
-#define smp_mb__before_atomic_dec()    barrier()
-#define smp_mb__after_atomic_dec()     barrier()
-#define smp_mb__before_atomic_inc()    barrier()
-#define smp_mb__after_atomic_inc()     barrier()
-
-#include <asm-generic/atomic-long.h>
-
 #endif /* _ASM_MICROBLAZE_ATOMIC_H */
index d6df1fd4e1e87522f22b494f465bdca17c0a3e5c..a72468f15c8b1cc8c696a4949e9365d0c975923e 100644 (file)
@@ -1,27 +1 @@
-/*
- * Copyright (C) 2006 Atmark Techno, Inc.
- *
- * This file is subject to the terms and conditions of the GNU General Public
- * License. See the file "COPYING" in the main directory of this archive
- * for more details.
- */
-
-#ifndef _ASM_MICROBLAZE_BITOPS_H
-#define _ASM_MICROBLAZE_BITOPS_H
-
-/*
- * Copyright 1992, Linus Torvalds.
- */
-
-#include <asm/byteorder.h> /* swab32 */
-#include <asm/system.h> /* save_flags */
-
-/*
- * clear_bit() doesn't provide any barrier for the compiler.
- */
-#define smp_mb__before_clear_bit()     barrier()
-#define smp_mb__after_clear_bit()      barrier()
 #include <asm-generic/bitops.h>
-#include <asm-generic/bitops/__fls.h>
-
-#endif /* _ASM_MICROBLAZE_BITOPS_H */
index 8eb2cdde11d7c28f417cd5f38420e51f33a36056..b12fd89e42e913ef67f0c05d95b98a21c1470c70 100644 (file)
@@ -1,15 +1 @@
-/*
- * Copyright (C) 2006 Atmark Techno, Inc.
- *
- * This file is subject to the terms and conditions of the GNU General Public
- * License. See the file "COPYING" in the main directory of this archive
- * for more details.
- */
-
-#ifndef _ASM_MICROBLAZE_BUG_H
-#define _ASM_MICROBLAZE_BUG_H
-
-#include <linux/kernel.h>
 #include <asm-generic/bug.h>
-
-#endif /* _ASM_MICROBLAZE_BUG_H */
index f2c6593653fb0217d0387523a0471ee2c28e3166..61791e1ad9f55cba48fafdf065e6fd05d9e95600 100644 (file)
@@ -1,17 +1 @@
-/*
- * Copyright (C) 2006 Atmark Techno, Inc.
- *
- * This file is subject to the terms and conditions of the GNU General Public
- * License. See the file "COPYING" in the main directory of this archive
- * for more details.
- */
-
-#ifndef _ASM_MICROBLAZE_BUGS_H
-#define _ASM_MICROBLAZE_BUGS_H
-
-static inline void check_bugs(void)
-{
-       /* nothing to do */
-}
-
-#endif /* _ASM_MICROBLAZE_BUGS_H */
+#include <asm-generic/bugs.h>
index 97ea46b5cf80a2a1071b5b89dc9a85cb2e8e3f28..128bf03b54b7e9435abe99f8af19ef4eae91b611 100644 (file)
 #ifndef _ASM_MICROBLAZE_CHECKSUM_H
 #define _ASM_MICROBLAZE_CHECKSUM_H
 
-#include <linux/in6.h>
-
 /*
  * computes the checksum of the TCP/UDP pseudo-header
  * returns a 16-bit checksum, already complemented
  */
+#define csum_tcpudp_nofold     csum_tcpudp_nofold
 static inline __wsum
 csum_tcpudp_nofold(__be32 saddr, __be32 daddr, unsigned short len,
                   unsigned short proto, __wsum sum)
@@ -30,71 +29,6 @@ csum_tcpudp_nofold(__be32 saddr, __be32 daddr, unsigned short len,
        return sum;
 }
 
-/*
- * computes the checksum of a memory block at buff, length len,
- * and adds in "sum" (32-bit)
- *
- * returns a 32-bit number suitable for feeding into itself
- * or csum_tcpudp_magic
- *
- * this function must be called with even lengths, except
- * for the last fragment, which may be odd
- *
- * it's best to have buff aligned on a 32-bit boundary
- */
-extern __wsum csum_partial(const void *buff, int len, __wsum sum);
-
-/*
- * the same as csum_partial, but copies from src while it
- * checksums
- *
- * here even more important to align src and dst on a 32-bit (or even
- * better 64-bit) boundary
- */
-extern __wsum csum_partial_copy(const void *src, void *dst, int len,
-                                                               __wsum sum);
-
-/*
- * the same as csum_partial_copy, but copies from user space.
- *
- * here even more important to align src and dst on a 32-bit (or even
- * better 64-bit) boundary
- */
-extern __wsum csum_partial_copy_from_user(const void __user *src, void *dst,
-                                       int len, __wsum sum, int *csum_err);
-
-#define csum_partial_copy_nocheck(src, dst, len, sum)  \
-       csum_partial_copy((src), (dst), (len), (sum))
-
-/*
- *     This is a version of ip_compute_csum() optimized for IP headers,
- *     which always checksum on 4 octet boundaries.
- *
- */
-extern __sum16 ip_fast_csum(const void *iph, unsigned int ihl);
-
-/*
- *     Fold a partial checksum
- */
-static inline __sum16 csum_fold(__wsum csum)
-{
-       u32 sum = (__force u32)csum;
-       sum = (sum & 0xffff) + (sum >> 16);
-       sum = (sum & 0xffff) + (sum >> 16);
-       return (__force __sum16)~sum;
-}
-
-static inline __sum16
-csum_tcpudp_magic(__be32 saddr, __be32 daddr, unsigned short len,
-                 unsigned short proto, __wsum sum)
-{
-       return csum_fold(csum_tcpudp_nofold(saddr, daddr, len, proto, sum));
-}
-
-/*
- * this routine is used for miscellaneous IP-like checksums, mainly
- * in icmp.c
- */
-extern __sum16 ip_compute_csum(const void *buff, int len);
+#include <asm-generic/checksum.h>
 
 #endif /* _ASM_MICROBLAZE_CHECKSUM_H */
diff --git a/arch/microblaze/include/asm/fb.h b/arch/microblaze/include/asm/fb.h
new file mode 100644 (file)
index 0000000..3a4988e
--- /dev/null
@@ -0,0 +1 @@
+#include <asm-generic/fb.h>
index 0f2d6b013e11ead33ee6e1ca594c9a5214eccce9..41e1e1aa36aca0d3b2ee37c59e796f094c5ae7f0 100644 (file)
@@ -9,21 +9,11 @@
 #ifndef _ASM_MICROBLAZE_HARDIRQ_H
 #define _ASM_MICROBLAZE_HARDIRQ_H
 
-#include <linux/cache.h>
-#include <linux/irq.h>
-#include <asm/irq.h>
-#include <asm/current.h>
-#include <linux/ptrace.h>
-
 /* should be defined in each interrupt controller driver */
 extern unsigned int get_irq(struct pt_regs *regs);
 
-typedef struct {
-       unsigned int __softirq_pending;
-} ____cacheline_aligned irq_cpustat_t;
-
+#define ack_bad_irq ack_bad_irq
 void ack_bad_irq(unsigned int irq);
-
-#include <linux/irq_cpustat.h> /* Standard mappings for irq_cpustat_t above */
+#include <asm-generic/hardirq.h>
 
 #endif /* _ASM_MICROBLAZE_HARDIRQ_H */
index 03582b2492047cdd98dcdd897ef45e899fa026fc..ec34c760665eaee4e4ee74311bdf6967bbad5b68 100644 (file)
@@ -1,91 +1 @@
-/*
- * Copyright (C) 2006 Atmark Techno, Inc.
- *
- * This file is subject to the terms and conditions of the GNU General Public
- * License. See the file "COPYING" in the main directory of this archive
- * for more details.
- */
-
-#ifndef _ASM_MICROBLAZE_IOCTLS_H
-#define _ASM_MICROBLAZE_IOCTLS_H
-
-#include <linux/ioctl.h>
-
-/* 0x54 is just a magic number to make these relatively unique ('T') */
-
-#define TCGETS         0x5401
-#define TCSETS         0x5402
-#define TCSETSW                0x5403
-#define TCSETSF                0x5404
-#define TCGETA         0x5405
-#define TCSETA         0x5406
-#define TCSETAW                0x5407
-#define TCSETAF                0x5408
-#define TCSBRK         0x5409
-#define TCXONC         0x540A
-#define TCFLSH         0x540B
-#define TIOCEXCL       0x540C
-#define TIOCNXCL       0x540D
-#define TIOCSCTTY      0x540E
-#define TIOCGPGRP      0x540F
-#define TIOCSPGRP      0x5410
-#define TIOCOUTQ       0x5411
-#define TIOCSTI                0x5412
-#define TIOCGWINSZ     0x5413
-#define TIOCSWINSZ     0x5414
-#define TIOCMGET       0x5415
-#define TIOCMBIS       0x5416
-#define TIOCMBIC       0x5417
-#define TIOCMSET       0x5418
-#define TIOCGSOFTCAR   0x5419
-#define TIOCSSOFTCAR   0x541A
-#define FIONREAD       0x541B
-#define TIOCINQ                FIONREAD
-#define TIOCLINUX      0x541C
-#define TIOCCONS       0x541D
-#define TIOCGSERIAL    0x541E
-#define TIOCSSERIAL    0x541F
-#define TIOCPKT                0x5420
-#define FIONBIO                0x5421
-#define TIOCNOTTY      0x5422
-#define TIOCSETD       0x5423
-#define TIOCGETD       0x5424
-#define TCSBRKP                0x5425 /* Needed for POSIX tcsendbreak() */
-#define TIOCTTYGSTRUCT 0x5426 /* For debugging only */
-#define TIOCSBRK       0x5427 /* BSD compatibility */
-#define TIOCCBRK       0x5428 /* BSD compatibility */
-#define TIOCGSID       0x5429 /* Return the session ID of FD */
-/* Get Pty Number (of pty-mux device) */
-#define TIOCGPTN       _IOR('T', 0x30, unsigned int)
-#define TIOCSPTLCK     _IOW('T', 0x31, int) /* Lock/unlock Pty */
-
-#define FIONCLEX       0x5450 /* these numbers need to be adjusted. */
-#define FIOCLEX                0x5451
-#define FIOASYNC       0x5452
-#define TIOCSERCONFIG  0x5453
-#define TIOCSERGWILD   0x5454
-#define TIOCSERSWILD   0x5455
-#define TIOCGLCKTRMIOS 0x5456
-#define TIOCSLCKTRMIOS 0x5457
-#define TIOCSERGSTRUCT 0x5458 /* For debugging only */
-#define TIOCSERGETLSR  0x5459 /* Get line status register */
-#define TIOCSERGETMULTI 0x545A /* Get multiport config */
-#define TIOCSERSETMULTI 0x545B /* Set multiport config */
-
-#define TIOCMIWAIT     0x545C /* wait for a change on serial input line(s) */
-#define TIOCGICOUNT    0x545D /* read serial port inline interrupt counts */
-
-#define        FIOQSIZE        0x545E
-
-/* Used for packet mode */
-#define TIOCPKT_DATA           0
-#define TIOCPKT_FLUSHREAD      1
-#define TIOCPKT_FLUSHWRITE     2
-#define TIOCPKT_STOP           4
-#define TIOCPKT_START          8
-#define TIOCPKT_NOSTOP         16
-#define TIOCPKT_DOSTOP         32
-
-#define TIOCSER_TEMT   0x01 /* Transmitter physically empty */
-
-#endif /* _ASM_MICROBLAZE_IOCTLS_H */
+#include <asm-generic/ioctls.h>
index b056fa4206544a6d148dcf3eb8bb7fb29ed9edcf..84c7e51cb6d0befd2b3c013c8bbbbaad6ae02297 100644 (file)
@@ -1,36 +1 @@
-/*
- * Copyright (C) 2006 Atmark Techno, Inc.
- *
- * This file is subject to the terms and conditions of the GNU General Public
- * License. See the file "COPYING" in the main directory of this archive
- * for more details.
- */
-
-#ifndef _ASM_MICROBLAZE_IPCBUF_H
-#define _ASM_MICROBLAZE_IPCBUF_H
-
-/*
- * The user_ipc_perm structure for microblaze architecture.
- * Note extra padding because this structure is passed back and forth
- * between kernel and user space.
- *
- * Pad space is left for:
- * - 32-bit mode_t and seq
- * - 2 miscellaneous 32-bit values
- */
-
-struct ipc64_perm {
-       __kernel_key_t          key;
-       __kernel_uid32_t        uid;
-       __kernel_gid32_t        gid;
-       __kernel_uid32_t        cuid;
-       __kernel_gid32_t        cgid;
-       __kernel_mode_t         mode;
-       unsigned short          __pad1;
-       unsigned short          seq;
-       unsigned short          __pad2;
-       unsigned long           __unused1;
-       unsigned long           __unused2;
-};
-
-#endif /* _ASM_MICROBLAZE_IPCBUF_H */
+#include <asm-generic/ipcbuf.h>
index db515deaa720c066c65c0bb85cce1ded59da015a..90f050535ebef0f51881fdc451bac5df84816a9d 100644 (file)
@@ -10,6 +10,7 @@
 #define _ASM_MICROBLAZE_IRQ_H
 
 #define NR_IRQS 32
+#include <asm-generic/irq.h>
 
 #include <linux/interrupt.h>
 
@@ -17,11 +18,6 @@ extern unsigned int nr_irq;
 
 #define NO_IRQ (-1)
 
-static inline int irq_canonicalize(int irq)
-{
-       return irq;
-}
-
 struct pt_regs;
 extern void do_IRQ(struct pt_regs *regs);
 
index 4914b1329445ed1b7f3bef722b3984bd7f726533..8eebf89f5ab17884a98543f3b37a3b710355083b 100644 (file)
@@ -1,25 +1 @@
-/*
- * Copyright (C) 2006 Atmark Techno, Inc.
- *
- * This file is subject to the terms and conditions of the GNU General Public
- * License. See the file "COPYING" in the main directory of this archive
- * for more details.
- */
-
-#ifndef _ASM_MICROBLAZE_MMAN_H
-#define _ASM_MICROBLAZE_MMAN_H
-
 #include <asm-generic/mman.h>
-
-#define MAP_GROWSDOWN  0x0100 /* stack-like segment */
-#define MAP_DENYWRITE  0x0800 /* ETXTBSY */
-#define MAP_EXECUTABLE 0x1000 /* mark it as an executable */
-#define MAP_LOCKED     0x2000 /* pages are locked */
-#define MAP_NORESERVE  0x4000 /* don't check for reservations */
-#define MAP_POPULATE   0x8000 /* populate (prefault) pagetables */
-#define MAP_NONBLOCK   0x10000 /* do not block on IO */
-
-#define MCL_CURRENT    1 /* lock all current mappings */
-#define MCL_FUTURE     2 /* lock all future mappings */
-
-#endif /* _ASM_MICROBLAZE_MMAN_H */
index 66cad6a99d77b41a8c5b50f140de1c3daf356121..8d6a654ceffb1b408532a27170d40909526aa157 100644 (file)
 #define _ASM_MICROBLAZE_MMU_H
 
 # ifndef CONFIG_MMU
-#  ifndef __ASSEMBLY__
-typedef struct {
-       struct vm_list_struct   *vmlist;
-       unsigned long           end_brk;
-} mm_context_t;
-#  endif /* __ASSEMBLY__ */
+#  include <asm-generic/mmu.h>
 # else /* CONFIG_MMU */
 #  ifdef __KERNEL__
 #   ifndef __ASSEMBLY__
index 385fed16bbfb12eb04281c838037c475fb72c8fa..24eab1674d3eeb53621c9f6afc7807a7f89d2c16 100644 (file)
@@ -1,5 +1,5 @@
 #ifdef CONFIG_MMU
 # include "mmu_context_mm.h"
 #else
-# include "mmu_context_no.h"
+# include <asm-generic/mmu_context.h>
 #endif
diff --git a/arch/microblaze/include/asm/mmu_context_no.h b/arch/microblaze/include/asm/mmu_context_no.h
deleted file mode 100644 (file)
index ba55671..0000000
+++ /dev/null
@@ -1,23 +0,0 @@
-/*
- * Copyright (C) 2008-2009 Michal Simek <monstr@monstr.eu>
- * Copyright (C) 2008-2009 PetaLogix
- * Copyright (C) 2006 Atmark Techno, Inc.
- *
- * This file is subject to the terms and conditions of the GNU General Public
- * License. See the file "COPYING" in the main directory of this archive
- * for more details.
- */
-
-#ifndef _ASM_MICROBLAZE_MMU_CONTEXT_H
-#define _ASM_MICROBLAZE_MMU_CONTEXT_H
-
-# define init_new_context(tsk, mm)             ({ 0; })
-
-# define enter_lazy_tlb(mm, tsk)               do {} while (0)
-# define change_mm_context(old, ctx, _pml4)    do {} while (0)
-# define destroy_context(mm)                   do {} while (0)
-# define deactivate_mm(tsk, mm)                        do {} while (0)
-# define switch_mm(prev, next, tsk)            do {} while (0)
-# define activate_mm(prev, next)               do {} while (0)
-
-#endif /* _ASM_MICROBLAZE_MMU_CONTEXT_H */
index 914565a90315138e2a091d5df5b642bb07df023a..7be1347fce42c0649e8e0a7d7b7941bd4f43db63 100644 (file)
@@ -9,6 +9,8 @@
 #ifndef _ASM_MICROBLAZE_MODULE_H
 #define _ASM_MICROBLAZE_MODULE_H
 
+#include <asm-generic/module.h>
+
 /* Microblaze Relocations */
 #define R_MICROBLAZE_NONE 0
 #define R_MICROBLAZE_32 1
 /* Keep this the last entry. */
 #define R_MICROBLAZE_NUM 11
 
-struct mod_arch_specific {
-       int foo;
-};
-
-#define Elf_Shdr       Elf32_Shdr
-#define Elf_Sym                Elf32_Sym
-#define Elf_Ehdr       Elf32_Ehdr
-
 typedef struct { volatile int counter; } module_t;
 
 #endif /* _ASM_MICROBLAZE_MODULE_H */
index 09dd97097211c5c2653716b93f27575839a7a547..809134c644a677032e9eb2ae5d5a844806bc347e 100644 (file)
@@ -1,31 +1 @@
-#ifndef _ASM_MICROBLAZE_MSGBUF_H
-#define _ASM_MICROBLAZE_MSGBUF_H
-
-/*
- * The msqid64_ds structure for microblaze architecture.
- * Note extra padding because this structure is passed back and forth
- * between kernel and user space.
- *
- * Pad space is left for:
- * - 64-bit time_t to solve y2038 problem
- * - 2 miscellaneous 32-bit values
- */
-
-struct msqid64_ds {
-       struct ipc64_perm msg_perm;
-       __kernel_time_t msg_stime; /* last msgsnd time */
-       unsigned long __unused1;
-       __kernel_time_t msg_rtime; /* last msgrcv time */
-       unsigned long __unused2;
-       __kernel_time_t msg_ctime; /* last change time */
-       unsigned long __unused3;
-       unsigned long msg_cbytes; /* current number of bytes on queue */
-       unsigned long msg_qnum; /* number of messages in queue */
-       unsigned long msg_qbytes; /* max number of bytes on queue */
-       __kernel_pid_t msg_lspid; /* pid of last msgsnd */
-       __kernel_pid_t msg_lrpid; /* last receive pid */
-       unsigned long __unused4;
-       unsigned long __unused5;
-};
-
-#endif /* _ASM_MICROBLAZE_MSGBUF_H */
+#include <asm-generic/msgbuf.h>
index 8c538a49616d818fce6eab212ed147a743e29468..965d45427975907ae67efb45e20c8f500fd1ad3a 100644 (file)
@@ -1,30 +1 @@
-/*
- * Copyright (C) 2006 Atmark Techno, Inc.
- *
- * This file is subject to the terms and conditions of the GNU General Public
- * License. See the file "COPYING" in the main directory of this archive
- * for more details.
- */
-
-#ifndef _ASM_MICROBLAZE_PARAM_H
-#define _ASM_MICROBLAZE_PARAM_H
-
-#ifdef __KERNEL__
-#define HZ             CONFIG_HZ       /* internal kernel timer frequency */
-#define USER_HZ                100             /* for user interfaces in "ticks" */
-#define CLOCKS_PER_SEC (USER_HZ)       /* frequency at which times() counts */
-#endif /* __KERNEL__ */
-
-#ifndef HZ
-#define HZ 100
-#endif
-
-#define EXEC_PAGESIZE  4096
-
-#ifndef NOGROUP
-#define NOGROUP                (-1)
-#endif
-
-#define MAXHOSTNAMELEN 64      /* max length of hostname */
-
-#endif /* _ASM_MICROBLAZE_PARAM_H */
+#include <asm-generic/param.h>
diff --git a/arch/microblaze/include/asm/parport.h b/arch/microblaze/include/asm/parport.h
new file mode 100644 (file)
index 0000000..cf252af
--- /dev/null
@@ -0,0 +1 @@
+#include <asm-generic/parport.h>
index ca03794cf3f0e748e3ee6690e84f9b958139bf61..9f0df5faf2c88d1d89b37ba56c7b535e0e29f4ba 100644 (file)
@@ -1 +1 @@
-#include <linux/io.h>
+#include <asm-generic/pci.h>
index 8c758b231f376780dad5b30a0ae8b8b29da54b00..0e15039673e34f46df971fcb21444321345ac0de 100644 (file)
@@ -1,73 +1,9 @@
-/*
- * Copyright (C) 2006 Atmark Techno, Inc.
- *
- * This file is subject to the terms and conditions of the GNU General Public
- * License. See the file "COPYING" in the main directory of this archive
- * for more details.
- */
-
 #ifndef _ASM_MICROBLAZE_POSIX_TYPES_H
 #define _ASM_MICROBLAZE_POSIX_TYPES_H
 
-/*
- * This file is generally used by user-level software, so you need to
- * be a little careful about namespace pollution etc. Also, we cannot
- * assume GCC is being used.
- */
-
-typedef unsigned long  __kernel_ino_t;
 typedef unsigned short __kernel_mode_t;
-typedef unsigned int   __kernel_nlink_t;
-typedef long           __kernel_off_t;
-typedef int            __kernel_pid_t;
-typedef unsigned int   __kernel_ipc_pid_t;
-typedef unsigned int   __kernel_uid_t;
-typedef unsigned int   __kernel_gid_t;
-typedef unsigned long  __kernel_size_t;
-typedef long           __kernel_ssize_t;
-typedef int            __kernel_ptrdiff_t;
-typedef long           __kernel_time_t;
-typedef long           __kernel_suseconds_t;
-typedef long           __kernel_clock_t;
-typedef int            __kernel_timer_t;
-typedef int            __kernel_clockid_t;
-typedef int            __kernel_daddr_t;
-typedef char           *__kernel_caddr_t;
-typedef unsigned short __kernel_uid16_t;
-typedef unsigned short __kernel_gid16_t;
-typedef unsigned int   __kernel_uid32_t;
-typedef unsigned int   __kernel_gid32_t;
-
-typedef unsigned int   __kernel_old_uid_t;
-typedef unsigned int   __kernel_old_gid_t;
-typedef unsigned int   __kernel_old_dev_t;
-
-#ifdef __GNUC__
-typedef long long      __kernel_loff_t;
-#endif
-
-typedef struct {
-#if defined(__KERNEL__) || defined(__USE_ALL)
-       int     val[2];
-#else /* !defined(__KERNEL__) && !defined(__USE_ALL) */
-       int     __val[2];
-#endif /* !defined(__KERNEL__) && !defined(__USE_ALL) */
-} __kernel_fsid_t;
-
-#if defined(__KERNEL__) || !defined(__GLIBC__) || (__GLIBC__ < 2)
-
-#undef __FD_SET
-#define        __FD_SET(d, set)        ((set)->fds_bits[__FDELT(d)] |= __FDMASK(d))
-
-#undef __FD_CLR
-#define        __FD_CLR(d, set)        ((set)->fds_bits[__FDELT(d)] &= ~__FDMASK(d))
-
-#undef __FD_ISSET
-#define        __FD_ISSET(d, set)      (!!((set)->fds_bits[__FDELT(d)] & __FDMASK(d)))
-
-#undef __FD_ZERO
-#define __FD_ZERO(fdsetp) (memset(fdsetp, 0, sizeof(*(fd_set *)fdsetp)))
+#define __kernel_mode_t __kernel_mode_t
 
-#endif /* defined(__KERNEL__) || !defined(__GLIBC__) || (__GLIBC__ < 2) */
+#include <asm-generic/posix_types.h>
 
 #endif /* _ASM_MICROBLAZE_POSIX_TYPES_H */
index 08ff1d049b4264a4d191abb970c0391fbb5cfc24..35d786fe93ae0dcba7e1cf434606e9e61d1b05c2 100644 (file)
@@ -1,28 +1 @@
-/*
- * Copyright (C) 2008 Michal Simek <monstr@monstr.eu>
- * Copyright (C) 2006 Atmark Techno, Inc.
- *
- * This file is subject to the terms and conditions of the GNU General Public
- * License. See the file "COPYING" in the main directory of this archive
- * for more details.
- */
-
-#ifndef _ASM_MICROBLAZE_SCATTERLIST_H
-#define _ASM_MICROBLAZE_SCATTERLIST_H
-
-struct scatterlist {
-#ifdef CONFIG_DEBUG_SG
-       unsigned long   sg_magic;
-#endif
-       unsigned long   page_link;
-       dma_addr_t      dma_address;
-       unsigned int    offset;
-       unsigned int    length;
-};
-
-#define sg_dma_address(sg)      ((sg)->dma_address)
-#define sg_dma_len(sg)          ((sg)->length)
-
-#define ISA_DMA_THRESHOLD (~0UL)
-
-#endif /* _ASM_MICROBLAZE_SCATTERLIST_H */
+#include <asm-generic/scatterlist.h>
index b804ed71a57e51d5eb186f3c1f196c17e5057546..7673b83cfef73397301a171e86cf492b771ad9b4 100644 (file)
@@ -1,34 +1 @@
-/*
- * Copyright (C) 2006 Atmark Techno, Inc.
- *
- * This file is subject to the terms and conditions of the GNU General Public
- * License. See the file "COPYING" in the main directory of this archive
- * for more details.
- */
-
-#ifndef _ASM_MICROBLAZE_SEMBUF_H
-#define _ASM_MICROBLAZE_SEMBUF_H
-
-/*
- * The semid64_ds structure for microblaze architecture.
- * Note extra padding because this structure is passed back and forth
- * between kernel and user space.
- *
- * Pad space is left for:
- * - 64-bit time_t to solve y2038 problem
- * - 2 miscellaneous 32-bit values
- */
-
-struct semid64_ds {
-       struct ipc64_perm sem_perm; /* permissions .. see ipc.h */
-       __kernel_time_t sem_otime; /* last semop time */
-       unsigned long   __unused1;
-       __kernel_time_t sem_ctime; /* last change time */
-       unsigned long   __unused2;
-       unsigned long   sem_nsems; /* no. of semaphores in array */
-       unsigned long   __unused3;
-       unsigned long   __unused4;
-};
-
-
-#endif /* _ASM_MICROBLAZE_SEMBUF_H */
+#include <asm-generic/sembuf.h>
index 39bfc8ce6af58348b1ede012394fda0802296bf6..a0cb0caff15241a41973f67b68756510b8bfe90e 100644 (file)
@@ -1,14 +1 @@
-/*
- * Copyright (C) 2009 Michal Simek <monstr@monstr.eu>
- *
- * This file is subject to the terms and conditions of the GNU General Public
- * License. See the file "COPYING" in the main directory of this archive
- * for more details.
- */
-
-#ifndef _ASM_MICROBLAZE_SERIAL_H
-#define _ASM_MICROBLAZE_SERIAL_H
-
-# define BASE_BAUD (1843200 / 16)
-
-#endif /* _ASM_MICROBLAZE_SERIAL_H */
+#include <asm-generic/serial.h>
index f829c584361858e93ceb0468e30d3a7e3cdc398e..83c05fc2de385c3260286bf12fed846617c8c095 100644 (file)
@@ -1,42 +1 @@
-#ifndef _ASM_MICROBLAZE_SHMBUF_H
-#define _ASM_MICROBLAZE_SHMBUF_H
-
-/*
- * The shmid64_ds structure for microblaze architecture.
- * Note extra padding because this structure is passed back and forth
- * between kernel and user space.
- *
- * Pad space is left for:
- * - 64-bit time_t to solve y2038 problem
- * - 2 miscellaneous 32-bit values
- */
-
-struct shmid64_ds {
-       struct ipc64_perm       shm_perm; /* operation perms */
-       size_t                  shm_segsz; /* size of segment (bytes) */
-       __kernel_time_t         shm_atime; /* last attach time */
-       unsigned long           __unused1;
-       __kernel_time_t         shm_dtime; /* last detach time */
-       unsigned long           __unused2;
-       __kernel_time_t         shm_ctime; /* last change time */
-       unsigned long           __unused3;
-       __kernel_pid_t          shm_cpid; /* pid of creator */
-       __kernel_pid_t          shm_lpid; /* pid of last operator */
-       unsigned long           shm_nattch; /* no. of current attaches */
-       unsigned long           __unused4;
-       unsigned long           __unused5;
-};
-
-struct shminfo64 {
-       unsigned long   shmmax;
-       unsigned long   shmmin;
-       unsigned long   shmmni;
-       unsigned long   shmseg;
-       unsigned long   shmall;
-       unsigned long   __unused1;
-       unsigned long   __unused2;
-       unsigned long   __unused3;
-       unsigned long   __unused4;
-};
-
-#endif /* _ASM_MICROBLAZE_SHMBUF_H */
+#include <asm-generic/shmbuf.h>
index 9f5fc2b3b6a3cbf6b7eb7aa83fc23a1eb75005c1..93f30deb95d0803ee9b84ade84d3c6738894603a 100644 (file)
@@ -1,6 +1 @@
-#ifndef _ASM_MICROBLAZE_SHMPARAM_H
-#define _ASM_MICROBLAZE_SHMPARAM_H
-
-#define SHMLBA PAGE_SIZE /* attach addr a multiple of this */
-
-#endif /* _ASM_MICROBLAZE_SHMPARAM_H */
+#include <asm-generic/shmparam.h>
index f162911a8f50cfebff36d7d07ee4223e4a1e6f68..0815d29d82e5f5f14d6e570f8768d184d63912a9 100644 (file)
@@ -1,15 +1 @@
-/*
- * Copyright (C) 2006 Atmark Techno, Inc.
- *
- * This file is subject to the terms and conditions of the GNU General Public
- * License. See the file "COPYING" in the main directory of this archive
- * for more details.
- */
-
-#ifndef _ASM_MICROBLAZE_SIGINFO_H
-#define _ASM_MICROBLAZE_SIGINFO_H
-
-#include <linux/types.h>
 #include <asm-generic/siginfo.h>
-
-#endif /* _ASM_MICROBLAZE_SIGINFO_H */
index 46bc2267d9497a751de01b75324120b384f4ce5f..7b1573ce19de50ed695751b2af1bd8dfc54b86e8 100644 (file)
@@ -1,165 +1 @@
-/*
- * Copyright (C) 2006 Atmark Techno, Inc.
- *     Yasushi SHOJI <yashi@atmark-techno.com>
- *     Tetsuya OHKAWA <tetsuya@atmark-techno.com>
- *
- * This file is subject to the terms and conditions of the GNU General Public
- * License. See the file "COPYING" in the main directory of this archive
- * for more details.
- */
-
-#ifndef _ASM_MICROBLAZE_SIGNAL_H
-#define _ASM_MICROBLAZE_SIGNAL_H
-
-#define SIGHUP         1
-#define SIGINT         2
-#define SIGQUIT                3
-#define SIGILL         4
-#define SIGTRAP                5
-#define SIGABRT                6
-#define SIGIOT         6
-#define SIGBUS         7
-#define SIGFPE         8
-#define SIGKILL                9
-#define SIGUSR1                10
-#define SIGSEGV                11
-#define SIGUSR2                12
-#define SIGPIPE                13
-#define SIGALRM                14
-#define SIGTERM                15
-#define SIGSTKFLT      16
-#define SIGCHLD                17
-#define SIGCONT                18
-#define SIGSTOP                19
-#define SIGTSTP                20
-#define SIGTTIN                21
-#define SIGTTOU                22
-#define SIGURG         23
-#define SIGXCPU                24
-#define SIGXFSZ                25
-#define SIGVTALRM      26
-#define SIGPROF                27
-#define SIGWINCH       28
-#define SIGIO          29
-#define SIGPOLL                SIGIO
-/*
-#define SIGLOST                29
-*/
-#define SIGPWR         30
-#define SIGSYS         31
-#define        SIGUNUSED       31
-
-/* These should not be considered constants from userland. */
-#define SIGRTMIN       32
-#define SIGRTMAX       _NSIG
-
-/*
- * SA_FLAGS values:
- *
- * SA_ONSTACK indicates that a registered stack_t will be used.
- * SA_RESTART flag to get restarting signals (which were the default long ago)
- * SA_NOCLDSTOP flag to turn off SIGCHLD when children stop.
- * SA_RESETHAND clears the handler when the signal is delivered.
- * SA_NOCLDWAIT flag on SIGCHLD to inhibit zombies.
- * SA_NODEFER prevents the current signal from being masked in the handler.
- *
- * SA_ONESHOT and SA_NOMASK are the historical Linux names for the Single
- * Unix names RESETHAND and NODEFER respectively.
- */
-#define SA_NOCLDSTOP   0x00000001
-#define SA_NOCLDWAIT   0x00000002
-#define SA_SIGINFO     0x00000004
-#define SA_ONSTACK     0x08000000
-#define SA_RESTART     0x10000000
-#define SA_NODEFER     0x40000000
-#define SA_RESETHAND   0x80000000
-
-#define SA_NOMASK      SA_NODEFER
-#define SA_ONESHOT     SA_RESETHAND
-
-#define SA_RESTORER    0x04000000
-
-/*
- * sigaltstack controls
- */
-#define SS_ONSTACK     1
-#define SS_DISABLE     2
-
-#define MINSIGSTKSZ    2048
-#define SIGSTKSZ       8192
-
-# ifndef __ASSEMBLY__
-# include <linux/types.h>
-# include <asm-generic/signal-defs.h>
-
-/* Avoid too many header ordering problems. */
-struct siginfo;
-
-#  ifdef __KERNEL__
-/*
- * Most things should be clean enough to redefine this at will, if care
- * is taken to make libc match.
- */
-#  define _NSIG                64
-#  define _NSIG_BPW    32
-#  define _NSIG_WORDS  (_NSIG / _NSIG_BPW)
-
-typedef unsigned long old_sigset_t; /* at least 32 bits */
-
-typedef struct {
-       unsigned long sig[_NSIG_WORDS];
-} sigset_t;
-
-struct old_sigaction {
-       __sighandler_t sa_handler;
-       old_sigset_t sa_mask;
-       unsigned long sa_flags;
-       void (*sa_restorer)(void);
-};
-
-struct sigaction {
-       __sighandler_t sa_handler;
-       unsigned long sa_flags;
-       void (*sa_restorer)(void);
-       sigset_t sa_mask; /* mask last for extensibility */
-};
-
-struct k_sigaction {
-       struct sigaction sa;
-};
-
-#  include <asm/sigcontext.h>
-#  undef __HAVE_ARCH_SIG_BITOPS
-
-#  define ptrace_signal_deliver(regs, cookie) do { } while (0)
-
-#  else /* !__KERNEL__ */
-
-/* Here we must cater to libcs that poke about in kernel headers. */
-
-#  define NSIG         32
-typedef unsigned long sigset_t;
-
-struct sigaction {
-       union {
-       __sighandler_t _sa_handler;
-       void (*_sa_sigaction)(int, struct siginfo *, void *);
-       } _u;
-       sigset_t sa_mask;
-       unsigned long sa_flags;
-       void (*sa_restorer)(void);
-};
-
-#  define sa_handler   _u._sa_handler
-#  define sa_sigaction _u._sa_sigaction
-
-#  endif /* __KERNEL__ */
-
-typedef struct sigaltstack {
-       void *ss_sp;
-       int ss_flags;
-       size_t ss_size;
-} stack_t;
-
-# endif /* __ASSEMBLY__ */
-#endif /* _ASM_MICROBLAZE_SIGNAL_H */
+#include <asm-generic/signal.h>
index 8259368603149ea09320b079b1d41bebfb385211..6b71384b9d8b42ac6cce8a955a73220bda4957d5 100644 (file)
@@ -1,69 +1 @@
-/*
- * Copyright (C) 2006 Atmark Techno, Inc.
- *
- * This file is subject to the terms and conditions of the GNU General Public
- * License. See the file "COPYING" in the main directory of this archive
- * for more details.
- */
-
-#ifndef _ASM_MICROBLAZE_SOCKET_H
-#define _ASM_MICROBLAZE_SOCKET_H
-
-#include <asm/sockios.h>
-
-/* For setsockoptions(2) */
-#define SOL_SOCKET     1
-
-#define SO_DEBUG       1
-#define SO_REUSEADDR   2
-#define SO_TYPE                3
-#define SO_ERROR       4
-#define SO_DONTROUTE   5
-#define SO_BROADCAST   6
-#define SO_SNDBUF      7
-#define SO_RCVBUF      8
-#define SO_SNDBUFFORCE 32
-#define SO_RCVBUFFORCE 33
-#define SO_KEEPALIVE   9
-#define SO_OOBINLINE   10
-#define SO_NO_CHECK    11
-#define SO_PRIORITY    12
-#define SO_LINGER      13
-#define SO_BSDCOMPAT   14
-/* To add :#define SO_REUSEPORT 15 */
-#define SO_PASSCRED    16
-#define SO_PEERCRED    17
-#define SO_RCVLOWAT    18
-#define SO_SNDLOWAT    19
-#define SO_RCVTIMEO    20
-#define SO_SNDTIMEO    21
-
-/* Security levels - as per NRL IPv6 - don't actually do anything */
-#define SO_SECURITY_AUTHENTICATION             22
-#define SO_SECURITY_ENCRYPTION_TRANSPORT       23
-#define SO_SECURITY_ENCRYPTION_NETWORK         24
-
-#define SO_BINDTODEVICE        25
-
-/* Socket filtering */
-#define SO_ATTACH_FILTER       26
-#define SO_DETACH_FILTER       27
-
-#define SO_PEERNAME            28
-#define SO_TIMESTAMP           29
-#define SCM_TIMESTAMP          SO_TIMESTAMP
-
-#define SO_ACCEPTCONN          30
-
-#define SO_PEERSEC             31
-#define SO_PASSSEC             34
-
-#define SO_TIMESTAMPNS         35
-#define SCM_TIMESTAMPNS                SO_TIMESTAMPNS
-
-#define SO_MARK                        36
-
-#define SO_TIMESTAMPING                37
-#define SCM_TIMESTAMPING       SO_TIMESTAMPING
-
-#endif /* _ASM_MICROBLAZE_SOCKET_H */
+#include <asm-generic/socket.h>
index 9fff57a701e1e0a35d0c165c7e83bc6e624b202f..def6d4746ee7fef64057f79e8d76ac41688671d9 100644 (file)
@@ -1,23 +1 @@
-/*
- * Copyright (C) 2006 Atmark Techno, Inc.
- *
- * This file is subject to the terms and conditions of the GNU General Public
- * License. See the file "COPYING" in the main directory of this archive
- * for more details.
- */
-
-#ifndef _ASM_MICROBLAZE_SOCKIOS_H
-#define _ASM_MICROBLAZE_SOCKIOS_H
-
-#include <linux/ioctl.h>
-
-/* Socket-level I/O control calls. */
-#define FIOSETOWN      0x8901
-#define SIOCSPGRP      0x8902
-#define FIOGETOWN      0x8903
-#define SIOCGPGRP      0x8904
-#define SIOCATMARK     0x8905
-#define SIOCGSTAMP     0x8906          /* Get stamp (timeval) */
-#define SIOCGSTAMPNS   0x8907          /* Get stamp (timespec) */
-
-#endif /* _ASM_MICROBLAZE_SOCKIOS_H */
+#include <asm-generic/sockios.h>
index a15f77520bfd74ac2dff80e4780d37c7b3574ed9..3dc90fa92c704d8fb07d66b034daadd44ee6376b 100644 (file)
@@ -1,68 +1 @@
-/*
- * Microblaze stat structure
- *
- * Copyright (C) 2001,02,03 NEC Electronics Corporation
- * Copyright (C) 2001,02,03 Miles Bader <miles@gnu.org>
- *
- * This file is subject to the terms and conditions of the GNU General
- * Public License. See the file COPYING in the main directory of this
- * archive for more details.
- *
- * Written by Miles Bader <miles@gnu.org>
- */
-
-#ifndef _ASM_MICROBLAZE_STAT_H
-#define _ASM_MICROBLAZE_STAT_H
-
-#include <linux/posix_types.h>
-
-#define STAT_HAVE_NSEC 1
-
-struct stat {
-       unsigned long   st_dev;
-       unsigned long   st_ino;
-       unsigned int    st_mode;
-       unsigned int    st_nlink;
-       unsigned int    st_uid;
-       unsigned int    st_gid;
-       unsigned long   st_rdev;
-       unsigned long   __pad1;
-       long            st_size;
-       int             st_blksize;
-       int             __pad2;
-       long            st_blocks;
-       int             st_atime;
-       unsigned int    st_atime_nsec;
-       int             st_mtime;
-       unsigned int    st_mtime_nsec;
-       int             st_ctime;
-       unsigned int    st_ctime_nsec;
-       unsigned long   __unused4;
-       unsigned long   __unused5;
-};
-
-struct stat64 {
-       unsigned long long      st_dev;         /* Device.  */
-       unsigned long long      st_ino;         /* File serial number.  */
-       unsigned int            st_mode;        /* File mode.  */
-       unsigned int            st_nlink;       /* Link count.  */
-       unsigned int            st_uid;         /* User ID of the file's owner.  */
-       unsigned int            st_gid;         /* Group ID of the file's group. */
-       unsigned long long      st_rdev;        /* Device number, if device.  */
-       unsigned long long      __pad1;
-       long long               st_size;        /* Size of file, in bytes.  */
-       int                     st_blksize;     /* Optimal block size for I/O.  */
-       int                     __pad2;
-       long long               st_blocks;      /* Number 512-byte blocks allocated. */
-       int                     st_atime;       /* Time of last access.  */
-       unsigned int            st_atime_nsec;
-       int                     st_mtime;       /* Time of last modification.  */
-       unsigned int            st_mtime_nsec;
-       int                     st_ctime;       /* Time of last status change.  */
-       unsigned int            st_ctime_nsec;
-       unsigned int            __unused4;
-       unsigned int            __unused5;
-};
-
-#endif /* _ASM_MICROBLAZE_STAT_H */
-
+#include <asm-generic/stat.h>
index b375d7b65ad73b7b7578da5dfc71ba71115f59a5..7847e563ab66f18af1951d9cf94bf353daf54596 100644 (file)
@@ -1,8 +1 @@
-#ifndef _ASM_MICROBLAZE_SWAB_H
-#define _ASM_MICROBLAZE_SWAB_H
-
-#if defined(__GNUC__) && !defined(__STRICT_ANSI__) || defined(__KERNEL__)
-#define __SWAB_64_THRU_32__
-#endif
-
-#endif /* _ASM_MICROBLAZE_SWAB_H */
+#include <asm-generic/swab.h>
index ddea9eb31f8da76aa4a3a820a7ee8a9c0744dae7..720761cc741f43209e8081afd8dde3d5fb028a40 100644 (file)
@@ -1,48 +1,8 @@
 #ifndef __ASM_MICROBLAZE_SYSCALLS_H
-#define __ASM_MICROBLAZE_SYSCALLS_H
-#ifdef __KERNEL__
 
-#include <linux/compiler.h>
-#include <linux/linkage.h>
-#include <linux/types.h>
-#include <linux/signal.h>
+asmlinkage long sys_clone(int flags, unsigned long stack, struct pt_regs *regs);
+#define sys_clone sys_clone
 
-/* FIXME will be removed */
-asmlinkage int sys_ipc(uint call, int first, int second,
-                               int third, void *ptr, long fifth);
+#include <asm-generic/syscalls.h>
 
-struct pt_regs;
-asmlinkage int sys_vfork(struct pt_regs *regs);
-asmlinkage int sys_clone(int flags, unsigned long stack, struct pt_regs *regs);
-asmlinkage int sys_execve(char __user *filenamei, char __user *__user *argv,
-                       char __user *__user *envp, struct pt_regs *regs);
-
-asmlinkage unsigned long sys_mmap2(unsigned long addr, size_t len,
-                       unsigned long prot, unsigned long flags,
-                       unsigned long fd, unsigned long pgoff);
-
-asmlinkage unsigned long sys_mmap(unsigned long addr, size_t len,
-                       unsigned long prot, unsigned long flags,
-                       unsigned long fd, off_t offset);
-
-/* from signal.c */
-asmlinkage int sys_sigsuspend(old_sigset_t mask, struct pt_regs *regs);
-
-asmlinkage int sys_rt_sigsuspend(sigset_t __user *unewset, size_t sigsetsize,
-               struct pt_regs *regs);
-
-asmlinkage int sys_sigaction(int sig, const struct old_sigaction *act,
-               struct old_sigaction *oact);
-
-asmlinkage long sys_rt_sigaction(int sig, const struct sigaction __user *act,
-               struct sigaction __user *oact, size_t sigsetsize);
-
-asmlinkage int sys_sigaltstack(const stack_t __user *uss, stack_t __user *uoss,
-               struct pt_regs *regs);
-
-asmlinkage int sys_sigreturn(struct pt_regs *regs);
-
-asmlinkage int sys_rt_sigreturn(struct pt_regs *regs);
-
-#endif /* __KERNEL__ */
 #endif /* __ASM_MICROBLAZE_SYSCALLS_H */
index c4e308850b5d6af1be1e1c0fd8487fd307e8ba22..b1ed6159066006bd3d635f57126316a12f25962a 100644 (file)
@@ -13,6 +13,9 @@
 #include <asm/setup.h>
 #include <asm/irqflags.h>
 
+#include <asm-generic/cmpxchg.h>
+#include <asm-generic/cmpxchg-local.h>
+
 struct task_struct;
 struct thread_info;
 
index a1b64bc4724ac0344b4f0d6b259719f808f2c643..3935b106de79bf2f8469b849576268ac1ca30bb2 100644 (file)
@@ -1,203 +1 @@
-/*
- * Copyright (C) 2006 Atmark Techno, Inc.
- *
- * This file is subject to the terms and conditions of the GNU General Public
- * License. See the file "COPYING" in the main directory of this archive
- * for more details.
- */
-
-#ifndef _ASM_MICROBLAZE_TERMBITS_H
-#define _ASM_MICROBLAZE_TERMBITS_H
-
-#include <linux/posix_types.h>
-
-typedef unsigned char  cc_t;
-typedef unsigned int   speed_t;
-typedef unsigned int   tcflag_t;
-
-#define NCCS 19
-struct termios {
-       tcflag_t c_iflag; /* input mode flags */
-       tcflag_t c_oflag; /* output mode flags */
-       tcflag_t c_cflag; /* control mode flags */
-       tcflag_t c_lflag; /* local mode flags */
-       cc_t c_line; /* line discipline */
-       cc_t c_cc[NCCS]; /* control characters */
-};
-
-struct ktermios {
-       tcflag_t c_iflag; /* input mode flags */
-       tcflag_t c_oflag; /* output mode flags */
-       tcflag_t c_cflag; /* control mode flags */
-       tcflag_t c_lflag; /* local mode flags */
-       cc_t c_line; /* line discipline */
-       cc_t c_cc[NCCS]; /* control characters */
-       speed_t c_ispeed; /* input speed */
-       speed_t c_ospeed; /* output speed */
-};
-
-/* c_cc characters */
-
-#define VINTR 0
-#define VQUIT 1
-#define VERASE 2
-#define VKILL 3
-#define VEOF 4
-#define VTIME 5
-#define VMIN 6
-#define VSWTC 7
-#define VSTART 8
-#define VSTOP 9
-#define VSUSP 10
-#define VEOL 11
-#define VREPRINT 12
-#define VDISCARD 13
-#define VWERASE 14
-#define VLNEXT 15
-#define VEOL2 16
-
-/* c_iflag bits */
-
-#define IGNBRK 0000001
-#define BRKINT 0000002
-#define IGNPAR 0000004
-#define PARMRK 0000010
-#define INPCK  0000020
-#define ISTRIP 0000040
-#define INLCR  0000100
-#define IGNCR  0000200
-#define ICRNL  0000400
-#define IUCLC  0001000
-#define IXON   0002000
-#define IXANY  0004000
-#define IXOFF  0010000
-#define IMAXBEL        0020000
-#define IUTF8  0040000
-
-/* c_oflag bits */
-
-#define OPOST  0000001
-#define OLCUC  0000002
-#define ONLCR  0000004
-#define OCRNL  0000010
-#define ONOCR  0000020
-#define ONLRET 0000040
-#define OFILL  0000100
-#define OFDEL  0000200
-#define NLDLY  0000400
-#define NL0    0000000
-#define NL1    0000400
-#define CRDLY  0003000
-#define CR0    0000000
-#define CR1    0001000
-#define CR2    0002000
-#define CR3    0003000
-#define TABDLY 0014000
-#define TAB0   0000000
-#define TAB1   0004000
-#define TAB2   0010000
-#define TAB3   0014000
-#define XTABS  0014000
-#define BSDLY  0020000
-#define BS0    0000000
-#define BS1    0020000
-#define VTDLY  0040000
-#define VT0    0000000
-#define VT1    0040000
-#define FFDLY  0100000
-#define FF0    0000000
-#define FF1    0100000
-
-/* c_cflag bit meaning */
-
-#define CBAUD  0010017
-#define B0     0000000 /* hang up */
-#define B50    0000001
-#define B75    0000002
-#define B110   0000003
-#define B134   0000004
-#define B150   0000005
-#define B200   0000006
-#define B300   0000007
-#define B600   0000010
-#define B1200  0000011
-#define B1800  0000012
-#define B2400  0000013
-#define B4800  0000014
-#define B9600  0000015
-#define B19200 0000016
-#define B38400 0000017
-#define EXTA B19200
-#define EXTB B38400
-#define CSIZE  0000060
-#define CS5    0000000
-#define CS6    0000020
-#define CS7    0000040
-#define CS8    0000060
-#define CSTOPB 0000100
-#define CREAD  0000200
-#define PARENB 0000400
-#define PARODD 0001000
-#define HUPCL  0002000
-#define CLOCAL 0004000
-#define CBAUDEX        0010000
-#define B57600 0010001
-#define B115200        0010002
-#define B230400        0010003
-#define B460800        0010004
-#define B500000        0010005
-#define B576000        0010006
-#define B921600        0010007
-#define BOTHER         0010000
-#define B1000000       0010010
-#define B1152000       0010011
-#define B1500000       0010012
-#define B2000000       0010013
-#define B2500000       0010014
-#define B3000000       0010015
-#define B3500000       0010016
-#define B4000000       0010017
-#define CIBAUD         002003600000 /* input baud rate (not used) */
-#define CMSPAR         010000000000 /* mark or space (stick) parity */
-#define CRTSCTS                020000000000 /* flow control */
-
-#define IBSHIFT        16              /* Shift from CBAUD to CIBAUD */
-
-/* c_lflag bits */
-
-#define ISIG   0000001
-#define ICANON 0000002
-#define XCASE  0000004
-#define ECHO   0000010
-#define ECHOE  0000020
-#define ECHOK  0000040
-#define ECHONL 0000100
-#define NOFLSH 0000200
-#define TOSTOP 0000400
-#define ECHOCTL        0001000
-#define ECHOPRT        0002000
-#define ECHOKE 0004000
-#define FLUSHO 0010000
-#define PENDIN 0040000
-#define IEXTEN 0100000
-
-/* tcflow() and TCXONC use these */
-
-#define        TCOOFF          0
-#define        TCOON           1
-#define        TCIOFF          2
-#define        TCION           3
-
-/* tcflush() and TCFLSH use these */
-
-#define        TCIFLUSH        0
-#define        TCOFLUSH        1
-#define        TCIOFLUSH       2
-
-/* tcsetattr uses these */
-
-#define        TCSANOW         0
-#define        TCSADRAIN       1
-#define        TCSAFLUSH       2
-
-#endif /* _ASM_MICROBLAZE_TERMBITS_H */
+#include <asm-generic/termbits.h>
index 47a46d1fbe26fa4e1ddd1bf7b66f3290ea1facc8..280d78a9d96637ccbc93bc4c0debc88eb9443bba 100644 (file)
@@ -1,88 +1 @@
-/*
- * Copyright (C) 2006 Atmark Techno, Inc.
- *
- * This file is subject to the terms and conditions of the GNU General Public
- * License. See the file "COPYING" in the main directory of this archive
- * for more details.
- */
-
-#ifndef _ASM_MICROBLAZE_TERMIOS_H
-#define _ASM_MICROBLAZE_TERMIOS_H
-
-#include <linux/string.h>
-#include <asm/termbits.h>
-#include <asm/ioctls.h>
-
-struct winsize {
-       unsigned short ws_row;
-       unsigned short ws_col;
-       unsigned short ws_xpixel;
-       unsigned short ws_ypixel;
-};
-
-#define NCC 8
-struct termio {
-       unsigned short c_iflag; /* input mode flags */
-       unsigned short c_oflag; /* output mode flags */
-       unsigned short c_cflag; /* control mode flags */
-       unsigned short c_lflag; /* local mode flags */
-       unsigned char c_line; /* line discipline */
-       unsigned char c_cc[NCC]; /* control characters */
-};
-
-#ifdef __KERNEL__
-/*     intr=^C         quit=^|         erase=del       kill=^U
-       eof=^D          vtime=\0        vmin=\1         sxtc=\0
-       start=^Q        stop=^S         susp=^Z         eol=\0
-       reprint=^R      discard=^U      werase=^W       lnext=^V
-       eol2=\0
-*/
-#define INIT_C_CC "\003\034\177\025\004\0\1\0\021\023\032\0\022\017\027\026\0"
-#endif
-
-/* Modem lines */
-
-#define TIOCM_LE       0x001
-#define TIOCM_DTR      0x002
-#define TIOCM_RTS      0x004
-#define TIOCM_ST       0x008
-#define TIOCM_SR       0x010
-#define TIOCM_CTS      0x020
-#define TIOCM_CAR      0x040
-#define TIOCM_RNG      0x080
-#define TIOCM_DSR      0x100
-#define TIOCM_CD       TIOCM_CAR
-#define TIOCM_RI       TIOCM_RNG
-#define TIOCM_OUT1     0x2000
-#define TIOCM_OUT2     0x4000
-#define TIOCM_LOOP     0x8000
-
-/* ioctl (fd, TIOCSERGETLSR, &result) where result may be as below */
-
-/* Line disciplines */
-
-#define N_TTY          0
-#define N_SLIP         1
-#define N_MOUSE                2
-#define N_PPP          3
-#define N_STRIP                4
-#define N_AX25         5
-#define N_X25          6 /* X.25 async */
-#define N_6PACK                7
-#define N_MASC         8 /* Reserved for Mobitex module <kaz@cafe.net> */
-#define N_R3964                9 /* Reserved for Simatic R3964 module */
-#define N_PROFIBUS_FDL 10 /* Reserved for Profibus <Dave@mvhi.com> */
-#define N_IRDA         11 /* Linux IR - http://irda.sourceforge.net/ */
-#define N_SMSBLOCK     12 /* SMS block mode - for talking to GSM data cards
-                               about SMS messages */
-#define N_HDLC         13 /* synchronous HDLC */
-#define N_SYNC_PPP     14
-#define N_HCI          15 /* Bluetooth HCI UART */
-
-#ifdef __KERNEL__
-
-#include <asm-generic/termios-base.h>
-
-#endif /* __KERNEL__ */
-
-#endif /* _ASM_MICROBLAZE_TERMIOS_H */
+#include <asm-generic/termios.h>
index 7fac44498445f82595431e75c28fcf61a6731e21..6e92885d381a80ee3adc680632415c3911ecdb64 100644 (file)
@@ -75,8 +75,6 @@ struct thread_info {
 
 /*
  * macros/functions for gaining access to the thread information structure
- *
- * preempt_count needs to be 1 initially, until the scheduler is functional.
  */
 #define INIT_THREAD_INFO(tsk)                  \
 {                                              \
@@ -84,7 +82,7 @@ struct thread_info {
        .exec_domain    = &default_exec_domain, \
        .flags          = 0,                    \
        .cpu            = 0,                    \
-       .preempt_count  = 1,                    \
+       .preempt_count  = INIT_PREEMPT_COUNT,   \
        .addr_limit     = KERNEL_DS,            \
        .restart_block = {                      \
                .fn = do_no_restart_syscall,    \
index 678525dc6d0b1ee8e9f7a67b6c6951b676cde889..befcf3de5532c2df283b45a55816d4037a6f2759 100644 (file)
@@ -9,10 +9,8 @@
 #ifndef _ASM_MICROBLAZE_TIMEX_H
 #define _ASM_MICROBLAZE_TIMEX_H
 
-#define CLOCK_TICK_RATE 1000 /* Timer input freq. */
-
-typedef unsigned long cycles_t;
+#include <asm-generic/timex.h>
 
-#define get_cycles()   (0)
+#define CLOCK_TICK_RATE 1000 /* Timer input freq. */
 
 #endif /* _ASM_TIMEX_H */
index bebc018318f5527a33d6f7b3d409bbf24cf5c322..b9e79bc580dd6cf47ae1c6a939eb8c67e6f5f7e5 100644 (file)
@@ -1,38 +1 @@
-/*
- * Copyright (C) Atmark Techno, Inc.
- *
- * This file is subject to the terms and conditions of the GNU General Public
- * License. See the file "COPYING" in the main directory of this archive
- * for more details.
- */
-
-#ifndef _ASM_MICROBLAZE_TYPES_H
-#define _ASM_MICROBLAZE_TYPES_H
-
-/*
- * This file is never included by application software unless
- * explicitly requested (e.g., via linux/types.h) in which case the
- * application is Linux specific so (user-) name space pollution is
- * not a major issue.  However, for interoperability, libraries still
- * need to be careful to avoid a name clashes.
- */
-
-#include <asm-generic/int-ll64.h>
-
-# ifndef __ASSEMBLY__
-
-typedef unsigned short umode_t;
-
-/*
- * These aren't exported outside the kernel to avoid name space clashes
- */
-#  ifdef __KERNEL__
-#  define BITS_PER_LONG 32
-
-/* Dma addresses are 32-bits wide. */
-
-typedef u32 dma_addr_t;
-
-#  endif/* __KERNEL__ */
-# endif /* __ASSEMBLY__ */
-#endif /* _ASM_MICROBLAZE_TYPES_H */
+#include <asm-generic/types.h>
index 11f6bb3ae3a4efd27d978a80dcb76651d0a6d20f..9bc07b9f30fba10518b48cadc01d9aa4eaa4260f 100644 (file)
@@ -1,22 +1 @@
-/*
- * Copyright (C) 2006 Atmark Techno, Inc.
- *
- * This file is subject to the terms and conditions of the GNU General Public
- * License. See the file "COPYING" in the main directory of this archive
- * for more details.
- */
-
-#ifndef _ASM_MICROBLAZE_UCONTEXT_H
-#define _ASM_MICROBLAZE_UCONTEXT_H
-
-#include <asm/sigcontext.h>
-
-struct ucontext {
-       unsigned long           uc_flags;
-       struct ucontext         *uc_link;
-       stack_t                 uc_stack;
-       struct sigcontext       uc_mcontext;
-       sigset_t                uc_sigmask; /* mask last for extensibility */
-};
-
-#endif /* _ASM_MICROBLAZE_UCONTEXT_H */
+#include <asm-generic/ucontext.h>
index b5e2f5fa5c53559adaf1cd1dd593b4c57aa34404..0b852327c0e7bcaf73d45daa15d5f047533f7485 100644 (file)
 #define __NR_accept04          362 /* new */
 #define __NR_preadv            363 /* new */
 #define __NR_pwritev           364 /* new */
+#define __NR_rt_tgsigqueueinfo 365 /* new */
+#define __NR_perf_counter_open 366 /* new */
 
-#define __NR_syscalls          365
+#define __NR_syscalls          367
 
 #ifdef __KERNEL__
 #ifndef __ASSEMBLY__
 #define __ARCH_WANT_SYS_SIGPENDING
 #define __ARCH_WANT_SYS_SIGPROCMASK
 #define __ARCH_WANT_SYS_RT_SIGACTION
-/* #define __ARCH_WANT_SYS_RT_SIGSUSPEND */
+#define __ARCH_WANT_SYS_RT_SIGSUSPEND
 
 /*
  * "Conditional" syscalls
index 8b137891791fe96927ad78e64b0aad7bded08bdc..89d82fd8fcf17bcea5c5d0644d4ceda64883bde8 100644 (file)
@@ -1 +1 @@
-
+#include <asm-generic/vga.h>
index 1fce6b803f54905b69ffadca0162a4db0593ed66..9083d85376a4dc57b6e7c535869eb4b3f11570f5 100644 (file)
@@ -551,30 +551,22 @@ no_work_pending:
        rtid    r14, 0
        nop
 
-sys_vfork_wrapper:
-       brid    sys_vfork
+sys_vfork:
+       brid    microblaze_vfork
        addk    r5, r1, r0
 
-sys_clone_wrapper:
-       brid    sys_clone
+sys_clone:
+       brid    microblaze_clone
        addk    r7, r1, r0
 
-sys_execve_wrapper:
-       brid    sys_execve
+sys_execve:
+       brid    microblaze_execve
        addk    r8, r1, r0
 
-sys_sigreturn_wrapper:
-       brid    sys_sigreturn
-       addk    r5, r1, r0
-
 sys_rt_sigreturn_wrapper:
        brid    sys_rt_sigreturn
        addk    r5, r1, r0
 
-sys_sigsuspend_wrapper:
-       brid    sys_rt_sigsuspend
-       addk    r6, r1, r0
-
 sys_rt_sigsuspend_wrapper:
        brid    sys_rt_sigsuspend
        addk    r7, r1, r0
index 91a0e7b185dd998c0b51981adc43e81ced768361..c7353e79f4a22f2ddb70d7b25d5e8c79783d8f0e 100644 (file)
@@ -429,12 +429,11 @@ C_ENTRY(ret_from_fork):
        brid    ret_from_trap;  /* Do normal trap return */
        nop;
 
-C_ENTRY(sys_vfork_wrapper):
+C_ENTRY(sys_vfork):
+       brid    microblaze_vfork        /* Do real work (tail-call) */
        la      r5, r1, PTO
-       brid    sys_vfork       /* Do real work (tail-call) */
-       nop
 
-C_ENTRY(sys_clone_wrapper):
+C_ENTRY(sys_clone):
        bnei    r6, 1f;                 /* See if child SP arg (arg 1) is 0. */
        lwi     r6, r1, PTO+PT_R1;      /* If so, use paret's stack ptr */
 1:     la      r7, r1, PTO;                    /* Arg 2: parent context */
@@ -444,20 +443,9 @@ C_ENTRY(sys_clone_wrapper):
        brid    do_fork         /* Do real work (tail-call) */
        nop;
 
-C_ENTRY(sys_execve_wrapper):
+C_ENTRY(sys_execve):
        la      r8, r1, PTO;            /* add user context as 4th arg */
-       brid    sys_execve;     /* Do real work (tail-call).*/
-       nop;
-
-C_ENTRY(sys_sigsuspend_wrapper):
-       swi     r3, r1, PTO+PT_R3; /* restore saved r3, r4 registers */
-       swi     r4, r1, PTO+PT_R4;
-       la      r6, r1, PTO;            /* add user context as 2nd arg */
-       bralid  r15, sys_sigsuspend; /* Do real work.*/
-       nop;
-       lwi     r3, r1, PTO+PT_R3; /* restore saved r3, r4 registers */
-       lwi     r4, r1, PTO+PT_R4;
-       bri ret_from_trap /* fall through will not work here due to align */
+       brid    microblaze_execve;      /* Do real work (tail-call).*/
        nop;
 
 C_ENTRY(sys_rt_sigsuspend_wrapper):
@@ -471,18 +459,6 @@ C_ENTRY(sys_rt_sigsuspend_wrapper):
        bri ret_from_trap /* fall through will not work here due to align */
        nop;
 
-
-C_ENTRY(sys_sigreturn_wrapper):
-       swi     r3, r1, PTO+PT_R3; /* restore saved r3, r4 registers */
-       swi     r4, r1, PTO+PT_R4;
-       la      r5, r1, PTO;            /* add user context as 1st arg */
-       brlid   r15, sys_sigreturn;     /* Do real work.*/
-       nop;
-       lwi     r3, r1, PTO+PT_R3; /* restore saved r3, r4 registers */
-       lwi     r4, r1, PTO+PT_R4;
-       bri ret_from_trap /* fall through will not work here due to align */
-       nop;
-
 C_ENTRY(sys_rt_sigreturn_wrapper):
        swi     r3, r1, PTO+PT_R3; /* restore saved r3, r4 registers */
        swi     r4, r1, PTO+PT_R4;
index b86aa623e36d053f95c61de5533782c0d92a8bb2..53ff39af6a5c0eebfcf156dd02969d231896229d 100644 (file)
@@ -27,7 +27,6 @@
 #include <linux/kernel.h>
 #include <linux/mm.h>
 #include <linux/sched.h>
-#include <linux/smp_lock.h>
 #include <linux/ptrace.h>
 #include <linux/signal.h>
 
index 4c0e6521b1140e6d92183fb165b03076253a889d..1c80e4fc40cef1fc0513951c449452ff23139c96 100644 (file)
@@ -21,7 +21,6 @@
 #include <linux/sched.h>
 #include <linux/mm.h>
 #include <linux/smp.h>
-#include <linux/smp_lock.h>
 #include <linux/kernel.h>
 #include <linux/signal.h>
 #include <linux/errno.h>
 
 asmlinkage int do_signal(struct pt_regs *regs, sigset_t *oldset, int in_sycall);
 
-/*
- * Atomically swap in the new signal mask, and wait for a signal.
- */
-asmlinkage int
-sys_sigsuspend(old_sigset_t mask, struct pt_regs *regs)
-{
-       sigset_t saveset;
-
-       mask &= _BLOCKABLE;
-       spin_lock_irq(&current->sighand->siglock);
-       saveset = current->blocked;
-       siginitset(&current->blocked, mask);
-       recalc_sigpending();
-       spin_unlock_irq(&current->sighand->siglock);
-
-       regs->r3 = -EINTR;
-       while (1) {
-               current->state = TASK_INTERRUPTIBLE;
-               schedule();
-               if (do_signal(regs, &saveset, 1))
-                       return -EINTR;
-       }
-}
-
-asmlinkage int
-sys_rt_sigsuspend(sigset_t __user *unewset, size_t sigsetsize,
-               struct pt_regs *regs)
-{
-       sigset_t saveset, newset;
-
-       /* XXX: Don't preclude handling different sized sigset_t's. */
-       if (sigsetsize != sizeof(sigset_t))
-               return -EINVAL;
-
-       if (copy_from_user(&newset, unewset, sizeof(newset)))
-               return -EFAULT;
-       sigdelsetmask(&newset, ~_BLOCKABLE);
-       spin_lock_irq(&current->sighand->siglock);
-       saveset = current->blocked;
-       current->blocked = newset;
-       recalc_sigpending();
-       spin_unlock_irq(&current->sighand->siglock);
-
-       regs->r3 = -EINTR;
-       while (1) {
-               current->state = TASK_INTERRUPTIBLE;
-               schedule();
-               if (do_signal(regs, &saveset, 1))
-                       return -EINTR;
-       }
-}
-
-asmlinkage int
-sys_sigaction(int sig, const struct old_sigaction *act,
-               struct old_sigaction *oact)
-{
-       struct k_sigaction new_ka, old_ka;
-       int ret;
-
-       if (act) {
-               old_sigset_t mask;
-               if (!access_ok(VERIFY_READ, act, sizeof(*act)) ||
-                       __get_user(new_ka.sa.sa_handler, &act->sa_handler) ||
-                       __get_user(new_ka.sa.sa_restorer, &act->sa_restorer))
-                       return -EFAULT;
-               __get_user(new_ka.sa.sa_flags, &act->sa_flags);
-               __get_user(mask, &act->sa_mask);
-               siginitset(&new_ka.sa.sa_mask, mask);
-       }
 
-       ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL);
-
-       if (!ret && oact) {
-               if (!access_ok(VERIFY_WRITE, oact, sizeof(*oact)) ||
-                       __put_user(old_ka.sa.sa_handler, &oact->sa_handler) ||
-                       __put_user(old_ka.sa.sa_restorer, &oact->sa_restorer))
-                       return -EFAULT;
-               __put_user(old_ka.sa.sa_flags, &oact->sa_flags);
-               __put_user(old_ka.sa.sa_mask.sig[0], &oact->sa_mask);
-       }
-
-       return ret;
-}
-
-asmlinkage int
+asmlinkage long
 sys_sigaltstack(const stack_t __user *uss, stack_t __user *uoss,
                struct pt_regs *regs)
 {
@@ -139,7 +55,6 @@ sys_sigaltstack(const stack_t __user *uss, stack_t __user *uoss,
 /*
  * Do a signal return; undo the signal stack.
  */
-
 struct sigframe {
        struct sigcontext sc;
        unsigned long extramask[_NSIG_WORDS-1];
@@ -176,40 +91,7 @@ static int restore_sigcontext(struct pt_regs *regs,
        return err;
 }
 
-asmlinkage int sys_sigreturn(struct pt_regs *regs)
-{
-       struct sigframe *frame =
-                       (struct sigframe *)(regs->r1 + STATE_SAVE_ARG_SPACE);
-
-       sigset_t set;
-       int rval;
-
-       if (!access_ok(VERIFY_READ, frame, sizeof(*frame)))
-               goto badframe;
-
-       if (__get_user(set.sig[0], &frame->sc.oldmask)
-               || (_NSIG_WORDS > 1
-               && __copy_from_user(&set.sig[1], &frame->extramask,
-                                       sizeof(frame->extramask))))
-               goto badframe;
-
-       sigdelsetmask(&set, ~_BLOCKABLE);
-
-       spin_lock_irq(&current->sighand->siglock);
-       current->blocked = set;
-       recalc_sigpending();
-       spin_unlock_irq(&current->sighand->siglock);
-
-       if (restore_sigcontext(regs, &frame->sc, &rval))
-               goto badframe;
-       return rval;
-
-badframe:
-       force_sig(SIGSEGV, current);
-       return 0;
-}
-
-asmlinkage int sys_rt_sigreturn(struct pt_regs *regs)
+asmlinkage long sys_rt_sigreturn(struct pt_regs *regs)
 {
        struct rt_sigframe __user *frame =
                (struct rt_sigframe __user *)(regs->r1 + STATE_SAVE_ARG_SPACE);
@@ -324,21 +206,17 @@ static void setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
        /* Set up to return from userspace. If provided, use a stub
         already in userspace. */
        /* minus 8 is offset to cater for "rtsd r15,8" */
-       if (ka->sa.sa_flags & SA_RESTORER) {
-               regs->r15 = ((unsigned long)ka->sa.sa_restorer)-8;
-       } else {
-               /* addi r12, r0, __NR_sigreturn */
-               err |= __put_user(0x31800000 | __NR_rt_sigreturn ,
-                               frame->tramp + 0);
-               /* brki r14, 0x8 */
-               err |= __put_user(0xb9cc0008, frame->tramp + 1);
-
-               /* Return from sighandler will jump to the tramp.
-                Negative 8 offset because return is rtsd r15, 8 */
-               regs->r15 = ((unsigned long)frame->tramp)-8;
-
-               __invalidate_cache_sigtramp((unsigned long)frame->tramp);
-       }
+       /* addi r12, r0, __NR_sigreturn */
+       err |= __put_user(0x31800000 | __NR_rt_sigreturn ,
+                       frame->tramp + 0);
+       /* brki r14, 0x8 */
+       err |= __put_user(0xb9cc0008, frame->tramp + 1);
+
+       /* Return from sighandler will jump to the tramp.
+        Negative 8 offset because return is rtsd r15, 8 */
+       regs->r15 = ((unsigned long)frame->tramp)-8;
+
+       __invalidate_cache_sigtramp((unsigned long)frame->tramp);
 
        if (err)
                goto give_sigsegv;
@@ -405,7 +283,7 @@ do_restart:
  * OK, we're invoking a handler
  */
 
-static void
+static int
 handle_signal(unsigned long sig, struct k_sigaction *ka,
                siginfo_t *info, sigset_t *oldset, struct pt_regs *regs)
 {
@@ -426,6 +304,7 @@ handle_signal(unsigned long sig, struct k_sigaction *ka,
                recalc_sigpending();
                spin_unlock_irq(&current->sighand->siglock);
        }
+       return 1;
 }
 
 /*
@@ -456,7 +335,9 @@ int do_signal(struct pt_regs *regs, sigset_t *oldset, int in_syscall)
        if (kernel_mode(regs))
                return 1;
 
-       if (!oldset)
+       if (current_thread_info()->status & TS_RESTORE_SIGMASK)
+               oldset = &current->saved_sigmask;
+       else
                oldset = &current->blocked;
 
        signr = get_signal_to_deliver(&info, &ka, regs, NULL);
@@ -464,13 +345,31 @@ int do_signal(struct pt_regs *regs, sigset_t *oldset, int in_syscall)
                /* Whee! Actually deliver the signal. */
                if (in_syscall)
                        handle_restart(regs, &ka, 1);
-               handle_signal(signr, &ka, &info, oldset, regs);
+               if (handle_signal(signr, &ka, &info, oldset, regs)) {
+                       /*
+                        * A signal was successfully delivered; the saved
+                        * sigmask will have been stored in the signal frame,
+                        * and will be restored by sigreturn, so we can simply
+                        * clear the TS_RESTORE_SIGMASK flag.
+                        */
+                       current_thread_info()->status &=
+                           ~TS_RESTORE_SIGMASK;
+               }
                return 1;
        }
 
        if (in_syscall)
                handle_restart(regs, NULL, 0);
 
+       /*
+        * If there's no signal to deliver, we just put the saved sigmask
+        * back.
+        */
+       if (current_thread_info()->status & TS_RESTORE_SIGMASK) {
+               current_thread_info()->status &= ~TS_RESTORE_SIGMASK;
+               sigprocmask(SIG_SETMASK, &current->saved_sigmask, NULL);
+       }
+
        /* Did we come from a system call? */
        return 0;
 }
index 31905ff590b704db07206f1d11d7acc84386d9ea..e000bce09b2bda6e41066e1ad77af992366a87be 100644 (file)
@@ -15,7 +15,6 @@
 #include <linux/errno.h>
 #include <linux/mm.h>
 #include <linux/smp.h>
-#include <linux/smp_lock.h>
 #include <linux/syscalls.h>
 #include <linux/sem.h>
 #include <linux/msg.h>
@@ -39,7 +38,7 @@
  *
  * This is really horribly ugly. This will be remove with new toolchain.
  */
-asmlinkage int
+asmlinkage long
 sys_ipc(uint call, int first, int second, int third, void *ptr, long fifth)
 {
        int version, ret;
@@ -134,20 +133,20 @@ sys_ipc(uint call, int first, int second, int third, void *ptr, long fifth)
        return ret;
 }
 
-asmlinkage int sys_vfork(struct pt_regs *regs)
+asmlinkage long microblaze_vfork(struct pt_regs *regs)
 {
        return do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, regs->r1,
                                                regs, 0, NULL, NULL);
 }
 
-asmlinkage int sys_clone(int flags, unsigned long stack, struct pt_regs *regs)
+asmlinkage long microblaze_clone(int flags, unsigned long stack, struct pt_regs *regs)
 {
        if (!stack)
                stack = regs->r1;
        return do_fork(flags, stack, regs, 0, NULL, NULL);
 }
 
-asmlinkage int sys_execve(char __user *filenamei, char __user *__user *argv,
+asmlinkage long microblaze_execve(char __user *filenamei, char __user *__user *argv,
                        char __user *__user *envp, struct pt_regs *regs)
 {
        int error;
@@ -163,8 +162,8 @@ out:
        return error;
 }
 
-asmlinkage unsigned long
-sys_mmap2(unsigned long addr, size_t len,
+asmlinkage long
+sys_mmap2(unsigned long addr, unsigned long len,
        unsigned long prot, unsigned long flags,
        unsigned long fd, unsigned long pgoff)
 {
@@ -189,18 +188,18 @@ out:
        return ret;
 }
 
-asmlinkage unsigned long sys_mmap(unsigned long addr, size_t len,
+asmlinkage long sys_mmap(unsigned long addr, unsigned long len,
                        unsigned long prot, unsigned long flags,
-                       unsigned long fd, off_t offset)
+                       unsigned long fd, off_t pgoff)
 {
        int err = -EINVAL;
 
-       if (offset & ~PAGE_MASK) {
+       if (pgoff & ~PAGE_MASK) {
                printk(KERN_INFO "no pagemask in mmap\r\n");
                goto out;
        }
 
-       err = sys_mmap2(addr, len, prot, flags, fd, offset >> PAGE_SHIFT);
+       err = sys_mmap2(addr, len, prot, flags, fd, pgoff >> PAGE_SHIFT);
 out:
        return err;
 }
index 376d1789f7c065e436fdf39d7b3e2f8f2318494f..31b32a6c5f4ee06a39c3defa757c27a8f13c5b5d 100644 (file)
@@ -15,7 +15,7 @@ ENTRY(sys_call_table)
        .long sys_creat
        .long sys_link
        .long sys_unlink                /* 10 */
-       .long sys_execve_wrapper
+       .long sys_execve
        .long sys_chdir
        .long sys_time
        .long sys_mknod
@@ -71,12 +71,12 @@ ENTRY(sys_call_table)
        .long sys_getppid
        .long sys_getpgrp               /* 65 */
        .long sys_setsid
-       .long sys_sigaction
+       .long sys_ni_syscall            /* sys_sigaction */
        .long sys_sgetmask
        .long sys_ssetmask
        .long sys_setreuid              /* 70 */
        .long sys_setregid
-       .long sys_sigsuspend_wrapper
+       .long sys_ni_syscall            /* sys_sigsuspend_wrapper */
        .long sys_sigpending
        .long sys_sethostname
        .long sys_setrlimit             /* 75 */
@@ -123,8 +123,8 @@ ENTRY(sys_call_table)
        .long sys_sysinfo
        .long sys_ipc
        .long sys_fsync
-       .long sys_sigreturn_wrapper
-       .long sys_clone_wrapper         /* 120 */
+       .long sys_ni_syscall            /* sys_sigreturn_wrapper */
+       .long sys_clone         /* 120 */
        .long sys_setdomainname
        .long sys_newuname
        .long sys_ni_syscall            /* modify_ldt */
@@ -194,7 +194,7 @@ ENTRY(sys_call_table)
        .long sys_sendfile
        .long sys_ni_syscall            /* reserved for streams1 */
        .long sys_ni_syscall            /* reserved for streams2 */
-       .long sys_vfork_wrapper         /* 190 */
+       .long sys_vfork         /* 190 */
        .long sys_getrlimit
        .long sys_mmap2                 /* mmap2 */
        .long sys_truncate64
@@ -369,3 +369,5 @@ ENTRY(sys_call_table)
        .long sys_ni_syscall
        .long sys_ni_syscall
        .long sys_ni_syscall
+       .long sys_rt_tgsigqueueinfo     /* 365 */
+       .long sys_perf_counter_open
index 71c8cb6c9e43767a4ebd43f9e4c54d3e9820928b..b579db068c06fd3346a1458879145ef8f50063b3 100644 (file)
@@ -2,7 +2,7 @@
 # Makefile
 #
 
-lib-y :=  memset.o checksum.o
+lib-y :=  memset.o
 
 ifeq ($(CONFIG_OPT_LIB_ASM),y)
 lib-y += fastcopy.o
diff --git a/arch/microblaze/lib/checksum.c b/arch/microblaze/lib/checksum.c
deleted file mode 100644 (file)
index f08e745..0000000
+++ /dev/null
@@ -1,172 +0,0 @@
-/*
- *
- * INET                An implementation of the TCP/IP protocol suite for the LINUX
- *             operating system.  INET is implemented using the  BSD Socket
- *             interface as the means of communication with the user level.
- *
- *             IP/TCP/UDP checksumming routines
- *
- * Authors:    Jorge Cwik, <jorge@laser.satlink.net>
- *             Arnt Gulbrandsen, <agulbra@nvg.unit.no>
- *             Tom May, <ftom@netcom.com>
- *             Andreas Schwab, <schwab@issan.informatik.uni-dortmund.de>
- *             Lots of code moved from tcp.c and ip.c; see those files
- *             for more names.
- *
- * 03/02/96    Jes Sorensen, Andreas Schwab, Roman Hodek:
- *             Fixed some nasty bugs, causing some horrible crashes.
- *             A: At some points, the sum (%0) was used as
- *             length-counter instead of the length counter
- *             (%1). Thanks to Roman Hodek for pointing this out.
- *             B: GCC seems to mess up if one uses too many
- *             data-registers to hold input values and one tries to
- *             specify d0 and d1 as scratch registers. Letting gcc
- *             choose these registers itself solves the problem.
- *
- *             This program is free software; you can redistribute it and/or
- *             modify it under the terms of the GNU General Public License
- *             as published by the Free Software Foundation; either version
- *             2 of the License, or (at your option) any later version.
- */
-
-/* Revised by Kenneth Albanowski for m68knommu. Basic problem: unaligned access
- kills, so most of the assembly has to go. */
-
-#include <linux/module.h>
-#include <net/checksum.h>
-
-#include <asm/byteorder.h>
-
-static inline unsigned short from32to16(unsigned long x)
-{
-       /* add up 16-bit and 16-bit for 16+c bit */
-       x = (x & 0xffff) + (x >> 16);
-       /* add up carry.. */
-       x = (x & 0xffff) + (x >> 16);
-       return x;
-}
-
-static unsigned int do_csum(const unsigned char *buff, int len)
-{
-       int odd, count;
-       unsigned long result = 0;
-
-       if (len <= 0)
-               goto out;
-       odd = 1 & (unsigned long) buff;
-       if (odd) {
-               result = *buff;
-               len--;
-               buff++;
-       }
-       count = len >> 1;               /* nr of 16-bit words.. */
-       if (count) {
-               if (2 & (unsigned long) buff) {
-                       result += *(unsigned short *) buff;
-                       count--;
-                       len -= 2;
-                       buff += 2;
-               }
-               count >>= 1;            /* nr of 32-bit words.. */
-               if (count) {
-                       unsigned long carry = 0;
-                       do {
-                               unsigned long w = *(unsigned long *) buff;
-                               count--;
-                               buff += 4;
-                               result += carry;
-                               result += w;
-                               carry = (w > result);
-                       } while (count);
-                       result += carry;
-                       result = (result & 0xffff) + (result >> 16);
-               }
-               if (len & 2) {
-                       result += *(unsigned short *) buff;
-                       buff += 2;
-               }
-       }
-       if (len & 1)
-               result += (*buff << 8);
-       result = from32to16(result);
-       if (odd)
-               result = ((result >> 8) & 0xff) | ((result & 0xff) << 8);
-out:
-       return result;
-}
-
-/*
- *     This is a version of ip_compute_csum() optimized for IP headers,
- *     which always checksum on 4 octet boundaries.
- */
-__sum16 ip_fast_csum(const void *iph, unsigned int ihl)
-{
-       return (__force __sum16)~do_csum(iph, ihl*4);
-}
-EXPORT_SYMBOL(ip_fast_csum);
-
-/*
- * computes the checksum of a memory block at buff, length len,
- * and adds in "sum" (32-bit)
- *
- * returns a 32-bit number suitable for feeding into itself
- * or csum_tcpudp_magic
- *
- * this function must be called with even lengths, except
- * for the last fragment, which may be odd
- *
- * it's best to have buff aligned on a 32-bit boundary
- */
-__wsum csum_partial(const void *buff, int len, __wsum wsum)
-{
-       unsigned int sum = (__force unsigned int)wsum;
-       unsigned int result = do_csum(buff, len);
-
-       /* add in old sum, and carry.. */
-       result += sum;
-       if (sum > result)
-               result += 1;
-       return (__force __wsum)result;
-}
-EXPORT_SYMBOL(csum_partial);
-
-/*
- * this routine is used for miscellaneous IP-like checksums, mainly
- * in icmp.c
- */
-__sum16 ip_compute_csum(const void *buff, int len)
-{
-       return (__force __sum16)~do_csum(buff, len);
-}
-EXPORT_SYMBOL(ip_compute_csum);
-
-/*
- * copy from fs while checksumming, otherwise like csum_partial
- */
-__wsum
-csum_partial_copy_from_user(const void __user *src, void *dst, int len,
-                                               __wsum sum, int *csum_err)
-{
-       int missing;
-
-       missing = __copy_from_user(dst, src, len);
-       if (missing) {
-               memset(dst + len - missing, 0, missing);
-               *csum_err = -EFAULT;
-       } else
-               *csum_err = 0;
-
-       return csum_partial(dst, len, sum);
-}
-EXPORT_SYMBOL(csum_partial_copy_from_user);
-
-/*
- * copy from ds while checksumming, otherwise like csum_partial
- */
-__wsum
-csum_partial_copy(const void *src, void *dst, int len, __wsum sum)
-{
-       memcpy(dst, src, len);
-       return csum_partial(dst, len, sum);
-}
-EXPORT_SYMBOL(csum_partial_copy);
index b5a701cd71e08d86ceec067f011c98b4abe0f419..8d92c4efe9a4c8aa86ab5c123913524cfc2947a8 100644 (file)
@@ -80,15 +80,15 @@ void __init setup_memory(void)
                        memory_size = memory_end - memory_start;
                        PAGE_OFFSET = memory_start;
                        printk(KERN_INFO "%s: Main mem: 0x%x-0x%x, "
-                               "size 0x%08x\n", __func__, memory_start,
-                                               memory_end, memory_size);
+                               "size 0x%08x\n", __func__, (u32) memory_start,
+                                       (u32) memory_end, (u32) memory_size);
                        break;
                }
        }
 
        if (!memory_start || !memory_end) {
                panic("%s: Missing memory setting 0x%08x-0x%08x\n",
-                       __func__, memory_start, memory_end);
+                       __func__, (u32) memory_start, (u32) memory_end);
        }
 
        /* reservation of region where is the kernel */
index b29f0280d71282ad2f2cf142d96e1dc84e0a591a..3ca0fe1a91231441d9767fdcd56a9caafe203c83 100644 (file)
@@ -22,6 +22,26 @@ choice
 config MACH_ALCHEMY
        bool "Alchemy processor based machines"
 
+config AR7
+       bool "Texas Instruments AR7"
+       select BOOT_ELF32
+       select DMA_NONCOHERENT
+       select CEVT_R4K
+       select CSRC_R4K
+       select IRQ_CPU
+       select NO_EXCEPT_FILL
+       select SWAP_IO_SPACE
+       select SYS_HAS_CPU_MIPS32_R1
+       select SYS_HAS_EARLY_PRINTK
+       select SYS_SUPPORTS_32BIT_KERNEL
+       select SYS_SUPPORTS_LITTLE_ENDIAN
+       select GENERIC_GPIO
+       select GCD
+       select VLYNQ
+       help
+         Support for the Texas Instruments AR7 System-on-a-Chip
+         family: TNETD7100, 7200 and 7300.
+
 config BASLER_EXCITE
        bool "Basler eXcite smart camera"
        select CEVT_R4K
@@ -209,7 +229,7 @@ config MIPS_MALTA
        select SYS_SUPPORTS_64BIT_KERNEL
        select SYS_SUPPORTS_BIG_ENDIAN
        select SYS_SUPPORTS_LITTLE_ENDIAN
-       select SYS_SUPPORTS_MIPS_CMP if BROKEN  # because SYNC_R4K is broken
+       select SYS_SUPPORTS_MIPS_CMP
        select SYS_SUPPORTS_MULTITHREADING
        select SYS_SUPPORTS_SMARTMIPS
        help
@@ -247,6 +267,7 @@ config MACH_VR41XX
        select CEVT_R4K
        select CSRC_R4K
        select SYS_HAS_CPU_VR41XX
+       select ARCH_REQUIRE_GPIOLIB
 
 config NXP_STB220
        bool "NXP STB220 board"
@@ -601,6 +622,7 @@ config CAVIUM_OCTEON_SIMULATOR
        select SYS_SUPPORTS_64BIT_KERNEL
        select SYS_SUPPORTS_BIG_ENDIAN
        select SYS_SUPPORTS_HIGHMEM
+       select SYS_SUPPORTS_HOTPLUG_CPU
        select SYS_HAS_CPU_CAVIUM_OCTEON
        help
          The Octeon simulator is software performance model of the Cavium
@@ -615,6 +637,7 @@ config CAVIUM_OCTEON_REFERENCE_BOARD
        select SYS_SUPPORTS_64BIT_KERNEL
        select SYS_SUPPORTS_BIG_ENDIAN
        select SYS_SUPPORTS_HIGHMEM
+       select SYS_SUPPORTS_HOTPLUG_CPU
        select SYS_HAS_EARLY_PRINTK
        select SYS_HAS_CPU_CAVIUM_OCTEON
        select SWAP_IO_SPACE
@@ -784,8 +807,17 @@ config SYS_HAS_EARLY_PRINTK
        bool
 
 config HOTPLUG_CPU
+       bool "Support for hot-pluggable CPUs"
+       depends on SMP && HOTPLUG && SYS_SUPPORTS_HOTPLUG_CPU
+       help
+         Say Y here to allow turning CPUs off and on. CPUs can be
+         controlled through /sys/devices/system/cpu.
+         (Note: power management support will enable this option
+           automatically on SMP systems. )
+         Say N if you want to disable CPU hotplug.
+
+config SYS_SUPPORTS_HOTPLUG_CPU
        bool
-       default n
 
 config I8259
        bool
@@ -1624,7 +1656,7 @@ config MIPS_APSP_KSPD
 config MIPS_CMP
        bool "MIPS CMP framework support"
        depends on SYS_SUPPORTS_MIPS_CMP
-       select SYNC_R4K if BROKEN
+       select SYNC_R4K
        select SYS_SUPPORTS_SMP
        select SYS_SUPPORTS_SCHED_SMT if SMP
        select WEAK_ORDERING
@@ -2136,11 +2168,11 @@ menu "Power management options"
 
 config ARCH_HIBERNATION_POSSIBLE
        def_bool y
-       depends on !SMP
+       depends on SYS_SUPPORTS_HOTPLUG_CPU || !SMP
 
 config ARCH_SUSPEND_POSSIBLE
        def_bool y
-       depends on !SMP
+       depends on SYS_SUPPORTS_HOTPLUG_CPU || !SMP
 
 source "kernel/power/Kconfig"
 
index 807572a6a4d2df80335ee2334518c9ae5726841f..861da514a468a7cf84bdb0d32cd703921f7853e0 100644 (file)
@@ -172,6 +172,13 @@ libs-y                             += arch/mips/fw/lib/
 # Board-dependent options and extra files
 #
 
+#
+# Texas Instruments AR7
+#
+core-$(CONFIG_AR7)             += arch/mips/ar7/
+cflags-$(CONFIG_AR7)           += -I$(srctree)/arch/mips/include/asm/mach-ar7
+load-$(CONFIG_AR7)             += 0xffffffff94100000
+
 #
 # Acer PICA 61, Mips Magnum 4000 and Olivetti M700.
 #
diff --git a/arch/mips/ar7/Makefile b/arch/mips/ar7/Makefile
new file mode 100644 (file)
index 0000000..7435e44
--- /dev/null
@@ -0,0 +1,10 @@
+
+obj-y := \
+       prom.o \
+       setup.o \
+       memory.o \
+       irq.o \
+       time.o \
+       platform.o \
+       gpio.o \
+       clock.o
diff --git a/arch/mips/ar7/clock.c b/arch/mips/ar7/clock.c
new file mode 100644 (file)
index 0000000..27dc666
--- /dev/null
@@ -0,0 +1,440 @@
+/*
+ * Copyright (C) 2007 Felix Fietkau <nbd@openwrt.org>
+ * Copyright (C) 2007 Eugene Konev <ejka@openwrt.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/types.h>
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/gcd.h>
+#include <linux/io.h>
+
+#include <asm/addrspace.h>
+#include <asm/mach-ar7/ar7.h>
+
+#define BOOT_PLL_SOURCE_MASK   0x3
+#define CPU_PLL_SOURCE_SHIFT   16
+#define BUS_PLL_SOURCE_SHIFT   14
+#define USB_PLL_SOURCE_SHIFT   18
+#define DSP_PLL_SOURCE_SHIFT   22
+#define BOOT_PLL_SOURCE_AFE    0
+#define BOOT_PLL_SOURCE_BUS    0
+#define BOOT_PLL_SOURCE_REF    1
+#define BOOT_PLL_SOURCE_XTAL   2
+#define BOOT_PLL_SOURCE_CPU    3
+#define BOOT_PLL_BYPASS                0x00000020
+#define BOOT_PLL_ASYNC_MODE    0x02000000
+#define BOOT_PLL_2TO1_MODE     0x00008000
+
+#define TNETD7200_CLOCK_ID_CPU 0
+#define TNETD7200_CLOCK_ID_DSP 1
+#define TNETD7200_CLOCK_ID_USB 2
+
+#define TNETD7200_DEF_CPU_CLK  211000000
+#define TNETD7200_DEF_DSP_CLK  125000000
+#define TNETD7200_DEF_USB_CLK  48000000
+
+struct tnetd7300_clock {
+       u32 ctrl;
+#define PREDIV_MASK    0x001f0000
+#define PREDIV_SHIFT   16
+#define POSTDIV_MASK   0x0000001f
+       u32 unused1[3];
+       u32 pll;
+#define MUL_MASK       0x0000f000
+#define MUL_SHIFT      12
+#define PLL_MODE_MASK  0x00000001
+#define PLL_NDIV       0x00000800
+#define PLL_DIV                0x00000002
+#define PLL_STATUS     0x00000001
+       u32 unused2[3];
+};
+
+struct tnetd7300_clocks {
+       struct tnetd7300_clock bus;
+       struct tnetd7300_clock cpu;
+       struct tnetd7300_clock usb;
+       struct tnetd7300_clock dsp;
+};
+
+struct tnetd7200_clock {
+       u32 ctrl;
+       u32 unused1[3];
+#define DIVISOR_ENABLE_MASK 0x00008000
+       u32 mul;
+       u32 prediv;
+       u32 postdiv;
+       u32 postdiv2;
+       u32 unused2[6];
+       u32 cmd;
+       u32 status;
+       u32 cmden;
+       u32 padding[15];
+};
+
+struct tnetd7200_clocks {
+       struct tnetd7200_clock cpu;
+       struct tnetd7200_clock dsp;
+       struct tnetd7200_clock usb;
+};
+
+int ar7_cpu_clock = 150000000;
+EXPORT_SYMBOL(ar7_cpu_clock);
+int ar7_bus_clock = 125000000;
+EXPORT_SYMBOL(ar7_bus_clock);
+int ar7_dsp_clock;
+EXPORT_SYMBOL(ar7_dsp_clock);
+
+static void approximate(int base, int target, int *prediv,
+                       int *postdiv, int *mul)
+{
+       int i, j, k, freq, res = target;
+       for (i = 1; i <= 16; i++)
+               for (j = 1; j <= 32; j++)
+                       for (k = 1; k <= 32; k++) {
+                               freq = abs(base / j * i / k - target);
+                               if (freq < res) {
+                                       res = freq;
+                                       *mul = i;
+                                       *prediv = j;
+                                       *postdiv = k;
+                               }
+                       }
+}
+
+static void calculate(int base, int target, int *prediv, int *postdiv,
+       int *mul)
+{
+       int tmp_gcd, tmp_base, tmp_freq;
+
+       for (*prediv = 1; *prediv <= 32; (*prediv)++) {
+               tmp_base = base / *prediv;
+               tmp_gcd = gcd(target, tmp_base);
+               *mul = target / tmp_gcd;
+               *postdiv = tmp_base / tmp_gcd;
+               if ((*mul < 1) || (*mul >= 16))
+                       continue;
+               if ((*postdiv > 0) & (*postdiv <= 32))
+                       break;
+       }
+
+       if (base / *prediv * *mul / *postdiv != target) {
+               approximate(base, target, prediv, postdiv, mul);
+               tmp_freq = base / *prediv * *mul / *postdiv;
+               printk(KERN_WARNING
+                      "Adjusted requested frequency %d to %d\n",
+                      target, tmp_freq);
+       }
+
+       printk(KERN_DEBUG "Clocks: prediv: %d, postdiv: %d, mul: %d\n",
+              *prediv, *postdiv, *mul);
+}
+
+static int tnetd7300_dsp_clock(void)
+{
+       u32 didr1, didr2;
+       u8 rev = ar7_chip_rev();
+       didr1 = readl((void *)KSEG1ADDR(AR7_REGS_GPIO + 0x18));
+       didr2 = readl((void *)KSEG1ADDR(AR7_REGS_GPIO + 0x1c));
+       if (didr2 & (1 << 23))
+               return 0;
+       if ((rev >= 0x23) && (rev != 0x57))
+               return 250000000;
+       if ((((didr2 & 0x1fff) << 10) | ((didr1 & 0xffc00000) >> 22))
+           > 4208000)
+               return 250000000;
+       return 0;
+}
+
+static int tnetd7300_get_clock(u32 shift, struct tnetd7300_clock *clock,
+       u32 *bootcr, u32 bus_clock)
+{
+       int product;
+       int base_clock = AR7_REF_CLOCK;
+       u32 ctrl = readl(&clock->ctrl);
+       u32 pll = readl(&clock->pll);
+       int prediv = ((ctrl & PREDIV_MASK) >> PREDIV_SHIFT) + 1;
+       int postdiv = (ctrl & POSTDIV_MASK) + 1;
+       int divisor = prediv * postdiv;
+       int mul = ((pll & MUL_MASK) >> MUL_SHIFT) + 1;
+
+       switch ((*bootcr & (BOOT_PLL_SOURCE_MASK << shift)) >> shift) {
+       case BOOT_PLL_SOURCE_BUS:
+               base_clock = bus_clock;
+               break;
+       case BOOT_PLL_SOURCE_REF:
+               base_clock = AR7_REF_CLOCK;
+               break;
+       case BOOT_PLL_SOURCE_XTAL:
+               base_clock = AR7_XTAL_CLOCK;
+               break;
+       case BOOT_PLL_SOURCE_CPU:
+               base_clock = ar7_cpu_clock;
+               break;
+       }
+
+       if (*bootcr & BOOT_PLL_BYPASS)
+               return base_clock / divisor;
+
+       if ((pll & PLL_MODE_MASK) == 0)
+               return (base_clock >> (mul / 16 + 1)) / divisor;
+
+       if ((pll & (PLL_NDIV | PLL_DIV)) == (PLL_NDIV | PLL_DIV)) {
+               product = (mul & 1) ?
+                       (base_clock * mul) >> 1 :
+                       (base_clock * (mul - 1)) >> 2;
+               return product / divisor;
+       }
+
+       if (mul == 16)
+               return base_clock / divisor;
+
+       return base_clock * mul / divisor;
+}
+
+static void tnetd7300_set_clock(u32 shift, struct tnetd7300_clock *clock,
+       u32 *bootcr, u32 frequency)
+{
+       int prediv, postdiv, mul;
+       int base_clock = ar7_bus_clock;
+
+       switch ((*bootcr & (BOOT_PLL_SOURCE_MASK << shift)) >> shift) {
+       case BOOT_PLL_SOURCE_BUS:
+               base_clock = ar7_bus_clock;
+               break;
+       case BOOT_PLL_SOURCE_REF:
+               base_clock = AR7_REF_CLOCK;
+               break;
+       case BOOT_PLL_SOURCE_XTAL:
+               base_clock = AR7_XTAL_CLOCK;
+               break;
+       case BOOT_PLL_SOURCE_CPU:
+               base_clock = ar7_cpu_clock;
+               break;
+       }
+
+       calculate(base_clock, frequency, &prediv, &postdiv, &mul);
+
+       writel(((prediv - 1) << PREDIV_SHIFT) | (postdiv - 1), &clock->ctrl);
+       msleep(1);
+       writel(4, &clock->pll);
+       while (readl(&clock->pll) & PLL_STATUS)
+               ;
+       writel(((mul - 1) << MUL_SHIFT) | (0xff << 3) | 0x0e, &clock->pll);
+       msleep(75);
+}
+
+static void __init tnetd7300_init_clocks(void)
+{
+       u32 *bootcr = (u32 *)ioremap_nocache(AR7_REGS_DCL, 4);
+       struct tnetd7300_clocks *clocks =
+                                       ioremap_nocache(UR8_REGS_CLOCKS,
+                                       sizeof(struct tnetd7300_clocks));
+
+       ar7_bus_clock = tnetd7300_get_clock(BUS_PLL_SOURCE_SHIFT,
+               &clocks->bus, bootcr, AR7_AFE_CLOCK);
+
+       if (*bootcr & BOOT_PLL_ASYNC_MODE)
+               ar7_cpu_clock = tnetd7300_get_clock(CPU_PLL_SOURCE_SHIFT,
+                       &clocks->cpu, bootcr, AR7_AFE_CLOCK);
+       else
+               ar7_cpu_clock = ar7_bus_clock;
+
+       if (ar7_dsp_clock == 250000000)
+               tnetd7300_set_clock(DSP_PLL_SOURCE_SHIFT, &clocks->dsp,
+                       bootcr, ar7_dsp_clock);
+
+       iounmap(clocks);
+       iounmap(bootcr);
+}
+
+static int tnetd7200_get_clock(int base, struct tnetd7200_clock *clock,
+       u32 *bootcr, u32 bus_clock)
+{
+       int divisor = ((readl(&clock->prediv) & 0x1f) + 1) *
+               ((readl(&clock->postdiv) & 0x1f) + 1);
+
+       if (*bootcr & BOOT_PLL_BYPASS)
+               return base / divisor;
+
+       return base * ((readl(&clock->mul) & 0xf) + 1) / divisor;
+}
+
+
+static void tnetd7200_set_clock(int base, struct tnetd7200_clock *clock,
+       int prediv, int postdiv, int postdiv2, int mul, u32 frequency)
+{
+       printk(KERN_INFO
+               "Clocks: base = %d, frequency = %u, prediv = %d, "
+               "postdiv = %d, postdiv2 = %d, mul = %d\n",
+               base, frequency, prediv, postdiv, postdiv2, mul);
+
+       writel(0, &clock->ctrl);
+       writel(DIVISOR_ENABLE_MASK | ((prediv - 1) & 0x1F), &clock->prediv);
+       writel((mul - 1) & 0xF, &clock->mul);
+
+       while (readl(&clock->status) & 0x1)
+               ; /* nop */
+
+       writel(DIVISOR_ENABLE_MASK | ((postdiv - 1) & 0x1F), &clock->postdiv);
+
+       writel(readl(&clock->cmden) | 1, &clock->cmden);
+       writel(readl(&clock->cmd) | 1, &clock->cmd);
+
+       while (readl(&clock->status) & 0x1)
+               ; /* nop */
+
+       writel(DIVISOR_ENABLE_MASK | ((postdiv2 - 1) & 0x1F), &clock->postdiv2);
+
+       writel(readl(&clock->cmden) | 1, &clock->cmden);
+       writel(readl(&clock->cmd) | 1, &clock->cmd);
+
+       while (readl(&clock->status) & 0x1)
+               ; /* nop */
+
+       writel(readl(&clock->ctrl) | 1, &clock->ctrl);
+}
+
+static int tnetd7200_get_clock_base(int clock_id, u32 *bootcr)
+{
+       if (*bootcr & BOOT_PLL_ASYNC_MODE)
+               /* Async */
+               switch (clock_id) {
+               case TNETD7200_CLOCK_ID_DSP:
+                       return AR7_REF_CLOCK;
+               default:
+                       return AR7_AFE_CLOCK;
+               }
+       else
+               /* Sync */
+               if (*bootcr & BOOT_PLL_2TO1_MODE)
+                       /* 2:1 */
+                       switch (clock_id) {
+                       case TNETD7200_CLOCK_ID_DSP:
+                               return AR7_REF_CLOCK;
+                       default:
+                               return AR7_AFE_CLOCK;
+                       }
+               else
+                       /* 1:1 */
+                       return AR7_REF_CLOCK;
+}
+
+
+static void __init tnetd7200_init_clocks(void)
+{
+       u32 *bootcr = (u32 *)ioremap_nocache(AR7_REGS_DCL, 4);
+       struct tnetd7200_clocks *clocks =
+                                       ioremap_nocache(AR7_REGS_CLOCKS,
+                                       sizeof(struct tnetd7200_clocks));
+       int cpu_base, cpu_mul, cpu_prediv, cpu_postdiv;
+       int dsp_base, dsp_mul, dsp_prediv, dsp_postdiv;
+       int usb_base, usb_mul, usb_prediv, usb_postdiv;
+
+       cpu_base = tnetd7200_get_clock_base(TNETD7200_CLOCK_ID_CPU, bootcr);
+       dsp_base = tnetd7200_get_clock_base(TNETD7200_CLOCK_ID_DSP, bootcr);
+
+       if (*bootcr & BOOT_PLL_ASYNC_MODE) {
+               printk(KERN_INFO "Clocks: Async mode\n");
+
+               printk(KERN_INFO "Clocks: Setting DSP clock\n");
+               calculate(dsp_base, TNETD7200_DEF_DSP_CLK,
+                       &dsp_prediv, &dsp_postdiv, &dsp_mul);
+               ar7_bus_clock =
+                       ((dsp_base / dsp_prediv) * dsp_mul) / dsp_postdiv;
+               tnetd7200_set_clock(dsp_base, &clocks->dsp,
+                       dsp_prediv, dsp_postdiv * 2, dsp_postdiv, dsp_mul * 2,
+                       ar7_bus_clock);
+
+               printk(KERN_INFO "Clocks: Setting CPU clock\n");
+               calculate(cpu_base, TNETD7200_DEF_CPU_CLK, &cpu_prediv,
+                       &cpu_postdiv, &cpu_mul);
+               ar7_cpu_clock =
+                       ((cpu_base / cpu_prediv) * cpu_mul) / cpu_postdiv;
+               tnetd7200_set_clock(cpu_base, &clocks->cpu,
+                       cpu_prediv, cpu_postdiv, -1, cpu_mul,
+                       ar7_cpu_clock);
+
+       } else
+               if (*bootcr & BOOT_PLL_2TO1_MODE) {
+                       printk(KERN_INFO "Clocks: Sync 2:1 mode\n");
+
+                       printk(KERN_INFO "Clocks: Setting CPU clock\n");
+                       calculate(cpu_base, TNETD7200_DEF_CPU_CLK, &cpu_prediv,
+                               &cpu_postdiv, &cpu_mul);
+                       ar7_cpu_clock = ((cpu_base / cpu_prediv) * cpu_mul)
+                                                               / cpu_postdiv;
+                       tnetd7200_set_clock(cpu_base, &clocks->cpu,
+                               cpu_prediv, cpu_postdiv, -1, cpu_mul,
+                               ar7_cpu_clock);
+
+                       printk(KERN_INFO "Clocks: Setting DSP clock\n");
+                       calculate(dsp_base, TNETD7200_DEF_DSP_CLK, &dsp_prediv,
+                               &dsp_postdiv, &dsp_mul);
+                       ar7_bus_clock = ar7_cpu_clock / 2;
+                       tnetd7200_set_clock(dsp_base, &clocks->dsp,
+                               dsp_prediv, dsp_postdiv * 2, dsp_postdiv,
+                               dsp_mul * 2, ar7_bus_clock);
+               } else {
+                       printk(KERN_INFO "Clocks: Sync 1:1 mode\n");
+
+                       printk(KERN_INFO "Clocks: Setting DSP clock\n");
+                       calculate(dsp_base, TNETD7200_DEF_DSP_CLK, &dsp_prediv,
+                               &dsp_postdiv, &dsp_mul);
+                       ar7_bus_clock = ((dsp_base / dsp_prediv) * dsp_mul)
+                                                               / dsp_postdiv;
+                       tnetd7200_set_clock(dsp_base, &clocks->dsp,
+                               dsp_prediv, dsp_postdiv * 2, dsp_postdiv,
+                               dsp_mul * 2, ar7_bus_clock);
+
+                       ar7_cpu_clock = ar7_bus_clock;
+               }
+
+       printk(KERN_INFO "Clocks: Setting USB clock\n");
+       usb_base = ar7_bus_clock;
+       calculate(usb_base, TNETD7200_DEF_USB_CLK, &usb_prediv,
+               &usb_postdiv, &usb_mul);
+       tnetd7200_set_clock(usb_base, &clocks->usb,
+               usb_prediv, usb_postdiv, -1, usb_mul,
+               TNETD7200_DEF_USB_CLK);
+
+       ar7_dsp_clock = ar7_cpu_clock;
+
+       iounmap(clocks);
+       iounmap(bootcr);
+}
+
+int __init ar7_init_clocks(void)
+{
+       switch (ar7_chip_id()) {
+       case AR7_CHIP_7100:
+       case AR7_CHIP_7200:
+               tnetd7200_init_clocks();
+               break;
+       case AR7_CHIP_7300:
+               ar7_dsp_clock = tnetd7300_dsp_clock();
+               tnetd7300_init_clocks();
+               break;
+       default:
+               break;
+       }
+
+       return 0;
+}
+arch_initcall(ar7_init_clocks);
diff --git a/arch/mips/ar7/gpio.c b/arch/mips/ar7/gpio.c
new file mode 100644 (file)
index 0000000..74e14a3
--- /dev/null
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2007 Felix Fietkau <nbd@openwrt.org>
+ * Copyright (C) 2007 Eugene Konev <ejka@openwrt.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+#include <linux/module.h>
+
+#include <asm/mach-ar7/gpio.h>
+
+static const char *ar7_gpio_list[AR7_GPIO_MAX];
+
+int gpio_request(unsigned gpio, const char *label)
+{
+       if (gpio >= AR7_GPIO_MAX)
+               return -EINVAL;
+
+       if (ar7_gpio_list[gpio])
+               return -EBUSY;
+
+       if (label)
+               ar7_gpio_list[gpio] = label;
+       else
+               ar7_gpio_list[gpio] = "busy";
+
+       return 0;
+}
+EXPORT_SYMBOL(gpio_request);
+
+void gpio_free(unsigned gpio)
+{
+       BUG_ON(!ar7_gpio_list[gpio]);
+       ar7_gpio_list[gpio] = NULL;
+}
+EXPORT_SYMBOL(gpio_free);
diff --git a/arch/mips/ar7/irq.c b/arch/mips/ar7/irq.c
new file mode 100644 (file)
index 0000000..c781556
--- /dev/null
@@ -0,0 +1,176 @@
+/*
+ * Copyright (C) 2006,2007 Felix Fietkau <nbd@openwrt.org>
+ * Copyright (C) 2006,2007 Eugene Konev <ejka@openwrt.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+#include <linux/interrupt.h>
+#include <linux/io.h>
+
+#include <asm/irq_cpu.h>
+#include <asm/mipsregs.h>
+#include <asm/mach-ar7/ar7.h>
+
+#define EXCEPT_OFFSET  0x80
+#define PACE_OFFSET    0xA0
+#define CHNLS_OFFSET   0x200
+
+#define REG_OFFSET(irq, reg)   ((irq) / 32 * 0x4 + reg * 0x10)
+#define SEC_REG_OFFSET(reg)    (EXCEPT_OFFSET + reg * 0x8)
+#define SEC_SR_OFFSET          (SEC_REG_OFFSET(0))     /* 0x80 */
+#define CR_OFFSET(irq)         (REG_OFFSET(irq, 1))    /* 0x10 */
+#define SEC_CR_OFFSET          (SEC_REG_OFFSET(1))     /* 0x88 */
+#define ESR_OFFSET(irq)                (REG_OFFSET(irq, 2))    /* 0x20 */
+#define SEC_ESR_OFFSET         (SEC_REG_OFFSET(2))     /* 0x90 */
+#define ECR_OFFSET(irq)                (REG_OFFSET(irq, 3))    /* 0x30 */
+#define SEC_ECR_OFFSET         (SEC_REG_OFFSET(3))     /* 0x98 */
+#define PIR_OFFSET             (0x40)
+#define MSR_OFFSET             (0x44)
+#define PM_OFFSET(irq)         (REG_OFFSET(irq, 5))    /* 0x50 */
+#define TM_OFFSET(irq)         (REG_OFFSET(irq, 6))    /* 0x60 */
+
+#define REG(addr) ((u32 *)(KSEG1ADDR(AR7_REGS_IRQ) + addr))
+
+#define CHNL_OFFSET(chnl) (CHNLS_OFFSET + (chnl * 4))
+
+static int ar7_irq_base;
+
+static void ar7_unmask_irq(unsigned int irq)
+{
+       writel(1 << ((irq - ar7_irq_base) % 32),
+              REG(ESR_OFFSET(irq - ar7_irq_base)));
+}
+
+static void ar7_mask_irq(unsigned int irq)
+{
+       writel(1 << ((irq - ar7_irq_base) % 32),
+              REG(ECR_OFFSET(irq - ar7_irq_base)));
+}
+
+static void ar7_ack_irq(unsigned int irq)
+{
+       writel(1 << ((irq - ar7_irq_base) % 32),
+              REG(CR_OFFSET(irq - ar7_irq_base)));
+}
+
+static void ar7_unmask_sec_irq(unsigned int irq)
+{
+       writel(1 << (irq - ar7_irq_base - 40), REG(SEC_ESR_OFFSET));
+}
+
+static void ar7_mask_sec_irq(unsigned int irq)
+{
+       writel(1 << (irq - ar7_irq_base - 40), REG(SEC_ECR_OFFSET));
+}
+
+static void ar7_ack_sec_irq(unsigned int irq)
+{
+       writel(1 << (irq - ar7_irq_base - 40), REG(SEC_CR_OFFSET));
+}
+
+static struct irq_chip ar7_irq_type = {
+       .name = "AR7",
+       .unmask = ar7_unmask_irq,
+       .mask = ar7_mask_irq,
+       .ack = ar7_ack_irq
+};
+
+static struct irq_chip ar7_sec_irq_type = {
+       .name = "AR7",
+       .unmask = ar7_unmask_sec_irq,
+       .mask = ar7_mask_sec_irq,
+       .ack = ar7_ack_sec_irq,
+};
+
+static struct irqaction ar7_cascade_action = {
+       .handler = no_action,
+       .name = "AR7 cascade interrupt"
+};
+
+static void __init ar7_irq_init(int base)
+{
+       int i;
+       /*
+        * Disable interrupts and clear pending
+        */
+       writel(0xffffffff, REG(ECR_OFFSET(0)));
+       writel(0xff, REG(ECR_OFFSET(32)));
+       writel(0xffffffff, REG(SEC_ECR_OFFSET));
+       writel(0xffffffff, REG(CR_OFFSET(0)));
+       writel(0xff, REG(CR_OFFSET(32)));
+       writel(0xffffffff, REG(SEC_CR_OFFSET));
+
+       ar7_irq_base = base;
+
+       for (i = 0; i < 40; i++) {
+               writel(i, REG(CHNL_OFFSET(i)));
+               /* Primary IRQ's */
+               set_irq_chip_and_handler(base + i, &ar7_irq_type,
+                                        handle_level_irq);
+               /* Secondary IRQ's */
+               if (i < 32)
+                       set_irq_chip_and_handler(base + i + 40,
+                                                &ar7_sec_irq_type,
+                                                handle_level_irq);
+       }
+
+       setup_irq(2, &ar7_cascade_action);
+       setup_irq(ar7_irq_base, &ar7_cascade_action);
+       set_c0_status(IE_IRQ0);
+}
+
+void __init arch_init_irq(void)
+{
+       mips_cpu_irq_init();
+       ar7_irq_init(8);
+}
+
+static void ar7_cascade(void)
+{
+       u32 status;
+       int i, irq;
+
+       /* Primary IRQ's */
+       irq = readl(REG(PIR_OFFSET)) & 0x3f;
+       if (irq) {
+               do_IRQ(ar7_irq_base + irq);
+               return;
+       }
+
+       /* Secondary IRQ's are cascaded through primary '0' */
+       writel(1, REG(CR_OFFSET(irq)));
+       status = readl(REG(SEC_SR_OFFSET));
+       for (i = 0; i < 32; i++) {
+               if (status & 1) {
+                       do_IRQ(ar7_irq_base + i + 40);
+                       return;
+               }
+               status >>= 1;
+       }
+
+       spurious_interrupt();
+}
+
+asmlinkage void plat_irq_dispatch(void)
+{
+       unsigned int pending = read_c0_status() & read_c0_cause() & ST0_IM;
+       if (pending & STATUSF_IP7)              /* cpu timer */
+               do_IRQ(7);
+       else if (pending & STATUSF_IP2)         /* int0 hardware line */
+               ar7_cascade();
+       else
+               spurious_interrupt();
+}
diff --git a/arch/mips/ar7/memory.c b/arch/mips/ar7/memory.c
new file mode 100644 (file)
index 0000000..46fed44
--- /dev/null
@@ -0,0 +1,72 @@
+/*
+ * Copyright (C) 2007 Felix Fietkau <nbd@openwrt.org>
+ * Copyright (C) 2007 Eugene Konev <ejka@openwrt.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+#include <linux/bootmem.h>
+#include <linux/init.h>
+#include <linux/mm.h>
+#include <linux/module.h>
+#include <linux/pfn.h>
+#include <linux/proc_fs.h>
+#include <linux/string.h>
+#include <linux/swap.h>
+
+#include <asm/bootinfo.h>
+#include <asm/page.h>
+#include <asm/sections.h>
+
+#include <asm/mach-ar7/ar7.h>
+#include <asm/mips-boards/prom.h>
+
+static int __init memsize(void)
+{
+       u32 size = (64 << 20);
+       u32 *addr = (u32 *)KSEG1ADDR(AR7_SDRAM_BASE + size - 4);
+       u32 *kernel_end = (u32 *)KSEG1ADDR(CPHYSADDR((u32)&_end));
+       u32 *tmpaddr = addr;
+
+       while (tmpaddr > kernel_end) {
+               *tmpaddr = (u32)tmpaddr;
+               size >>= 1;
+               tmpaddr -= size >> 2;
+       }
+
+       do {
+               tmpaddr += size >> 2;
+               if (*tmpaddr != (u32)tmpaddr)
+                       break;
+               size <<= 1;
+       } while (size < (64 << 20));
+
+       writel(tmpaddr, &addr);
+
+       return size;
+}
+
+void __init prom_meminit(void)
+{
+       unsigned long pages;
+
+       pages = memsize() >> PAGE_SHIFT;
+       add_memory_region(PHYS_OFFSET, pages << PAGE_SHIFT,
+                         BOOT_MEM_RAM);
+}
+
+void __init prom_free_prom_memory(void)
+{
+       /* Nothing to free */
+}
diff --git a/arch/mips/ar7/platform.c b/arch/mips/ar7/platform.c
new file mode 100644 (file)
index 0000000..5422449
--- /dev/null
@@ -0,0 +1,555 @@
+/*
+ * Copyright (C) 2006,2007 Felix Fietkau <nbd@openwrt.org>
+ * Copyright (C) 2006,2007 Eugene Konev <ejka@openwrt.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+#include <linux/init.h>
+#include <linux/types.h>
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/dma-mapping.h>
+#include <linux/platform_device.h>
+#include <linux/mtd/physmap.h>
+#include <linux/serial.h>
+#include <linux/serial_8250.h>
+#include <linux/ioport.h>
+#include <linux/io.h>
+#include <linux/version.h>
+#include <linux/vlynq.h>
+#include <linux/leds.h>
+#include <linux/string.h>
+#include <linux/etherdevice.h>
+
+#include <asm/addrspace.h>
+#include <asm/mach-ar7/ar7.h>
+#include <asm/mach-ar7/gpio.h>
+#include <asm/mach-ar7/prom.h>
+
+struct plat_vlynq_data {
+       struct plat_vlynq_ops ops;
+       int gpio_bit;
+       int reset_bit;
+};
+
+
+static int vlynq_on(struct vlynq_device *dev)
+{
+       int result;
+       struct plat_vlynq_data *pdata = dev->dev.platform_data;
+
+       result = gpio_request(pdata->gpio_bit, "vlynq");
+       if (result)
+               goto out;
+
+       ar7_device_reset(pdata->reset_bit);
+
+       result = ar7_gpio_disable(pdata->gpio_bit);
+       if (result)
+               goto out_enabled;
+
+       result = ar7_gpio_enable(pdata->gpio_bit);
+       if (result)
+               goto out_enabled;
+
+       result = gpio_direction_output(pdata->gpio_bit, 0);
+       if (result)
+               goto out_gpio_enabled;
+
+       msleep(50);
+
+       gpio_set_value(pdata->gpio_bit, 1);
+       msleep(50);
+
+       return 0;
+
+out_gpio_enabled:
+       ar7_gpio_disable(pdata->gpio_bit);
+out_enabled:
+       ar7_device_disable(pdata->reset_bit);
+       gpio_free(pdata->gpio_bit);
+out:
+       return result;
+}
+
+static void vlynq_off(struct vlynq_device *dev)
+{
+       struct plat_vlynq_data *pdata = dev->dev.platform_data;
+       ar7_gpio_disable(pdata->gpio_bit);
+       gpio_free(pdata->gpio_bit);
+       ar7_device_disable(pdata->reset_bit);
+}
+
+static struct resource physmap_flash_resource = {
+       .name = "mem",
+       .flags = IORESOURCE_MEM,
+       .start = 0x10000000,
+       .end = 0x107fffff,
+};
+
+static struct resource cpmac_low_res[] = {
+       {
+               .name = "regs",
+               .flags = IORESOURCE_MEM,
+               .start = AR7_REGS_MAC0,
+               .end = AR7_REGS_MAC0 + 0x7ff,
+       },
+       {
+               .name = "irq",
+               .flags = IORESOURCE_IRQ,
+               .start = 27,
+               .end = 27,
+       },
+};
+
+static struct resource cpmac_high_res[] = {
+       {
+               .name = "regs",
+               .flags = IORESOURCE_MEM,
+               .start = AR7_REGS_MAC1,
+               .end = AR7_REGS_MAC1 + 0x7ff,
+       },
+       {
+               .name = "irq",
+               .flags = IORESOURCE_IRQ,
+               .start = 41,
+               .end = 41,
+       },
+};
+
+static struct resource vlynq_low_res[] = {
+       {
+               .name = "regs",
+               .flags = IORESOURCE_MEM,
+               .start = AR7_REGS_VLYNQ0,
+               .end = AR7_REGS_VLYNQ0 + 0xff,
+       },
+       {
+               .name = "irq",
+               .flags = IORESOURCE_IRQ,
+               .start = 29,
+               .end = 29,
+       },
+       {
+               .name = "mem",
+               .flags = IORESOURCE_MEM,
+               .start = 0x04000000,
+               .end = 0x04ffffff,
+       },
+       {
+               .name = "devirq",
+               .flags = IORESOURCE_IRQ,
+               .start = 80,
+               .end = 111,
+       },
+};
+
+static struct resource vlynq_high_res[] = {
+       {
+               .name = "regs",
+               .flags = IORESOURCE_MEM,
+               .start = AR7_REGS_VLYNQ1,
+               .end = AR7_REGS_VLYNQ1 + 0xff,
+       },
+       {
+               .name = "irq",
+               .flags = IORESOURCE_IRQ,
+               .start = 33,
+               .end = 33,
+       },
+       {
+               .name = "mem",
+               .flags = IORESOURCE_MEM,
+               .start = 0x0c000000,
+               .end = 0x0cffffff,
+       },
+       {
+               .name = "devirq",
+               .flags = IORESOURCE_IRQ,
+               .start = 112,
+               .end = 143,
+       },
+};
+
+static struct resource usb_res[] = {
+       {
+               .name = "regs",
+               .flags = IORESOURCE_MEM,
+               .start = AR7_REGS_USB,
+               .end = AR7_REGS_USB + 0xff,
+       },
+       {
+               .name = "irq",
+               .flags = IORESOURCE_IRQ,
+               .start = 32,
+               .end = 32,
+       },
+       {
+               .name = "mem",
+               .flags = IORESOURCE_MEM,
+               .start = 0x03400000,
+               .end = 0x034001fff,
+       },
+};
+
+static struct physmap_flash_data physmap_flash_data = {
+       .width = 2,
+};
+
+static struct plat_cpmac_data cpmac_low_data = {
+       .reset_bit = 17,
+       .power_bit = 20,
+       .phy_mask = 0x80000000,
+};
+
+static struct plat_cpmac_data cpmac_high_data = {
+       .reset_bit = 21,
+       .power_bit = 22,
+       .phy_mask = 0x7fffffff,
+};
+
+static struct plat_vlynq_data vlynq_low_data = {
+       .ops.on = vlynq_on,
+       .ops.off = vlynq_off,
+       .reset_bit = 20,
+       .gpio_bit = 18,
+};
+
+static struct plat_vlynq_data vlynq_high_data = {
+       .ops.on = vlynq_on,
+       .ops.off = vlynq_off,
+       .reset_bit = 16,
+       .gpio_bit = 19,
+};
+
+static struct platform_device physmap_flash = {
+       .id = 0,
+       .name = "physmap-flash",
+       .dev.platform_data = &physmap_flash_data,
+       .resource = &physmap_flash_resource,
+       .num_resources = 1,
+};
+
+static u64 cpmac_dma_mask = DMA_32BIT_MASK;
+static struct platform_device cpmac_low = {
+       .id = 0,
+       .name = "cpmac",
+       .dev = {
+               .dma_mask = &cpmac_dma_mask,
+               .coherent_dma_mask = DMA_32BIT_MASK,
+               .platform_data = &cpmac_low_data,
+       },
+       .resource = cpmac_low_res,
+       .num_resources = ARRAY_SIZE(cpmac_low_res),
+};
+
+static struct platform_device cpmac_high = {
+       .id = 1,
+       .name = "cpmac",
+       .dev = {
+               .dma_mask = &cpmac_dma_mask,
+               .coherent_dma_mask = DMA_32BIT_MASK,
+               .platform_data = &cpmac_high_data,
+       },
+       .resource = cpmac_high_res,
+       .num_resources = ARRAY_SIZE(cpmac_high_res),
+};
+
+static struct platform_device vlynq_low = {
+       .id = 0,
+       .name = "vlynq",
+       .dev.platform_data = &vlynq_low_data,
+       .resource = vlynq_low_res,
+       .num_resources = ARRAY_SIZE(vlynq_low_res),
+};
+
+static struct platform_device vlynq_high = {
+       .id = 1,
+       .name = "vlynq",
+       .dev.platform_data = &vlynq_high_data,
+       .resource = vlynq_high_res,
+       .num_resources = ARRAY_SIZE(vlynq_high_res),
+};
+
+
+static struct gpio_led default_leds[] = {
+       {
+               .name = "status",
+               .gpio = 8,
+               .active_low = 1,
+       },
+};
+
+static struct gpio_led dsl502t_leds[] = {
+       {
+               .name = "status",
+               .gpio = 9,
+               .active_low = 1,
+       },
+       {
+               .name = "ethernet",
+               .gpio = 7,
+               .active_low = 1,
+       },
+       {
+               .name = "usb",
+               .gpio = 12,
+               .active_low = 1,
+       },
+};
+
+static struct gpio_led dg834g_leds[] = {
+       {
+               .name = "ppp",
+               .gpio = 6,
+               .active_low = 1,
+       },
+       {
+               .name = "status",
+               .gpio = 7,
+               .active_low = 1,
+       },
+       {
+               .name = "adsl",
+               .gpio = 8,
+               .active_low = 1,
+       },
+       {
+               .name = "wifi",
+               .gpio = 12,
+               .active_low = 1,
+       },
+       {
+               .name = "power",
+               .gpio = 14,
+               .active_low = 1,
+               .default_trigger = "default-on",
+       },
+};
+
+static struct gpio_led fb_sl_leds[] = {
+       {
+               .name = "1",
+               .gpio = 7,
+       },
+       {
+               .name = "2",
+               .gpio = 13,
+               .active_low = 1,
+       },
+       {
+               .name = "3",
+               .gpio = 10,
+               .active_low = 1,
+       },
+       {
+               .name = "4",
+               .gpio = 12,
+               .active_low = 1,
+       },
+       {
+               .name = "5",
+               .gpio = 9,
+               .active_low = 1,
+       },
+};
+
+static struct gpio_led fb_fon_leds[] = {
+       {
+               .name = "1",
+               .gpio = 8,
+       },
+       {
+               .name = "2",
+               .gpio = 3,
+               .active_low = 1,
+       },
+       {
+               .name = "3",
+               .gpio = 5,
+       },
+       {
+               .name = "4",
+               .gpio = 4,
+               .active_low = 1,
+       },
+       {
+               .name = "5",
+               .gpio = 11,
+               .active_low = 1,
+       },
+};
+
+static struct gpio_led_platform_data ar7_led_data;
+
+static struct platform_device ar7_gpio_leds = {
+       .name = "leds-gpio",
+       .id = -1,
+       .dev = {
+               .platform_data = &ar7_led_data,
+       }
+};
+
+static struct platform_device ar7_udc = {
+       .id = -1,
+       .name = "ar7_udc",
+       .resource = usb_res,
+       .num_resources = ARRAY_SIZE(usb_res),
+};
+
+static inline unsigned char char2hex(char h)
+{
+       switch (h) {
+       case '0': case '1': case '2': case '3': case '4':
+       case '5': case '6': case '7': case '8': case '9':
+               return h - '0';
+       case 'A': case 'B': case 'C': case 'D': case 'E': case 'F':
+               return h - 'A' + 10;
+       case 'a': case 'b': case 'c': case 'd': case 'e': case 'f':
+               return h - 'a' + 10;
+       default:
+               return 0;
+       }
+}
+
+static void cpmac_get_mac(int instance, unsigned char *dev_addr)
+{
+       int i;
+       char name[5], default_mac[ETH_ALEN], *mac;
+
+       mac = NULL;
+       sprintf(name, "mac%c", 'a' + instance);
+       mac = prom_getenv(name);
+       if (!mac) {
+               sprintf(name, "mac%c", 'a');
+               mac = prom_getenv(name);
+       }
+       if (!mac) {
+               random_ether_addr(default_mac);
+               mac = default_mac;
+       }
+       for (i = 0; i < 6; i++)
+               dev_addr[i] = (char2hex(mac[i * 3]) << 4) +
+                       char2hex(mac[i * 3 + 1]);
+}
+
+static void __init detect_leds(void)
+{
+       char *prid, *usb_prod;
+
+       /* Default LEDs */
+       ar7_led_data.num_leds = ARRAY_SIZE(default_leds);
+       ar7_led_data.leds = default_leds;
+
+       /* FIXME: the whole thing is unreliable */
+       prid = prom_getenv("ProductID");
+       usb_prod = prom_getenv("usb_prod");
+
+       /* If we can't get the product id from PROM, use the default LEDs */
+       if (!prid)
+               return;
+
+       if (strstr(prid, "Fritz_Box_FON")) {
+               ar7_led_data.num_leds = ARRAY_SIZE(fb_fon_leds);
+               ar7_led_data.leds = fb_fon_leds;
+       } else if (strstr(prid, "Fritz_Box_")) {
+               ar7_led_data.num_leds = ARRAY_SIZE(fb_sl_leds);
+               ar7_led_data.leds = fb_sl_leds;
+       } else if ((!strcmp(prid, "AR7RD") || !strcmp(prid, "AR7DB"))
+               && usb_prod != NULL && strstr(usb_prod, "DSL-502T")) {
+               ar7_led_data.num_leds = ARRAY_SIZE(dsl502t_leds);
+               ar7_led_data.leds = dsl502t_leds;
+       } else if (strstr(prid, "DG834")) {
+               ar7_led_data.num_leds = ARRAY_SIZE(dg834g_leds);
+               ar7_led_data.leds = dg834g_leds;
+       }
+}
+
+static int __init ar7_register_devices(void)
+{
+       int res;
+       static struct uart_port uart_port[2];
+
+       memset(uart_port, 0, sizeof(struct uart_port) * 2);
+
+       uart_port[0].type = PORT_16550A;
+       uart_port[0].line = 0;
+       uart_port[0].irq = AR7_IRQ_UART0;
+       uart_port[0].uartclk = ar7_bus_freq() / 2;
+       uart_port[0].iotype = UPIO_MEM32;
+       uart_port[0].mapbase = AR7_REGS_UART0;
+       uart_port[0].membase = ioremap(uart_port[0].mapbase, 256);
+       uart_port[0].regshift = 2;
+       res = early_serial_setup(&uart_port[0]);
+       if (res)
+               return res;
+
+
+       /* Only TNETD73xx have a second serial port */
+       if (ar7_has_second_uart()) {
+               uart_port[1].type = PORT_16550A;
+               uart_port[1].line = 1;
+               uart_port[1].irq = AR7_IRQ_UART1;
+               uart_port[1].uartclk = ar7_bus_freq() / 2;
+               uart_port[1].iotype = UPIO_MEM32;
+               uart_port[1].mapbase = UR8_REGS_UART1;
+               uart_port[1].membase = ioremap(uart_port[1].mapbase, 256);
+               uart_port[1].regshift = 2;
+               res = early_serial_setup(&uart_port[1]);
+               if (res)
+                       return res;
+       }
+
+       res = platform_device_register(&physmap_flash);
+       if (res)
+               return res;
+
+       ar7_device_disable(vlynq_low_data.reset_bit);
+       res = platform_device_register(&vlynq_low);
+       if (res)
+               return res;
+
+       if (ar7_has_high_vlynq()) {
+               ar7_device_disable(vlynq_high_data.reset_bit);
+               res = platform_device_register(&vlynq_high);
+               if (res)
+                       return res;
+       }
+
+       if (ar7_has_high_cpmac()) {
+               cpmac_get_mac(1, cpmac_high_data.dev_addr);
+               res = platform_device_register(&cpmac_high);
+               if (res)
+                       return res;
+       } else {
+               cpmac_low_data.phy_mask = 0xffffffff;
+       }
+
+       cpmac_get_mac(0, cpmac_low_data.dev_addr);
+       res = platform_device_register(&cpmac_low);
+       if (res)
+               return res;
+
+       detect_leds();
+       res = platform_device_register(&ar7_gpio_leds);
+       if (res)
+               return res;
+
+       res = platform_device_register(&ar7_udc);
+
+       return res;
+}
+arch_initcall(ar7_register_devices);
diff --git a/arch/mips/ar7/prom.c b/arch/mips/ar7/prom.c
new file mode 100644 (file)
index 0000000..a320bce
--- /dev/null
@@ -0,0 +1,297 @@
+/*
+ * Carsten Langgaard, carstenl@mips.com
+ * Copyright (C) 1999,2000 MIPS Technologies, Inc.  All rights reserved.
+ *
+ *  This program is free software; you can distribute it and/or modify it
+ *  under the terms of the GNU General Public License (Version 2) as
+ *  published by the Free Software Foundation.
+ *
+ *  This program is distributed in the hope it will be useful, but WITHOUT
+ *  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ *  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ *  for more details.
+ *
+ *  You should have received a copy of the GNU General Public License along
+ *  with this program; if not, write to the Free Software Foundation, Inc.,
+ *  59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
+ *
+ * Putting things on the screen/serial line using YAMONs facilities.
+ */
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/serial_reg.h>
+#include <linux/spinlock.h>
+#include <linux/module.h>
+#include <linux/string.h>
+#include <linux/io.h>
+#include <asm/bootinfo.h>
+
+#include <asm/mach-ar7/ar7.h>
+#include <asm/mach-ar7/prom.h>
+
+#define MAX_ENTRY 80
+
+struct env_var {
+       char *name;
+       char *value;
+};
+
+static struct env_var adam2_env[MAX_ENTRY];
+
+char *prom_getenv(const char *name)
+{
+       int i;
+       for (i = 0; (i < MAX_ENTRY) && adam2_env[i].name; i++)
+               if (!strcmp(name, adam2_env[i].name))
+                       return adam2_env[i].value;
+
+       return NULL;
+}
+EXPORT_SYMBOL(prom_getenv);
+
+char * __init prom_getcmdline(void)
+{
+       return &(arcs_cmdline[0]);
+}
+
+static void  __init ar7_init_cmdline(int argc, char *argv[])
+{
+       char *cp;
+       int actr;
+
+       actr = 1; /* Always ignore argv[0] */
+
+       cp = &(arcs_cmdline[0]);
+       while (actr < argc) {
+               strcpy(cp, argv[actr]);
+               cp += strlen(argv[actr]);
+               *cp++ = ' ';
+               actr++;
+       }
+       if (cp != &(arcs_cmdline[0])) {
+               /* get rid of trailing space */
+               --cp;
+               *cp = '\0';
+       }
+}
+
+struct psbl_rec {
+       u32 psbl_size;
+       u32 env_base;
+       u32 env_size;
+       u32 ffs_base;
+       u32 ffs_size;
+};
+
+static __initdata char psp_env_version[] = "TIENV0.8";
+
+struct psp_env_chunk {
+       u8 num;
+       u8 ctrl;
+       u16 csum;
+       u8 len;
+       char data[11];
+} __attribute__ ((packed));
+
+struct psp_var_map_entry {
+       u8 num;
+       char *value;
+};
+
+static struct psp_var_map_entry psp_var_map[] = {
+       { 1, "cpufrequency" },
+       { 2, "memsize" },
+       { 3, "flashsize" },
+       { 4, "modetty0" },
+       { 5, "modetty1" },
+       { 8, "maca" },
+       { 9, "macb" },
+       { 28, "sysfrequency" },
+       { 38, "mipsfrequency" },
+};
+
+/*
+
+Well-known variable (num is looked up in table above for matching variable name)
+Example: cpufrequency=211968000
++----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+---
+| 01 |CTRL|CHECKSUM | 01 | _2 | _1 | _1 | _9 | _6 | _8 | _0 | _0 | _0 | \0 | FF
++----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+---
+
+Name=Value pair in a single chunk
+Example: NAME=VALUE
++----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+---
+| 00 |CTRL|CHECKSUM | 01 | _N | _A | _M | _E | _0 | _V | _A | _L | _U | _E | \0
++----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+---
+
+Name=Value pair in 2 chunks (len is the number of chunks)
+Example: bootloaderVersion=1.3.7.15
++----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+---
+| 00 |CTRL|CHECKSUM | 02 | _b | _o | _o | _t | _l | _o | _a | _d | _e | _r | _V
++----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+---
+| _e | _r | _s | _i | _o | _n | \0 | _1 | _. | _3 | _. | _7 | _. | _1 | _5 | \0
++----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+---
+
+Data is padded with 0xFF
+
+*/
+
+#define PSP_ENV_SIZE  4096
+
+static char psp_env_data[PSP_ENV_SIZE] = { 0, };
+
+static char * __init lookup_psp_var_map(u8 num)
+{
+       int i;
+
+       for (i = 0; i < sizeof(psp_var_map); i++)
+               if (psp_var_map[i].num == num)
+                       return psp_var_map[i].value;
+
+       return NULL;
+}
+
+static void __init add_adam2_var(char *name, char *value)
+{
+       int i;
+       for (i = 0; i < MAX_ENTRY; i++) {
+               if (!adam2_env[i].name) {
+                       adam2_env[i].name = name;
+                       adam2_env[i].value = value;
+                       return;
+               } else if (!strcmp(adam2_env[i].name, name)) {
+                       adam2_env[i].value = value;
+                       return;
+               }
+       }
+}
+
+static int __init parse_psp_env(void *psp_env_base)
+{
+       int i, n;
+       char *name, *value;
+       struct psp_env_chunk *chunks = (struct psp_env_chunk *)psp_env_data;
+
+       memcpy_fromio(chunks, psp_env_base, PSP_ENV_SIZE);
+
+       i = 1;
+       n = PSP_ENV_SIZE / sizeof(struct psp_env_chunk);
+       while (i < n) {
+               if ((chunks[i].num == 0xff) || ((i + chunks[i].len) > n))
+                       break;
+               value = chunks[i].data;
+               if (chunks[i].num) {
+                       name = lookup_psp_var_map(chunks[i].num);
+               } else {
+                       name = value;
+                       value += strlen(name) + 1;
+               }
+               if (name)
+                       add_adam2_var(name, value);
+               i += chunks[i].len;
+       }
+       return 0;
+}
+
+static void __init ar7_init_env(struct env_var *env)
+{
+       int i;
+       struct psbl_rec *psbl = (struct psbl_rec *)(KSEG1ADDR(0x14000300));
+       void *psp_env = (void *)KSEG1ADDR(psbl->env_base);
+
+       if (strcmp(psp_env, psp_env_version) == 0) {
+               parse_psp_env(psp_env);
+       } else {
+               for (i = 0; i < MAX_ENTRY; i++, env++)
+                       if (env->name)
+                               add_adam2_var(env->name, env->value);
+       }
+}
+
+static void __init console_config(void)
+{
+#ifdef CONFIG_SERIAL_8250_CONSOLE
+       char console_string[40];
+       int baud = 0;
+       char parity = '\0', bits = '\0', flow = '\0';
+       char *s, *p;
+
+       if (strstr(prom_getcmdline(), "console="))
+               return;
+
+#ifdef CONFIG_KGDB
+       if (!strstr(prom_getcmdline(), "nokgdb")) {
+               strcat(prom_getcmdline(), " console=kgdb");
+               kgdb_enabled = 1;
+               return;
+       }
+#endif
+
+       s = prom_getenv("modetty0");
+       if (s) {
+               baud = simple_strtoul(s, &p, 10);
+               s = p;
+               if (*s == ',')
+                       s++;
+               if (*s)
+                       parity = *s++;
+               if (*s == ',')
+                       s++;
+               if (*s)
+                       bits = *s++;
+               if (*s == ',')
+                       s++;
+               if (*s == 'h')
+                       flow = 'r';
+       }
+
+       if (baud == 0)
+               baud = 38400;
+       if (parity != 'n' && parity != 'o' && parity != 'e')
+               parity = 'n';
+       if (bits != '7' && bits != '8')
+               bits = '8';
+
+       if (flow == 'r')
+               sprintf(console_string, " console=ttyS0,%d%c%c%c", baud,
+                       parity, bits, flow);
+       else
+               sprintf(console_string, " console=ttyS0,%d%c%c", baud, parity,
+                       bits);
+       strcat(prom_getcmdline(), console_string);
+#endif
+}
+
+void __init prom_init(void)
+{
+       ar7_init_cmdline(fw_arg0, (char **)fw_arg1);
+       ar7_init_env((struct env_var *)fw_arg2);
+       console_config();
+}
+
+#define PORT(offset) (KSEG1ADDR(AR7_REGS_UART0 + (offset * 4)))
+static inline unsigned int serial_in(int offset)
+{
+       return readl((void *)PORT(offset));
+}
+
+static inline void serial_out(int offset, int value)
+{
+       writel(value, (void *)PORT(offset));
+}
+
+char prom_getchar(void)
+{
+       while (!(serial_in(UART_LSR) & UART_LSR_DR))
+               ;
+       return serial_in(UART_RX);
+}
+
+int prom_putchar(char c)
+{
+       while ((serial_in(UART_LSR) & UART_LSR_TEMT) == 0)
+               ;
+       serial_out(UART_TX, c);
+       return 1;
+}
+
diff --git a/arch/mips/ar7/setup.c b/arch/mips/ar7/setup.c
new file mode 100644 (file)
index 0000000..6ebb5f1
--- /dev/null
@@ -0,0 +1,94 @@
+/*
+ * Carsten Langgaard, carstenl@mips.com
+ * Copyright (C) 2000 MIPS Technologies, Inc.  All rights reserved.
+ *
+ *  This program is free software; you can distribute it and/or modify it
+ *  under the terms of the GNU General Public License (Version 2) as
+ *  published by the Free Software Foundation.
+ *
+ *  This program is distributed in the hope it will be useful, but WITHOUT
+ *  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ *  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ *  for more details.
+ *
+ *  You should have received a copy of the GNU General Public License along
+ *  with this program; if not, write to the Free Software Foundation, Inc.,
+ *  59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
+ */
+#include <linux/version.h>
+#include <linux/init.h>
+#include <linux/ioport.h>
+#include <linux/pm.h>
+#include <linux/time.h>
+
+#include <asm/reboot.h>
+#include <asm/mach-ar7/ar7.h>
+#include <asm/mach-ar7/prom.h>
+
+static void ar7_machine_restart(char *command)
+{
+       u32 *softres_reg = ioremap(AR7_REGS_RESET +
+                                         AR7_RESET_SOFTWARE, 1);
+       writel(1, softres_reg);
+}
+
+static void ar7_machine_halt(void)
+{
+       while (1)
+               ;
+}
+
+static void ar7_machine_power_off(void)
+{
+       u32 *power_reg = (u32 *)ioremap(AR7_REGS_POWER, 1);
+       u32 power_state = readl(power_reg) | (3 << 30);
+       writel(power_state, power_reg);
+       ar7_machine_halt();
+}
+
+const char *get_system_type(void)
+{
+       u16 chip_id = ar7_chip_id();
+       switch (chip_id) {
+       case AR7_CHIP_7300:
+               return "TI AR7 (TNETD7300)";
+       case AR7_CHIP_7100:
+               return "TI AR7 (TNETD7100)";
+       case AR7_CHIP_7200:
+               return "TI AR7 (TNETD7200)";
+       default:
+               return "TI AR7 (Unknown)";
+       }
+}
+
+static int __init ar7_init_console(void)
+{
+       return 0;
+}
+console_initcall(ar7_init_console);
+
+/*
+ * Initializes basic routines and structures pointers, memory size (as
+ * given by the bios and saves the command line.
+ */
+
+void __init plat_mem_setup(void)
+{
+       unsigned long io_base;
+
+       _machine_restart = ar7_machine_restart;
+       _machine_halt = ar7_machine_halt;
+       pm_power_off = ar7_machine_power_off;
+       panic_timeout = 3;
+
+       io_base = (unsigned long)ioremap(AR7_REGS_BASE, 0x10000);
+       if (!io_base)
+               panic("Can't remap IO base!\n");
+       set_io_port_base(io_base);
+
+       prom_meminit();
+
+       printk(KERN_INFO "%s, ID: 0x%04x, Revision: 0x%02x\n",
+                                       get_system_type(),
+               ar7_chip_id(), ar7_chip_rev());
+}
diff --git a/arch/mips/ar7/time.c b/arch/mips/ar7/time.c
new file mode 100644 (file)
index 0000000..a1fba89
--- /dev/null
@@ -0,0 +1,30 @@
+/*
+ * Carsten Langgaard, carstenl@mips.com
+ * Copyright (C) 1999,2000 MIPS Technologies, Inc.  All rights reserved.
+ *
+ *  This program is free software; you can distribute it and/or modify it
+ *  under the terms of the GNU General Public License (Version 2) as
+ *  published by the Free Software Foundation.
+ *
+ *  This program is distributed in the hope it will be useful, but WITHOUT
+ *  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ *  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ *  for more details.
+ *
+ *  You should have received a copy of the GNU General Public License along
+ *  with this program; if not, write to the Free Software Foundation, Inc.,
+ *  59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
+ *
+ * Setting up the clock on the MIPS boards.
+ */
+
+#include <linux/init.h>
+#include <linux/time.h>
+
+#include <asm/time.h>
+#include <asm/mach-ar7/ar7.h>
+
+void __init plat_time_init(void)
+{
+       mips_hpt_frequency = ar7_cpu_freq() / 2;
+}
index 7c0528b0e34ccabd1668bcd5c3b4436076f00e76..d6903c3f3d513c0cd0990138aaada2445d27562b 100644 (file)
@@ -14,9 +14,5 @@ obj-y += dma-octeon.o flash_setup.o
 obj-y += octeon-memcpy.o
 
 obj-$(CONFIG_SMP)                     += smp.o
-obj-$(CONFIG_PCI)                     += pci-common.o
-obj-$(CONFIG_PCI)                     += pci.o
-obj-$(CONFIG_PCI)                     += pcie.o
-obj-$(CONFIG_PCI_MSI)                 += msi.o
 
 EXTRA_CFLAGS += -Werror
index 627c162a615980df13bffda63dc8517d66ac5695..4b92bfc662db0b629e253a92336a9396b41555ac 100644 (file)
@@ -29,7 +29,7 @@
 #include <dma-coherence.h>
 
 #ifdef CONFIG_PCI
-#include "pci-common.h"
+#include <asm/octeon/pci-octeon.h>
 #endif
 
 #define BAR2_PCI_ADDRESS 0x8000000000ul
index 8dfa009e00706a6a48e3b0d646c16e62021ac36d..384f1842bfb1a4c0743979f55ec40b07b4172abb 100644 (file)
@@ -7,7 +7,7 @@
  */
 #include <linux/irq.h>
 #include <linux/interrupt.h>
-#include <linux/hardirq.h>
+#include <linux/smp.h>
 
 #include <asm/octeon/octeon.h>
 #include <asm/octeon/cvmx-pexp-defs.h>
@@ -501,3 +501,62 @@ asmlinkage void plat_irq_dispatch(void)
                }
        }
 }
+
+#ifdef CONFIG_HOTPLUG_CPU
+static int is_irq_enabled_on_cpu(unsigned int irq, unsigned int cpu)
+{
+       unsigned int isset;
+#ifdef CONFIG_SMP
+       int coreid = cpu_logical_map(cpu);
+#else
+       int coreid = cvmx_get_core_num();
+#endif
+       int bit = (irq < OCTEON_IRQ_WDOG0) ?
+               irq - OCTEON_IRQ_WORKQ0 : irq - OCTEON_IRQ_WDOG0;
+       if (irq < 64) {
+               isset = (cvmx_read_csr(CVMX_CIU_INTX_EN0(coreid * 2)) &
+                       (1ull << bit)) >> bit;
+       } else {
+              isset = (cvmx_read_csr(CVMX_CIU_INTX_EN1(coreid * 2 + 1)) &
+                       (1ull << bit)) >> bit;
+       }
+       return isset;
+}
+
+void fixup_irqs(void)
+{
+       int irq;
+
+       for (irq = OCTEON_IRQ_SW0; irq <= OCTEON_IRQ_TIMER; irq++)
+               octeon_irq_core_disable_local(irq);
+
+       for (irq = OCTEON_IRQ_WORKQ0; irq <= OCTEON_IRQ_GPIO15; irq++) {
+               if (is_irq_enabled_on_cpu(irq, smp_processor_id())) {
+                       /* ciu irq migrates to next cpu */
+                       octeon_irq_chip_ciu0.disable(irq);
+                       octeon_irq_ciu0_set_affinity(irq, &cpu_online_map);
+               }
+       }
+
+#if 0
+       for (irq = OCTEON_IRQ_MBOX0; irq <= OCTEON_IRQ_MBOX1; irq++)
+               octeon_irq_mailbox_mask(irq);
+#endif
+       for (irq = OCTEON_IRQ_UART0; irq <= OCTEON_IRQ_BOOTDMA; irq++) {
+               if (is_irq_enabled_on_cpu(irq, smp_processor_id())) {
+                       /* ciu irq migrates to next cpu */
+                       octeon_irq_chip_ciu0.disable(irq);
+                       octeon_irq_ciu0_set_affinity(irq, &cpu_online_map);
+               }
+       }
+
+       for (irq = OCTEON_IRQ_UART2; irq <= OCTEON_IRQ_RESERVED135; irq++) {
+               if (is_irq_enabled_on_cpu(irq, smp_processor_id())) {
+                       /* ciu irq migrates to next cpu */
+                       octeon_irq_chip_ciu1.disable(irq);
+                       octeon_irq_ciu1_set_affinity(irq, &cpu_online_map);
+               }
+       }
+}
+
+#endif /* CONFIG_HOTPLUG_CPU */
diff --git a/arch/mips/cavium-octeon/octeon_boot.h b/arch/mips/cavium-octeon/octeon_boot.h
new file mode 100644 (file)
index 0000000..0f7f84a
--- /dev/null
@@ -0,0 +1,70 @@
+/*
+ * (C) Copyright 2004, 2005 Cavium Networks
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#ifndef __OCTEON_BOOT_H__
+#define __OCTEON_BOOT_H__
+
+#include <linux/types.h>
+
+struct boot_init_vector {
+       uint32_t stack_addr;
+       uint32_t code_addr;
+       uint32_t app_start_func_addr;
+       uint32_t k0_val;
+       uint32_t flags;
+       uint32_t boot_info_addr;
+       uint32_t pad;
+       uint32_t pad2;
+};
+
+/* similar to bootloader's linux_app_boot_info but without global data */
+struct linux_app_boot_info {
+       uint32_t labi_signature;
+       uint32_t start_core0_addr;
+       uint32_t avail_coremask;
+       uint32_t pci_console_active;
+       uint32_t icache_prefetch_disable;
+       uint32_t InitTLBStart_addr;
+       uint32_t start_app_addr;
+       uint32_t cur_exception_base;
+       uint32_t no_mark_private_data;
+       uint32_t compact_flash_common_base_addr;
+       uint32_t compact_flash_attribute_base_addr;
+       uint32_t led_display_base_addr;
+};
+
+/* If not to copy a lot of bootloader's structures
+   here is only offset of requested member */
+#define AVAIL_COREMASK_OFFSET_IN_LINUX_APP_BOOT_BLOCK    0x765c
+
+/* hardcoded in bootloader */
+#define  LABI_ADDR_IN_BOOTLOADER                         0x700
+
+#define LINUX_APP_BOOT_BLOCK_NAME "linux-app-boot"
+
+#define LABI_SIGNATURE 0xAABBCCDD
+
+/*  from uboot-headers/octeon_mem_map.h */
+#define EXCEPTION_BASE_INCR     (4 * 1024)
+                              /* Increment size for exception base addresses (4k minimum) */
+#define EXCEPTION_BASE_BASE     0
+#define BOOTLOADER_PRIV_DATA_BASE       (EXCEPTION_BASE_BASE + 0x800)
+#define BOOTLOADER_BOOT_VECTOR          (BOOTLOADER_PRIV_DATA_BASE)
+
+#endif /* __OCTEON_BOOT_H__ */
diff --git a/arch/mips/cavium-octeon/pci-common.c b/arch/mips/cavium-octeon/pci-common.c
deleted file mode 100644 (file)
index cd029f8..0000000
+++ /dev/null
@@ -1,137 +0,0 @@
-/*
- * This file is subject to the terms and conditions of the GNU General Public
- * License.  See the file "COPYING" in the main directory of this archive
- * for more details.
- *
- * Copyright (C) 2005-2007 Cavium Networks
- */
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/pci.h>
-#include <linux/interrupt.h>
-#include <linux/time.h>
-#include <linux/delay.h>
-#include "pci-common.h"
-
-typeof(pcibios_map_irq) *octeon_pcibios_map_irq;
-enum octeon_dma_bar_type octeon_dma_bar_type = OCTEON_DMA_BAR_TYPE_INVALID;
-
-/**
- * Map a PCI device to the appropriate interrupt line
- *
- * @param dev    The Linux PCI device structure for the device to map
- * @param slot   The slot number for this device on __BUS 0__. Linux
- *               enumerates through all the bridges and figures out the
- *               slot on Bus 0 where this device eventually hooks to.
- * @param pin    The PCI interrupt pin read from the device, then swizzled
- *               as it goes through each bridge.
- * @return Interrupt number for the device
- */
-int __init pcibios_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
-{
-       if (octeon_pcibios_map_irq)
-               return octeon_pcibios_map_irq(dev, slot, pin);
-       else
-               panic("octeon_pcibios_map_irq doesn't point to a "
-                     "pcibios_map_irq() function");
-}
-
-
-/**
- * Called to perform platform specific PCI setup
- *
- * @param dev
- * @return
- */
-int pcibios_plat_dev_init(struct pci_dev *dev)
-{
-       uint16_t config;
-       uint32_t dconfig;
-       int pos;
-       /*
-        * Force the Cache line setting to 64 bytes. The standard
-        * Linux bus scan doesn't seem to set it. Octeon really has
-        * 128 byte lines, but Intel bridges get really upset if you
-        * try and set values above 64 bytes. Value is specified in
-        * 32bit words.
-        */
-       pci_write_config_byte(dev, PCI_CACHE_LINE_SIZE, 64 / 4);
-       /* Set latency timers for all devices */
-       pci_write_config_byte(dev, PCI_LATENCY_TIMER, 48);
-
-       /* Enable reporting System errors and parity errors on all devices */
-       /* Enable parity checking and error reporting */
-       pci_read_config_word(dev, PCI_COMMAND, &config);
-       config |= PCI_COMMAND_PARITY | PCI_COMMAND_SERR;
-       pci_write_config_word(dev, PCI_COMMAND, config);
-
-       if (dev->subordinate) {
-               /* Set latency timers on sub bridges */
-               pci_write_config_byte(dev, PCI_SEC_LATENCY_TIMER, 48);
-               /* More bridge error detection */
-               pci_read_config_word(dev, PCI_BRIDGE_CONTROL, &config);
-               config |= PCI_BRIDGE_CTL_PARITY | PCI_BRIDGE_CTL_SERR;
-               pci_write_config_word(dev, PCI_BRIDGE_CONTROL, config);
-       }
-
-       /* Enable the PCIe normal error reporting */
-       pos = pci_find_capability(dev, PCI_CAP_ID_EXP);
-       if (pos) {
-               /* Update Device Control */
-               pci_read_config_word(dev, pos + PCI_EXP_DEVCTL, &config);
-               /* Correctable Error Reporting */
-               config |= PCI_EXP_DEVCTL_CERE;
-               /* Non-Fatal Error Reporting */
-               config |= PCI_EXP_DEVCTL_NFERE;
-               /* Fatal Error Reporting */
-               config |= PCI_EXP_DEVCTL_FERE;
-               /* Unsupported Request */
-               config |= PCI_EXP_DEVCTL_URRE;
-               pci_write_config_word(dev, pos + PCI_EXP_DEVCTL, config);
-       }
-
-       /* Find the Advanced Error Reporting capability */
-       pos = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_ERR);
-       if (pos) {
-               /* Clear Uncorrectable Error Status */
-               pci_read_config_dword(dev, pos + PCI_ERR_UNCOR_STATUS,
-                                     &dconfig);
-               pci_write_config_dword(dev, pos + PCI_ERR_UNCOR_STATUS,
-                                      dconfig);
-               /* Enable reporting of all uncorrectable errors */
-               /* Uncorrectable Error Mask - turned on bits disable errors */
-               pci_write_config_dword(dev, pos + PCI_ERR_UNCOR_MASK, 0);
-               /*
-                * Leave severity at HW default. This only controls if
-                * errors are reported as uncorrectable or
-                * correctable, not if the error is reported.
-                */
-               /* PCI_ERR_UNCOR_SEVER - Uncorrectable Error Severity */
-               /* Clear Correctable Error Status */
-               pci_read_config_dword(dev, pos + PCI_ERR_COR_STATUS, &dconfig);
-               pci_write_config_dword(dev, pos + PCI_ERR_COR_STATUS, dconfig);
-               /* Enable reporting of all correctable errors */
-               /* Correctable Error Mask - turned on bits disable errors */
-               pci_write_config_dword(dev, pos + PCI_ERR_COR_MASK, 0);
-               /* Advanced Error Capabilities */
-               pci_read_config_dword(dev, pos + PCI_ERR_CAP, &dconfig);
-               /* ECRC Generation Enable */
-               if (config & PCI_ERR_CAP_ECRC_GENC)
-                       config |= PCI_ERR_CAP_ECRC_GENE;
-               /* ECRC Check Enable */
-               if (config & PCI_ERR_CAP_ECRC_CHKC)
-                       config |= PCI_ERR_CAP_ECRC_CHKE;
-               pci_write_config_dword(dev, pos + PCI_ERR_CAP, dconfig);
-               /* PCI_ERR_HEADER_LOG - Header Log Register (16 bytes) */
-               /* Report all errors to the root complex */
-               pci_write_config_dword(dev, pos + PCI_ERR_ROOT_COMMAND,
-                                      PCI_ERR_ROOT_CMD_COR_EN |
-                                      PCI_ERR_ROOT_CMD_NONFATAL_EN |
-                                      PCI_ERR_ROOT_CMD_FATAL_EN);
-               /* Clear the Root status register */
-               pci_read_config_dword(dev, pos + PCI_ERR_ROOT_STATUS, &dconfig);
-               pci_write_config_dword(dev, pos + PCI_ERR_ROOT_STATUS, dconfig);
-       }
-
-       return 0;
-}
index 5f4e49ba4713fcc1fdd3040074e04acd24cf255e..da559249cc2fae44161c5322ce7cfd61b3cac328 100644 (file)
@@ -13,6 +13,7 @@
 #include <linux/io.h>
 #include <linux/irq.h>
 #include <linux/serial.h>
+#include <linux/smp.h>
 #include <linux/types.h>
 #include <linux/string.h>      /* for memset */
 #include <linux/tty.h>
index 24e0ad63980afe3940e2618778fd7d136c25e34c..0b891a9c6253125ddd54e863ff1d23b8299d4e25 100644 (file)
@@ -5,6 +5,7 @@
  *
  * Copyright (C) 2004-2008 Cavium Networks
  */
+#include <linux/cpu.h>
 #include <linux/init.h>
 #include <linux/delay.h>
 #include <linux/smp.h>
 
 #include <asm/octeon/octeon.h>
 
+#include "octeon_boot.h"
+
 volatile unsigned long octeon_processor_boot = 0xff;
 volatile unsigned long octeon_processor_sp;
 volatile unsigned long octeon_processor_gp;
 
+#ifdef CONFIG_HOTPLUG_CPU
+static unsigned int InitTLBStart_addr;
+#endif
+
 static irqreturn_t mailbox_interrupt(int irq, void *dev_id)
 {
        const int coreid = cvmx_get_core_num();
@@ -67,8 +74,28 @@ static inline void octeon_send_ipi_mask(cpumask_t mask, unsigned int action)
 }
 
 /**
- * Detect available CPUs, populate phys_cpu_present_map
+ * Detect available CPUs, populate cpu_possible_map
  */
+static void octeon_smp_hotplug_setup(void)
+{
+#ifdef CONFIG_HOTPLUG_CPU
+       uint32_t labi_signature;
+
+       labi_signature =
+               cvmx_read64_uint32(CVMX_ADD_SEG(CVMX_MIPS_SPACE_XKPHYS,
+                                       LABI_ADDR_IN_BOOTLOADER +
+                                       offsetof(struct linux_app_boot_info,
+                                                   labi_signature)));
+       if (labi_signature != LABI_SIGNATURE)
+               pr_err("The bootloader version on this board is incorrect\n");
+       InitTLBStart_addr =
+               cvmx_read64_uint32(CVMX_ADD_SEG(CVMX_MIPS_SPACE_XKPHYS,
+                                  LABI_ADDR_IN_BOOTLOADER +
+                                          offsetof(struct linux_app_boot_info,
+                                                   InitTLBStart_addr)));
+#endif
+}
+
 static void octeon_smp_setup(void)
 {
        const int coreid = cvmx_get_core_num();
@@ -91,6 +118,9 @@ static void octeon_smp_setup(void)
                        cpus++;
                }
        }
+       cpu_present_map = cpu_possible_map;
+
+       octeon_smp_hotplug_setup();
 }
 
 /**
@@ -128,6 +158,17 @@ static void octeon_init_secondary(void)
        const int coreid = cvmx_get_core_num();
        union cvmx_ciu_intx_sum0 interrupt_enable;
 
+#ifdef CONFIG_HOTPLUG_CPU
+       unsigned int cur_exception_base;
+
+       cur_exception_base = cvmx_read64_uint32(
+               CVMX_ADD_SEG(CVMX_MIPS_SPACE_XKPHYS,
+                            LABI_ADDR_IN_BOOTLOADER +
+                            offsetof(struct linux_app_boot_info,
+                                     cur_exception_base)));
+       /* cur_exception_base is incremented in bootloader after setting */
+       write_c0_ebase((unsigned int)(cur_exception_base - EXCEPTION_BASE_INCR));
+#endif
        octeon_check_cpu_bist();
        octeon_init_cvmcount();
        /*
@@ -199,6 +240,193 @@ static void octeon_cpus_done(void)
 #endif
 }
 
+#ifdef CONFIG_HOTPLUG_CPU
+
+/* State of each CPU. */
+DEFINE_PER_CPU(int, cpu_state);
+
+extern void fixup_irqs(void);
+
+static DEFINE_SPINLOCK(smp_reserve_lock);
+
+static int octeon_cpu_disable(void)
+{
+       unsigned int cpu = smp_processor_id();
+
+       if (cpu == 0)
+               return -EBUSY;
+
+       spin_lock(&smp_reserve_lock);
+
+       cpu_clear(cpu, cpu_online_map);
+       cpu_clear(cpu, cpu_callin_map);
+       local_irq_disable();
+       fixup_irqs();
+       local_irq_enable();
+
+       flush_cache_all();
+       local_flush_tlb_all();
+
+       spin_unlock(&smp_reserve_lock);
+
+       return 0;
+}
+
+static void octeon_cpu_die(unsigned int cpu)
+{
+       int coreid = cpu_logical_map(cpu);
+       uint32_t avail_coremask;
+       struct cvmx_bootmem_named_block_desc *block_desc;
+
+#ifdef CONFIG_CAVIUM_OCTEON_WATCHDOG
+       /* Disable the watchdog */
+       cvmx_ciu_wdogx_t ciu_wdog;
+       ciu_wdog.u64 = cvmx_read_csr(CVMX_CIU_WDOGX(cpu));
+       ciu_wdog.s.mode = 0;
+       cvmx_write_csr(CVMX_CIU_WDOGX(cpu), ciu_wdog.u64);
+#endif
+
+       while (per_cpu(cpu_state, cpu) != CPU_DEAD)
+               cpu_relax();
+
+       /*
+        * This is a bit complicated strategics of getting/settig available
+        * cores mask, copied from bootloader
+        */
+       /* LINUX_APP_BOOT_BLOCK is initialized in bootoct binary */
+       block_desc = cvmx_bootmem_find_named_block(LINUX_APP_BOOT_BLOCK_NAME);
+
+       if (!block_desc) {
+               avail_coremask =
+                       cvmx_read64_uint32(CVMX_ADD_SEG(CVMX_MIPS_SPACE_XKPHYS,
+                                                  LABI_ADDR_IN_BOOTLOADER +
+                                                  offsetof
+                                                  (struct linux_app_boot_info,
+                                                   avail_coremask)));
+       } else {                       /* alternative, already initialized */
+              avail_coremask =
+                  cvmx_read64_uint32(CVMX_ADD_SEG(CVMX_MIPS_SPACE_XKPHYS,
+                                                  block_desc->base_addr +
+                                                 AVAIL_COREMASK_OFFSET_IN_LINUX_APP_BOOT_BLOCK));
+       }
+
+       avail_coremask |= 1 << coreid;
+
+       /* Setting avail_coremask for bootoct binary */
+       if (!block_desc) {
+               cvmx_write64_uint32(CVMX_ADD_SEG(CVMX_MIPS_SPACE_XKPHYS,
+                                               LABI_ADDR_IN_BOOTLOADER +
+                                               offsetof(struct linux_app_boot_info,
+                                                        avail_coremask)),
+                                  avail_coremask);
+       } else {
+               cvmx_write64_uint32(CVMX_ADD_SEG(CVMX_MIPS_SPACE_XKPHYS,
+                                               block_desc->base_addr +
+                                               AVAIL_COREMASK_OFFSET_IN_LINUX_APP_BOOT_BLOCK),
+                                  avail_coremask);
+       }
+
+       pr_info("Reset core %d. Available Coremask = %x \n", coreid,
+               avail_coremask);
+       cvmx_write_csr(CVMX_CIU_PP_RST, 1 << coreid);
+       cvmx_write_csr(CVMX_CIU_PP_RST, 0);
+}
+
+void play_dead(void)
+{
+       int coreid = cvmx_get_core_num();
+
+       idle_task_exit();
+       octeon_processor_boot = 0xff;
+       per_cpu(cpu_state, coreid) = CPU_DEAD;
+
+       while (1)       /* core will be reset here */
+               ;
+}
+
+extern void kernel_entry(unsigned long arg1, ...);
+
+static void start_after_reset(void)
+{
+       kernel_entry(0, 0, 0);  /* set a2 = 0 for secondary core */
+}
+
+int octeon_update_boot_vector(unsigned int cpu)
+{
+
+       int coreid = cpu_logical_map(cpu);
+       unsigned int avail_coremask;
+       struct cvmx_bootmem_named_block_desc *block_desc;
+       struct boot_init_vector *boot_vect =
+               (struct boot_init_vector *) cvmx_phys_to_ptr(0x0 +
+                                                 BOOTLOADER_BOOT_VECTOR);
+
+       block_desc = cvmx_bootmem_find_named_block(LINUX_APP_BOOT_BLOCK_NAME);
+
+       if (!block_desc) {
+               avail_coremask =
+                       cvmx_read64_uint32(CVMX_ADD_SEG(CVMX_MIPS_SPACE_XKPHYS,
+                                          LABI_ADDR_IN_BOOTLOADER +
+                                               offsetof(struct linux_app_boot_info,
+                                               avail_coremask)));
+       } else {                       /* alternative, already initialized */
+              avail_coremask =
+                  cvmx_read64_uint32(CVMX_ADD_SEG(CVMX_MIPS_SPACE_XKPHYS,
+                                                  block_desc->base_addr +
+                                                  AVAIL_COREMASK_OFFSET_IN_LINUX_APP_BOOT_BLOCK));
+       }
+
+       if (!(avail_coremask & (1 << coreid))) {
+               /* core not available, assume, that catched by simple-executive */
+               cvmx_write_csr(CVMX_CIU_PP_RST, 1 << coreid);
+               cvmx_write_csr(CVMX_CIU_PP_RST, 0);
+       }
+
+       boot_vect[coreid].app_start_func_addr =
+               (uint32_t) (unsigned long) start_after_reset;
+       boot_vect[coreid].code_addr = InitTLBStart_addr;
+
+       CVMX_SYNC;
+
+       cvmx_write_csr(CVMX_CIU_NMI, (1 << coreid) & avail_coremask);
+
+       return 0;
+}
+
+static int __cpuinit octeon_cpu_callback(struct notifier_block *nfb,
+       unsigned long action, void *hcpu)
+{
+       unsigned int cpu = (unsigned long)hcpu;
+
+       switch (action) {
+       case CPU_UP_PREPARE:
+               octeon_update_boot_vector(cpu);
+               break;
+       case CPU_ONLINE:
+               pr_info("Cpu %d online\n", cpu);
+               break;
+       case CPU_DEAD:
+               break;
+       }
+
+       return NOTIFY_OK;
+}
+
+static struct notifier_block __cpuinitdata octeon_cpu_notifier = {
+       .notifier_call = octeon_cpu_callback,
+};
+
+static int __cpuinit register_cavium_notifier(void)
+{
+       register_hotcpu_notifier(&octeon_cpu_notifier);
+
+       return 0;
+}
+
+late_initcall(register_cavium_notifier);
+
+#endif  /* CONFIG_HOTPLUG_CPU */
+
 struct plat_smp_ops octeon_smp_ops = {
        .send_ipi_single        = octeon_send_ipi_single,
        .send_ipi_mask          = octeon_send_ipi_mask,
@@ -208,4 +436,8 @@ struct plat_smp_ops octeon_smp_ops = {
        .boot_secondary         = octeon_boot_secondary,
        .smp_setup              = octeon_smp_setup,
        .prepare_cpus           = octeon_prepare_cpus,
+#ifdef CONFIG_HOTPLUG_CPU
+       .cpu_disable            = octeon_cpu_disable,
+       .cpu_die                = octeon_cpu_die,
+#endif
 };
index 9e143989c7b8b889dcabc900fa86058d9c1517b2..4eaec8b46e0ce16280b70f261e1199fcf0959ee6 100644 (file)
@@ -1,7 +1,7 @@
 /*
  *  Cobalt buttons platform device.
  *
- *  Copyright (C) 2007  Yoichi Yuasa <yoichi_yuasa@tripeaks.co.jp>
+ *  Copyright (C) 2007  Yoichi Yuasa <yuasa@linux-mips.org>
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
index 0720e4fae3112c41fb3c52cff618ad22bb5d4134..0f1cd90f37edcbcfcfa37447831045777374fbc5 100644 (file)
@@ -1,7 +1,7 @@
 /*
  *  Registration of Cobalt LCD platform device.
  *
- *  Copyright (C) 2008  Yoichi Yuasa <yoichi_yuasa@tripeaks.co.jp>
+ *  Copyright (C) 2008  Yoichi Yuasa <yuasa@linux-mips.org>
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
index 1c6ebd468b07ff3f440f5fd2401c7f78b4d1c3f6..d3ce6fa1dc74cec54c66d6e973ae03eeb429e2e0 100644 (file)
@@ -1,7 +1,7 @@
 /*
  *  Registration of Cobalt LED platform device.
  *
- *  Copyright (C) 2007  Yoichi Yuasa <yoichi_yuasa@tripeaks.co.jp>
+ *  Copyright (C) 2007  Yoichi Yuasa <yuasa@linux-mips.org>
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
index 2b088ef3839a4b69d275b3b2e30eedc31051198c..691d620b6766a078b51c051ceeb4c57af4e76033 100644 (file)
@@ -1,7 +1,7 @@
 /*
  *  Registration of Cobalt MTD device.
  *
- *  Copyright (C) 2006  Yoichi Yuasa <yoichi_yuasa@tripeaks.co.jp>
+ *  Copyright (C) 2006  Yoichi Yuasa <yuasa@linux-mips.org>
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
index e70794b8bcba897dc818a196c44581e4b6cac7ab..3ab39898b4e46b3a3b7c5615b8b5fe85b5e8473b 100644 (file)
@@ -1,7 +1,7 @@
 /*
  *  Registration of Cobalt RTC platform device.
  *
- *  Copyright (C) 2007  Yoichi Yuasa <yoichi_yuasa@tripeaks.co.jp>
+ *  Copyright (C) 2007  Yoichi Yuasa <yuasa@linux-mips.org>
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
index 53b8d0d6da90824ccc2d4447526f205bf36ed506..7cb51f57275e584bdf4d7ba61762e004023f01d7 100644 (file)
@@ -1,7 +1,7 @@
 /*
  *  Registration of Cobalt UART platform device.
  *
- *  Copyright (C) 2007  Yoichi Yuasa <yoichi_yuasa@tripeaks.co.jp>
+ *  Copyright (C) 2007  Yoichi Yuasa <yuasa@linux-mips.org>
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
index 4a570e7145fe65fc0d551f60600feb916541bc3c..0162f9edc693c57bcf35c614be66289eb3db7f90 100644 (file)
@@ -1,7 +1,7 @@
 /*
  *  Cobalt time initialization.
  *
- *  Copyright (C) 2007  Yoichi Yuasa <yoichi_yuasa@tripeaks.co.jp>
+ *  Copyright (C) 2007  Yoichi Yuasa <yuasa@linux-mips.org>
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
diff --git a/arch/mips/configs/ar7_defconfig b/arch/mips/configs/ar7_defconfig
new file mode 100644 (file)
index 0000000..dad5b67
--- /dev/null
@@ -0,0 +1,1182 @@
+#
+# Automatically generated make config: don't edit
+# Linux kernel version: 2.6.30
+# Wed Jun 24 14:08:59 2009
+#
+CONFIG_MIPS=y
+
+#
+# Machine selection
+#
+# CONFIG_MACH_ALCHEMY is not set
+CONFIG_AR7=y
+# CONFIG_BASLER_EXCITE is not set
+# CONFIG_BCM47XX is not set
+# CONFIG_MIPS_COBALT is not set
+# CONFIG_MACH_DECSTATION is not set
+# CONFIG_MACH_JAZZ is not set
+# CONFIG_LASAT is not set
+# CONFIG_LEMOTE_FULONG is not set
+# CONFIG_MIPS_MALTA is not set
+# CONFIG_MIPS_SIM is not set
+# CONFIG_NEC_MARKEINS is not set
+# CONFIG_MACH_VR41XX is not set
+# CONFIG_NXP_STB220 is not set
+# CONFIG_NXP_STB225 is not set
+# CONFIG_PNX8550_JBS is not set
+# CONFIG_PNX8550_STB810 is not set
+# CONFIG_PMC_MSP is not set
+# CONFIG_PMC_YOSEMITE is not set
+# CONFIG_SGI_IP22 is not set
+# CONFIG_SGI_IP27 is not set
+# CONFIG_SGI_IP28 is not set
+# CONFIG_SGI_IP32 is not set
+# CONFIG_SIBYTE_CRHINE is not set
+# CONFIG_SIBYTE_CARMEL is not set
+# CONFIG_SIBYTE_CRHONE is not set
+# CONFIG_SIBYTE_RHONE is not set
+# CONFIG_SIBYTE_SWARM is not set
+# CONFIG_SIBYTE_LITTLESUR is not set
+# CONFIG_SIBYTE_SENTOSA is not set
+# CONFIG_SIBYTE_BIGSUR is not set
+# CONFIG_SNI_RM is not set
+# CONFIG_MACH_TX39XX is not set
+# CONFIG_MACH_TX49XX is not set
+# CONFIG_MIKROTIK_RB532 is not set
+# CONFIG_WR_PPMC is not set
+# CONFIG_CAVIUM_OCTEON_SIMULATOR is not set
+# CONFIG_CAVIUM_OCTEON_REFERENCE_BOARD is not set
+# CONFIG_ALCHEMY_GPIO_INDIRECT is not set
+CONFIG_RWSEM_GENERIC_SPINLOCK=y
+# CONFIG_ARCH_HAS_ILOG2_U32 is not set
+# CONFIG_ARCH_HAS_ILOG2_U64 is not set
+CONFIG_ARCH_SUPPORTS_OPROFILE=y
+CONFIG_GENERIC_FIND_NEXT_BIT=y
+CONFIG_GENERIC_HWEIGHT=y
+CONFIG_GENERIC_CALIBRATE_DELAY=y
+CONFIG_GENERIC_CLOCKEVENTS=y
+CONFIG_GENERIC_TIME=y
+CONFIG_GENERIC_CMOS_UPDATE=y
+CONFIG_SCHED_OMIT_FRAME_POINTER=y
+CONFIG_GENERIC_HARDIRQS_NO__DO_IRQ=y
+CONFIG_CEVT_R4K_LIB=y
+CONFIG_CEVT_R4K=y
+CONFIG_CSRC_R4K_LIB=y
+CONFIG_CSRC_R4K=y
+CONFIG_DMA_NONCOHERENT=y
+CONFIG_DMA_NEED_PCI_MAP_STATE=y
+CONFIG_EARLY_PRINTK=y
+CONFIG_SYS_HAS_EARLY_PRINTK=y
+# CONFIG_HOTPLUG_CPU is not set
+# CONFIG_NO_IOPORT is not set
+CONFIG_GENERIC_GPIO=y
+# CONFIG_CPU_BIG_ENDIAN is not set
+CONFIG_CPU_LITTLE_ENDIAN=y
+CONFIG_SYS_SUPPORTS_LITTLE_ENDIAN=y
+CONFIG_IRQ_CPU=y
+CONFIG_NO_EXCEPT_FILL=y
+CONFIG_SWAP_IO_SPACE=y
+CONFIG_BOOT_ELF32=y
+CONFIG_MIPS_L1_CACHE_SHIFT=5
+
+#
+# CPU selection
+#
+# CONFIG_CPU_LOONGSON2 is not set
+CONFIG_CPU_MIPS32_R1=y
+# CONFIG_CPU_MIPS32_R2 is not set
+# CONFIG_CPU_MIPS64_R1 is not set
+# CONFIG_CPU_MIPS64_R2 is not set
+# CONFIG_CPU_R3000 is not set
+# CONFIG_CPU_TX39XX is not set
+# CONFIG_CPU_VR41XX is not set
+# CONFIG_CPU_R4300 is not set
+# CONFIG_CPU_R4X00 is not set
+# CONFIG_CPU_TX49XX is not set
+# CONFIG_CPU_R5000 is not set
+# CONFIG_CPU_R5432 is not set
+# CONFIG_CPU_R5500 is not set
+# CONFIG_CPU_R6000 is not set
+# CONFIG_CPU_NEVADA is not set
+# CONFIG_CPU_R8000 is not set
+# CONFIG_CPU_R10000 is not set
+# CONFIG_CPU_RM7000 is not set
+# CONFIG_CPU_RM9000 is not set
+# CONFIG_CPU_SB1 is not set
+# CONFIG_CPU_CAVIUM_OCTEON is not set
+CONFIG_SYS_HAS_CPU_MIPS32_R1=y
+CONFIG_CPU_MIPS32=y
+CONFIG_CPU_MIPSR1=y
+CONFIG_SYS_SUPPORTS_32BIT_KERNEL=y
+CONFIG_CPU_SUPPORTS_32BIT_KERNEL=y
+CONFIG_HARDWARE_WATCHPOINTS=y
+
+#
+# Kernel type
+#
+CONFIG_32BIT=y
+# CONFIG_64BIT is not set
+CONFIG_PAGE_SIZE_4KB=y
+# CONFIG_PAGE_SIZE_8KB is not set
+# CONFIG_PAGE_SIZE_16KB is not set
+# CONFIG_PAGE_SIZE_32KB is not set
+# CONFIG_PAGE_SIZE_64KB is not set
+CONFIG_CPU_HAS_PREFETCH=y
+CONFIG_MIPS_MT_DISABLED=y
+# CONFIG_MIPS_MT_SMP is not set
+# CONFIG_MIPS_MT_SMTC is not set
+CONFIG_CPU_HAS_LLSC=y
+CONFIG_CPU_HAS_SYNC=y
+CONFIG_GENERIC_HARDIRQS=y
+CONFIG_GENERIC_IRQ_PROBE=y
+CONFIG_CPU_SUPPORTS_HIGHMEM=y
+CONFIG_ARCH_FLATMEM_ENABLE=y
+CONFIG_ARCH_POPULATES_NODE_MAP=y
+CONFIG_SELECT_MEMORY_MODEL=y
+CONFIG_FLATMEM_MANUAL=y
+# CONFIG_DISCONTIGMEM_MANUAL is not set
+# CONFIG_SPARSEMEM_MANUAL is not set
+CONFIG_FLATMEM=y
+CONFIG_FLAT_NODE_MEM_MAP=y
+CONFIG_PAGEFLAGS_EXTENDED=y
+CONFIG_SPLIT_PTLOCK_CPUS=4
+# CONFIG_PHYS_ADDR_T_64BIT is not set
+CONFIG_ZONE_DMA_FLAG=0
+CONFIG_VIRT_TO_BUS=y
+CONFIG_HAVE_MLOCK=y
+CONFIG_HAVE_MLOCKED_PAGE_BIT=y
+CONFIG_DEFAULT_MMAP_MIN_ADDR=4096
+CONFIG_TICK_ONESHOT=y
+# CONFIG_NO_HZ is not set
+CONFIG_HIGH_RES_TIMERS=y
+CONFIG_GENERIC_CLOCKEVENTS_BUILD=y
+# CONFIG_HZ_48 is not set
+CONFIG_HZ_100=y
+# CONFIG_HZ_128 is not set
+# CONFIG_HZ_250 is not set
+# CONFIG_HZ_256 is not set
+# CONFIG_HZ_1000 is not set
+# CONFIG_HZ_1024 is not set
+CONFIG_SYS_SUPPORTS_ARBIT_HZ=y
+CONFIG_HZ=100
+CONFIG_PREEMPT_NONE=y
+# CONFIG_PREEMPT_VOLUNTARY is not set
+# CONFIG_PREEMPT is not set
+CONFIG_KEXEC=y
+# CONFIG_SECCOMP is not set
+CONFIG_LOCKDEP_SUPPORT=y
+CONFIG_STACKTRACE_SUPPORT=y
+CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+
+#
+# General setup
+#
+CONFIG_EXPERIMENTAL=y
+CONFIG_BROKEN_ON_SMP=y
+CONFIG_INIT_ENV_ARG_LIMIT=32
+CONFIG_LOCALVERSION=""
+# CONFIG_LOCALVERSION_AUTO is not set
+CONFIG_SWAP=y
+CONFIG_SYSVIPC=y
+CONFIG_SYSVIPC_SYSCTL=y
+# CONFIG_POSIX_MQUEUE is not set
+CONFIG_BSD_PROCESS_ACCT=y
+# CONFIG_BSD_PROCESS_ACCT_V3 is not set
+# CONFIG_TASKSTATS is not set
+# CONFIG_AUDIT is not set
+
+#
+# RCU Subsystem
+#
+CONFIG_CLASSIC_RCU=y
+# CONFIG_TREE_RCU is not set
+# CONFIG_PREEMPT_RCU is not set
+# CONFIG_TREE_RCU_TRACE is not set
+# CONFIG_PREEMPT_RCU_TRACE is not set
+# CONFIG_IKCONFIG is not set
+CONFIG_LOG_BUF_SHIFT=14
+# CONFIG_GROUP_SCHED is not set
+# CONFIG_CGROUPS is not set
+CONFIG_SYSFS_DEPRECATED=y
+CONFIG_SYSFS_DEPRECATED_V2=y
+CONFIG_RELAY=y
+# CONFIG_NAMESPACES is not set
+CONFIG_BLK_DEV_INITRD=y
+CONFIG_INITRAMFS_SOURCE=""
+CONFIG_RD_GZIP=y
+# CONFIG_RD_BZIP2 is not set
+CONFIG_RD_LZMA=y
+CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+CONFIG_SYSCTL=y
+CONFIG_ANON_INODES=y
+CONFIG_EMBEDDED=y
+CONFIG_SYSCTL_SYSCALL=y
+# CONFIG_KALLSYMS is not set
+CONFIG_HOTPLUG=y
+CONFIG_PRINTK=y
+CONFIG_BUG=y
+# CONFIG_ELF_CORE is not set
+# CONFIG_PCSPKR_PLATFORM is not set
+CONFIG_BASE_FULL=y
+CONFIG_FUTEX=y
+CONFIG_EPOLL=y
+CONFIG_SIGNALFD=y
+CONFIG_TIMERFD=y
+CONFIG_EVENTFD=y
+CONFIG_SHMEM=y
+CONFIG_AIO=y
+
+#
+# Performance Counters
+#
+# CONFIG_VM_EVENT_COUNTERS is not set
+CONFIG_STRIP_ASM_SYMS=y
+# CONFIG_COMPAT_BRK is not set
+CONFIG_SLAB=y
+# CONFIG_SLUB is not set
+# CONFIG_SLOB is not set
+# CONFIG_PROFILING is not set
+# CONFIG_MARKERS is not set
+CONFIG_HAVE_OPROFILE=y
+# CONFIG_SLOW_WORK is not set
+# CONFIG_HAVE_GENERIC_DMA_COHERENT is not set
+CONFIG_SLABINFO=y
+CONFIG_RT_MUTEXES=y
+CONFIG_BASE_SMALL=0
+CONFIG_MODULES=y
+# CONFIG_MODULE_FORCE_LOAD is not set
+CONFIG_MODULE_UNLOAD=y
+# CONFIG_MODULE_FORCE_UNLOAD is not set
+# CONFIG_MODVERSIONS is not set
+# CONFIG_MODULE_SRCVERSION_ALL is not set
+CONFIG_BLOCK=y
+# CONFIG_LBD is not set
+# CONFIG_BLK_DEV_BSG is not set
+# CONFIG_BLK_DEV_INTEGRITY is not set
+
+#
+# IO Schedulers
+#
+CONFIG_IOSCHED_NOOP=y
+# CONFIG_IOSCHED_AS is not set
+CONFIG_IOSCHED_DEADLINE=y
+# CONFIG_IOSCHED_CFQ is not set
+# CONFIG_DEFAULT_AS is not set
+CONFIG_DEFAULT_DEADLINE=y
+# CONFIG_DEFAULT_CFQ is not set
+# CONFIG_DEFAULT_NOOP is not set
+CONFIG_DEFAULT_IOSCHED="deadline"
+CONFIG_PROBE_INITRD_HEADER=y
+# CONFIG_FREEZER is not set
+
+#
+# Bus options (PCI, PCMCIA, EISA, ISA, TC)
+#
+# CONFIG_ARCH_SUPPORTS_MSI is not set
+CONFIG_MMU=y
+# CONFIG_PCCARD is not set
+
+#
+# Executable file formats
+#
+CONFIG_BINFMT_ELF=y
+# CONFIG_HAVE_AOUT is not set
+# CONFIG_BINFMT_MISC is not set
+CONFIG_TRAD_SIGNALS=y
+
+#
+# Power management options
+#
+CONFIG_ARCH_HIBERNATION_POSSIBLE=y
+CONFIG_ARCH_SUSPEND_POSSIBLE=y
+# CONFIG_PM is not set
+CONFIG_NET=y
+
+#
+# Networking options
+#
+CONFIG_PACKET=y
+CONFIG_PACKET_MMAP=y
+CONFIG_UNIX=y
+# CONFIG_NET_KEY is not set
+CONFIG_INET=y
+CONFIG_IP_MULTICAST=y
+CONFIG_IP_ADVANCED_ROUTER=y
+CONFIG_ASK_IP_FIB_HASH=y
+# CONFIG_IP_FIB_TRIE is not set
+CONFIG_IP_FIB_HASH=y
+CONFIG_IP_MULTIPLE_TABLES=y
+CONFIG_IP_ROUTE_MULTIPATH=y
+CONFIG_IP_ROUTE_VERBOSE=y
+# CONFIG_IP_PNP is not set
+# CONFIG_NET_IPIP is not set
+# CONFIG_NET_IPGRE is not set
+CONFIG_IP_MROUTE=y
+# CONFIG_IP_PIMSM_V1 is not set
+# CONFIG_IP_PIMSM_V2 is not set
+CONFIG_ARPD=y
+CONFIG_SYN_COOKIES=y
+# CONFIG_INET_AH is not set
+# CONFIG_INET_ESP is not set
+# CONFIG_INET_IPCOMP is not set
+# CONFIG_INET_XFRM_TUNNEL is not set
+# CONFIG_INET_TUNNEL is not set
+# CONFIG_INET_XFRM_MODE_TRANSPORT is not set
+# CONFIG_INET_XFRM_MODE_TUNNEL is not set
+# CONFIG_INET_XFRM_MODE_BEET is not set
+# CONFIG_INET_LRO is not set
+# CONFIG_INET_DIAG is not set
+CONFIG_TCP_CONG_ADVANCED=y
+# CONFIG_TCP_CONG_BIC is not set
+# CONFIG_TCP_CONG_CUBIC is not set
+CONFIG_TCP_CONG_WESTWOOD=y
+# CONFIG_TCP_CONG_HTCP is not set
+# CONFIG_TCP_CONG_HSTCP is not set
+# CONFIG_TCP_CONG_HYBLA is not set
+# CONFIG_TCP_CONG_VEGAS is not set
+# CONFIG_TCP_CONG_SCALABLE is not set
+# CONFIG_TCP_CONG_LP is not set
+# CONFIG_TCP_CONG_VENO is not set
+# CONFIG_TCP_CONG_YEAH is not set
+# CONFIG_TCP_CONG_ILLINOIS is not set
+# CONFIG_DEFAULT_BIC is not set
+# CONFIG_DEFAULT_CUBIC is not set
+# CONFIG_DEFAULT_HTCP is not set
+# CONFIG_DEFAULT_VEGAS is not set
+CONFIG_DEFAULT_WESTWOOD=y
+# CONFIG_DEFAULT_RENO is not set
+CONFIG_DEFAULT_TCP_CONG="westwood"
+# CONFIG_TCP_MD5SIG is not set
+# CONFIG_IPV6 is not set
+# CONFIG_NETWORK_SECMARK is not set
+CONFIG_NETFILTER=y
+# CONFIG_NETFILTER_DEBUG is not set
+CONFIG_NETFILTER_ADVANCED=y
+# CONFIG_BRIDGE_NETFILTER is not set
+
+#
+# Core Netfilter Configuration
+#
+# CONFIG_NETFILTER_NETLINK_QUEUE is not set
+# CONFIG_NETFILTER_NETLINK_LOG is not set
+CONFIG_NF_CONNTRACK=m
+# CONFIG_NF_CT_ACCT is not set
+CONFIG_NF_CONNTRACK_MARK=y
+# CONFIG_NF_CONNTRACK_EVENTS is not set
+# CONFIG_NF_CT_PROTO_DCCP is not set
+# CONFIG_NF_CT_PROTO_SCTP is not set
+# CONFIG_NF_CT_PROTO_UDPLITE is not set
+# CONFIG_NF_CONNTRACK_AMANDA is not set
+CONFIG_NF_CONNTRACK_FTP=m
+# CONFIG_NF_CONNTRACK_H323 is not set
+CONFIG_NF_CONNTRACK_IRC=m
+# CONFIG_NF_CONNTRACK_NETBIOS_NS is not set
+# CONFIG_NF_CONNTRACK_PPTP is not set
+# CONFIG_NF_CONNTRACK_SANE is not set
+# CONFIG_NF_CONNTRACK_SIP is not set
+CONFIG_NF_CONNTRACK_TFTP=m
+# CONFIG_NF_CT_NETLINK is not set
+# CONFIG_NETFILTER_TPROXY is not set
+CONFIG_NETFILTER_XTABLES=m
+# CONFIG_NETFILTER_XT_TARGET_CLASSIFY is not set
+# CONFIG_NETFILTER_XT_TARGET_CONNMARK is not set
+# CONFIG_NETFILTER_XT_TARGET_DSCP is not set
+# CONFIG_NETFILTER_XT_TARGET_HL is not set
+# CONFIG_NETFILTER_XT_TARGET_LED is not set
+# CONFIG_NETFILTER_XT_TARGET_MARK is not set
+# CONFIG_NETFILTER_XT_TARGET_NFLOG is not set
+# CONFIG_NETFILTER_XT_TARGET_NFQUEUE is not set
+CONFIG_NETFILTER_XT_TARGET_NOTRACK=m
+# CONFIG_NETFILTER_XT_TARGET_RATEEST is not set
+# CONFIG_NETFILTER_XT_TARGET_TRACE is not set
+CONFIG_NETFILTER_XT_TARGET_TCPMSS=m
+# CONFIG_NETFILTER_XT_TARGET_TCPOPTSTRIP is not set
+# CONFIG_NETFILTER_XT_MATCH_CLUSTER is not set
+# CONFIG_NETFILTER_XT_MATCH_COMMENT is not set
+# CONFIG_NETFILTER_XT_MATCH_CONNBYTES is not set
+# CONFIG_NETFILTER_XT_MATCH_CONNLIMIT is not set
+# CONFIG_NETFILTER_XT_MATCH_CONNMARK is not set
+# CONFIG_NETFILTER_XT_MATCH_CONNTRACK is not set
+# CONFIG_NETFILTER_XT_MATCH_DCCP is not set
+# CONFIG_NETFILTER_XT_MATCH_DSCP is not set
+# CONFIG_NETFILTER_XT_MATCH_ESP is not set
+# CONFIG_NETFILTER_XT_MATCH_HASHLIMIT is not set
+# CONFIG_NETFILTER_XT_MATCH_HELPER is not set
+# CONFIG_NETFILTER_XT_MATCH_HL is not set
+# CONFIG_NETFILTER_XT_MATCH_IPRANGE is not set
+# CONFIG_NETFILTER_XT_MATCH_LENGTH is not set
+CONFIG_NETFILTER_XT_MATCH_LIMIT=m
+CONFIG_NETFILTER_XT_MATCH_MAC=m
+# CONFIG_NETFILTER_XT_MATCH_MARK is not set
+CONFIG_NETFILTER_XT_MATCH_MULTIPORT=m
+# CONFIG_NETFILTER_XT_MATCH_OWNER is not set
+# CONFIG_NETFILTER_XT_MATCH_PKTTYPE is not set
+# CONFIG_NETFILTER_XT_MATCH_QUOTA is not set
+# CONFIG_NETFILTER_XT_MATCH_RATEEST is not set
+# CONFIG_NETFILTER_XT_MATCH_REALM is not set
+# CONFIG_NETFILTER_XT_MATCH_RECENT is not set
+# CONFIG_NETFILTER_XT_MATCH_SCTP is not set
+CONFIG_NETFILTER_XT_MATCH_STATE=m
+# CONFIG_NETFILTER_XT_MATCH_STATISTIC is not set
+# CONFIG_NETFILTER_XT_MATCH_STRING is not set
+# CONFIG_NETFILTER_XT_MATCH_TCPMSS is not set
+# CONFIG_NETFILTER_XT_MATCH_TIME is not set
+# CONFIG_NETFILTER_XT_MATCH_U32 is not set
+# CONFIG_IP_VS is not set
+
+#
+# IP: Netfilter Configuration
+#
+CONFIG_NF_DEFRAG_IPV4=m
+CONFIG_NF_CONNTRACK_IPV4=m
+CONFIG_NF_CONNTRACK_PROC_COMPAT=y
+# CONFIG_IP_NF_QUEUE is not set
+CONFIG_IP_NF_IPTABLES=m
+# CONFIG_IP_NF_MATCH_ADDRTYPE is not set
+# CONFIG_IP_NF_MATCH_AH is not set
+# CONFIG_IP_NF_MATCH_ECN is not set
+# CONFIG_IP_NF_MATCH_TTL is not set
+CONFIG_IP_NF_FILTER=m
+CONFIG_IP_NF_TARGET_REJECT=m
+CONFIG_IP_NF_TARGET_LOG=m
+# CONFIG_IP_NF_TARGET_ULOG is not set
+CONFIG_NF_NAT=m
+CONFIG_NF_NAT_NEEDED=y
+CONFIG_IP_NF_TARGET_MASQUERADE=m
+# CONFIG_IP_NF_TARGET_NETMAP is not set
+# CONFIG_IP_NF_TARGET_REDIRECT is not set
+# CONFIG_NF_NAT_SNMP_BASIC is not set
+CONFIG_NF_NAT_FTP=m
+CONFIG_NF_NAT_IRC=m
+CONFIG_NF_NAT_TFTP=m
+# CONFIG_NF_NAT_AMANDA is not set
+# CONFIG_NF_NAT_PPTP is not set
+# CONFIG_NF_NAT_H323 is not set
+# CONFIG_NF_NAT_SIP is not set
+CONFIG_IP_NF_MANGLE=m
+# CONFIG_IP_NF_TARGET_CLUSTERIP is not set
+# CONFIG_IP_NF_TARGET_ECN is not set
+# CONFIG_IP_NF_TARGET_TTL is not set
+CONFIG_IP_NF_RAW=m
+# CONFIG_IP_NF_ARPTABLES is not set
+# CONFIG_IP_DCCP is not set
+# CONFIG_IP_SCTP is not set
+# CONFIG_TIPC is not set
+CONFIG_ATM=m
+# CONFIG_ATM_CLIP is not set
+# CONFIG_ATM_LANE is not set
+CONFIG_ATM_BR2684=m
+CONFIG_ATM_BR2684_IPFILTER=y
+CONFIG_STP=y
+CONFIG_BRIDGE=y
+# CONFIG_NET_DSA is not set
+CONFIG_VLAN_8021Q=y
+# CONFIG_VLAN_8021Q_GVRP is not set
+# CONFIG_DECNET is not set
+CONFIG_LLC=y
+# CONFIG_LLC2 is not set
+# CONFIG_IPX is not set
+# CONFIG_ATALK is not set
+# CONFIG_X25 is not set
+# CONFIG_LAPB is not set
+# CONFIG_ECONET is not set
+# CONFIG_WAN_ROUTER is not set
+# CONFIG_PHONET is not set
+# CONFIG_IEEE802154 is not set
+CONFIG_NET_SCHED=y
+
+#
+# Queueing/Scheduling
+#
+# CONFIG_NET_SCH_CBQ is not set
+# CONFIG_NET_SCH_HTB is not set
+# CONFIG_NET_SCH_HFSC is not set
+# CONFIG_NET_SCH_ATM is not set
+# CONFIG_NET_SCH_PRIO is not set
+# CONFIG_NET_SCH_MULTIQ is not set
+# CONFIG_NET_SCH_RED is not set
+# CONFIG_NET_SCH_SFQ is not set
+# CONFIG_NET_SCH_TEQL is not set
+# CONFIG_NET_SCH_TBF is not set
+# CONFIG_NET_SCH_GRED is not set
+# CONFIG_NET_SCH_DSMARK is not set
+# CONFIG_NET_SCH_NETEM is not set
+# CONFIG_NET_SCH_DRR is not set
+# CONFIG_NET_SCH_INGRESS is not set
+
+#
+# Classification
+#
+# CONFIG_NET_CLS_BASIC is not set
+# CONFIG_NET_CLS_TCINDEX is not set
+# CONFIG_NET_CLS_ROUTE4 is not set
+# CONFIG_NET_CLS_FW is not set
+# CONFIG_NET_CLS_U32 is not set
+# CONFIG_NET_CLS_RSVP is not set
+# CONFIG_NET_CLS_RSVP6 is not set
+# CONFIG_NET_CLS_FLOW is not set
+# CONFIG_NET_EMATCH is not set
+CONFIG_NET_CLS_ACT=y
+CONFIG_NET_ACT_POLICE=y
+# CONFIG_NET_ACT_GACT is not set
+# CONFIG_NET_ACT_MIRRED is not set
+# CONFIG_NET_ACT_IPT is not set
+# CONFIG_NET_ACT_NAT is not set
+# CONFIG_NET_ACT_PEDIT is not set
+# CONFIG_NET_ACT_SIMP is not set
+# CONFIG_NET_ACT_SKBEDIT is not set
+CONFIG_NET_SCH_FIFO=y
+# CONFIG_DCB is not set
+
+#
+# Network testing
+#
+# CONFIG_NET_PKTGEN is not set
+CONFIG_HAMRADIO=y
+
+#
+# Packet Radio protocols
+#
+# CONFIG_AX25 is not set
+# CONFIG_CAN is not set
+# CONFIG_IRDA is not set
+# CONFIG_BT is not set
+# CONFIG_AF_RXRPC is not set
+CONFIG_FIB_RULES=y
+CONFIG_WIRELESS=y
+CONFIG_CFG80211=m
+# CONFIG_CFG80211_REG_DEBUG is not set
+# CONFIG_CFG80211_DEBUGFS is not set
+# CONFIG_WIRELESS_OLD_REGULATORY is not set
+CONFIG_WIRELESS_EXT=y
+CONFIG_WIRELESS_EXT_SYSFS=y
+# CONFIG_LIB80211 is not set
+CONFIG_MAC80211=m
+CONFIG_MAC80211_DEFAULT_PS=y
+CONFIG_MAC80211_DEFAULT_PS_VALUE=1
+
+#
+# Rate control algorithm selection
+#
+CONFIG_MAC80211_RC_PID=y
+CONFIG_MAC80211_RC_MINSTREL=y
+CONFIG_MAC80211_RC_DEFAULT_PID=y
+# CONFIG_MAC80211_RC_DEFAULT_MINSTREL is not set
+CONFIG_MAC80211_RC_DEFAULT="pid"
+# CONFIG_MAC80211_MESH is not set
+# CONFIG_MAC80211_LEDS is not set
+# CONFIG_MAC80211_DEBUGFS is not set
+# CONFIG_MAC80211_DEBUG_MENU is not set
+# CONFIG_WIMAX is not set
+# CONFIG_RFKILL is not set
+# CONFIG_NET_9P is not set
+
+#
+# Device Drivers
+#
+
+#
+# Generic Driver Options
+#
+CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
+CONFIG_STANDALONE=y
+CONFIG_PREVENT_FIRMWARE_BUILD=y
+CONFIG_FW_LOADER=y
+# CONFIG_FIRMWARE_IN_KERNEL is not set
+CONFIG_EXTRA_FIRMWARE=""
+# CONFIG_SYS_HYPERVISOR is not set
+# CONFIG_CONNECTOR is not set
+CONFIG_MTD=y
+# CONFIG_MTD_DEBUG is not set
+# CONFIG_MTD_CONCAT is not set
+CONFIG_MTD_PARTITIONS=y
+# CONFIG_MTD_TESTS is not set
+# CONFIG_MTD_REDBOOT_PARTS is not set
+# CONFIG_MTD_CMDLINE_PARTS is not set
+# CONFIG_MTD_AR7_PARTS is not set
+
+#
+# User Modules And Translation Layers
+#
+CONFIG_MTD_CHAR=y
+CONFIG_MTD_BLKDEVS=y
+CONFIG_MTD_BLOCK=y
+# CONFIG_FTL is not set
+# CONFIG_NFTL is not set
+# CONFIG_INFTL is not set
+# CONFIG_RFD_FTL is not set
+# CONFIG_SSFDC is not set
+# CONFIG_MTD_OOPS is not set
+
+#
+# RAM/ROM/Flash chip drivers
+#
+CONFIG_MTD_CFI=y
+# CONFIG_MTD_JEDECPROBE is not set
+CONFIG_MTD_GEN_PROBE=y
+# CONFIG_MTD_CFI_ADV_OPTIONS is not set
+CONFIG_MTD_MAP_BANK_WIDTH_1=y
+CONFIG_MTD_MAP_BANK_WIDTH_2=y
+CONFIG_MTD_MAP_BANK_WIDTH_4=y
+# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set
+CONFIG_MTD_CFI_I1=y
+CONFIG_MTD_CFI_I2=y
+# CONFIG_MTD_CFI_I4 is not set
+# CONFIG_MTD_CFI_I8 is not set
+CONFIG_MTD_CFI_INTELEXT=y
+CONFIG_MTD_CFI_AMDSTD=y
+CONFIG_MTD_CFI_STAA=y
+CONFIG_MTD_CFI_UTIL=y
+# CONFIG_MTD_RAM is not set
+# CONFIG_MTD_ROM is not set
+# CONFIG_MTD_ABSENT is not set
+
+#
+# Mapping drivers for chip access
+#
+CONFIG_MTD_COMPLEX_MAPPINGS=y
+CONFIG_MTD_PHYSMAP=y
+# CONFIG_MTD_PHYSMAP_COMPAT is not set
+# CONFIG_MTD_PLATRAM is not set
+
+#
+# Self-contained MTD device drivers
+#
+# CONFIG_MTD_SLRAM is not set
+# CONFIG_MTD_PHRAM is not set
+# CONFIG_MTD_MTDRAM is not set
+# CONFIG_MTD_BLOCK2MTD is not set
+
+#
+# Disk-On-Chip Device Drivers
+#
+# CONFIG_MTD_DOC2000 is not set
+# CONFIG_MTD_DOC2001 is not set
+# CONFIG_MTD_DOC2001PLUS is not set
+# CONFIG_MTD_NAND is not set
+# CONFIG_MTD_ONENAND is not set
+
+#
+# LPDDR flash memory drivers
+#
+# CONFIG_MTD_LPDDR is not set
+
+#
+# UBI - Unsorted block images
+#
+# CONFIG_MTD_UBI is not set
+# CONFIG_PARPORT is not set
+CONFIG_BLK_DEV=y
+# CONFIG_BLK_DEV_COW_COMMON is not set
+# CONFIG_BLK_DEV_LOOP is not set
+# CONFIG_BLK_DEV_NBD is not set
+# CONFIG_BLK_DEV_RAM is not set
+# CONFIG_CDROM_PKTCDVD is not set
+# CONFIG_ATA_OVER_ETH is not set
+# CONFIG_BLK_DEV_HD is not set
+CONFIG_MISC_DEVICES=y
+# CONFIG_ENCLOSURE_SERVICES is not set
+# CONFIG_C2PORT is not set
+
+#
+# EEPROM support
+#
+# CONFIG_EEPROM_93CX6 is not set
+CONFIG_HAVE_IDE=y
+# CONFIG_IDE is not set
+
+#
+# SCSI device support
+#
+# CONFIG_RAID_ATTRS is not set
+# CONFIG_SCSI is not set
+# CONFIG_SCSI_DMA is not set
+# CONFIG_SCSI_NETLINK is not set
+# CONFIG_ATA is not set
+# CONFIG_MD is not set
+CONFIG_NETDEVICES=y
+# CONFIG_IFB is not set
+# CONFIG_DUMMY is not set
+# CONFIG_BONDING is not set
+# CONFIG_MACVLAN is not set
+# CONFIG_EQUALIZER is not set
+# CONFIG_TUN is not set
+# CONFIG_VETH is not set
+CONFIG_PHYLIB=y
+
+#
+# MII PHY device drivers
+#
+# CONFIG_MARVELL_PHY is not set
+# CONFIG_DAVICOM_PHY is not set
+# CONFIG_QSEMI_PHY is not set
+# CONFIG_LXT_PHY is not set
+# CONFIG_CICADA_PHY is not set
+# CONFIG_VITESSE_PHY is not set
+# CONFIG_SMSC_PHY is not set
+# CONFIG_BROADCOM_PHY is not set
+# CONFIG_ICPLUS_PHY is not set
+# CONFIG_REALTEK_PHY is not set
+# CONFIG_NATIONAL_PHY is not set
+# CONFIG_STE10XP is not set
+# CONFIG_LSI_ET1011C_PHY is not set
+CONFIG_FIXED_PHY=y
+# CONFIG_MDIO_BITBANG is not set
+CONFIG_NET_ETHERNET=y
+CONFIG_MII=y
+# CONFIG_AX88796 is not set
+# CONFIG_SMC91X is not set
+# CONFIG_DM9000 is not set
+# CONFIG_ETHOC is not set
+# CONFIG_DNET is not set
+# CONFIG_IBM_NEW_EMAC_ZMII is not set
+# CONFIG_IBM_NEW_EMAC_RGMII is not set
+# CONFIG_IBM_NEW_EMAC_TAH is not set
+# CONFIG_IBM_NEW_EMAC_EMAC4 is not set
+# CONFIG_IBM_NEW_EMAC_NO_FLOW_CTRL is not set
+# CONFIG_IBM_NEW_EMAC_MAL_CLR_ICINTSTAT is not set
+# CONFIG_IBM_NEW_EMAC_MAL_COMMON_ERR is not set
+# CONFIG_B44 is not set
+# CONFIG_KS8842 is not set
+CONFIG_CPMAC=y
+# CONFIG_NETDEV_1000 is not set
+# CONFIG_NETDEV_10000 is not set
+
+#
+# Wireless LAN
+#
+# CONFIG_WLAN_PRE80211 is not set
+CONFIG_WLAN_80211=y
+# CONFIG_LIBERTAS is not set
+# CONFIG_LIBERTAS_THINFIRM is not set
+# CONFIG_MAC80211_HWSIM is not set
+# CONFIG_P54_COMMON is not set
+# CONFIG_HOSTAP is not set
+# CONFIG_B43 is not set
+# CONFIG_B43LEGACY is not set
+# CONFIG_RT2X00 is not set
+
+#
+# Enable WiMAX (Networking options) to see the WiMAX drivers
+#
+# CONFIG_WAN is not set
+CONFIG_ATM_DRIVERS=y
+# CONFIG_ATM_DUMMY is not set
+# CONFIG_ATM_TCP is not set
+CONFIG_PPP=m
+CONFIG_PPP_MULTILINK=y
+CONFIG_PPP_FILTER=y
+CONFIG_PPP_ASYNC=m
+# CONFIG_PPP_SYNC_TTY is not set
+# CONFIG_PPP_DEFLATE is not set
+# CONFIG_PPP_BSDCOMP is not set
+# CONFIG_PPP_MPPE is not set
+CONFIG_PPPOE=m
+CONFIG_PPPOATM=m
+# CONFIG_PPPOL2TP is not set
+# CONFIG_SLIP is not set
+CONFIG_SLHC=m
+# CONFIG_NETCONSOLE is not set
+# CONFIG_NETPOLL is not set
+# CONFIG_NET_POLL_CONTROLLER is not set
+# CONFIG_ISDN is not set
+# CONFIG_PHONE is not set
+
+#
+# Input device support
+#
+# CONFIG_INPUT is not set
+
+#
+# Hardware I/O ports
+#
+# CONFIG_SERIO is not set
+# CONFIG_GAMEPORT is not set
+
+#
+# Character devices
+#
+# CONFIG_VT is not set
+# CONFIG_DEVKMEM is not set
+# CONFIG_SERIAL_NONSTANDARD is not set
+
+#
+# Serial drivers
+#
+CONFIG_SERIAL_8250=y
+CONFIG_SERIAL_8250_CONSOLE=y
+CONFIG_SERIAL_8250_NR_UARTS=2
+CONFIG_SERIAL_8250_RUNTIME_UARTS=2
+# CONFIG_SERIAL_8250_EXTENDED is not set
+
+#
+# Non-8250 serial port support
+#
+CONFIG_SERIAL_CORE=y
+CONFIG_SERIAL_CORE_CONSOLE=y
+CONFIG_UNIX98_PTYS=y
+# CONFIG_DEVPTS_MULTIPLE_INSTANCES is not set
+# CONFIG_LEGACY_PTYS is not set
+# CONFIG_IPMI_HANDLER is not set
+CONFIG_HW_RANDOM=y
+# CONFIG_HW_RANDOM_TIMERIOMEM is not set
+# CONFIG_R3964 is not set
+# CONFIG_RAW_DRIVER is not set
+# CONFIG_TCG_TPM is not set
+# CONFIG_I2C is not set
+# CONFIG_SPI is not set
+# CONFIG_W1 is not set
+# CONFIG_POWER_SUPPLY is not set
+# CONFIG_HWMON is not set
+# CONFIG_THERMAL is not set
+# CONFIG_THERMAL_HWMON is not set
+CONFIG_WATCHDOG=y
+# CONFIG_WATCHDOG_NOWAYOUT is not set
+
+#
+# Watchdog Device Drivers
+#
+# CONFIG_SOFT_WATCHDOG is not set
+CONFIG_AR7_WDT=y
+CONFIG_SSB_POSSIBLE=y
+
+#
+# Sonics Silicon Backplane
+#
+CONFIG_SSB=y
+# CONFIG_SSB_SILENT is not set
+# CONFIG_SSB_DEBUG is not set
+CONFIG_SSB_SERIAL=y
+CONFIG_SSB_DRIVER_MIPS=y
+CONFIG_SSB_EMBEDDED=y
+CONFIG_SSB_DRIVER_EXTIF=y
+
+#
+# Multifunction device drivers
+#
+# CONFIG_MFD_CORE is not set
+# CONFIG_MFD_SM501 is not set
+# CONFIG_HTC_PASIC3 is not set
+# CONFIG_MFD_TMIO is not set
+# CONFIG_REGULATOR is not set
+# CONFIG_MEDIA_SUPPORT is not set
+
+#
+# Graphics support
+#
+# CONFIG_VGASTATE is not set
+# CONFIG_VIDEO_OUTPUT_CONTROL is not set
+# CONFIG_FB is not set
+# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
+
+#
+# Display device support
+#
+# CONFIG_DISPLAY_SUPPORT is not set
+# CONFIG_SOUND is not set
+# CONFIG_USB_SUPPORT is not set
+# CONFIG_MMC is not set
+# CONFIG_MEMSTICK is not set
+CONFIG_NEW_LEDS=y
+CONFIG_LEDS_CLASS=y
+
+#
+# LED drivers
+#
+# CONFIG_LEDS_GPIO is not set
+
+#
+# LED Triggers
+#
+CONFIG_LEDS_TRIGGERS=y
+CONFIG_LEDS_TRIGGER_TIMER=y
+CONFIG_LEDS_TRIGGER_HEARTBEAT=y
+# CONFIG_LEDS_TRIGGER_BACKLIGHT is not set
+CONFIG_LEDS_TRIGGER_DEFAULT_ON=y
+
+#
+# iptables trigger is under Netfilter config (LED target)
+#
+# CONFIG_ACCESSIBILITY is not set
+CONFIG_RTC_LIB=y
+# CONFIG_RTC_CLASS is not set
+# CONFIG_DMADEVICES is not set
+# CONFIG_AUXDISPLAY is not set
+# CONFIG_UIO is not set
+
+#
+# TI VLYNQ
+#
+CONFIG_VLYNQ=y
+# CONFIG_STAGING is not set
+
+#
+# File systems
+#
+# CONFIG_EXT2_FS is not set
+# CONFIG_EXT3_FS is not set
+# CONFIG_EXT4_FS is not set
+# CONFIG_REISERFS_FS is not set
+# CONFIG_JFS_FS is not set
+# CONFIG_FS_POSIX_ACL is not set
+# CONFIG_XFS_FS is not set
+# CONFIG_OCFS2_FS is not set
+# CONFIG_BTRFS_FS is not set
+CONFIG_FILE_LOCKING=y
+CONFIG_FSNOTIFY=y
+# CONFIG_DNOTIFY is not set
+# CONFIG_INOTIFY is not set
+CONFIG_INOTIFY_USER=y
+# CONFIG_QUOTA is not set
+# CONFIG_AUTOFS_FS is not set
+# CONFIG_AUTOFS4_FS is not set
+# CONFIG_FUSE_FS is not set
+
+#
+# Caches
+#
+# CONFIG_FSCACHE is not set
+
+#
+# CD-ROM/DVD Filesystems
+#
+# CONFIG_ISO9660_FS is not set
+# CONFIG_UDF_FS is not set
+
+#
+# DOS/FAT/NT Filesystems
+#
+# CONFIG_MSDOS_FS is not set
+# CONFIG_VFAT_FS is not set
+# CONFIG_NTFS_FS is not set
+
+#
+# Pseudo filesystems
+#
+CONFIG_PROC_FS=y
+CONFIG_PROC_KCORE=y
+CONFIG_PROC_SYSCTL=y
+# CONFIG_PROC_PAGE_MONITOR is not set
+CONFIG_SYSFS=y
+CONFIG_TMPFS=y
+# CONFIG_TMPFS_POSIX_ACL is not set
+# CONFIG_HUGETLB_PAGE is not set
+# CONFIG_CONFIGFS_FS is not set
+CONFIG_MISC_FILESYSTEMS=y
+# CONFIG_ADFS_FS is not set
+# CONFIG_AFFS_FS is not set
+# CONFIG_HFS_FS is not set
+# CONFIG_HFSPLUS_FS is not set
+# CONFIG_BEFS_FS is not set
+# CONFIG_BFS_FS is not set
+# CONFIG_EFS_FS is not set
+CONFIG_JFFS2_FS=y
+CONFIG_JFFS2_FS_DEBUG=0
+CONFIG_JFFS2_FS_WRITEBUFFER=y
+# CONFIG_JFFS2_FS_WBUF_VERIFY is not set
+CONFIG_JFFS2_SUMMARY=y
+# CONFIG_JFFS2_FS_XATTR is not set
+CONFIG_JFFS2_COMPRESSION_OPTIONS=y
+CONFIG_JFFS2_ZLIB=y
+# CONFIG_JFFS2_LZO is not set
+CONFIG_JFFS2_RTIME=y
+# CONFIG_JFFS2_RUBIN is not set
+# CONFIG_JFFS2_CMODE_NONE is not set
+CONFIG_JFFS2_CMODE_PRIORITY=y
+# CONFIG_JFFS2_CMODE_SIZE is not set
+# CONFIG_JFFS2_CMODE_FAVOURLZO is not set
+# CONFIG_CRAMFS is not set
+CONFIG_SQUASHFS=y
+# CONFIG_SQUASHFS_EMBEDDED is not set
+CONFIG_SQUASHFS_FRAGMENT_CACHE_SIZE=3
+# CONFIG_VXFS_FS is not set
+# CONFIG_MINIX_FS is not set
+# CONFIG_OMFS_FS is not set
+# CONFIG_HPFS_FS is not set
+# CONFIG_QNX4FS_FS is not set
+# CONFIG_ROMFS_FS is not set
+# CONFIG_SYSV_FS is not set
+# CONFIG_UFS_FS is not set
+# CONFIG_NILFS2_FS is not set
+CONFIG_NETWORK_FILESYSTEMS=y
+# CONFIG_NFS_FS is not set
+# CONFIG_NFSD is not set
+# CONFIG_SMB_FS is not set
+# CONFIG_CIFS is not set
+# CONFIG_NCP_FS is not set
+# CONFIG_CODA_FS is not set
+# CONFIG_AFS_FS is not set
+
+#
+# Partition Types
+#
+CONFIG_PARTITION_ADVANCED=y
+# CONFIG_ACORN_PARTITION is not set
+# CONFIG_OSF_PARTITION is not set
+# CONFIG_AMIGA_PARTITION is not set
+# CONFIG_ATARI_PARTITION is not set
+# CONFIG_MAC_PARTITION is not set
+CONFIG_MSDOS_PARTITION=y
+CONFIG_BSD_DISKLABEL=y
+# CONFIG_MINIX_SUBPARTITION is not set
+# CONFIG_SOLARIS_X86_PARTITION is not set
+# CONFIG_UNIXWARE_DISKLABEL is not set
+# CONFIG_LDM_PARTITION is not set
+# CONFIG_SGI_PARTITION is not set
+# CONFIG_ULTRIX_PARTITION is not set
+# CONFIG_SUN_PARTITION is not set
+# CONFIG_KARMA_PARTITION is not set
+# CONFIG_EFI_PARTITION is not set
+# CONFIG_SYSV68_PARTITION is not set
+# CONFIG_NLS is not set
+# CONFIG_DLM is not set
+
+#
+# Kernel hacking
+#
+CONFIG_TRACE_IRQFLAGS_SUPPORT=y
+# CONFIG_PRINTK_TIME is not set
+CONFIG_ENABLE_WARN_DEPRECATED=y
+# CONFIG_ENABLE_MUST_CHECK is not set
+CONFIG_FRAME_WARN=1024
+# CONFIG_MAGIC_SYSRQ is not set
+# CONFIG_UNUSED_SYMBOLS is not set
+CONFIG_DEBUG_FS=y
+# CONFIG_HEADERS_CHECK is not set
+# CONFIG_DEBUG_KERNEL is not set
+# CONFIG_DEBUG_MEMORY_INIT is not set
+# CONFIG_RCU_CPU_STALL_DETECTOR is not set
+CONFIG_SYSCTL_SYSCALL_CHECK=y
+CONFIG_TRACING_SUPPORT=y
+# CONFIG_FTRACE is not set
+# CONFIG_DYNAMIC_DEBUG is not set
+# CONFIG_SAMPLES is not set
+CONFIG_HAVE_ARCH_KGDB=y
+CONFIG_CMDLINE="rootfstype=squashfs,jffs2"
+
+#
+# Security options
+#
+# CONFIG_KEYS is not set
+# CONFIG_SECURITY is not set
+# CONFIG_SECURITYFS is not set
+# CONFIG_SECURITY_FILE_CAPABILITIES is not set
+CONFIG_CRYPTO=y
+
+#
+# Crypto core or helper
+#
+# CONFIG_CRYPTO_FIPS is not set
+CONFIG_CRYPTO_ALGAPI=m
+CONFIG_CRYPTO_ALGAPI2=m
+CONFIG_CRYPTO_AEAD2=m
+CONFIG_CRYPTO_BLKCIPHER=m
+CONFIG_CRYPTO_BLKCIPHER2=m
+CONFIG_CRYPTO_HASH2=m
+CONFIG_CRYPTO_RNG2=m
+CONFIG_CRYPTO_PCOMP=m
+CONFIG_CRYPTO_MANAGER=m
+CONFIG_CRYPTO_MANAGER2=m
+# CONFIG_CRYPTO_GF128MUL is not set
+# CONFIG_CRYPTO_NULL is not set
+CONFIG_CRYPTO_WORKQUEUE=m
+# CONFIG_CRYPTO_CRYPTD is not set
+# CONFIG_CRYPTO_AUTHENC is not set
+# CONFIG_CRYPTO_TEST is not set
+
+#
+# Authenticated Encryption with Associated Data
+#
+# CONFIG_CRYPTO_CCM is not set
+# CONFIG_CRYPTO_GCM is not set
+# CONFIG_CRYPTO_SEQIV is not set
+
+#
+# Block modes
+#
+# CONFIG_CRYPTO_CBC is not set
+# CONFIG_CRYPTO_CTR is not set
+# CONFIG_CRYPTO_CTS is not set
+CONFIG_CRYPTO_ECB=m
+# CONFIG_CRYPTO_LRW is not set
+# CONFIG_CRYPTO_PCBC is not set
+# CONFIG_CRYPTO_XTS is not set
+
+#
+# Hash modes
+#
+# CONFIG_CRYPTO_HMAC is not set
+# CONFIG_CRYPTO_XCBC is not set
+
+#
+# Digest
+#
+# CONFIG_CRYPTO_CRC32C is not set
+# CONFIG_CRYPTO_MD4 is not set
+# CONFIG_CRYPTO_MD5 is not set
+# CONFIG_CRYPTO_MICHAEL_MIC is not set
+# CONFIG_CRYPTO_RMD128 is not set
+# CONFIG_CRYPTO_RMD160 is not set
+# CONFIG_CRYPTO_RMD256 is not set
+# CONFIG_CRYPTO_RMD320 is not set
+# CONFIG_CRYPTO_SHA1 is not set
+# CONFIG_CRYPTO_SHA256 is not set
+# CONFIG_CRYPTO_SHA512 is not set
+# CONFIG_CRYPTO_TGR192 is not set
+# CONFIG_CRYPTO_WP512 is not set
+
+#
+# Ciphers
+#
+CONFIG_CRYPTO_AES=m
+# CONFIG_CRYPTO_ANUBIS is not set
+CONFIG_CRYPTO_ARC4=m
+# CONFIG_CRYPTO_BLOWFISH is not set
+# CONFIG_CRYPTO_CAMELLIA is not set
+# CONFIG_CRYPTO_CAST5 is not set
+# CONFIG_CRYPTO_CAST6 is not set
+# CONFIG_CRYPTO_DES is not set
+# CONFIG_CRYPTO_FCRYPT is not set
+# CONFIG_CRYPTO_KHAZAD is not set
+# CONFIG_CRYPTO_SALSA20 is not set
+# CONFIG_CRYPTO_SEED is not set
+# CONFIG_CRYPTO_SERPENT is not set
+# CONFIG_CRYPTO_TEA is not set
+# CONFIG_CRYPTO_TWOFISH is not set
+
+#
+# Compression
+#
+# CONFIG_CRYPTO_DEFLATE is not set
+# CONFIG_CRYPTO_ZLIB is not set
+# CONFIG_CRYPTO_LZO is not set
+
+#
+# Random Number Generation
+#
+# CONFIG_CRYPTO_ANSI_CPRNG is not set
+# CONFIG_CRYPTO_HW is not set
+# CONFIG_BINARY_PRINTF is not set
+
+#
+# Library routines
+#
+CONFIG_BITREVERSE=y
+CONFIG_GENERIC_FIND_LAST_BIT=y
+CONFIG_CRC_CCITT=m
+# CONFIG_CRC16 is not set
+# CONFIG_CRC_T10DIF is not set
+# CONFIG_CRC_ITU_T is not set
+CONFIG_CRC32=y
+# CONFIG_CRC7 is not set
+# CONFIG_LIBCRC32C is not set
+CONFIG_ZLIB_INFLATE=y
+CONFIG_ZLIB_DEFLATE=y
+CONFIG_DECOMPRESS_GZIP=y
+CONFIG_DECOMPRESS_LZMA=y
+CONFIG_HAS_IOMEM=y
+CONFIG_HAS_IOPORT=y
+CONFIG_HAS_DMA=y
+CONFIG_NLATTR=y
index 5ec1c2ffd3a5e24b8c588156288c26195ebfb84e..6f9d0858f596e1ad53445c051a057b0cad348b22 100644 (file)
@@ -1,7 +1,7 @@
 /*
  *  Registration of WRPPMC UART platform device.
  *
- *  Copyright (C) 2007  Yoichi Yuasa <yoichi_yuasa@tripeaks.co.jp>
+ *  Copyright (C) 2007  Yoichi Yuasa <yuasa@linux-mips.org>
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
diff --git a/arch/mips/include/asm/amon.h b/arch/mips/include/asm/amon.h
new file mode 100644 (file)
index 0000000..c3dc1a6
--- /dev/null
@@ -0,0 +1,7 @@
+/*
+ * Amon support
+ */
+
+int amon_cpu_avail(int);
+void amon_cpu_start(int, unsigned long, unsigned long,
+                   unsigned long, unsigned long);
index 08ea46863fe5ca8ce6683fe71f527a6c4346b690..6cf29c26e873788a78221ab517dc97cc6ae5386c 100644 (file)
@@ -1,6 +1,7 @@
 #ifndef __ASM_BUG_H
 #define __ASM_BUG_H
 
+#include <linux/compiler.h>
 #include <asm/sgidefs.h>
 
 #ifdef CONFIG_BUG
index 9dc10df32078e10475dd49c60248c06d31461139..b160a706795dcf17d3b0ea4c8d0278748cd1a458 100644 (file)
@@ -11,6 +11,7 @@
 
 #include <linux/bug.h>
 #include <linux/delay.h>
+#include <linux/smp.h>
 
 #include <asm/cpu.h>
 #include <asm/cpu-info.h>
index ba1702e86931bff400708ee1c6d23089c9e705ed..3af0b8fb3b8c23500f9cd7476f769ae36cc05cfc 100644 (file)
@@ -1,7 +1,7 @@
 /*
  *  DS1287 timer functions.
  *
- *  Copyright (C) 2008  Yoichi Yuasa <yoichi_yuasa@tripeaks.co.jp>
+ *  Copyright (C) 2008  Yoichi Yuasa <yuasa@linux-mips.org>
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
index d58f128aa747be974ac10ffd5fb1749d3292f505..7990694cda221dbd9f0da1c2b11b4f8e77688680 100644 (file)
@@ -316,9 +316,13 @@ extern void elf_dump_regs(elf_greg_t *, struct pt_regs *regs);
 extern int dump_task_regs(struct task_struct *, elf_gregset_t *);
 extern int dump_task_fpu(struct task_struct *, elf_fpregset_t *);
 
+#ifndef ELF_CORE_COPY_REGS
 #define ELF_CORE_COPY_REGS(elf_regs, regs)                     \
        elf_dump_regs((elf_greg_t *)&(elf_regs), regs);
+#endif
+#ifndef ELF_CORE_COPY_TASK_REGS
 #define ELF_CORE_COPY_TASK_REGS(tsk, elf_regs) dump_task_regs(tsk, elf_regs)
+#endif
 #define ELF_CORE_COPY_FPREGS(tsk, elf_fpregs)                  \
        dump_task_fpu(tsk, elf_fpregs)
 
index d74a8a4ca861a9d5b2de96e995e5e7b1302b26d5..36fd969d64d6fc83a1b37daf5a22fe3b46c504b1 100644 (file)
 #define GCMP_CCB_DINTGROUP_OFS         0x0030          /* DINT Group Participate */
 #define GCMP_CCB_DBGGROUP_OFS          0x0100          /* DebugBreak Group */
 
+extern int __init gcmp_probe(unsigned long, unsigned long);
+
 #endif /* _ASM_GCMPREGS_H */
index 954807d9d66ae82233cc48362c0ebeb7ce144eff..10292e37c1f714b56d2b4eb854f180cc8f5c0975 100644 (file)
 #define GIC_TRIG_EDGE                  1
 #define GIC_TRIG_LEVEL                 0
 
+#if CONFIG_SMP
+#define GIC_NUM_INTRS                  (24 + NR_CPUS * 2)
+#else
 #define GIC_NUM_INTRS                  32
+#endif
 
 #define MSK(n) ((1 << (n)) - 1)
 #define REG32(addr)            (*(volatile unsigned int *) (addr))
@@ -483,5 +487,7 @@ extern void gic_init(unsigned long gic_base_addr,
 
 extern unsigned int gic_get_int(void);
 extern void gic_send_ipi(unsigned int intr);
+extern unsigned int plat_ipi_call_int_xlate(unsigned int);
+extern unsigned int plat_ipi_resched_int_xlate(unsigned int);
 
 #endif /* _ASM_GICREGS_H */
index 4f1eed107b08217f8f2991ed17f92c424b6c437f..09b08d05ff721707ea5c968fe1e369b19141014c 100644 (file)
@@ -10,6 +10,7 @@
 #define _ASM_IRQ_H
 
 #include <linux/linkage.h>
+#include <linux/smp.h>
 
 #include <asm/mipsmtregs.h>
 
index f9a7c3ac2e6677445e25a47df7248b1fd2773f19..250a2407b599c32b51b71d803bce7c4694666854 100644 (file)
@@ -1,7 +1,7 @@
 /*
  *  Galileo/Marvell GT641xx IRQ definitions.
  *
- *  Copyright (C) 2007  Yoichi Yuasa <yoichi_yuasa@tripeaks.co.jp>
+ *  Copyright (C) 2007  Yoichi Yuasa <yuasa@linux-mips.org>
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
diff --git a/arch/mips/include/asm/mach-ar7/ar7.h b/arch/mips/include/asm/mach-ar7/ar7.h
new file mode 100644 (file)
index 0000000..de71694
--- /dev/null
@@ -0,0 +1,178 @@
+/*
+ * Copyright (C) 2006,2007 Felix Fietkau <nbd@openwrt.org>
+ * Copyright (C) 2006,2007 Eugene Konev <ejka@openwrt.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+#ifndef __AR7_H__
+#define __AR7_H__
+
+#include <linux/delay.h>
+#include <linux/io.h>
+#include <linux/errno.h>
+
+#include <asm/addrspace.h>
+
+#define AR7_SDRAM_BASE 0x14000000
+
+#define AR7_REGS_BASE  0x08610000
+
+#define AR7_REGS_MAC0  (AR7_REGS_BASE + 0x0000)
+#define AR7_REGS_GPIO  (AR7_REGS_BASE + 0x0900)
+/* 0x08610A00 - 0x08610BFF (512 bytes, 128 bytes / clock) */
+#define AR7_REGS_POWER (AR7_REGS_BASE + 0x0a00)
+#define AR7_REGS_CLOCKS (AR7_REGS_POWER + 0x80)
+#define UR8_REGS_CLOCKS (AR7_REGS_POWER + 0x20)
+#define AR7_REGS_UART0 (AR7_REGS_BASE + 0x0e00)
+#define AR7_REGS_USB   (AR7_REGS_BASE + 0x1200)
+#define AR7_REGS_RESET (AR7_REGS_BASE + 0x1600)
+#define AR7_REGS_VLYNQ0        (AR7_REGS_BASE + 0x1800)
+#define AR7_REGS_DCL   (AR7_REGS_BASE + 0x1a00)
+#define AR7_REGS_VLYNQ1        (AR7_REGS_BASE + 0x1c00)
+#define AR7_REGS_MDIO  (AR7_REGS_BASE + 0x1e00)
+#define AR7_REGS_IRQ   (AR7_REGS_BASE + 0x2400)
+#define AR7_REGS_MAC1  (AR7_REGS_BASE + 0x2800)
+
+#define AR7_REGS_WDT   (AR7_REGS_BASE + 0x1f00)
+#define UR8_REGS_WDT   (AR7_REGS_BASE + 0x0b00)
+#define UR8_REGS_UART1 (AR7_REGS_BASE + 0x0f00)
+
+#define AR7_RESET_PEREPHERIAL  0x0
+#define AR7_RESET_SOFTWARE     0x4
+#define AR7_RESET_STATUS       0x8
+
+#define AR7_RESET_BIT_CPMAC_LO 17
+#define AR7_RESET_BIT_CPMAC_HI 21
+#define AR7_RESET_BIT_MDIO     22
+#define AR7_RESET_BIT_EPHY     26
+
+/* GPIO control registers */
+#define AR7_GPIO_INPUT 0x0
+#define AR7_GPIO_OUTPUT        0x4
+#define AR7_GPIO_DIR   0x8
+#define AR7_GPIO_ENABLE        0xc
+
+#define AR7_CHIP_7100  0x18
+#define AR7_CHIP_7200  0x2b
+#define AR7_CHIP_7300  0x05
+
+/* Interrupts */
+#define AR7_IRQ_UART0  15
+#define AR7_IRQ_UART1  16
+
+/* Clocks */
+#define AR7_AFE_CLOCK  35328000
+#define AR7_REF_CLOCK  25000000
+#define AR7_XTAL_CLOCK 24000000
+
+struct plat_cpmac_data {
+       int reset_bit;
+       int power_bit;
+       u32 phy_mask;
+       char dev_addr[6];
+};
+
+struct plat_dsl_data {
+       int reset_bit_dsl;
+       int reset_bit_sar;
+};
+
+extern int ar7_cpu_clock, ar7_bus_clock, ar7_dsp_clock;
+
+static inline u16 ar7_chip_id(void)
+{
+       return readl((void *)KSEG1ADDR(AR7_REGS_GPIO + 0x14)) & 0xffff;
+}
+
+static inline u8 ar7_chip_rev(void)
+{
+       return (readl((void *)KSEG1ADDR(AR7_REGS_GPIO + 0x14)) >> 16) & 0xff;
+}
+
+static inline int ar7_cpu_freq(void)
+{
+       return ar7_cpu_clock;
+}
+
+static inline int ar7_bus_freq(void)
+{
+       return ar7_bus_clock;
+}
+
+static inline int ar7_vbus_freq(void)
+{
+       return ar7_bus_clock / 2;
+}
+#define ar7_cpmac_freq ar7_vbus_freq
+
+static inline int ar7_dsp_freq(void)
+{
+       return ar7_dsp_clock;
+}
+
+static inline int ar7_has_high_cpmac(void)
+{
+       u16 chip_id = ar7_chip_id();
+       switch (chip_id) {
+       case AR7_CHIP_7100:
+       case AR7_CHIP_7200:
+               return 0;
+       case AR7_CHIP_7300:
+               return 1;
+       default:
+               return -ENXIO;
+       }
+}
+#define ar7_has_high_vlynq ar7_has_high_cpmac
+#define ar7_has_second_uart ar7_has_high_cpmac
+
+static inline void ar7_device_enable(u32 bit)
+{
+       void *reset_reg =
+               (void *)KSEG1ADDR(AR7_REGS_RESET + AR7_RESET_PEREPHERIAL);
+       writel(readl(reset_reg) | (1 << bit), reset_reg);
+       msleep(20);
+}
+
+static inline void ar7_device_disable(u32 bit)
+{
+       void *reset_reg =
+               (void *)KSEG1ADDR(AR7_REGS_RESET + AR7_RESET_PEREPHERIAL);
+       writel(readl(reset_reg) & ~(1 << bit), reset_reg);
+       msleep(20);
+}
+
+static inline void ar7_device_reset(u32 bit)
+{
+       ar7_device_disable(bit);
+       ar7_device_enable(bit);
+}
+
+static inline void ar7_device_on(u32 bit)
+{
+       void *power_reg = (void *)KSEG1ADDR(AR7_REGS_POWER);
+       writel(readl(power_reg) | (1 << bit), power_reg);
+       msleep(20);
+}
+
+static inline void ar7_device_off(u32 bit)
+{
+       void *power_reg = (void *)KSEG1ADDR(AR7_REGS_POWER);
+       writel(readl(power_reg) & ~(1 << bit), power_reg);
+       msleep(20);
+}
+
+#endif /* __AR7_H__ */
diff --git a/arch/mips/include/asm/mach-ar7/gpio.h b/arch/mips/include/asm/mach-ar7/gpio.h
new file mode 100644 (file)
index 0000000..cbe9c4f
--- /dev/null
@@ -0,0 +1,110 @@
+/*
+ * Copyright (C) 2007 Florian Fainelli <florian@openwrt.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+#ifndef __AR7_GPIO_H__
+#define __AR7_GPIO_H__
+
+#include <asm/mach-ar7/ar7.h>
+
+#define AR7_GPIO_MAX 32
+
+extern int gpio_request(unsigned gpio, const char *label);
+extern void gpio_free(unsigned gpio);
+
+/* Common GPIO layer */
+static inline int gpio_get_value(unsigned gpio)
+{
+       void __iomem *gpio_in =
+               (void __iomem *)KSEG1ADDR(AR7_REGS_GPIO + AR7_GPIO_INPUT);
+
+       return readl(gpio_in) & (1 << gpio);
+}
+
+static inline void gpio_set_value(unsigned gpio, int value)
+{
+       void __iomem *gpio_out =
+               (void __iomem *)KSEG1ADDR(AR7_REGS_GPIO + AR7_GPIO_OUTPUT);
+       unsigned tmp;
+
+       tmp = readl(gpio_out) & ~(1 << gpio);
+       if (value)
+               tmp |= 1 << gpio;
+       writel(tmp, gpio_out);
+}
+
+static inline int gpio_direction_input(unsigned gpio)
+{
+       void __iomem *gpio_dir =
+               (void __iomem *)KSEG1ADDR(AR7_REGS_GPIO + AR7_GPIO_DIR);
+
+       if (gpio >= AR7_GPIO_MAX)
+               return -EINVAL;
+
+       writel(readl(gpio_dir) | (1 << gpio), gpio_dir);
+
+       return 0;
+}
+
+static inline int gpio_direction_output(unsigned gpio, int value)
+{
+       void __iomem *gpio_dir =
+               (void __iomem *)KSEG1ADDR(AR7_REGS_GPIO + AR7_GPIO_DIR);
+
+       if (gpio >= AR7_GPIO_MAX)
+               return -EINVAL;
+
+       gpio_set_value(gpio, value);
+       writel(readl(gpio_dir) & ~(1 << gpio), gpio_dir);
+
+       return 0;
+}
+
+static inline int gpio_to_irq(unsigned gpio)
+{
+       return -EINVAL;
+}
+
+static inline int irq_to_gpio(unsigned irq)
+{
+       return -EINVAL;
+}
+
+/* Board specific GPIO functions */
+static inline int ar7_gpio_enable(unsigned gpio)
+{
+       void __iomem *gpio_en =
+               (void __iomem *)KSEG1ADDR(AR7_REGS_GPIO + AR7_GPIO_ENABLE);
+
+       writel(readl(gpio_en) | (1 << gpio), gpio_en);
+
+       return 0;
+}
+
+static inline int ar7_gpio_disable(unsigned gpio)
+{
+       void __iomem *gpio_en =
+               (void __iomem *)KSEG1ADDR(AR7_REGS_GPIO + AR7_GPIO_ENABLE);
+
+       writel(readl(gpio_en) & ~(1 << gpio), gpio_en);
+
+       return 0;
+}
+
+#include <asm-generic/gpio.h>
+
+#endif
diff --git a/arch/mips/include/asm/mach-ar7/irq.h b/arch/mips/include/asm/mach-ar7/irq.h
new file mode 100644 (file)
index 0000000..39e9757
--- /dev/null
@@ -0,0 +1,16 @@
+/*
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Shamelessly copied from asm-mips/mach-emma2rh/
+ * Copyright (C) 2003 by Ralf Baechle
+ */
+#ifndef __ASM_AR7_IRQ_H
+#define __ASM_AR7_IRQ_H
+
+#define NR_IRQS        256
+
+#include_next <irq.h>
+
+#endif /* __ASM_AR7_IRQ_H */
diff --git a/arch/mips/include/asm/mach-ar7/prom.h b/arch/mips/include/asm/mach-ar7/prom.h
new file mode 100644 (file)
index 0000000..088f61f
--- /dev/null
@@ -0,0 +1,25 @@
+/*
+ * Copyright (C) 2006, 2007 Florian Fainelli <florian@openwrt.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+#ifndef __PROM_H__
+#define __PROM_H__
+
+extern char *prom_getenv(const char *name);
+extern void prom_meminit(void);
+
+#endif /* __PROM_H__ */
diff --git a/arch/mips/include/asm/mach-ar7/spaces.h b/arch/mips/include/asm/mach-ar7/spaces.h
new file mode 100644 (file)
index 0000000..ac28f27
--- /dev/null
@@ -0,0 +1,22 @@
+/*
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 1994 - 1999, 2000, 03, 04 Ralf Baechle
+ * Copyright (C) 2000, 2002  Maciej W. Rozycki
+ * Copyright (C) 1990, 1999, 2000 Silicon Graphics, Inc.
+ */
+#ifndef _ASM_AR7_SPACES_H
+#define _ASM_AR7_SPACES_H
+
+/*
+ * This handles the memory map.
+ * We handle pages at KSEG0 for kernels with 32 bit address space.
+ */
+#define PAGE_OFFSET            0x94000000UL
+#define PHYS_OFFSET            0x14000000UL
+
+#include <asm/mach-generic/spaces.h>
+
+#endif /* __ASM_AR7_SPACES_H */
diff --git a/arch/mips/include/asm/mach-ar7/war.h b/arch/mips/include/asm/mach-ar7/war.h
new file mode 100644 (file)
index 0000000..f4862b5
--- /dev/null
@@ -0,0 +1,25 @@
+/*
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 2002, 2004, 2007 by Ralf Baechle <ralf@linux-mips.org>
+ */
+#ifndef __ASM_MIPS_MACH_AR7_WAR_H
+#define __ASM_MIPS_MACH_AR7_WAR_H
+
+#define R4600_V1_INDEX_ICACHEOP_WAR    0
+#define R4600_V1_HIT_CACHEOP_WAR       0
+#define R4600_V2_HIT_CACHEOP_WAR       0
+#define R5432_CP0_INTERRUPT_WAR                0
+#define BCM1250_M3_WAR                 0
+#define SIBYTE_1956_WAR                        0
+#define MIPS4K_ICACHE_REFILL_WAR       0
+#define MIPS_CACHE_SYNC_WAR            0
+#define TX49XX_ICACHE_INDEX_INV_WAR    0
+#define RM9000_CDEX_SMP_WAR            0
+#define ICACHE_REFILLS_WORKAROUND_WAR  0
+#define R10000_LLSC_WAR                        0
+#define MIPS34K_MISSED_ITLB_WAR                0
+
+#endif /* __ASM_MIPS_MACH_AR7_WAR_H */
index 57c8c9ac585162b6a16a32d912d7d438d0a772be..9da9acf5dcba4754642404fc05380946aa4a7ff8 100644 (file)
@@ -8,7 +8,7 @@
  * Copyright (C) 1997 Cobalt Microserver
  * Copyright (C) 1997, 2003 Ralf Baechle
  * Copyright (C) 2001-2003 Liam Davies (ldavies@agile.tv)
- * Copyright (C) 2007 Yoichi Yuasa <yoichi_yuasa@tripeaks.co.jp>
+ * Copyright (C) 2007 Yoichi Yuasa <yuasa@linux-mips.org>
  */
 #ifndef _ASM_COBALT_IRQ_H
 #define _ASM_COBALT_IRQ_H
index ae9c5523c7effae9679ce4c3b79a290121d58fd0..f8afec3f294330ea4322211f7b640f4146aabad8 100644 (file)
@@ -1,5 +1,5 @@
 /*
- *  Copyright (C) 2006  Yoichi Yuasa <yoichi_yuasa@tripeaks.co.jp>
+ *  Copyright (C) 2006  Yoichi Yuasa <yuasa@linux-mips.org>
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
index d7f3eb03ad12b3a87702115f0247562293e9ef80..d3bea88d8744ace24ad245062830c6cc64ea7886 100644 (file)
@@ -13,6 +13,7 @@
 
 #include <linux/errno.h>
 #include <linux/sched.h>
+#include <linux/smp.h>
 #include <linux/slab.h>
 #include <asm/cacheflush.h>
 #include <asm/tlbflush.h>
similarity index 52%
rename from arch/mips/cavium-octeon/pci-common.h
rename to arch/mips/include/asm/octeon/pci-octeon.h
index 74ae79991e456410f35424b09b4d180feceab6cc..6ac5d3e3398eaff20144dafc5190910eb8f4ef13 100644 (file)
@@ -3,23 +3,29 @@
  * License.  See the file "COPYING" in the main directory of this archive
  * for more details.
  *
- * Copyright (C) 2005-2007 Cavium Networks
+ * Copyright (C) 2005-2009 Cavium Networks
  */
-#ifndef __OCTEON_PCI_COMMON_H__
-#define __OCTEON_PCI_COMMON_H__
+
+#ifndef __PCI_OCTEON_H__
+#define __PCI_OCTEON_H__
 
 #include <linux/pci.h>
 
 /* Some PCI cards require delays when accessing config space. */
 #define PCI_CONFIG_SPACE_DELAY 10000
 
-/* pcibios_map_irq() is defined inside pci-common.c. All it does is call the
-   Octeon specific version pointed to by this variable. This function needs to
-   change for PCI or PCIe based hosts */
-extern typeof(pcibios_map_irq) *octeon_pcibios_map_irq;
+/*
+ * pcibios_map_irq() is defined inside pci-octeon.c. All it does is
+ * call the Octeon specific version pointed to by this variable. This
+ * function needs to change for PCI or PCIe based hosts.
+ */
+extern int (*octeon_pcibios_map_irq)(const struct pci_dev *dev,
+                                    u8 slot, u8 pin);
 
-/* The following defines are only used when octeon_dma_bar_type =
-   OCTEON_DMA_BAR_TYPE_BIG */
+/*
+ * The following defines are used when octeon_dma_bar_type =
+ * OCTEON_DMA_BAR_TYPE_BIG
+ */
 #define OCTEON_PCI_BAR1_HOLE_BITS 5
 #define OCTEON_PCI_BAR1_HOLE_SIZE (1ul<<(OCTEON_PCI_BAR1_HOLE_BITS+3))
 
@@ -30,9 +36,9 @@ enum octeon_dma_bar_type {
        OCTEON_DMA_BAR_TYPE_PCIE
 };
 
-/**
- * This is a variable to tell the DMA mapping system in dma-octeon.c
- * how to map PCI DMA addresses.
+/*
+ * This tells the DMA mapping system in dma-octeon.c how to map PCI
+ * DMA addresses.
  */
 extern enum octeon_dma_bar_type octeon_dma_bar_type;
 
index dc0eaa7312816112a006cb6af0a0b0b6f5022979..96a14a426a7c39f7e2d4ccf5bef49a7be5c425f7 100644 (file)
@@ -165,7 +165,14 @@ typedef struct { unsigned long pgprot; } pgprot_t;
 
 #ifdef CONFIG_FLATMEM
 
-#define pfn_valid(pfn)         ((pfn) >= ARCH_PFN_OFFSET && (pfn) < max_mapnr)
+#define pfn_valid(pfn)                                                 \
+({                                                                     \
+       unsigned long __pfn = (pfn);                                    \
+       /* avoid <linux/bootmem.h> include hell */                      \
+       extern unsigned long min_low_pfn;                               \
+                                                                       \
+       __pfn >= min_low_pfn && __pfn < max_mapnr;                      \
+})
 
 #elif defined(CONFIG_SPARSEMEM)
 
index 634b55d7e7f6d1ada10dfa02175c11a81790f78d..910e71a12466de2f1fb3f1fab82c6203ef062e63 100644 (file)
@@ -69,7 +69,7 @@
 
 #endif
 
-#ifdef CONFIG_64BIT
+#if defined(CONFIG_64BIT) && !defined(WANT_COMPAT_REG_H)
 
 #define EF_R0                   0
 #define EF_R1                   1
index 64ffc0290b84dcf98fb003ba0ba7e77f6faed454..fd545547b8aa961a544de03b8843d852269be7ca 100644 (file)
@@ -26,6 +26,10 @@ struct plat_smp_ops {
        void (*boot_secondary)(int cpu, struct task_struct *idle);
        void (*smp_setup)(void);
        void (*prepare_cpus)(unsigned int max_cpus);
+#ifdef CONFIG_HOTPLUG_CPU
+       int (*cpu_disable)(void);
+       void (*cpu_die)(unsigned int cpu);
+#endif
 };
 
 extern void register_smp_ops(struct plat_smp_ops *ops);
index 40e5ef1d4d26b195b205433c5d14a5c2ba382e35..aaa2d4ab26dc5589c034a9a86db28fb8b33cbdd8 100644 (file)
@@ -13,6 +13,7 @@
 
 #include <linux/bitops.h>
 #include <linux/linkage.h>
+#include <linux/smp.h>
 #include <linux/threads.h>
 #include <linux/cpumask.h>
 
@@ -40,6 +41,7 @@ extern int __cpu_logical_map[NR_CPUS];
 /* Octeon - Tell another core to flush its icache */
 #define SMP_ICACHE_FLUSH       0x4
 
+extern volatile cpumask_t cpu_callin_map;
 
 extern void asmlinkage smp_bootstrap(void);
 
@@ -55,6 +57,24 @@ static inline void smp_send_reschedule(int cpu)
        mp_ops->send_ipi_single(cpu, SMP_RESCHEDULE_YOURSELF);
 }
 
+#ifdef CONFIG_HOTPLUG_CPU
+static inline int __cpu_disable(void)
+{
+       extern struct plat_smp_ops *mp_ops;     /* private */
+
+       return mp_ops->cpu_disable();
+}
+
+static inline void __cpu_die(unsigned int cpu)
+{
+       extern struct plat_smp_ops *mp_ops;     /* private */
+
+       mp_ops->cpu_die(cpu);
+}
+
+extern void play_dead(void);
+#endif
+
 extern asmlinkage void smp_call_function_interrupt(void);
 
 extern void arch_send_call_function_single_ipi(int cpu);
index 3a56d90abfa670ebb805b6295e5c0528b02bd9ca..2367b56dcdef8badffd247e973524007cd859719 100644 (file)
@@ -11,6 +11,7 @@
 
 
 #ifndef __ASSEMBLY__
+#include <linux/smp.h>
 #include <linux/types.h>
 #endif /* !__ASSEMBLY__ */
 
index 99993c0d6c12bb3ea50996991c8072ed254d7155..97c2f81b4b43af66d766778ea2c17dcca6d8303b 100644 (file)
@@ -38,7 +38,11 @@ static inline __attribute_const__ __u32 __arch_swab32(__u32 x)
 }
 #define __arch_swab32 __arch_swab32
 
-#ifdef CONFIG_CPU_MIPS64_R2
+/*
+ * Having already checked for CONFIG_CPU_MIPSR2, enable the
+ * optimized version for 64-bit kernel on r2 CPUs.
+ */
+#ifdef CONFIG_64BIT
 static inline __attribute_const__ __u64 __arch_swab64(__u64 x)
 {
        __asm__(
@@ -50,6 +54,6 @@ static inline __attribute_const__ __u64 __arch_swab64(__u64 x)
        return x;
 }
 #define __arch_swab64 __arch_swab64
-#endif /* CONFIG_CPU_MIPS64_R2 */
+#endif /* CONFIG_64BIT */
 #endif /* CONFIG_CPU_MIPSR2 */
 #endif /* _ASM_SWAB_H */
index 143a48136a4b0f7e599adf1ce41d2bea290a7777..f9df720d2e40e215aa0cb21561f467d6d95a2b6b 100644 (file)
@@ -39,8 +39,6 @@ struct thread_info {
 
 /*
  * macros/functions for gaining access to the thread information structure
- *
- * preempt_count needs to be 1 initially, until the scheduler is functional.
  */
 #define INIT_THREAD_INFO(tsk)                  \
 {                                              \
@@ -48,7 +46,7 @@ struct thread_info {
        .exec_domain    = &default_exec_domain, \
        .flags          = _TIF_FIXADE,          \
        .cpu            = 0,                    \
-       .preempt_count  = 1,                    \
+       .preempt_count  = INIT_PREEMPT_COUNT,   \
        .addr_limit     = KERNEL_DS,            \
        .restart_block  = {                     \
                .fn = do_no_restart_syscall,    \
index 40005010827cb4f72c1734778a520a74c7958153..b70c49fdda26afb0b66b6f74f241d570da09ad09 100644 (file)
 #define __NR_inotify_init1             (__NR_Linux + 329)
 #define __NR_preadv                    (__NR_Linux + 330)
 #define __NR_pwritev                   (__NR_Linux + 331)
+#define __NR_rt_tgsigqueueinfo         (__NR_Linux + 332)
+#define __NR_perf_counter_open         (__NR_Linux + 333)
 
 /*
  * Offset of the last Linux o32 flavoured syscall
  */
-#define __NR_Linux_syscalls            331
+#define __NR_Linux_syscalls            333
 
 #endif /* _MIPS_SIM == _MIPS_SIM_ABI32 */
 
 #define __NR_O32_Linux                 4000
-#define __NR_O32_Linux_syscalls                331
+#define __NR_O32_Linux_syscalls                333
 
 #if _MIPS_SIM == _MIPS_SIM_ABI64
 
 #define __NR_inotify_init1             (__NR_Linux + 288)
 #define __NR_preadv                    (__NR_Linux + 289)
 #define __NR_pwritev                   (__NR_Linux + 290)
+#define __NR_rt_tgsigqueueinfo         (__NR_Linux + 291)
+#define __NR_perf_counter_open         (__NR_Linux + 292)
 
 /*
  * Offset of the last Linux 64-bit flavoured syscall
  */
-#define __NR_Linux_syscalls            290
+#define __NR_Linux_syscalls            292
 
 #endif /* _MIPS_SIM == _MIPS_SIM_ABI64 */
 
 #define __NR_64_Linux                  5000
-#define __NR_64_Linux_syscalls         290
+#define __NR_64_Linux_syscalls         292
 
 #if _MIPS_SIM == _MIPS_SIM_NABI32
 
 #define __NR_inotify_init1             (__NR_Linux + 292)
 #define __NR_preadv                    (__NR_Linux + 293)
 #define __NR_pwritev                   (__NR_Linux + 294)
+#define __NR_rt_tgsigqueueinfo         (__NR_Linux + 295)
+#define __NR_perf_counter_open         (__NR_Linux + 296)
 
 /*
  * Offset of the last N32 flavoured syscall
  */
-#define __NR_Linux_syscalls            294
+#define __NR_Linux_syscalls            296
 
 #endif /* _MIPS_SIM == _MIPS_SIM_NABI32 */
 
 #define __NR_N32_Linux                 6000
-#define __NR_N32_Linux_syscalls                294
+#define __NR_N32_Linux_syscalls                296
 
 #ifdef __KERNEL__
 
index e0ee05a3dfcccfd3c1bc13e1d843793bfb78f8ba..fcc6569414faaf2fda683289894fa78a32e8f985 100644 (file)
@@ -1,7 +1,7 @@
 /*
  *  capcella.h, Include file for ZAO Networks Capcella.
  *
- *  Copyright (C) 2002-2004  Yoichi Yuasa <yoichi_yuasa@tripeaks.co.jp>
+ *  Copyright (C) 2002-2004  Yoichi Yuasa <yuasa@linux-mips.org>
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
index 0bcdd3a5c2560b6817174af92d1e1dbfe2a9cd07..6a90bc1d916b4aa58ddc57ae6edd8ee40ae9b4ee 100644 (file)
@@ -1,7 +1,7 @@
 /*
  *  Include file for NEC VR4100 series General-purpose I/O Unit.
  *
- *  Copyright (C) 2005  Yoichi Yuasa <yoichi_yuasa@tripeaks.co.jp>
+ *  Copyright (C) 2005-2009  Yoichi Yuasa <yuasa@linux-mips.org>
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
@@ -41,7 +41,8 @@ typedef enum {
        IRQ_SIGNAL_HOLD,
 } irq_signal_t;
 
-extern void vr41xx_set_irq_trigger(unsigned int pin, irq_trigger_t trigger, irq_signal_t signal);
+extern void vr41xx_set_irq_trigger(unsigned int pin, irq_trigger_t trigger,
+                                  irq_signal_t signal);
 
 typedef enum {
        IRQ_LEVEL_LOW,
@@ -50,23 +51,6 @@ typedef enum {
 
 extern void vr41xx_set_irq_level(unsigned int pin, irq_level_t level);
 
-typedef enum {
-       GPIO_DATA_LOW,
-       GPIO_DATA_HIGH,
-       GPIO_DATA_INVAL,
-} gpio_data_t;
-
-extern gpio_data_t vr41xx_gpio_get_pin(unsigned int pin);
-extern int vr41xx_gpio_set_pin(unsigned int pin, gpio_data_t data);
-
-typedef enum {
-       GPIO_INPUT,
-       GPIO_OUTPUT,
-       GPIO_OUTPUT_DISABLE,
-} gpio_direction_t;
-
-extern int vr41xx_gpio_set_direction(unsigned int pin, gpio_direction_t dir);
-
 typedef enum {
        GPIO_PULL_DOWN,
        GPIO_PULL_UP,
index d315dfbc08f2c269fcc4b0c1ebfde5b0b38c5292..b07f7321751dd577004e4e3025acc272a09d31f2 100644 (file)
@@ -7,7 +7,7 @@
  * Copyright (C) 2001, 2002 Paul Mundt
  * Copyright (C) 2002 MontaVista Software, Inc.
  * Copyright (C) 2002 TimeSys Corp.
- * Copyright (C) 2003-2006 Yoichi Yuasa <yoichi_yuasa@tripeaks.co.jp>
+ * Copyright (C) 2003-2006 Yoichi Yuasa <yuasa@linux-mips.org>
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the
index 1d67df843dc32d93f9feada3ab2a3d0df5fe0454..130d09d8c8cbbc285a44fca21063569a4004454b 100644 (file)
@@ -1,7 +1,7 @@
 /*
  *  mpc30x.h, Include file for Victor MP-C303/304.
  *
- *  Copyright (C) 2002-2004  Yoichi Yuasa <yoichi_yuasa@tripeaks.co.jp>
+ *  Copyright (C) 2002-2004  Yoichi Yuasa <yuasa@linux-mips.org>
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
index 6fc01ce1977706fbb09325299342d55d7b073358..c231a3d6cfd8fb5ccb01b1da7cdb72238c1a84b3 100644 (file)
@@ -1,7 +1,7 @@
 /*
  *  Include file for NEC VR4100 series PCI Control Unit.
  *
- *  Copyright (C) 2004-2005  Yoichi Yuasa <yoichi_yuasa@tripeaks.co.jp>
+ *  Copyright (C) 2004-2005  Yoichi Yuasa <yuasa@linux-mips.org>
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
index da9f6e3734099b31198cf31dd77b6070e158fdbb..ca806bc4ddc8a8857247e3985672a8d343c49a0f 100644 (file)
@@ -1,7 +1,7 @@
 /*
  *  Include file for NEC VR4100 series Serial Interface Unit.
  *
- *  Copyright (C) 2005-2008  Yoichi Yuasa <yoichi_yuasa@tripeaks.co.jp>
+ *  Copyright (C) 2005-2008  Yoichi Yuasa <yuasa@linux-mips.org>
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
index dc981b4be0a404bd0ff3090baccbcd22be8d20ed..c78e8243b447e3b4fde3d697d58be19d125a6c45 100644 (file)
@@ -1,7 +1,7 @@
 /*
  *  tb0219.h, Include file for TANBAC TB0219.
  *
- *  Copyright (C) 2002-2004  Yoichi Yuasa <yoichi_yuasa@tripeaks.co.jp>
+ *  Copyright (C) 2002-2004  Yoichi Yuasa <yuasa@linux-mips.org>
  *
  *  Modified for TANBAC TB0219:
  *  Copyright (C) 2003 Megasolution Inc.  <matsu@megasolution.jp>
index de527dcfa5f31b0301430c170aa36cc0afba32bf..36f5f798e4169cb4a05db452960fcb97bbffa9be 100644 (file)
@@ -1,7 +1,7 @@
 /*
  *  tb0226.h, Include file for TANBAC TB0226.
  *
- *  Copyright (C) 2002-2004  Yoichi Yuasa <yoichi_yuasa@tripeaks.co.jp>
+ *  Copyright (C) 2002-2004  Yoichi Yuasa <yuasa@linux-mips.org>
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
index 22be64971cc69202823ddb79ff83f32500f1a7da..7b96a43b72ba5e09351f48e21a7d7d01006d1624 100644 (file)
@@ -7,7 +7,7 @@
  * Copyright (C) 2001, 2002 Paul Mundt
  * Copyright (C) 2002 MontaVista Software, Inc.
  * Copyright (C) 2002 TimeSys Corp.
- * Copyright (C) 2003-2008 Yoichi Yuasa <yoichi_yuasa@tripeaks.co.jp>
+ * Copyright (C) 2003-2008 Yoichi Yuasa <yuasa@linux-mips.org>
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the
index d9b6a5b5399d25b3959921288e84b08074571965..7fd170d007e7587d4839abcfd1f48370285c5c34 100644 (file)
@@ -10,6 +10,7 @@
 #include <linux/init.h>
 #include <linux/interrupt.h>
 #include <linux/kernel.h>
+#include <linux/smp.h>
 #include <linux/spinlock.h>
 
 #include <asm/irq_cpu.h>
index e1333d7319e275a065546490baa8401b87c9bf47..ff448233dab55737ca2ba1aa54edfa252263b924 100644 (file)
@@ -53,6 +53,23 @@ typedef elf_fpreg_t elf_fpregset_t[ELF_NFPREG];
 #define ELF_ET_DYN_BASE         (TASK32_SIZE / 3 * 2)
 
 #include <asm/processor.h>
+
+/*
+ * When this file is selected, we are definitely running a 64bit kernel.
+ * So using the right regs define in asm/reg.h
+ */
+#define WANT_COMPAT_REG_H
+
+/* These MUST be defined before elf.h gets included */
+extern void elf32_core_copy_regs(elf_gregset_t grp, struct pt_regs *regs);
+#define ELF_CORE_COPY_REGS(_dest, _regs) elf32_core_copy_regs(_dest, _regs);
+#define ELF_CORE_COPY_TASK_REGS(_tsk, _dest)                           \
+({                                                                     \
+       int __res = 1;                                                  \
+       elf32_core_copy_regs(*(_dest), task_pt_regs(_tsk));             \
+       __res;                                                          \
+})
+
 #include <linux/module.h>
 #include <linux/elfcore.h>
 #include <linux/compat.h>
@@ -110,9 +127,6 @@ jiffies_to_compat_timeval(unsigned long jiffies, struct compat_timeval *value)
        value->tv_usec = rem / NSEC_PER_USEC;
 }
 
-#undef ELF_CORE_COPY_REGS
-#define ELF_CORE_COPY_REGS(_dest, _regs) elf32_core_copy_regs(_dest, _regs);
-
 void elf32_core_copy_regs(elf_gregset_t grp, struct pt_regs *regs)
 {
        int i;
index a5182a20769619dda6bc81a216f89e2059769052..e02f79b1eb516f3213914fe2bc5fb3dec909b5c9 100644 (file)
@@ -18,6 +18,7 @@
 #include <linux/clockchips.h>
 #include <linux/interrupt.h>
 #include <linux/percpu.h>
+#include <linux/smp.h>
 
 #include <asm/addrspace.h>
 #include <asm/io.h>
index 1ada45ea07003d426cf591b2d639d45ffda0c53b..6996da4d74a276ed1d61cf07459fb7ac82dfd7db 100644 (file)
@@ -1,7 +1,7 @@
 /*
  *  DS1287 clockevent driver
  *
- *  Copyright (C) 2008  Yoichi Yuasa <yoichi_yuasa@tripeaks.co.jp>
+ *  Copyright (C) 2008  Yoichi Yuasa <yuasa@linux-mips.org>
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
index e9b787feedcb7595fb763e057cfb18a06fb1ede1..92351e00ae0e2ff3f98f8d7432aebf88d659966f 100644 (file)
@@ -1,7 +1,7 @@
 /*
  *  GT641xx clockevent routines.
  *
- *  Copyright (C) 2007  Yoichi Yuasa <yoichi_yuasa@tripeaks.co.jp>
+ *  Copyright (C) 2007  Yoichi Yuasa <yuasa@linux-mips.org>
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
index 0015e442572b5189b8f9b1dba5a25f96041d2493..2652362ce0477d9449dfbd6fa4a0f7e48a2f0ef0 100644 (file)
@@ -9,6 +9,7 @@
 #include <linux/clockchips.h>
 #include <linux/interrupt.h>
 #include <linux/percpu.h>
+#include <linux/smp.h>
 
 #include <asm/smtc_ipi.h>
 #include <asm/time.h>
index 340f53e5c6b19cd686f2a45bd69dc3f139d581d1..ac5903d1b20e3490bd7e3f0cc02336184c5f7777 100644 (file)
@@ -18,6 +18,7 @@
 #include <linux/clockchips.h>
 #include <linux/interrupt.h>
 #include <linux/percpu.h>
+#include <linux/smp.h>
 
 #include <asm/addrspace.h>
 #include <asm/io.h>
index df6f5bc60572b4e2425f76166ee81d60b3d0c720..98bd7de7577811e13c4a04379025f8c6e026a24d 100644 (file)
@@ -10,6 +10,7 @@
 #include <linux/clockchips.h>
 #include <linux/interrupt.h>
 #include <linux/percpu.h>
+#include <linux/smp.h>
 
 #include <asm/smtc_ipi.h>
 #include <asm/time.h>
index b13b8eb3059631c732479aa4da8ed35c4cb48c5c..1abe9905c9c1895ef220bc51f7f4ddf366b5cfad 100644 (file)
@@ -14,6 +14,7 @@
 #include <linux/init.h>
 #include <linux/kernel.h>
 #include <linux/ptrace.h>
+#include <linux/smp.h>
 #include <linux/stddef.h>
 
 #include <asm/bugs.h>
index b551f48d3a076483eccd3b543f6188c4f87797df..23da108506b0a325a8c0c4f8de12d744129d2676 100644 (file)
@@ -1,7 +1,7 @@
 /*
  *  DEC I/O ASIC's counter clocksource
  *
- *  Copyright (C) 2008  Yoichi Yuasa <yoichi_yuasa@tripeaks.co.jp>
+ *  Copyright (C) 2008  Yoichi Yuasa <yuasa@linux-mips.org>
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
index ed20e7fe65e3270dfe2fe9c41cc3eee071ddcd4b..f7d8d5d0ddbf0337978cacacf5232b38bf4a87a4 100644 (file)
@@ -7,6 +7,7 @@
 #include <linux/interrupt.h>
 #include <linux/jiffies.h>
 #include <linux/module.h>
+#include <linux/smp.h>
 #include <linux/spinlock.h>
 
 #include <asm/delay.h>
index 3f43c2e3aa5a59ede8eab7ecdaee7762ea6afb68..d2072cd385922db78c5b1278622ad4d4243a4949 100644 (file)
@@ -2,6 +2,7 @@
 
 #include <linux/bitmap.h>
 #include <linux/init.h>
+#include <linux/smp.h>
 
 #include <asm/io.h>
 #include <asm/gic.h>
@@ -106,9 +107,7 @@ static unsigned int gic_irq_startup(unsigned int irq)
 {
        pr_debug("CPU%d: %s: irq%d\n", smp_processor_id(), __func__, irq);
        irq -= _irqbase;
-       /* FIXME: this is wrong for !GICISWORDLITTLEENDIAN */
-       GICWRITE(GIC_REG_ADDR(SHARED, (GIC_SH_SMASK_31_0_OFS + (irq / 32))),
-                1 << (irq % 32));
+       GIC_SET_INTR_MASK(irq, 1);
        return 0;
 }
 
@@ -119,8 +118,7 @@ static void gic_irq_ack(unsigned int irq)
 #endif
        pr_debug("CPU%d: %s: irq%d\n", smp_processor_id(), __func__, irq);
        irq -= _irqbase;
-       GICWRITE(GIC_REG_ADDR(SHARED, (GIC_SH_RMASK_31_0_OFS + (irq / 32))),
-                1 << (irq % 32));
+       GIC_CLR_INTR_MASK(irq, 1);
 
        if (_intrmap[irq].trigtype == GIC_TRIG_EDGE) {
                if (!gic_wedgeb2bok)
@@ -137,18 +135,14 @@ static void gic_mask_irq(unsigned int irq)
 {
        pr_debug("CPU%d: %s: irq%d\n", smp_processor_id(), __func__, irq);
        irq -= _irqbase;
-       /* FIXME: this is wrong for !GICISWORDLITTLEENDIAN */
-       GICWRITE(GIC_REG_ADDR(SHARED, (GIC_SH_RMASK_31_0_OFS + (irq / 32))),
-                1 << (irq % 32));
+       GIC_CLR_INTR_MASK(irq, 1);
 }
 
 static void gic_unmask_irq(unsigned int irq)
 {
        pr_debug("CPU%d: %s: irq%d\n", smp_processor_id(), __func__, irq);
        irq -= _irqbase;
-       /* FIXME: this is wrong for !GICISWORDLITTLEENDIAN */
-       GICWRITE(GIC_REG_ADDR(SHARED, (GIC_SH_SMASK_31_0_OFS + (irq / 32))),
-                1 << (irq % 32));
+       GIC_SET_INTR_MASK(irq, 1);
 }
 
 #ifdef CONFIG_SMP
@@ -253,6 +247,10 @@ static void __init gic_basic_init(void)
                if (cpu == X)
                        continue;
 
+               if (cpu == 0 && i != 0 && _intrmap[i].intrnum == 0 &&
+                                       _intrmap[i].ipiflag == 0)
+                       continue;
+
                setup_intr(_intrmap[i].intrnum,
                                _intrmap[i].cpunum,
                                _intrmap[i].pin,
index 1b81b131f43c9acff2f39b9b954651555020a06a..ebcc5f7ad9c21e6155413e826613c5dc39c58220 100644 (file)
@@ -1,7 +1,7 @@
 /*
  *  GT641xx IRQ routines.
  *
- *  Copyright (C) 2007  Yoichi Yuasa <yoichi_yuasa@tripeaks.co.jp>
+ *  Copyright (C) 2007  Yoichi Yuasa <yuasa@linux-mips.org>
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
index 6e152c80cd4a5bb3d0a73816311a850181371b81..50c9bb880667560bbb6f869e8b6af60a60d2a66e 100644 (file)
@@ -26,6 +26,7 @@
 #include <linux/kgdb.h>
 #include <linux/kdebug.h>
 #include <linux/sched.h>
+#include <linux/smp.h>
 #include <asm/inst.h>
 #include <asm/fpu.h>
 #include <asm/cacheflush.h>
index 1eaaa450e20c3a83be8daf6cafe0e2935e45e5a1..c09d681b7181dbc15851cc9f425ae98ba6e3c561 100644 (file)
  */
 void __noreturn cpu_idle(void)
 {
+       int cpu;
+
+       /* CPU is going idle. */
+       cpu = smp_processor_id();
+
        /* endless idle loop with no priority at all */
        while (1) {
                tick_nohz_stop_sched_tick(1);
-               while (!need_resched()) {
+               while (!need_resched() && cpu_online(cpu)) {
 #ifdef CONFIG_MIPS_MT_SMTC
                        extern void smtc_idle_loop_hook(void);
 
@@ -62,6 +67,12 @@ void __noreturn cpu_idle(void)
                        if (cpu_wait)
                                (*cpu_wait)();
                }
+#ifdef CONFIG_HOTPLUG_CPU
+               if (!cpu_online(cpu) && !cpu_isset(cpu, cpu_callin_map) &&
+                   (system_state == SYSTEM_RUNNING ||
+                    system_state == SYSTEM_BOOTING))
+                       play_dead();
+#endif
                tick_nohz_restart_sched_tick();
                preempt_enable_no_resched();
                schedule();
index c4f9ac17474a2157d7a6ab12e0c485cd61b11c48..32644b4a07144979be8d1466ad639787abcf795d 100644 (file)
@@ -22,7 +22,6 @@
 #include <linux/errno.h>
 #include <linux/ptrace.h>
 #include <linux/smp.h>
-#include <linux/smp_lock.h>
 #include <linux/user.h>
 #include <linux/security.h>
 
index 0b31b9bda0486988128d39d07d52ac2c0d0ad8d8..20a86e08fd58d4bf942688fd4e4d02d1333d4a8a 100644 (file)
@@ -652,6 +652,8 @@ einval:     li      v0, -ENOSYS
        sys     sys_inotify_init1       1
        sys     sys_preadv              6       /* 4330 */
        sys     sys_pwritev             6
+       sys     sys_rt_tgsigqueueinfo   4
+       sys     sys_perf_counter_open   5
        .endm
 
        /* We pre-compute the number of _instruction_ bytes needed to
index c647fd6e722f7acb2872ad0f01491b6f2a2637e9..b046130d4c5d57338c3aa5aac9b109eff297d412 100644 (file)
@@ -489,4 +489,6 @@ sys_call_table:
        PTR     sys_inotify_init1
        PTR     sys_preadv
        PTR     sys_pwritev                     /* 5390 */
+       PTR     sys_rt_tgsigqueueinfo
+       PTR     sys_perf_counter_open
        .size   sys_call_table,.-sys_call_table
index 93cc672f4522169977739553eeb1001ddb40bd2b..15874f9812ccc1cb3fae7d56147fc51502f10810 100644 (file)
@@ -415,4 +415,6 @@ EXPORT(sysn32_call_table)
        PTR     sys_inotify_init1
        PTR     sys_preadv
        PTR     sys_pwritev
+       PTR     compat_sys_rt_tgsigqueueinfo    /* 5295 */
+       PTR     sys_perf_counter_open
        .size   sysn32_call_table,.-sysn32_call_table
index a5598b2339dd451a4586d3dde4b30050a48c5290..781e0f1e9533ae3f36c9624b3f9554d3c90520a2 100644 (file)
@@ -535,4 +535,6 @@ sys_call_table:
        PTR     sys_inotify_init1
        PTR     compat_sys_preadv               /* 4330 */
        PTR     compat_sys_pwritev
+       PTR     compat_sys_rt_tgsigqueueinfo
+       PTR     sys_perf_counter_open
        .size   sys_call_table,.-sys_call_table
index f27beca4b26d22c67366b1be5d1f263637ad21c3..ad0ff5dc4d59bfbcdef6e967f1317b0ea2459c3a 100644 (file)
@@ -20,6 +20,7 @@
 
 #include <linux/kernel.h>
 #include <linux/sched.h>
+#include <linux/smp.h>
 #include <linux/cpumask.h>
 #include <linux/interrupt.h>
 #include <linux/compiler.h>
 #include <asm/mipsregs.h>
 #include <asm/mipsmtregs.h>
 #include <asm/mips_mt.h>
-
-/*
- * Crude manipulation of the CPU masks to control which
- * which CPU's are brought online during initialisation
- *
- * Beware... this needs to be called after CPU discovery
- * but before CPU bringup
- */
-static int __init allowcpus(char *str)
-{
-       cpumask_t cpu_allow_map;
-       char buf[256];
-       int len;
-
-       cpus_clear(cpu_allow_map);
-       if (cpulist_parse(str, &cpu_allow_map) == 0) {
-               cpu_set(0, cpu_allow_map);
-               cpus_and(cpu_possible_map, cpu_possible_map, cpu_allow_map);
-               len = cpulist_scnprintf(buf, sizeof(buf)-1, &cpu_possible_map);
-               buf[len] = '\0';
-               pr_debug("Allowable CPUs: %s\n", buf);
-               return 1;
-       } else
-               return 0;
-}
-__setup("allowcpus=", allowcpus);
+#include <asm/amon.h>
+#include <asm/gic.h>
 
 static void ipi_call_function(unsigned int cpu)
 {
-       unsigned int action = 0;
-
        pr_debug("CPU%d: %s cpu %d status %08x\n",
                 smp_processor_id(), __func__, cpu, read_c0_status());
 
-       switch (cpu) {
-       case 0:
-               action = GIC_IPI_EXT_INTR_CALLFNC_VPE0;
-               break;
-       case 1:
-               action = GIC_IPI_EXT_INTR_CALLFNC_VPE1;
-               break;
-       case 2:
-               action = GIC_IPI_EXT_INTR_CALLFNC_VPE2;
-               break;
-       case 3:
-               action = GIC_IPI_EXT_INTR_CALLFNC_VPE3;
-               break;
-       }
-       gic_send_ipi(action);
+       gic_send_ipi(plat_ipi_call_int_xlate(cpu));
 }
 
 
 static void ipi_resched(unsigned int cpu)
 {
-       unsigned int action = 0;
-
        pr_debug("CPU%d: %s cpu %d status %08x\n",
                 smp_processor_id(), __func__, cpu, read_c0_status());
 
-       switch (cpu) {
-       case 0:
-               action = GIC_IPI_EXT_INTR_RESCHED_VPE0;
-               break;
-       case 1:
-               action = GIC_IPI_EXT_INTR_RESCHED_VPE1;
-               break;
-       case 2:
-               action = GIC_IPI_EXT_INTR_RESCHED_VPE2;
-               break;
-       case 3:
-               action = GIC_IPI_EXT_INTR_RESCHED_VPE3;
-               break;
-       }
-       gic_send_ipi(action);
+       gic_send_ipi(plat_ipi_resched_int_xlate(cpu));
 }
 
 /*
@@ -205,7 +150,7 @@ static void cmp_boot_secondary(int cpu, struct task_struct *idle)
                           (unsigned long)(gp + sizeof(struct thread_info)));
 #endif
 
-       amon_cpu_start(cpu, pc, sp, gp, a0);
+       amon_cpu_start(cpu, pc, sp, (unsigned long)gp, a0);
 }
 
 /*
index 878e3733bbb2c6577074899e34cb034accee3d60..2508d55d68fd4b7292013bd6fd8964f865d23250 100644 (file)
@@ -55,6 +55,18 @@ static void __init up_prepare_cpus(unsigned int max_cpus)
 {
 }
 
+#ifdef CONFIG_HOTPLUG_CPU
+static int up_cpu_disable(void)
+{
+       return -ENOSYS;
+}
+
+static void up_cpu_die(unsigned int cpu)
+{
+       BUG();
+}
+#endif
+
 struct plat_smp_ops up_smp_ops = {
        .send_ipi_single        = up_send_ipi_single,
        .send_ipi_mask          = up_send_ipi_mask,
@@ -64,4 +76,8 @@ struct plat_smp_ops up_smp_ops = {
        .boot_secondary         = up_boot_secondary,
        .smp_setup              = up_smp_setup,
        .prepare_cpus           = up_prepare_cpus,
+#ifdef CONFIG_HOTPLUG_CPU
+       .cpu_disable            = up_cpu_disable,
+       .cpu_die                = up_cpu_die,
+#endif
 };
index c937506a03aac9f1eedcea13f05e30c0ed0c9fcc..bc7d9b05e2f4e4d218f0b87c81ee98e9f708b34a 100644 (file)
@@ -22,6 +22,7 @@
 #include <linux/delay.h>
 #include <linux/init.h>
 #include <linux/interrupt.h>
+#include <linux/smp.h>
 #include <linux/spinlock.h>
 #include <linux/threads.h>
 #include <linux/module.h>
@@ -44,7 +45,7 @@
 #include <asm/mipsmtregs.h>
 #endif /* CONFIG_MIPS_MT_SMTC */
 
-static volatile cpumask_t cpu_callin_map;      /* Bitmask of started secondaries */
+volatile cpumask_t cpu_callin_map;     /* Bitmask of started secondaries */
 int __cpu_number_map[NR_CPUS];         /* Map physical to logical */
 int __cpu_logical_map[NR_CPUS];                /* Map logical to physical */
 
@@ -200,6 +201,8 @@ void __devinit smp_prepare_boot_cpu(void)
  * and keep control until "cpu_online(cpu)" is set.  Note: cpu is
  * physical, not logical.
  */
+static struct task_struct *cpu_idle_thread[NR_CPUS];
+
 int __cpuinit __cpu_up(unsigned int cpu)
 {
        struct task_struct *idle;
@@ -209,9 +212,16 @@ int __cpuinit __cpu_up(unsigned int cpu)
         * The following code is purely to make sure
         * Linux can schedule processes on this slave.
         */
-       idle = fork_idle(cpu);
-       if (IS_ERR(idle))
-               panic(KERN_ERR "Fork failed for CPU %d", cpu);
+       if (!cpu_idle_thread[cpu]) {
+               idle = fork_idle(cpu);
+               cpu_idle_thread[cpu] = idle;
+
+               if (IS_ERR(idle))
+                       panic(KERN_ERR "Fork failed for CPU %d", cpu);
+       } else {
+               idle = cpu_idle_thread[cpu];
+               init_idle(idle, cpu);
+       }
 
        mp_ops->boot_secondary(cpu, idle);
 
index 37d51cd124e9d6e7ec11230f0d38d475b3276267..8a0626cbb108ff0a1231dadb74b54b4a2d3576a9 100644 (file)
@@ -20,6 +20,7 @@
 #include <linux/clockchips.h>
 #include <linux/kernel.h>
 #include <linux/sched.h>
+#include <linux/smp.h>
 #include <linux/cpumask.h>
 #include <linux/interrupt.h>
 #include <linux/kernel_stat.h>
index 9021108eb9c1af0edbf67946284ebf3dad8c5513..05dd170a83f7e379ec4e40fe37c454e2c7a4e61a 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * Count register synchronisation.
  *
- * All CPUs will have their count registers synchronised to the CPU0 expirelo
+ * All CPUs will have their count registers synchronised to the CPU0 next time
  * value. This can cause a small timewarp for CPU0. All other CPU's should
  * not have done anything significant (but they may have had interrupts
  * enabled briefly - prom_smp_finish() should not be responsible for enabling
 #include <linux/kernel.h>
 #include <linux/init.h>
 #include <linux/irqflags.h>
-#include <linux/r4k-timer.h>
+#include <linux/cpumask.h>
 
+#include <asm/r4k-timer.h>
 #include <asm/atomic.h>
 #include <asm/barrier.h>
-#include <asm/cpumask.h>
 #include <asm/mipsregs.h>
 
-static atomic_t __initdata count_start_flag = ATOMIC_INIT(0);
-static atomic_t __initdata count_count_start = ATOMIC_INIT(0);
-static atomic_t __initdata count_count_stop = ATOMIC_INIT(0);
+static atomic_t __cpuinitdata count_start_flag = ATOMIC_INIT(0);
+static atomic_t __cpuinitdata count_count_start = ATOMIC_INIT(0);
+static atomic_t __cpuinitdata count_count_stop = ATOMIC_INIT(0);
+static atomic_t __cpuinitdata count_reference = ATOMIC_INIT(0);
 
 #define COUNTON        100
 #define NR_LOOPS 5
 
-void __init synchronise_count_master(void)
+void __cpuinit synchronise_count_master(void)
 {
        int i;
        unsigned long flags;
@@ -42,19 +43,20 @@ void __init synchronise_count_master(void)
        return;
 #endif
 
-       pr_info("Checking COUNT synchronization across %u CPUs: ",
-               num_online_cpus());
+       printk(KERN_INFO "Synchronize counters across %u CPUs: ",
+              num_online_cpus());
 
        local_irq_save(flags);
 
        /*
         * Notify the slaves that it's time to start
         */
+       atomic_set(&count_reference, read_c0_count());
        atomic_set(&count_start_flag, 1);
        smp_wmb();
 
-       /* Count will be initialised to expirelo for all CPU's */
-       initcount = expirelo;
+       /* Count will be initialised to current timer for all CPU's */
+       initcount = read_c0_count();
 
        /*
         * We loop a few times to get a primed instruction cache,
@@ -106,7 +108,7 @@ void __init synchronise_count_master(void)
        printk("done.\n");
 }
 
-void __init synchronise_count_slave(void)
+void __cpuinit synchronise_count_slave(void)
 {
        int i;
        unsigned long flags;
@@ -131,8 +133,8 @@ void __init synchronise_count_slave(void)
        while (!atomic_read(&count_start_flag))
                mb();
 
-       /* Count will be initialised to expirelo for all CPU's */
-       initcount = expirelo;
+       /* Count will be initialised to next expire for all CPU's */
+       initcount = atomic_read(&count_reference);
 
        ncpus = num_online_cpus();
        for (i = 0; i < NR_LOOPS; i++) {
@@ -156,4 +158,3 @@ void __init synchronise_count_slave(void)
        local_irq_restore(flags);
 }
 #undef NR_LOOPS
-#endif
index 660e44ed44d72dc794225d4338e696bf2384ea60..cf3eb61fad121340707b8ccfe1baf6fcb4993a42 100644 (file)
@@ -17,7 +17,10 @@ static int __init topology_init(void)
 #endif /* CONFIG_NUMA */
 
        for_each_present_cpu(i) {
-               ret = register_cpu(&per_cpu(cpu_devices, i), i);
+               struct cpu *c = &per_cpu(cpu_devices, i);
+
+               c->hotpluggable = 1;
+               ret = register_cpu(c, i);
                if (ret)
                        printk(KERN_WARNING "topology_init: register_cpu %d "
                               "failed (%d)\n", i, ret);
index 3ca5f42e819dc3ab4a6793510216d38218b6bc72..07b9ec2c6e3d04d1194a46a66e6783f2dcf0d29b 100644 (file)
@@ -1387,7 +1387,7 @@ static ssize_t store_ntcs(struct device *dev, struct device_attribute *attr,
        return len;
 
 out_einval:
-       return -EINVAL;;
+       return -EINVAL;
 }
 
 static struct device_attribute vpe_class_attributes[] = {
index 881ecbc1fa238d62790bcf9dcd946137cad7639f..0cea932f12411f069b0bde34d6a76535178650c0 100644 (file)
@@ -91,6 +91,7 @@ unsigned __cpuinit get_c0_compare_int(void)
                mips_cpu_timer_irq = MSC01E_INT_BASE + MSC01E_INT_CPUCTR;
        } else {
 #endif
+              {
                if (cpu_has_vint)
                        set_vi_handler(cp0_compare_irq, mips_timer_dispatch);
                mips_cpu_timer_irq = MIPS_CPU_IRQ_BASE + cp0_compare_irq;
index 44d01a0a849070d7943c209d16d8aaa55035cfdb..b165cdcb281815e4d95452283ac87ba8150200ed 100644 (file)
@@ -8,6 +8,7 @@
 #include <linux/init.h>
 #include <linux/kernel.h>
 #include <linux/sched.h>
+#include <linux/smp.h>
 #include <linux/mm.h>
 #include <linux/bitops.h>
 #include <linux/cpu.h>
index 5500c20c79aeafc491c3b9b43cbe8f5e816e084c..54e5f7b9f440a973f555a5f76b841093ee38e710 100644 (file)
@@ -12,6 +12,7 @@
 #include <linux/init.h>
 #include <linux/kernel.h>
 #include <linux/sched.h>
+#include <linux/smp.h>
 #include <linux/mm.h>
 
 #include <asm/page.h>
index 71fe4cb778cd9b92d70122ce17e72984c3fc9093..6721ee2b1e8ba8308730f262898dc3c792730f49 100644 (file)
@@ -13,6 +13,7 @@
 #include <linux/kernel.h>
 #include <linux/linkage.h>
 #include <linux/sched.h>
+#include <linux/smp.h>
 #include <linux/mm.h>
 #include <linux/module.h>
 #include <linux/bitops.h>
index f7c8f9ce39c1b1e983d54b6414c3a4bd1a2b8010..6515b4418714d454d55ac311d11c21663f355835 100644 (file)
@@ -11,6 +11,7 @@
 #include <linux/init.h>
 #include <linux/kernel.h>
 #include <linux/sched.h>
+#include <linux/smp.h>
 #include <linux/mm.h>
 
 #include <asm/cacheops.h>
index 2b1309b2580a79e09a4be60d315317842f1a9295..e274fda329f4e5bc9ef0a90484972b650390e2b0 100644 (file)
@@ -1,5 +1,6 @@
 #include <linux/module.h>
 #include <linux/highmem.h>
+#include <linux/smp.h>
 #include <asm/fixmap.h>
 #include <asm/tlbflush.h>
 
index 471c09aa1614ae4aebe0b3d4143cef29e9bd52e9..8c2834f5919da563a06a861206cf37164b06615c 100644 (file)
@@ -16,7 +16,6 @@
 #include <linux/mm.h>
 #include <linux/hugetlb.h>
 #include <linux/pagemap.h>
-#include <linux/smp_lock.h>
 #include <linux/slab.h>
 #include <linux/err.h>
 #include <linux/sysctl.h>
index c5511294a9eef5106e1783759d74fd02b17d2b4f..0e820508ff23fd8bbfe8a4642c5f9acf1c3a9e73 100644 (file)
@@ -13,6 +13,7 @@
 #include <linux/module.h>
 #include <linux/signal.h>
 #include <linux/sched.h>
+#include <linux/smp.h>
 #include <linux/kernel.h>
 #include <linux/errno.h>
 #include <linux/string.h>
index 48060c635acdc91458fe2528c599c395ae410b6b..f5c73754d664ec9ef4d84a1c12245cecb8dfbc67 100644 (file)
@@ -10,6 +10,7 @@
 #include <linux/init.h>
 #include <linux/kernel.h>
 #include <linux/sched.h>
+#include <linux/smp.h>
 #include <linux/mm.h>
 #include <linux/module.h>
 #include <linux/proc_fs.h>
index 1c0048a6f5cf082531cf8e189e1d7712725d2614..0f5ab236ab69e30bba6076060d6b8a18b277a02c 100644 (file)
@@ -13,6 +13,7 @@
 #include <linux/init.h>
 #include <linux/kernel.h>
 #include <linux/sched.h>
+#include <linux/smp.h>
 #include <linux/mm.h>
 
 #include <asm/page.h>
index f60fe513eb60ca91e91fe3956d0920eb79b75a57..cee502caf398403bef0365c7969b1ecfad6c8626 100644 (file)
@@ -10,6 +10,7 @@
  */
 #include <linux/init.h>
 #include <linux/sched.h>
+#include <linux/smp.h>
 #include <linux/mm.h>
 #include <linux/hugetlb.h>
 
index 4ec95cc2df2f06b9811434cb14791a401a5968dd..2b82f23df1a12dfab17d83c228c3128d208f1685 100644 (file)
@@ -10,6 +10,7 @@
  */
 #include <linux/init.h>
 #include <linux/sched.h>
+#include <linux/smp.h>
 #include <linux/mm.h>
 
 #include <asm/cpu.h>
index 8f606ead826e29502a571dfc654b7450b69ce6ac..9a17bf8395df1c92be94a48a6820891623154fe6 100644 (file)
@@ -23,6 +23,7 @@
 #include <linux/bug.h>
 #include <linux/kernel.h>
 #include <linux/types.h>
+#include <linux/smp.h>
 #include <linux/string.h>
 #include <linux/init.h>
 
index 475038a141a65038ee34792a6d06395010004a93..27c807b67feaf4fc1a8f7e745462d8dd1bcc9624 100644 (file)
@@ -30,6 +30,7 @@
 #include <asm/cacheflush.h>
 #include <asm/traps.h>
 
+#include <asm/gcmpregs.h>
 #include <asm/mips-boards/prom.h>
 #include <asm/mips-boards/generic.h>
 #include <asm/mips-boards/bonito64.h>
@@ -192,6 +193,8 @@ extern struct plat_smp_ops msmtc_smp_ops;
 
 void __init prom_init(void)
 {
+       int result;
+
        prom_argc = fw_arg0;
        _prom_argv = (int *) fw_arg1;
        _prom_envp = (int *) fw_arg2;
@@ -358,12 +361,21 @@ void __init prom_init(void)
 #ifdef CONFIG_SERIAL_8250_CONSOLE
        console_config();
 #endif
+       /* Early detection of CMP support */
+       result = gcmp_probe(GCMP_BASE_ADDR, GCMP_ADDRSPACE_SZ);
+
 #ifdef CONFIG_MIPS_CMP
-       register_smp_ops(&cmp_smp_ops);
+       if (result)
+               register_smp_ops(&cmp_smp_ops);
 #endif
 #ifdef CONFIG_MIPS_MT_SMP
+#ifdef CONFIG_MIPS_CMP
+       if (!result)
+               register_smp_ops(&vsmp_smp_ops);
+#else
        register_smp_ops(&vsmp_smp_ops);
 #endif
+#endif
 #ifdef CONFIG_MIPS_MT_SMTC
        register_smp_ops(&msmtc_smp_ops);
 #endif
index ea176113fea9b46b7b2aafeadc57ce2757f13d34..a8756f82c31b9d6d06a7f5191c9d7c67fc28118c 100644 (file)
@@ -24,6 +24,7 @@
 #include <linux/init.h>
 #include <linux/irq.h>
 #include <linux/sched.h>
+#include <linux/smp.h>
 #include <linux/slab.h>
 #include <linux/interrupt.h>
 #include <linux/io.h>
@@ -330,6 +331,21 @@ static struct irqaction irq_call = {
        .flags          = IRQF_DISABLED|IRQF_PERCPU,
        .name           = "IPI_call"
 };
+
+static int gic_resched_int_base;
+static int gic_call_int_base;
+#define GIC_RESCHED_INT(cpu) (gic_resched_int_base+(cpu))
+#define GIC_CALL_INT(cpu) (gic_call_int_base+(cpu))
+
+unsigned int plat_ipi_call_int_xlate(unsigned int cpu)
+{
+       return GIC_CALL_INT(cpu);
+}
+
+unsigned int plat_ipi_resched_int_xlate(unsigned int cpu)
+{
+       return GIC_RESCHED_INT(cpu);
+}
 #endif /* CONFIG_MIPS_MT_SMP */
 
 static struct irqaction i8259irq = {
@@ -369,7 +385,7 @@ static int __initdata msc_nr_eicirqs = ARRAY_SIZE(msc_eicirqmap);
  * Interrupts and CPUs/Core Interrupts. The nature of the External
  * Interrupts is also defined here - polarity/trigger.
  */
-static struct gic_intr_map gic_intr_map[] = {
+static struct gic_intr_map gic_intr_map[GIC_NUM_INTRS] = {
        { GIC_EXT_INTR(0),      X,      X,              X,              X,              0 },
        { GIC_EXT_INTR(1),      X,      X,              X,              X,              0 },
        { GIC_EXT_INTR(2),      X,      X,              X,              X,              0 },
@@ -386,21 +402,14 @@ static struct gic_intr_map gic_intr_map[] = {
        { GIC_EXT_INTR(13),     0,      GIC_MAP_TO_NMI_MSK,     GIC_POL_POS, GIC_TRIG_LEVEL,    0 },
        { GIC_EXT_INTR(14),     0,      GIC_MAP_TO_NMI_MSK,     GIC_POL_POS, GIC_TRIG_LEVEL,    0 },
        { GIC_EXT_INTR(15),     X,      X,              X,              X,              0 },
-       { GIC_EXT_INTR(16),     0,      GIC_CPU_INT1,   GIC_POL_POS, GIC_TRIG_EDGE,     1 },
-       { GIC_EXT_INTR(17),     0,      GIC_CPU_INT2,   GIC_POL_POS, GIC_TRIG_EDGE,     1 },
-       { GIC_EXT_INTR(18),     1,      GIC_CPU_INT1,   GIC_POL_POS, GIC_TRIG_EDGE,     1 },
-       { GIC_EXT_INTR(19),     1,      GIC_CPU_INT2,   GIC_POL_POS, GIC_TRIG_EDGE,     1 },
-       { GIC_EXT_INTR(20),     2,      GIC_CPU_INT1,   GIC_POL_POS, GIC_TRIG_EDGE,     1 },
-       { GIC_EXT_INTR(21),     2,      GIC_CPU_INT2,   GIC_POL_POS, GIC_TRIG_EDGE,     1 },
-       { GIC_EXT_INTR(22),     3,      GIC_CPU_INT1,   GIC_POL_POS, GIC_TRIG_EDGE,     1 },
-       { GIC_EXT_INTR(23),     3,      GIC_CPU_INT2,   GIC_POL_POS, GIC_TRIG_EDGE,     1 },
+/* This is the end of the general interrupts now we do IPI ones */
 };
 #endif
 
 /*
  * GCMP needs to be detected before any SMP initialisation
  */
-static int __init gcmp_probe(unsigned long addr, unsigned long size)
+int __init gcmp_probe(unsigned long addr, unsigned long size)
 {
        if (gcmp_present >= 0)
                return gcmp_present;
@@ -415,28 +424,36 @@ static int __init gcmp_probe(unsigned long addr, unsigned long size)
 }
 
 #if defined(CONFIG_MIPS_MT_SMP)
+static void __init fill_ipi_map1(int baseintr, int cpu, int cpupin)
+{
+       int intr = baseintr + cpu;
+       gic_intr_map[intr].intrnum = GIC_EXT_INTR(intr);
+       gic_intr_map[intr].cpunum = cpu;
+       gic_intr_map[intr].pin = cpupin;
+       gic_intr_map[intr].polarity = GIC_POL_POS;
+       gic_intr_map[intr].trigtype = GIC_TRIG_EDGE;
+       gic_intr_map[intr].ipiflag = 1;
+       ipi_map[cpu] |= (1 << (cpupin + 2));
+}
+
 static void __init fill_ipi_map(void)
 {
-       int i;
+       int cpu;
 
-       for (i = 0; i < ARRAY_SIZE(gic_intr_map); i++) {
-               if (gic_intr_map[i].ipiflag && (gic_intr_map[i].cpunum != X))
-                       ipi_map[gic_intr_map[i].cpunum] |=
-                               (1 << (gic_intr_map[i].pin + 2));
+       for (cpu = 0; cpu < NR_CPUS; cpu++) {
+               fill_ipi_map1(gic_resched_int_base, cpu, GIC_CPU_INT1);
+               fill_ipi_map1(gic_call_int_base, cpu, GIC_CPU_INT2);
        }
 }
 #endif
 
 void __init arch_init_irq(void)
 {
-       int gic_present, gcmp_present;
-
        init_i8259_irqs();
 
        if (!cpu_has_veic)
                mips_cpu_irq_init();
 
-       gcmp_present = gcmp_probe(GCMP_BASE_ADDR, GCMP_ADDRSPACE_SZ);
        if (gcmp_present)  {
                GCMPGCB(GICBA) = GIC_BASE_ADDR | GCMP_GCB_GICBA_EN_MSK;
                gic_present = 1;
@@ -513,24 +530,10 @@ void __init arch_init_irq(void)
        if (gic_present) {
                /* FIXME */
                int i;
-               struct {
-                       unsigned int resched;
-                       unsigned int call;
-               } ipiirq[] = {
-                       {
-                               .resched = GIC_IPI_EXT_INTR_RESCHED_VPE0,
-                               .call =  GIC_IPI_EXT_INTR_CALLFNC_VPE0},
-                       {
-                               .resched = GIC_IPI_EXT_INTR_RESCHED_VPE1,
-                               .call =  GIC_IPI_EXT_INTR_CALLFNC_VPE1
-                       }, {
-                               .resched = GIC_IPI_EXT_INTR_RESCHED_VPE2,
-                               .call =  GIC_IPI_EXT_INTR_CALLFNC_VPE2
-                       }, {
-                               .resched = GIC_IPI_EXT_INTR_RESCHED_VPE3,
-                               .call =  GIC_IPI_EXT_INTR_CALLFNC_VPE3
-                       }
-               };
+
+               gic_call_int_base = GIC_NUM_INTRS - NR_CPUS;
+               gic_resched_int_base = gic_call_int_base - NR_CPUS;
+
                fill_ipi_map();
                gic_init(GIC_BASE_ADDR, GIC_ADDRSPACE_SZ, gic_intr_map, ARRAY_SIZE(gic_intr_map), MIPS_GIC_IRQ_BASE);
                if (!gcmp_present) {
@@ -552,12 +555,15 @@ void __init arch_init_irq(void)
                printk("CPU%d: status register now %08x\n", smp_processor_id(), read_c0_status());
                write_c0_status(0x1100dc00);
                printk("CPU%d: status register frc %08x\n", smp_processor_id(), read_c0_status());
-               for (i = 0; i < ARRAY_SIZE(ipiirq); i++) {
-                       setup_irq(MIPS_GIC_IRQ_BASE + ipiirq[i].resched, &irq_resched);
-                       setup_irq(MIPS_GIC_IRQ_BASE + ipiirq[i].call, &irq_call);
-
-                       set_irq_handler(MIPS_GIC_IRQ_BASE + ipiirq[i].resched, handle_percpu_irq);
-                       set_irq_handler(MIPS_GIC_IRQ_BASE + ipiirq[i].call, handle_percpu_irq);
+               for (i = 0; i < NR_CPUS; i++) {
+                       setup_irq(MIPS_GIC_IRQ_BASE +
+                                       GIC_RESCHED_INT(i), &irq_resched);
+                       setup_irq(MIPS_GIC_IRQ_BASE +
+                                       GIC_CALL_INT(i), &irq_call);
+                       set_irq_handler(MIPS_GIC_IRQ_BASE +
+                                       GIC_RESCHED_INT(i), handle_percpu_irq);
+                       set_irq_handler(MIPS_GIC_IRQ_BASE +
+                                       GIC_CALL_INT(i), handle_percpu_irq);
                }
        } else {
                /* set up ipi interrupts */
index 42dee4da37bad5ad5d0b2932b475bf99577d9e2c..f48d60e8429017b52352e8e0b59bc18faa0e9061 100644 (file)
@@ -28,9 +28,6 @@
 #include <asm/reboot.h>
 #include <asm/mips-boards/generic.h>
 
-static void mips_machine_restart(char *command);
-static void mips_machine_halt(void);
-
 static void mips_machine_restart(char *command)
 {
        unsigned int __iomem *softres_reg =
index e8a97f59e0661e585fc40565212d0e7d74130d1f..63d8a297c58da4f85abf378fa4da6e7e2c9ed5e6 100644 (file)
@@ -52,3 +52,8 @@ obj-$(CONFIG_VICTOR_MPC30X)   += fixup-mpc30x.o
 obj-$(CONFIG_ZAO_CAPCELLA)     += fixup-capcella.o
 obj-$(CONFIG_WR_PPMC)          += fixup-wrppmc.o
 obj-$(CONFIG_MIKROTIK_RB532)   += pci-rc32434.o ops-rc32434.o fixup-rc32434.o
+obj-$(CONFIG_CPU_CAVIUM_OCTEON)        += pci-octeon.o pcie-octeon.o
+
+ifdef CONFIG_PCI_MSI
+obj-$(CONFIG_CPU_CAVIUM_OCTEON)        += msi-octeon.o
+endif
index 1416bca6d1a3f8962bd23e76d34d0668c703d767..1c02f5737367aa7e75569afeb98aebcd3ebb5327 100644 (file)
@@ -1,7 +1,7 @@
 /*
  *  fixup-cappcela.c, The ZAO Networks Capcella specific PCI fixups.
  *
- *  Copyright (C) 2002,2004  Yoichi Yuasa <yoichi_yuasa@tripeaks.co.jp>
+ *  Copyright (C) 2002,2004  Yoichi Yuasa <yuasa@linux-mips.org>
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
index 5911596257222dec18a807e3fdae132ac2548a50..e08f49cb6875abd65d50b7cb1cee964f816d96b7 100644 (file)
@@ -1,7 +1,7 @@
 /*
  *  fixup-mpc30x.c, The Victor MP-C303/304 specific PCI fixups.
  *
- *  Copyright (C) 2002,2004  Yoichi Yuasa <yoichi_yuasa@tripeaks.co.jp>
+ *  Copyright (C) 2002,2004  Yoichi Yuasa <yuasa@linux-mips.org>
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
index ed87733f679682d778b4b31a1cd62c10ffbe3f45..8084b17d44066a3f1ca658902f4b191939c91d84 100644 (file)
@@ -2,7 +2,7 @@
  *  fixup-tb0219.c, The TANBAC TB0219 specific PCI fixups.
  *
  *  Copyright (C) 2003  Megasolution Inc. <matsu@megasolution.jp>
- *  Copyright (C) 2004-2005  Yoichi Yuasa <yoichi_yuasa@tripeaks.co.jp>
+ *  Copyright (C) 2004-2005  Yoichi Yuasa <yuasa@linux-mips.org>
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
index e3eedf4bf9bd088567074cd3dc12df6f28fac811..4196ccf3ea3da5e6783de7acd913f68d2fc218bc 100644 (file)
@@ -1,7 +1,7 @@
 /*
  *  fixup-tb0226.c, The TANBAC TB0226 specific PCI fixups.
  *
- *  Copyright (C) 2002-2005  Yoichi Yuasa <yoichi_yuasa@tripeaks.co.jp>
+ *  Copyright (C) 2002-2005  Yoichi Yuasa <yuasa@linux-mips.org>
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
index 267ab3dc3d421420cde426812bf71ce6d661acaa..2fe29db4372595d5393ab11b38c8ac3f0fff466d 100644 (file)
@@ -1,7 +1,7 @@
 /*
  *  fixup-tb0287.c, The TANBAC TB0287 specific PCI fixups.
  *
- *  Copyright (C) 2005  Yoichi Yuasa <yoichi_yuasa@tripeaks.co.jp>
+ *  Copyright (C) 2005  Yoichi Yuasa <yuasa@linux-mips.org>
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
similarity index 88%
rename from arch/mips/cavium-octeon/msi.c
rename to arch/mips/pci/msi-octeon.c
index 964b03b75a8f29b775ea0b19d80c1d23763230dc..03742e64765717ec3976c0eb7d7e77c8d8a283e0 100644 (file)
@@ -3,7 +3,7 @@
  * License.  See the file "COPYING" in the main directory of this archive
  * for more details.
  *
- * Copyright (C) 2005-2007 Cavium Networks
+ * Copyright (C) 2005-2009 Cavium Networks
  */
 #include <linux/kernel.h>
 #include <linux/init.h>
@@ -16,8 +16,7 @@
 #include <asm/octeon/cvmx-pci-defs.h>
 #include <asm/octeon/cvmx-npei-defs.h>
 #include <asm/octeon/cvmx-pexp-defs.h>
-
-#include "pci-common.h"
+#include <asm/octeon/pci-octeon.h>
 
 /*
  * Each bit in msi_free_irq_bitmask represents a MSI interrupt that is
@@ -47,8 +46,8 @@ static DEFINE_SPINLOCK(msi_free_irq_bitmask_lock);
  * programming the MSI control bits [6:4] before calling
  * pci_enable_msi().
  *
- * @param dev    Device requesting MSI interrupts
- * @param desc   MSI descriptor
+ * @dev:    Device requesting MSI interrupts
+ * @desc:   MSI descriptor
  *
  * Returns 0 on success.
  */
@@ -213,14 +212,9 @@ void arch_teardown_msi_irq(unsigned int irq)
 }
 
 
-/**
+/*
  * Called by the interrupt handling code when an MSI interrupt
  * occurs.
- *
- * @param cpl
- * @param dev_id
- *
- * @return
  */
 static irqreturn_t octeon_msi_interrupt(int cpl, void *dev_id)
 {
@@ -256,31 +250,37 @@ static irqreturn_t octeon_msi_interrupt(int cpl, void *dev_id)
 }
 
 
-/**
+/*
  * Initializes the MSI interrupt handling code
- *
- * @return
  */
 int octeon_msi_initialize(void)
 {
-       int r;
        if (octeon_has_feature(OCTEON_FEATURE_PCIE)) {
-               r = request_irq(OCTEON_IRQ_PCI_MSI0, octeon_msi_interrupt,
+               if (request_irq(OCTEON_IRQ_PCI_MSI0, octeon_msi_interrupt,
                                IRQF_SHARED,
-                               "MSI[0:63]", octeon_msi_interrupt);
+                               "MSI[0:63]", octeon_msi_interrupt))
+                       panic("request_irq(OCTEON_IRQ_PCI_MSI0) failed");
        } else if (octeon_is_pci_host()) {
-               r = request_irq(OCTEON_IRQ_PCI_MSI0, octeon_msi_interrupt,
+               if (request_irq(OCTEON_IRQ_PCI_MSI0, octeon_msi_interrupt,
                                IRQF_SHARED,
-                               "MSI[0:15]", octeon_msi_interrupt);
-               r += request_irq(OCTEON_IRQ_PCI_MSI1, octeon_msi_interrupt,
-                                IRQF_SHARED,
-                                "MSI[16:31]", octeon_msi_interrupt);
-               r += request_irq(OCTEON_IRQ_PCI_MSI2, octeon_msi_interrupt,
-                                IRQF_SHARED,
-                                "MSI[32:47]", octeon_msi_interrupt);
-               r += request_irq(OCTEON_IRQ_PCI_MSI3, octeon_msi_interrupt,
-                                IRQF_SHARED,
-                                "MSI[48:63]", octeon_msi_interrupt);
+                               "MSI[0:15]", octeon_msi_interrupt))
+                       panic("request_irq(OCTEON_IRQ_PCI_MSI0) failed");
+
+               if (request_irq(OCTEON_IRQ_PCI_MSI1, octeon_msi_interrupt,
+                               IRQF_SHARED,
+                               "MSI[16:31]", octeon_msi_interrupt))
+                       panic("request_irq(OCTEON_IRQ_PCI_MSI1) failed");
+
+               if (request_irq(OCTEON_IRQ_PCI_MSI2, octeon_msi_interrupt,
+                               IRQF_SHARED,
+                               "MSI[32:47]", octeon_msi_interrupt))
+                       panic("request_irq(OCTEON_IRQ_PCI_MSI2) failed");
+
+               if (request_irq(OCTEON_IRQ_PCI_MSI3, octeon_msi_interrupt,
+                               IRQF_SHARED,
+                               "MSI[48:63]", octeon_msi_interrupt))
+                       panic("request_irq(OCTEON_IRQ_PCI_MSI3) failed");
+
        }
        return 0;
 }
index 900c6b32576c3db47e301655f42b5ca4f4c69f4b..28962a7c66066140865072556c741441ee9b2fd8 100644 (file)
@@ -2,8 +2,8 @@
  *  ops-vr41xx.c, PCI configuration routines for the PCIU of NEC VR4100 series.
  *
  *  Copyright (C) 2001-2003 MontaVista Software Inc.
- *    Author: Yoichi Yuasa <yyuasa@mvista.com or source@mvista.com>
- *  Copyright (C) 2004-2005  Yoichi Yuasa <yoichi_yuasa@tripeaks.co.jp>
+ *    Author: Yoichi Yuasa <source@mvista.com>
+ *  Copyright (C) 2004-2005  Yoichi Yuasa <yuasa@linux-mips.org>
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
@@ -21,7 +21,7 @@
  */
 /*
  * Changes:
- *  MontaVista Software Inc. <yyuasa@mvista.com> or <source@mvista.com>
+ *  MontaVista Software Inc. <source@mvista.com>
  *  - New creation, NEC VR4122 and VR4131 are supported.
  */
 #include <linux/pci.h>
index dda6f2058665b665c3a857c8a2e420f97f74f194..a0e726eb039aeb0cd8c842d72873d4fcfd8ed3a7 100644 (file)
@@ -10,6 +10,7 @@
 #include <linux/init.h>
 #include <linux/kernel.h>
 #include <linux/pci.h>
+#include <linux/smp.h>
 #include <asm/sn/arch.h>
 #include <asm/pci/bridge.h>
 #include <asm/paccess.h>
similarity index 78%
rename from arch/mips/cavium-octeon/pci.c
rename to arch/mips/pci/pci-octeon.c
index 67c0ff5e92f1a528a7b133c1df206001cbf7532f..9cb0c807f564bdc00ac7e0f3f4e6ee43d4c1d730 100644 (file)
@@ -3,7 +3,7 @@
  * License.  See the file "COPYING" in the main directory of this archive
  * for more details.
  *
- * Copyright (C) 2005-2007 Cavium Networks
+ * Copyright (C) 2005-2009 Cavium Networks
  */
 #include <linux/kernel.h>
 #include <linux/init.h>
@@ -17,8 +17,7 @@
 #include <asm/octeon/octeon.h>
 #include <asm/octeon/cvmx-npi-defs.h>
 #include <asm/octeon/cvmx-pci-defs.h>
-
-#include "pci-common.h"
+#include <asm/octeon/pci-octeon.h>
 
 #define USE_OCTEON_INTERNAL_ARBITER
 
@@ -54,6 +53,126 @@ union octeon_pci_address {
        } s;
 };
 
+int __initdata (*octeon_pcibios_map_irq)(const struct pci_dev *dev,
+                                        u8 slot, u8 pin);
+enum octeon_dma_bar_type octeon_dma_bar_type = OCTEON_DMA_BAR_TYPE_INVALID;
+
+/**
+ * Map a PCI device to the appropriate interrupt line
+ *
+ * @dev:    The Linux PCI device structure for the device to map
+ * @slot:   The slot number for this device on __BUS 0__. Linux
+ *               enumerates through all the bridges and figures out the
+ *               slot on Bus 0 where this device eventually hooks to.
+ * @pin:    The PCI interrupt pin read from the device, then swizzled
+ *               as it goes through each bridge.
+ * Returns Interrupt number for the device
+ */
+int __init pcibios_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
+{
+       if (octeon_pcibios_map_irq)
+               return octeon_pcibios_map_irq(dev, slot, pin);
+       else
+               panic("octeon_pcibios_map_irq not set.");
+}
+
+
+/*
+ * Called to perform platform specific PCI setup
+ */
+int pcibios_plat_dev_init(struct pci_dev *dev)
+{
+       uint16_t config;
+       uint32_t dconfig;
+       int pos;
+       /*
+        * Force the Cache line setting to 64 bytes. The standard
+        * Linux bus scan doesn't seem to set it. Octeon really has
+        * 128 byte lines, but Intel bridges get really upset if you
+        * try and set values above 64 bytes. Value is specified in
+        * 32bit words.
+        */
+       pci_write_config_byte(dev, PCI_CACHE_LINE_SIZE, 64 / 4);
+       /* Set latency timers for all devices */
+       pci_write_config_byte(dev, PCI_LATENCY_TIMER, 48);
+
+       /* Enable reporting System errors and parity errors on all devices */
+       /* Enable parity checking and error reporting */
+       pci_read_config_word(dev, PCI_COMMAND, &config);
+       config |= PCI_COMMAND_PARITY | PCI_COMMAND_SERR;
+       pci_write_config_word(dev, PCI_COMMAND, config);
+
+       if (dev->subordinate) {
+               /* Set latency timers on sub bridges */
+               pci_write_config_byte(dev, PCI_SEC_LATENCY_TIMER, 48);
+               /* More bridge error detection */
+               pci_read_config_word(dev, PCI_BRIDGE_CONTROL, &config);
+               config |= PCI_BRIDGE_CTL_PARITY | PCI_BRIDGE_CTL_SERR;
+               pci_write_config_word(dev, PCI_BRIDGE_CONTROL, config);
+       }
+
+       /* Enable the PCIe normal error reporting */
+       pos = pci_find_capability(dev, PCI_CAP_ID_EXP);
+       if (pos) {
+               /* Update Device Control */
+               pci_read_config_word(dev, pos + PCI_EXP_DEVCTL, &config);
+               /* Correctable Error Reporting */
+               config |= PCI_EXP_DEVCTL_CERE;
+               /* Non-Fatal Error Reporting */
+               config |= PCI_EXP_DEVCTL_NFERE;
+               /* Fatal Error Reporting */
+               config |= PCI_EXP_DEVCTL_FERE;
+               /* Unsupported Request */
+               config |= PCI_EXP_DEVCTL_URRE;
+               pci_write_config_word(dev, pos + PCI_EXP_DEVCTL, config);
+       }
+
+       /* Find the Advanced Error Reporting capability */
+       pos = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_ERR);
+       if (pos) {
+               /* Clear Uncorrectable Error Status */
+               pci_read_config_dword(dev, pos + PCI_ERR_UNCOR_STATUS,
+                                     &dconfig);
+               pci_write_config_dword(dev, pos + PCI_ERR_UNCOR_STATUS,
+                                      dconfig);
+               /* Enable reporting of all uncorrectable errors */
+               /* Uncorrectable Error Mask - turned on bits disable errors */
+               pci_write_config_dword(dev, pos + PCI_ERR_UNCOR_MASK, 0);
+               /*
+                * Leave severity at HW default. This only controls if
+                * errors are reported as uncorrectable or
+                * correctable, not if the error is reported.
+                */
+               /* PCI_ERR_UNCOR_SEVER - Uncorrectable Error Severity */
+               /* Clear Correctable Error Status */
+               pci_read_config_dword(dev, pos + PCI_ERR_COR_STATUS, &dconfig);
+               pci_write_config_dword(dev, pos + PCI_ERR_COR_STATUS, dconfig);
+               /* Enable reporting of all correctable errors */
+               /* Correctable Error Mask - turned on bits disable errors */
+               pci_write_config_dword(dev, pos + PCI_ERR_COR_MASK, 0);
+               /* Advanced Error Capabilities */
+               pci_read_config_dword(dev, pos + PCI_ERR_CAP, &dconfig);
+               /* ECRC Generation Enable */
+               if (config & PCI_ERR_CAP_ECRC_GENC)
+                       config |= PCI_ERR_CAP_ECRC_GENE;
+               /* ECRC Check Enable */
+               if (config & PCI_ERR_CAP_ECRC_CHKC)
+                       config |= PCI_ERR_CAP_ECRC_CHKE;
+               pci_write_config_dword(dev, pos + PCI_ERR_CAP, dconfig);
+               /* PCI_ERR_HEADER_LOG - Header Log Register (16 bytes) */
+               /* Report all errors to the root complex */
+               pci_write_config_dword(dev, pos + PCI_ERR_ROOT_COMMAND,
+                                      PCI_ERR_ROOT_CMD_COR_EN |
+                                      PCI_ERR_ROOT_CMD_NONFATAL_EN |
+                                      PCI_ERR_ROOT_CMD_FATAL_EN);
+               /* Clear the Root status register */
+               pci_read_config_dword(dev, pos + PCI_ERR_ROOT_STATUS, &dconfig);
+               pci_write_config_dword(dev, pos + PCI_ERR_ROOT_STATUS, dconfig);
+       }
+
+       return 0;
+}
+
 /**
  * Return the mapping of PCI device number to IRQ line. Each
  * character in the return string represents the interrupt
@@ -136,9 +255,8 @@ int __init octeon_pci_pcibios_map_irq(const struct pci_dev *dev,
 }
 
 
-/**
+/*
  * Read a value from configuration space
- *
  */
 static int octeon_read_config(struct pci_bus *bus, unsigned int devfn,
                              int reg, int size, u32 *val)
@@ -174,15 +292,8 @@ static int octeon_read_config(struct pci_bus *bus, unsigned int devfn,
 }
 
 
-/**
+/*
  * Write a value to PCI configuration space
- *
- * @bus:
- * @devfn:
- * @reg:
- * @size:
- * @val:
- * Returns
  */
 static int octeon_write_config(struct pci_bus *bus, unsigned int devfn,
                               int reg, int size, u32 val)
@@ -251,10 +362,8 @@ static struct pci_controller octeon_pci_controller = {
 };
 
 
-/**
+/*
  * Low level initialize the Octeon PCI controller
- *
- * Returns
  */
 static void octeon_pci_initialize(void)
 {
@@ -398,7 +507,7 @@ static void octeon_pci_initialize(void)
                pci_int_arb_cfg.s.en = 1;       /* Internal arbiter enable */
                cvmx_write_csr(CVMX_NPI_PCI_INT_ARB_CFG, pci_int_arb_cfg.u64);
        }
-#endif                         /* USE_OCTEON_INTERNAL_ARBITER */
+#endif /* USE_OCTEON_INTERNAL_ARBITER */
 
        /*
         * Preferrably written to 1 to set MLTD. [RDSATI,TRTAE,
@@ -457,10 +566,8 @@ static void octeon_pci_initialize(void)
 }
 
 
-/**
+/*
  * Initialize the Octeon PCI controller
- *
- * Returns
  */
 static int __init octeon_pci_setup(void)
 {
index d1e049b55f34f07f2035f830fd82d7324f8fbe41..56525711f8b75deb270b6c6b7f32db0b38289029 100644 (file)
@@ -2,8 +2,8 @@
  *  pci-vr41xx.c, PCI Control Unit routines for the NEC VR4100 series.
  *
  *  Copyright (C) 2001-2003 MontaVista Software Inc.
- *    Author: Yoichi Yuasa <yyuasa@mvista.com or source@mvista.com>
- *  Copyright (C) 2004-2008  Yoichi Yuasa <yoichi_yuasa@tripeaks.co.jp>
+ *    Author: Yoichi Yuasa <source@mvista.com>
+ *  Copyright (C) 2004-2008  Yoichi Yuasa <yuasa@linux-mips.org>
  *  Copyright (C) 2004 by Ralf Baechle (ralf@linux-mips.org)
  *
  *  This program is free software; you can redistribute it and/or modify
@@ -22,7 +22,7 @@
  */
 /*
  * Changes:
- *  MontaVista Software Inc. <yyuasa@mvista.com> or <source@mvista.com>
+ *  MontaVista Software Inc. <source@mvista.com>
  *  - New creation, NEC VR4122 and VR4131 are supported.
  */
 #include <linux/init.h>
index 8a35e32b8376f734f61da3a74ec5b8726f5f1e48..6b1ae2eb1c065bc3b5b547ec6ff6258e14f05926 100644 (file)
@@ -2,8 +2,8 @@
  *  pci-vr41xx.h, Include file for PCI Control Unit of the NEC VR4100 series.
  *
  *  Copyright (C) 2002  MontaVista Software Inc.
- *    Author: Yoichi Yuasa <yyuasa@mvista.com or source@mvista.com>
- *  Copyright (C) 2004-2005  Yoichi Yuasa <yoichi_yuasa@tripeaks.co.jp>
+ *    Author: Yoichi Yuasa <source@mvista.com>
+ *  Copyright (C) 2004-2005  Yoichi Yuasa <yuasa@linux-mips.org>
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
similarity index 98%
rename from arch/mips/cavium-octeon/pcie.c
rename to arch/mips/pci/pcie-octeon.c
index 49d14081b3b5aa2585911f812732a04cf61a7f12..75262247f3e482d445c677dcf6d4d2590b596727 100644 (file)
@@ -18,8 +18,7 @@
 #include <asm/octeon/cvmx-pescx-defs.h>
 #include <asm/octeon/cvmx-pexp-defs.h>
 #include <asm/octeon/cvmx-helper-errata.h>
-
-#include "pci-common.h"
+#include <asm/octeon/pci-octeon.h>
 
 union cvmx_pcie_address {
        uint64_t u64;
@@ -976,13 +975,13 @@ static int cvmx_pcie_rc_initialize(int pcie_port)
 /**
  * Map a PCI device to the appropriate interrupt line
  *
- * @param dev    The Linux PCI device structure for the device to map
- * @param slot   The slot number for this device on __BUS 0__. Linux
+ * @dev:    The Linux PCI device structure for the device to map
+ * @slot:   The slot number for this device on __BUS 0__. Linux
  *               enumerates through all the bridges and figures out the
  *               slot on Bus 0 where this device eventually hooks to.
- * @param pin    The PCI interrupt pin read from the device, then swizzled
+ * @pin:    The PCI interrupt pin read from the device, then swizzled
  *               as it goes through each bridge.
- * @return Interrupt number for the device
+ * Returns Interrupt number for the device
  */
 int __init octeon_pcie_pcibios_map_irq(const struct pci_dev *dev,
                                       u8 slot, u8 pin)
@@ -1025,12 +1024,12 @@ int __init octeon_pcie_pcibios_map_irq(const struct pci_dev *dev,
 /**
  * Read a value from configuration space
  *
- * @param bus
- * @param devfn
- * @param reg
- * @param size
- * @param val
- * @return
+ * @bus:
+ * @devfn:
+ * @reg:
+ * @size:
+ * @val:
+ * Returns
  */
 static inline int octeon_pcie_read_config(int pcie_port, struct pci_bus *bus,
                                          unsigned int devfn, int reg, int size,
@@ -1156,12 +1155,12 @@ static int octeon_pcie1_read_config(struct pci_bus *bus, unsigned int devfn,
 /**
  * Write a value to PCI configuration space
  *
- * @param bus
- * @param devfn
- * @param reg
- * @param size
- * @param val
- * @return
+ * @bus:
+ * @devfn:
+ * @reg:
+ * @size:
+ * @val:
+ * Returns
  */
 static inline int octeon_pcie_write_config(int pcie_port, struct pci_bus *bus,
                                           unsigned int devfn, int reg,
@@ -1254,7 +1253,7 @@ static struct pci_controller octeon_pcie1_controller = {
 /**
  * Initialize the Octeon PCIe controllers
  *
- * @return
+ * Returns
  */
 static int __init octeon_pcie_setup(void)
 {
index f78c29b68d77015e114195154c76671e2ce7d1a6..8ace27716232ec496f0a2ba5045e653dc8320765 100644 (file)
@@ -1,5 +1,6 @@
 #include <linux/linkage.h>
 #include <linux/sched.h>
+#include <linux/smp.h>
 
 #include <asm/pmon.h>
 #include <asm/titan_dep.h>
index 486bd3fd01a14669e8ce9140d8729db10c95dcf0..4b8174b382d742f17e3dc846a67f1e707f26c432 100644 (file)
@@ -43,15 +43,6 @@ LEAF(swsusp_arch_resume)
        bne t1, t3, 1b
        PTR_L t0, PBE_NEXT(t0)
        bnez t0, 0b
-       /* flush caches to make sure context is in memory */
-       PTR_L t0, __flush_cache_all
-       jalr t0
-       /* flush tlb entries */
-#ifdef CONFIG_SMP
-       jal     flush_tlb_all
-#else
-       jal     local_flush_tlb_all
-#endif
        PTR_LA t0, saved_regs
        PTR_L ra, PT_R31(t0)
        PTR_L sp, PT_R29(t0)
index 4a500e8cd3cc2e86f0e4503b871f918095a1757a..51d3a4f2d7e1bed2df4a85071b4b435399ff9f9d 100644 (file)
@@ -9,6 +9,7 @@
 #include <linux/kernel.h>
 #include <linux/init.h>
 #include <linux/sched.h>
+#include <linux/smp.h>
 #include <linux/mm.h>
 #include <linux/module.h>
 #include <linux/cpumask.h>
index 1bb692a3b31948d2a9abb4a13e7f5049ae38886a..c1c8e40d65d6a5f5353768d0729f067097d0dad3 100644 (file)
@@ -18,6 +18,7 @@
 #include <linux/ioport.h>
 #include <linux/timex.h>
 #include <linux/slab.h>
+#include <linux/smp.h>
 #include <linux/random.h>
 #include <linux/kernel.h>
 #include <linux/kernel_stat.h>
index f10a7cd64f7eb787f05039f22f382f7783478af4..6d0e59ffba2ed17826a13d475961c7c10fe82c4a 100644 (file)
@@ -10,6 +10,7 @@
 #include <linux/interrupt.h>
 #include <linux/kernel_stat.h>
 #include <linux/param.h>
+#include <linux/smp.h>
 #include <linux/time.h>
 #include <linux/timex.h>
 #include <linux/mm.h>
index 6ae64e8dfc408473ddd9f34ee569886f8c0abac3..5e871e75a8d9c3cabd975b4495199d4dbbba079d 100644 (file)
@@ -9,6 +9,7 @@
 
 #include <linux/init.h>
 #include <linux/kernel.h>
+#include <linux/smp.h>
 #include <asm/sn/types.h>
 #include <asm/sn/klconfig.h>
 #include <asm/sn/hub.h>
index 690de06bde902f38a49b8d1e1765ae3fd2251b48..ba59839a021ee688b37761e54b8cd966abc537e5 100644 (file)
@@ -19,6 +19,7 @@
 #include <linux/init.h>
 #include <linux/linkage.h>
 #include <linux/interrupt.h>
+#include <linux/smp.h>
 #include <linux/spinlock.h>
 #include <linux/mm.h>
 #include <linux/slab.h>
index 81e3d54376e920d3e6b73aa23c71a7bb614dd7d7..1ad2da103fe9016f95207500d4c0b7def5c1fe61 100644 (file)
@@ -51,12 +51,13 @@ static int cfe_console_setup(struct console *cons, char *str)
                        setleds("u0cn");
                } else if (!strcmp(consdev, "uart1")) {
                        setleds("u1cn");
+               } else
 #endif
 #ifdef CONFIG_VGA_CONSOLE
-               } else if (!strcmp(consdev, "pcconsole0")) {
-                       setleds("pccn");
-#endif
+                      if (!strcmp(consdev, "pcconsole0")) {
+                               setleds("pccn");
                } else
+#endif
                        return -ENODEV;
        }
        return 0;
index 69f5f88711cca8721cbc97ad4fda96e6682ecffd..0d9ec1a5c24aa679df38fa0faabdf5c1046d3b0d 100644 (file)
@@ -1,5 +1,6 @@
 #include <linux/types.h>
 #include <linux/interrupt.h>
+#include <linux/smp.h>
 #include <linux/time.h>
 #include <linux/clockchips.h>
 
index 6d9bab8905877fe1b7b0324a4670bd424584b706..719f4a5b984458103ac95de630b0c6d3dfb9d7ae 100644 (file)
@@ -1,7 +1,7 @@
 /*
  *  setup.c, Setup for the CASIO CASSIOPEIA E-11/15/55/65.
  *
- *  Copyright (C) 2002-2006  Yoichi Yuasa <yoichi_yuasa@tripeaks.co.jp>
+ *  Copyright (C) 2002-2006  Yoichi Yuasa <yuasa@linux-mips.org>
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
index d77c330a0d592b49b700597529ec48a0f03e2f4a..6346c59c9f9d96d361396944c4e40e4fb20052e6 100644 (file)
@@ -2,8 +2,8 @@
  *  bcu.c, Bus Control Unit routines for the NEC VR4100 series.
  *
  *  Copyright (C) 2002  MontaVista Software Inc.
- *    Author: Yoichi Yuasa <yyuasa@mvista.com, or source@mvista.com>
- *  Copyright (C) 2003-2005  Yoichi Yuasa <yoichi_yuasa@tripeaks.co.jp>
+ *    Author: Yoichi Yuasa <source@mvista.com>
+ *  Copyright (C) 2003-2005  Yoichi Yuasa <yuasa@linux-mips.org>
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
  */
 /*
  * Changes:
- *  MontaVista Software Inc. <yyuasa@mvista.com> or <source@mvista.com>
+ *  MontaVista Software Inc. <source@mvista.com>
  *  - New creation, NEC VR4122 and VR4131 are supported.
  *  - Added support for NEC VR4111 and VR4121.
  *
- *  Yoichi Yuasa <yoichi_yuasa@tripeaks.co.jp>
+ *  Yoichi Yuasa <yuasa@linux-mips.org>
  *  - Added support for NEC VR4133.
  */
 #include <linux/kernel.h>
index ad0e8e3409d9099d3d6450a31533c1204574b152..8ba7d04a5ec58e4b05cf1d792eb766698b66e850 100644 (file)
@@ -2,8 +2,8 @@
  *  cmu.c, Clock Mask Unit routines for the NEC VR4100 series.
  *
  *  Copyright (C) 2001-2002  MontaVista Software Inc.
- *    Author: Yoichi Yuasa <yyuasa@mvista.com or source@mvista.com>
- *  Copuright (C) 2003-2005  Yoichi Yuasa <yoichi_yuasa@tripeaks.co.jp>
+ *    Author: Yoichi Yuasa <source@mvista.com>
+ *  Copuright (C) 2003-2005  Yoichi Yuasa <yuasa@linux-mips.org>
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
  */
 /*
  * Changes:
- *  MontaVista Software Inc. <yyuasa@mvista.com> or <source@mvista.com>
+ *  MontaVista Software Inc. <source@mvista.com>
  *  - New creation, NEC VR4122 and VR4131 are supported.
  *  - Added support for NEC VR4111 and VR4121.
  *
- *  Yoichi Yuasa <yoichi_yuasa@tripeaks.co.jp>
+ *  Yoichi Yuasa <yuasa@linux-mips.org>
  *  - Added support for NEC VR4133.
  */
 #include <linux/init.h>
index 2b272f1496fe97e55b57975e1850ad32e2ee26e0..22cc6f2100a1acba6d15f983804c3ee46660bdaa 100644 (file)
@@ -1,7 +1,7 @@
 /*
  *  NEC VR4100 series GIU platform device.
  *
- *  Copyright (C) 2007  Yoichi Yuasa <yoichi_yuasa@tripeaks.co.jp>
+ *  Copyright (C) 2007  Yoichi Yuasa <yuasa@linux-mips.org>
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
index 3f23d9fda662621e2879ff37a2d1ecbef24cf1a5..6d39e222b170b1db7250cb990c7726f875127305 100644 (file)
@@ -2,8 +2,8 @@
  *  icu.c, Interrupt Control Unit routines for the NEC VR4100 series.
  *
  *  Copyright (C) 2001-2002  MontaVista Software Inc.
- *    Author: Yoichi Yuasa <yyuasa@mvista.com or source@mvista.com>
- *  Copyright (C) 2003-2006  Yoichi Yuasa <yoichi_yuasa@tripeaks.co.jp>
+ *    Author: Yoichi Yuasa <source@mvista.com>
+ *  Copyright (C) 2003-2006  Yoichi Yuasa <yuasa@linux-mips.org>
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
  */
 /*
  * Changes:
- *  MontaVista Software Inc. <yyuasa@mvista.com> or <source@mvista.com>
+ *  MontaVista Software Inc. <source@mvista.com>
  *  - New creation, NEC VR4122 and VR4131 are supported.
  *  - Added support for NEC VR4111 and VR4121.
  *
- *  Yoichi Yuasa <yoichi_yuasa@tripeaks.co.jp>
+ *  Yoichi Yuasa <yuasa@linux-mips.org>
  *  - Coped with INTASSIGN of NEC VR4133.
  */
 #include <linux/errno.h>
index c64995342ba82f12922267674f46936fbf2b9571..1386e6f081c86aa370e3ddf31179b07b668f9ba0 100644 (file)
@@ -1,7 +1,7 @@
 /*
  *  init.c, Common initialization routines for NEC VR4100 series.
  *
- *  Copyright (C) 2003-2008  Yoichi Yuasa <yoichi_yuasa@tripeaks.co.jp>
+ *  Copyright (C) 2003-2008  Yoichi Yuasa <yuasa@linux-mips.org>
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
index 9cc389109b19f42ee82f5d09f69b8d3e8de27024..bef06872f012d6ecb055aafeae92d9ed6f962135 100644 (file)
@@ -1,7 +1,7 @@
 /*
  *  Interrupt handing routines for NEC VR4100 series.
  *
- *  Copyright (C) 2005-2007  Yoichi Yuasa <yoichi_yuasa@tripeaks.co.jp>
+ *  Copyright (C) 2005-2007  Yoichi Yuasa <yuasa@linux-mips.org>
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
index 028aaf75eb216690a5217cfa69fb1bb65a4d4d5f..692b4e85b7fc98475ed33b5a8f3b9efd6733aa67 100644 (file)
@@ -1,7 +1,7 @@
 /*
  *  pmu.c, Power Management Unit routines for NEC VR4100 series.
  *
- *  Copyright (C) 2003-2007  Yoichi Yuasa <yoichi_yuasa@tripeaks.co.jp>
+ *  Copyright (C) 2003-2007  Yoichi Yuasa <yuasa@linux-mips.org>
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
index 9f26c14edcac25cfdbf588babf855c9b0b1d8109..ebc5dcf0ed8e29dad672a529e6cf6abf45c66f6c 100644 (file)
@@ -1,7 +1,7 @@
 /*
  *  NEC VR4100 series RTC platform device.
  *
- *  Copyright (C) 2007  Yoichi Yuasa <yoichi_yuasa@tripeaks.co.jp>
+ *  Copyright (C) 2007  Yoichi Yuasa <yuasa@linux-mips.org>
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
index 654dee6208be2258ce85ef608c0cc7a639696ad4..54eae56108fb94db06a5add150e8baad4ef5dbfe 100644 (file)
@@ -1,7 +1,7 @@
 /*
  *  NEC VR4100 series SIU platform device.
  *
- *  Copyright (C) 2007-2008  Yoichi Yuasa <yoichi_yuasa@tripeaks.co.jp>
+ *  Copyright (C) 2007-2008  Yoichi Yuasa <yuasa@linux-mips.org>
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
index e0c1ac5e988e48335b471f8bf752ac21485a851f..ff841422b6389317567054761990d7d39ff4cb3b 100644 (file)
@@ -1,7 +1,7 @@
 /*
  *  type.c, System type for NEC VR4100 series.
  *
- *  Copyright (C) 2005  Yoichi Yuasa <yoichi_yuasa@tripeaks.co.jp>
+ *  Copyright (C) 2005  Yoichi Yuasa <yuasa@linux-mips.org>
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
index 9eef297eca1a9ec1d52dbe7f3cda2a5ff200a4c8..3982f378a3e603242ebffe85fa45e6e4dbb52ae5 100644 (file)
@@ -1,7 +1,7 @@
 /*
  *  setup.c, Setup for the IBM WorkPad z50.
  *
- *  Copyright (C) 2002-2006  Yoichi Yuasa <yoichi_yuasa@tripeaks.co.jp>
+ *  Copyright (C) 2002-2006  Yoichi Yuasa <yuasa@linux-mips.org>
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
index e58b9a46e1b14a0a8274479de290872ef28063fd..35d2ed6396f60dba7bb02777000a503b192c5a6c 100644 (file)
@@ -70,10 +70,6 @@ struct pci_dev;
  */
 #define PCI_DMA_BUS_IS_PHYS    (1)
 
-
-/* This is always fine. */
-#define pci_dac_dma_supported(pci_dev, mask)   (0)
-
 /* Return the index of the PCI controller for device. */
 static inline int pci_controller_num(struct pci_dev *dev)
 {
index 78a3881f3c1250f39eea83dc80a320c826ed650d..58d64f8b2cc3d44769ecdcee23c3ccb9477a4239 100644 (file)
@@ -65,8 +65,6 @@ struct thread_info {
 
 /*
  * macros/functions for gaining access to the thread information structure
- *
- * preempt_count needs to be 1 initially, until the scheduler is functional.
  */
 #ifndef __ASSEMBLY__
 
@@ -76,7 +74,7 @@ struct thread_info {
        .exec_domain    = &default_exec_domain, \
        .flags          = 0,                    \
        .cpu            = 0,                    \
-       .preempt_count  = 1,                    \
+       .preempt_count  = INIT_PREEMPT_COUNT,   \
        .addr_limit     = KERNEL_DS,            \
        .restart_block = {                      \
                .fn = do_no_restart_syscall,    \
index fef5b434dadcc6977212b6b1c821efbf211ead85..fad68616af32b4a9e73ed955975f9422d7026483 100644 (file)
 #define __NR_inotify_init1     333
 #define __NR_preadv            334
 #define __NR_pwritev           335
+#define __NR_rt_tgsigqueueinfo 336
+#define __NR_perf_counter_open 337
 
 #ifdef __KERNEL__
 
-#define NR_syscalls 326
+#define NR_syscalls 338
 
 /*
  * specify the deprecated syscalls we want to support on this arch
index 7408a27199f342fd26679db7a326aa0b07885f53..e0d2563af4f24ad68ea2a0b0a72a76489257a99e 100644 (file)
@@ -722,6 +722,8 @@ ENTRY(sys_call_table)
        .long sys_inotify_init1
        .long sys_preadv
        .long sys_pwritev               /* 335 */
+       .long sys_rt_tgsigqueueinfo
+       .long sys_perf_counter_open
 
 
 nr_syscalls=(.-sys_call_table)/4
index e143339ad28e00869d9b23c1d882d994cdd89d62..cf847dabc1bd3a7cd810628ea2500bbfd8b922a7 100644 (file)
@@ -13,7 +13,6 @@
 #include <linux/sched.h>
 #include <linux/mm.h>
 #include <linux/smp.h>
-#include <linux/smp_lock.h>
 #include <linux/errno.h>
 #include <linux/ptrace.h>
 #include <linux/user.h>
index 9f7572a0f5784a30d9ff16bbcfa407d10fc8a066..feb2f2e810db7c785ea5a7562ac77dfb79666a79 100644 (file)
@@ -12,7 +12,6 @@
 #include <linux/sched.h>
 #include <linux/mm.h>
 #include <linux/smp.h>
-#include <linux/smp_lock.h>
 #include <linux/kernel.h>
 #include <linux/signal.h>
 #include <linux/errno.h>
index bca5a84dc72cced1e6c597a02ec725181a651cfb..3e52a105432791ccab5860dac6fbc4f2b0436db1 100644 (file)
@@ -13,7 +13,6 @@
 #include <linux/syscalls.h>
 #include <linux/mm.h>
 #include <linux/smp.h>
-#include <linux/smp_lock.h>
 #include <linux/sem.h>
 #include <linux/msg.h>
 #include <linux/shm.h>
@@ -21,7 +20,6 @@
 #include <linux/mman.h>
 #include <linux/file.h>
 #include <linux/utsname.h>
-#include <linux/syscalls.h>
 #include <linux/tty.h>
 
 #include <asm/uaccess.h>
index 681ad8c9e4fb68b59eebd992a7ee32f8be747e18..91365adba4f5568925d3398545d3b9bcc9ed9f96 100644 (file)
@@ -17,7 +17,6 @@
 #include <linux/timer.h>
 #include <linux/mm.h>
 #include <linux/smp.h>
-#include <linux/smp_lock.h>
 #include <linux/init.h>
 #include <linux/delay.h>
 #include <linux/spinlock.h>
@@ -136,8 +135,7 @@ void show_trace(unsigned long *sp)
        unsigned long *stack, addr, module_start, module_end;
        int i;
 
-       printk(KERN_EMERG "\n"
-              KERN_EMERG "Call Trace:");
+       printk(KERN_EMERG "\nCall Trace:");
 
        stack = sp;
        i = 0;
@@ -153,7 +151,7 @@ void show_trace(unsigned long *sp)
                        printk("\n");
 #else
                        if ((i % 6) == 0)
-                               printk("\n" KERN_EMERG "  ");
+                               printk(KERN_EMERG "  ");
                        printk("[<%08lx>] ", addr);
                        i++;
 #endif
@@ -180,7 +178,7 @@ void show_stack(struct task_struct *task, unsigned long *sp)
                if (((long) stack & (THREAD_SIZE - 1)) == 0)
                        break;
                if ((i % 8) == 0)
-                       printk("\n" KERN_EMERG "  ");
+                       printk(KERN_EMERG "  ");
                printk("%08lx ", *stack++);
        }
 
@@ -264,8 +262,7 @@ void show_registers(struct pt_regs *regs)
                show_stack(current, (unsigned long *) sp);
 
 #if 0
-               printk(KERN_EMERG "\n"
-                      KERN_EMERG "Code: ");
+               printk(KERN_EMERG "\nCode: ");
                if (regs->pc < PAGE_OFFSET)
                        goto bad;
 
@@ -311,16 +308,14 @@ void die(const char *str, struct pt_regs *regs, enum exception_code code)
 {
        console_verbose();
        spin_lock_irq(&die_lock);
-       printk(KERN_EMERG "\n"
-              KERN_EMERG "%s: %04x\n",
+       printk(KERN_EMERG "\n%s: %04x\n",
               str, code & 0xffff);
        show_registers(regs);
 
        if (regs->pc >= 0x02000000 && regs->pc < 0x04000000 &&
            (regs->epsw & (EPSW_IM | EPSW_IE)) != (EPSW_IM | EPSW_IE)) {
                printk(KERN_EMERG "Exception in usermode interrupt handler\n");
-               printk(KERN_EMERG "\n"
-                      KERN_EMERG "  Please connect to kernel debugger !!\n");
+               printk(KERN_EMERG "\nPlease connect to kernel debugger !!\n");
                asm volatile ("0: bra 0b");
        }
 
@@ -429,9 +424,8 @@ asmlinkage void io_bus_error(u32 bcberr, u32 bcbear, struct pt_regs *regs)
 {
        console_verbose();
 
-       printk(KERN_EMERG "\n"
-              KERN_EMERG "Asynchronous I/O Bus Error\n"
-              KERN_EMERG "==========================\n");
+       printk(KERN_EMERG "Asynchronous I/O Bus Error\n");
+       printk(KERN_EMERG "==========================\n");
 
        if (bcberr & BCBERR_BEME)
                printk(KERN_EMERG "- Multiple recorded errors\n");
index bcebcefb4ad7abee8b96bd69e4d231e355fb44d6..c96ba3da95ac15b6b2582fae648925179e2d9d6b 100644 (file)
@@ -61,7 +61,7 @@ SECTIONS
        _edata = .;             /* End of data section */
   }
 
-  .data.init_task : { INIT_TASK(THREAD_SIZE); }
+  .data.init_task : { INIT_TASK_DATA(THREAD_SIZE); }
 
   /* might get freed after init */
   . = ALIGN(PAGE_SIZE);
index a62e1e138bc101c112872eae8b4eb9e0ce61d8cf..53bb17d0f0687764ab1d8a4e05d6cdfc81c03e25 100644 (file)
@@ -20,7 +20,6 @@
 #include <linux/mman.h>
 #include <linux/mm.h>
 #include <linux/smp.h>
-#include <linux/smp_lock.h>
 #include <linux/interrupt.h>
 #include <linux/init.h>
 #include <linux/vt_kern.h>             /* For unblank_screen() */
index 94c4a43580657a74b594561180759b5d2b43c37c..30016251f658507ec5a6501c35028dd74be22716 100644 (file)
@@ -17,7 +17,6 @@
 #include <linux/timer.h>
 #include <linux/mm.h>
 #include <linux/smp.h>
-#include <linux/smp_lock.h>
 #include <linux/init.h>
 #include <linux/delay.h>
 #include <linux/spinlock.h>
index 9038f39d9d736320996f95e6bae5d10473895da0..06f8d5b5b0f96d4bbb30cc5653cc6490d47df93e 100644 (file)
@@ -16,6 +16,8 @@ config PARISC
        select RTC_DRV_GENERIC
        select INIT_ALL_POSSIBLE
        select BUG
+       select HAVE_PERF_COUNTERS
+       select GENERIC_ATOMIC64 if !64BIT
        help
          The PA-RISC microprocessor is designed by Hewlett-Packard and used
          in many of their workstations & servers (HP9000 700 and 800 series,
index 7eeaff944360335c8548b0f25e1828432ea55f9b..8bc9e96699b2a690456aa75585a9f89c05cad7bf 100644 (file)
@@ -222,13 +222,13 @@ static __inline__ int atomic_add_unless(atomic_t *v, int a, int u)
 
 #define atomic_inc_not_zero(v) atomic_add_unless((v), 1, 0)
 
-#define atomic_add(i,v)        ((void)(__atomic_add_return( ((int)(i)),(v))))
-#define atomic_sub(i,v)        ((void)(__atomic_add_return(-((int)(i)),(v))))
+#define atomic_add(i,v)        ((void)(__atomic_add_return( (i),(v))))
+#define atomic_sub(i,v)        ((void)(__atomic_add_return(-(i),(v))))
 #define atomic_inc(v)  ((void)(__atomic_add_return(   1,(v))))
 #define atomic_dec(v)  ((void)(__atomic_add_return(  -1,(v))))
 
-#define atomic_add_return(i,v) (__atomic_add_return( ((int)(i)),(v)))
-#define atomic_sub_return(i,v) (__atomic_add_return(-((int)(i)),(v)))
+#define atomic_add_return(i,v) (__atomic_add_return( (i),(v)))
+#define atomic_sub_return(i,v) (__atomic_add_return(-(i),(v)))
 #define atomic_inc_return(v)   (__atomic_add_return(   1,(v)))
 #define atomic_dec_return(v)   (__atomic_add_return(  -1,(v)))
 
@@ -336,7 +336,11 @@ static __inline__ int atomic64_add_unless(atomic64_t *v, long a, long u)
 
 #define atomic64_inc_not_zero(v) atomic64_add_unless((v), 1, 0)
 
-#endif /* CONFIG_64BIT */
+#else /* CONFIG_64BIT */
+
+#include <asm-generic/atomic64.h>
+
+#endif /* !CONFIG_64BIT */
 
 #include <asm-generic/atomic-long.h>
 
index 31ad0f05af3d4dec0a66bba5d02a118f748d5896..f7a18f96870347172594335092840aa10a060683 100644 (file)
@@ -1,5 +1,4 @@
-/* $Id: dma.h,v 1.2 1999/04/27 00:46:18 deller Exp $
- * linux/include/asm/dma.h: Defines for using and allocating dma channels.
+/* asm/dma.h: Defines for using and allocating dma channels.
  * Written by Hennus Bergman, 1992.
  * High DMA channel support & info by Hannu Savolainen
  * and John Boyd, Nov. 1992.
diff --git a/arch/parisc/include/asm/perf_counter.h b/arch/parisc/include/asm/perf_counter.h
new file mode 100644 (file)
index 0000000..dc9e829
--- /dev/null
@@ -0,0 +1,7 @@
+#ifndef __ASM_PARISC_PERF_COUNTER_H
+#define __ASM_PARISC_PERF_COUNTER_H
+
+/* parisc only supports software counters through this interface. */
+static inline void set_perf_counter_pending(void) { }
+
+#endif /* __ASM_PARISC_PERF_COUNTER_H */
index 9d64df8754ba5203c9a7299038ab5c01ea68185b..9ce66e9d1c2b845275c41aaaf290a5fb5e123ba1 100644 (file)
@@ -18,6 +18,7 @@
 #include <asm/types.h>
 #include <asm/system.h>
 #include <asm/percpu.h>
+
 #endif /* __ASSEMBLY__ */
 
 #define KERNEL_STACK_SIZE      (4*PAGE_SIZE)
@@ -127,6 +128,8 @@ struct thread_struct {
        unsigned long  flags;
 }; 
 
+#define task_pt_regs(tsk) ((struct pt_regs *)&((tsk)->thread.regs))
+
 /* Thread struct flags. */
 #define PARISC_UAC_NOPRINT     (1UL << 0)      /* see prctl and unaligned.c */
 #define PARISC_UAC_SIGBUS      (1UL << 1)
index ee80c920b464e549848664794ac742a9e4714fd9..d91357bca5b4cc18a3c143f948f24c7afef379cc 100644 (file)
@@ -168,8 +168,8 @@ static inline void set_eiem(unsigned long val)
 /* LDCW, the only atomic read-write operation PA-RISC has. *sigh*.  */
 #define __ldcw(a) ({                                           \
        unsigned __ret;                                         \
-       __asm__ __volatile__(__LDCW " 0(%1),%0"                 \
-               : "=r" (__ret) : "r" (a));                      \
+       __asm__ __volatile__(__LDCW " 0(%2),%0"                 \
+               : "=r" (__ret), "+m" (*(a)) : "r" (a));         \
        __ret;                                                  \
 })
 
index 0407959da489d54a72b4ccab371cc21e996e79a3..4ce0edfbe9694dc4daaed2253a625e9d46a25c72 100644 (file)
@@ -23,7 +23,7 @@ struct thread_info {
        .flags          = 0,                    \
        .cpu            = 0,                    \
        .addr_limit     = KERNEL_DS,            \
-       .preempt_count  = 1,                    \
+       .preempt_count  = INIT_PREEMPT_COUNT,   \
        .restart_block  = {                     \
                .fn = do_no_restart_syscall     \
        }                                       \
index 1f6fd4fc05b91b518f4f574b3ada13ddd24b285a..8f1a8100bf2df394f0ca78e90dbec9f33d33125d 100644 (file)
  * N class systems, only one PxTLB inter processor broadcast can be
  * active at any one time on the Merced bus.  This tlb purge
  * synchronisation is fairly lightweight and harmless so we activate
- * it on all SMP systems not just the N class.  We also need to have
- * preemption disabled on uniprocessor machines, and spin_lock does that
- * nicely.
+ * it on all systems not just the N class.
  */
 extern spinlock_t pa_tlb_lock;
 
-#define purge_tlb_start(x) spin_lock(&pa_tlb_lock)
-#define purge_tlb_end(x) spin_unlock(&pa_tlb_lock)
+#define purge_tlb_start(flags) spin_lock_irqsave(&pa_tlb_lock, flags)
+#define purge_tlb_end(flags)   spin_unlock_irqrestore(&pa_tlb_lock, flags)
 
 extern void flush_tlb_all(void);
 extern void flush_tlb_all_local(void *);
@@ -63,14 +61,16 @@ static inline void flush_tlb_mm(struct mm_struct *mm)
 static inline void flush_tlb_page(struct vm_area_struct *vma,
        unsigned long addr)
 {
+       unsigned long flags;
+
        /* For one page, it's not worth testing the split_tlb variable */
 
        mb();
        mtsp(vma->vm_mm->context,1);
-       purge_tlb_start();
+       purge_tlb_start(flags);
        pdtlb(addr);
        pitlb(addr);
-       purge_tlb_end();
+       purge_tlb_end(flags);
 }
 
 void __flush_tlb_range(unsigned long sid,
index ef26b009dc5da1f323a7fc77d329e6c520b5e40f..f3d3b8b012c494e9783511da12c37277c4d7c920 100644 (file)
 #define __NR_dup3              (__NR_Linux + 312)
 #define __NR_pipe2             (__NR_Linux + 313)
 #define __NR_inotify_init1     (__NR_Linux + 314)
+#define __NR_preadv            (__NR_Linux + 315)
+#define __NR_pwritev           (__NR_Linux + 316)
+#define __NR_rt_tgsigqueueinfo (__NR_Linux + 317)
+#define __NR_perf_counter_open (__NR_Linux + 318)
 
-#define __NR_Linux_syscalls    (__NR_inotify_init1 + 1)
+#define __NR_Linux_syscalls    (__NR_perf_counter_open + 1)
 
 
 #define __IGNORE_select                /* newselect */
index 837530ea32e783e6671ce2793bf08f30424b6808..b6ed34de14e15899cbcfccdbfa25cd80649282a6 100644 (file)
@@ -1,5 +1,4 @@
-/* $Id: cache.c,v 1.4 2000/01/25 00:11:38 prumpf Exp $
- *
+/*
  * This file is subject to the terms and conditions of the GNU General Public
  * License.  See the file "COPYING" in the main directory of this archive
  * for more details.
@@ -398,12 +397,13 @@ EXPORT_SYMBOL(flush_kernel_icache_range_asm);
 
 void clear_user_page_asm(void *page, unsigned long vaddr)
 {
+       unsigned long flags;
        /* This function is implemented in assembly in pacache.S */
        extern void __clear_user_page_asm(void *page, unsigned long vaddr);
 
-       purge_tlb_start();
+       purge_tlb_start(flags);
        __clear_user_page_asm(page, vaddr);
-       purge_tlb_end();
+       purge_tlb_end(flags);
 }
 
 #define FLUSH_THRESHOLD 0x80000 /* 0.5MB */
@@ -444,20 +444,24 @@ extern void clear_user_page_asm(void *page, unsigned long vaddr);
 
 void clear_user_page(void *page, unsigned long vaddr, struct page *pg)
 {
+       unsigned long flags;
+
        purge_kernel_dcache_page((unsigned long)page);
-       purge_tlb_start();
+       purge_tlb_start(flags);
        pdtlb_kernel(page);
-       purge_tlb_end();
+       purge_tlb_end(flags);
        clear_user_page_asm(page, vaddr);
 }
 EXPORT_SYMBOL(clear_user_page);
 
 void flush_kernel_dcache_page_addr(void *addr)
 {
+       unsigned long flags;
+
        flush_kernel_dcache_page_asm(addr);
-       purge_tlb_start();
+       purge_tlb_start(flags);
        pdtlb_kernel(addr);
-       purge_tlb_end();
+       purge_tlb_end(flags);
 }
 EXPORT_SYMBOL(flush_kernel_dcache_page_addr);
 
@@ -490,8 +494,10 @@ void __flush_tlb_range(unsigned long sid, unsigned long start,
        if (npages >= 512)  /* 2MB of space: arbitrary, should be tuned */
                flush_tlb_all();
        else {
+               unsigned long flags;
+
                mtsp(sid, 1);
-               purge_tlb_start();
+               purge_tlb_start(flags);
                if (split_tlb) {
                        while (npages--) {
                                pdtlb(start);
@@ -504,7 +510,7 @@ void __flush_tlb_range(unsigned long sid, unsigned long start,
                                start += PAGE_SIZE;
                        }
                }
-               purge_tlb_end();
+               purge_tlb_end(flags);
        }
 }
 
index bd1f7f1ff74e7b6589c4a97f6fcebd28453a1d19..d228d823787991f138cea6651bbb6787701b7db5 100644 (file)
@@ -170,23 +170,27 @@ static void __init pagezero_memconfig(void)
 static int __init 
 pat_query_module(ulong pcell_loc, ulong mod_index)
 {
-       pdc_pat_cell_mod_maddr_block_t pa_pdc_cell;
+       pdc_pat_cell_mod_maddr_block_t *pa_pdc_cell;
        unsigned long bytecnt;
        unsigned long temp;     /* 64-bit scratch value */
        long status;            /* PDC return value status */
        struct parisc_device *dev;
 
+       pa_pdc_cell = kmalloc(sizeof (*pa_pdc_cell), GFP_KERNEL);
+       if (!pa_pdc_cell)
+               panic("couldn't allocate memory for PDC_PAT_CELL!");
+
        /* return cell module (PA or Processor view) */
        status = pdc_pat_cell_module(&bytecnt, pcell_loc, mod_index,
-                                    PA_VIEW, &pa_pdc_cell);
+                                    PA_VIEW, pa_pdc_cell);
 
        if (status != PDC_OK) {
                /* no more cell modules or error */
                return status;
        }
 
-       temp = pa_pdc_cell.cba;
-       dev = alloc_pa_dev(PAT_GET_CBA(temp), &pa_pdc_cell.mod_path);
+       temp = pa_pdc_cell->cba;
+       dev = alloc_pa_dev(PAT_GET_CBA(temp), &(pa_pdc_cell->mod_path));
        if (!dev) {
                return PDC_OK;
        }
@@ -203,8 +207,8 @@ pat_query_module(ulong pcell_loc, ulong mod_index)
 
        /* save generic info returned from the call */
        /* REVISIT: who is the consumer of this? not sure yet... */
-       dev->mod_info = pa_pdc_cell.mod_info;   /* pass to PAT_GET_ENTITY() */
-       dev->pmod_loc = pa_pdc_cell.mod_location;
+       dev->mod_info = pa_pdc_cell->mod_info;  /* pass to PAT_GET_ENTITY() */
+       dev->pmod_loc = pa_pdc_cell->mod_location;
 
        register_parisc_device(dev);    /* advertise device */
 
@@ -216,14 +220,14 @@ pat_query_module(ulong pcell_loc, ulong mod_index)
 
        case PAT_ENTITY_PROC:
                printk(KERN_DEBUG "PAT_ENTITY_PROC: id_eid 0x%lx\n",
-                       pa_pdc_cell.mod[0]);
+                       pa_pdc_cell->mod[0]);
                break;
 
        case PAT_ENTITY_MEM:
                printk(KERN_DEBUG 
                        "PAT_ENTITY_MEM: amount 0x%lx min_gni_base 0x%lx min_gni_len 0x%lx\n",
-                       pa_pdc_cell.mod[0], pa_pdc_cell.mod[1], 
-                       pa_pdc_cell.mod[2]);
+                       pa_pdc_cell->mod[0], pa_pdc_cell->mod[1],
+                       pa_pdc_cell->mod[2]);
                break;
        case PAT_ENTITY_CA:
                printk(KERN_DEBUG "PAT_ENTITY_CA: %ld\n", pcell_loc);
@@ -243,23 +247,26 @@ pat_query_module(ulong pcell_loc, ulong mod_index)
  print_ranges:
                pdc_pat_cell_module(&bytecnt, pcell_loc, mod_index,
                                    IO_VIEW, &io_pdc_cell);
-               printk(KERN_DEBUG "ranges %ld\n", pa_pdc_cell.mod[1]);
-               for (i = 0; i < pa_pdc_cell.mod[1]; i++) {
+               printk(KERN_DEBUG "ranges %ld\n", pa_pdc_cell->mod[1]);
+               for (i = 0; i < pa_pdc_cell->mod[1]; i++) {
                        printk(KERN_DEBUG 
                                "  PA_VIEW %ld: 0x%016lx 0x%016lx 0x%016lx\n", 
-                               i, pa_pdc_cell.mod[2 + i * 3],  /* type */
-                               pa_pdc_cell.mod[3 + i * 3],     /* start */
-                               pa_pdc_cell.mod[4 + i * 3]);    /* finish (ie end) */
+                               i, pa_pdc_cell->mod[2 + i * 3], /* type */
+                               pa_pdc_cell->mod[3 + i * 3],    /* start */
+                               pa_pdc_cell->mod[4 + i * 3]);   /* finish (ie end) */
                        printk(KERN_DEBUG 
                                "  IO_VIEW %ld: 0x%016lx 0x%016lx 0x%016lx\n", 
-                               i, io_pdc_cell.mod[2 + i * 3],  /* type */
-                               io_pdc_cell.mod[3 + i * 3],     /* start */
-                               io_pdc_cell.mod[4 + i * 3]);    /* finish (ie end) */
+                               i, io_pdc_cell->mod[2 + i * 3], /* type */
+                               io_pdc_cell->mod[3 + i * 3],    /* start */
+                               io_pdc_cell->mod[4 + i * 3]);   /* finish (ie end) */
                }
                printk(KERN_DEBUG "\n");
                break;
        }
 #endif /* DEBUG_PAT */
+
+       kfree(pa_pdc_cell);
+
        return PDC_OK;
 }
 
index 8007f1e6572986559789a2520603a77336c72214..330f536a9324798afda4580d152c09eb3b04c141 100644 (file)
@@ -120,7 +120,7 @@ int cpu_check_affinity(unsigned int irq, const struct cpumask *dest)
        if (CHECK_IRQ_PER_CPU(irq)) {
                /* Bad linux design decision.  The mask has already
                 * been set; we must reset it */
-               cpumask_setall(&irq_desc[irq].affinity);
+               cpumask_setall(irq_desc[irq].affinity);
                return -EINVAL;
        }
 
@@ -138,13 +138,13 @@ static int cpu_set_affinity_irq(unsigned int irq, const struct cpumask *dest)
        if (cpu_dest < 0)
                return -1;
 
-       cpumask_copy(&irq_desc[irq].affinity, dest);
+       cpumask_copy(irq_desc[irq].affinity, dest);
 
        return 0;
 }
 #endif
 
-static struct hw_interrupt_type cpu_interrupt_type = {
+static struct irq_chip cpu_interrupt_type = {
        .typename       = "CPU",
        .startup        = cpu_startup_irq,
        .shutdown       = cpu_disable_irq,
@@ -299,7 +299,7 @@ int txn_alloc_irq(unsigned int bits_wide)
 unsigned long txn_affinity_addr(unsigned int irq, int cpu)
 {
 #ifdef CONFIG_SMP
-       cpumask_copy(&irq_desc[irq].affinity, cpumask_of(cpu));
+       cpumask_copy(irq_desc[irq].affinity, cpumask_of(cpu));
 #endif
 
        return per_cpu(cpu_data, cpu).txn_addr;
@@ -356,7 +356,7 @@ void do_cpu_irq_mask(struct pt_regs *regs)
        irq = eirr_to_irq(eirr_val);
 
 #ifdef CONFIG_SMP
-       cpumask_copy(&dest, &irq_desc[irq].affinity);
+       cpumask_copy(&dest, irq_desc[irq].affinity);
        if (CHECK_IRQ_PER_CPU(irq_desc[irq].status) &&
            !cpu_isset(smp_processor_id(), dest)) {
                int cpu = first_cpu(dest);
index 7d927eac932b9ccf598bc710bba8e965b2bcd539..c07f618ff7da9264fc9aa242cfaf1515b72d8af5 100644 (file)
@@ -90,12 +90,14 @@ static inline int map_pte_uncached(pte_t * pte,
        if (end > PMD_SIZE)
                end = PMD_SIZE;
        do {
+               unsigned long flags;
+
                if (!pte_none(*pte))
                        printk(KERN_ERR "map_pte_uncached: page already exists\n");
                set_pte(pte, __mk_pte(*paddr_ptr, PAGE_KERNEL_UNC));
-               purge_tlb_start();
+               purge_tlb_start(flags);
                pdtlb_kernel(orig_vaddr);
-               purge_tlb_end();
+               purge_tlb_end(flags);
                vaddr += PAGE_SIZE;
                orig_vaddr += PAGE_SIZE;
                (*paddr_ptr) += PAGE_SIZE;
@@ -168,11 +170,13 @@ static inline void unmap_uncached_pte(pmd_t * pmd, unsigned long vaddr,
        if (end > PMD_SIZE)
                end = PMD_SIZE;
        do {
+               unsigned long flags;
                pte_t page = *pte;
+
                pte_clear(&init_mm, vaddr, pte);
-               purge_tlb_start();
+               purge_tlb_start(flags);
                pdtlb_kernel(orig_vaddr);
-               purge_tlb_end();
+               purge_tlb_end(flags);
                vaddr += PAGE_SIZE;
                orig_vaddr += PAGE_SIZE;
                pte++;
index 6936386c9861a3721aba9a857158e8cc9133743e..f7064abc3bb6e60a544e3bfb97c12f468768fd89 100644 (file)
@@ -1,5 +1,4 @@
-/* $Id: pci.c,v 1.6 2000/01/29 00:12:05 grundler Exp $
- *
+/*
  * This file is subject to the terms and conditions of the GNU General Public
  * License.  See the file "COPYING" in the main directory of this archive
  * for more details.
index 61c07078c072d69c60769e4273339c3ac8fe8d62..1f3aa8db02030a1509253b6d0d51d4910f522761 100644 (file)
@@ -156,7 +156,7 @@ void machine_power_off(void)
         * software. The user has to press the button himself. */
 
        printk(KERN_EMERG "System shut down completed.\n"
-              KERN_EMERG "Please power this system off now.");
+              "Please power this system off now.");
 }
 
 void (*pm_power_off)(void) = machine_power_off;
index e09d0f7fb6b047ad2c2cf34d95046f89f2263874..c8fb61ed32f4eeee5bb27b648468e10da0962034 100644 (file)
@@ -1,5 +1,4 @@
-/*    $Id: processor.c,v 1.1 2002/07/20 16:27:06 rhirst Exp $
- *
+/*
  *    Initial setup-routines for HP 9000 based hardware.
  *
  *    Copyright (C) 1991, 1992, 1995  Linus Torvalds
@@ -121,22 +120,28 @@ static int __cpuinit processor_probe(struct parisc_device *dev)
        if (is_pdc_pat()) {
                ulong status;
                unsigned long bytecnt;
-               pdc_pat_cell_mod_maddr_block_t pa_pdc_cell;
+               pdc_pat_cell_mod_maddr_block_t *pa_pdc_cell;
 #undef USE_PAT_CPUID
 #ifdef USE_PAT_CPUID
                struct pdc_pat_cpu_num cpu_info;
 #endif
 
+               pa_pdc_cell = kmalloc(sizeof (*pa_pdc_cell), GFP_KERNEL);
+               if (!pa_pdc_cell)
+                       panic("couldn't allocate memory for PDC_PAT_CELL!");
+
                status = pdc_pat_cell_module(&bytecnt, dev->pcell_loc,
-                       dev->mod_index, PA_VIEW, &pa_pdc_cell);
+                       dev->mod_index, PA_VIEW, pa_pdc_cell);
 
                BUG_ON(PDC_OK != status);
 
                /* verify it's the same as what do_pat_inventory() found */
-               BUG_ON(dev->mod_info != pa_pdc_cell.mod_info);
-               BUG_ON(dev->pmod_loc != pa_pdc_cell.mod_location);
+               BUG_ON(dev->mod_info != pa_pdc_cell->mod_info);
+               BUG_ON(dev->pmod_loc != pa_pdc_cell->mod_location);
+
+               txn_addr = pa_pdc_cell->mod[0];   /* id_eid for IO sapic */
 
-               txn_addr = pa_pdc_cell.mod[0];   /* id_eid for IO sapic */
+               kfree(pa_pdc_cell);
 
 #ifdef USE_PAT_CPUID
 /* We need contiguous numbers for cpuid. Firmware's notion
index 82131ca8e05c28790bbc133690e2267f1be67034..cb71f3dac99525a525027fa2f532a20e4c3caa93 100644 (file)
@@ -1,5 +1,4 @@
-/*    $Id: setup.c,v 1.8 2000/02/02 04:42:38 prumpf Exp $
- *
+/*
  *    Initial setup-routines for HP 9000 based hardware.
  *
  *    Copyright (C) 1991, 1992, 1995  Linus Torvalds
index 1adb40c8166965ae1c397abe272187a42639fcf6..92a0acaa0d1213042bd871e83a2024cc1ae59aa6 100644 (file)
@@ -174,68 +174,6 @@ asmlinkage long sys32_sched_rr_get_interval(pid_t pid,
        return ret;
 }
 
-/*** copied from mips64 ***/
-/*
- * Ooo, nasty.  We need here to frob 32-bit unsigned longs to
- * 64-bit unsigned longs.
- */
-
-static inline int
-get_fd_set32(unsigned long n, u32 *ufdset, unsigned long *fdset)
-{
-       n = (n + 8*sizeof(u32) - 1) / (8*sizeof(u32));
-       if (ufdset) {
-               unsigned long odd;
-
-               if (!access_ok(VERIFY_WRITE, ufdset, n*sizeof(u32)))
-                       return -EFAULT;
-
-               odd = n & 1UL;
-               n &= ~1UL;
-               while (n) {
-                       unsigned long h, l;
-                       __get_user(l, ufdset);
-                       __get_user(h, ufdset+1);
-                       ufdset += 2;
-                       *fdset++ = h << 32 | l;
-                       n -= 2;
-               }
-               if (odd)
-                       __get_user(*fdset, ufdset);
-       } else {
-               /* Tricky, must clear full unsigned long in the
-                * kernel fdset at the end, this makes sure that
-                * actually happens.
-                */
-               memset(fdset, 0, ((n + 1) & ~1)*sizeof(u32));
-       }
-       return 0;
-}
-
-static inline void
-set_fd_set32(unsigned long n, u32 *ufdset, unsigned long *fdset)
-{
-       unsigned long odd;
-       n = (n + 8*sizeof(u32) - 1) / (8*sizeof(u32));
-
-       if (!ufdset)
-               return;
-
-       odd = n & 1UL;
-       n &= ~1UL;
-       while (n) {
-               unsigned long h, l;
-               l = *fdset++;
-               h = l >> 32;
-               __put_user(l, ufdset);
-               __put_user(h, ufdset+1);
-               ufdset += 2;
-               n -= 2;
-       }
-       if (odd)
-               __put_user(*fdset, ufdset);
-}
-
 struct msgbuf32 {
     int mtype;
     char mtext[1];
index 03b9a01bc16cf49340db4d69329a08338e47650f..cf145eb026b34f9049075b2c6bf348ebef2ceb43 100644 (file)
        ENTRY_SAME(dup3)
        ENTRY_SAME(pipe2)
        ENTRY_SAME(inotify_init1)
+       ENTRY_COMP(preadv)              /* 315 */
+       ENTRY_COMP(pwritev)
+       ENTRY_COMP(rt_tgsigqueueinfo)
+       ENTRY_SAME(perf_counter_open)
 
        /* Nothing yet */
 
index d4dd05674c6234b495acdb25431bb5fd9a437261..a79c6f9e7e2c441f0d2d7feda117ae14c72ad065 100644 (file)
@@ -56,9 +56,9 @@ static unsigned long clocktick __read_mostly; /* timer cycles per tick */
  */
 irqreturn_t __irq_entry timer_interrupt(int irq, void *dev_id)
 {
-       unsigned long now;
+       unsigned long now, now2;
        unsigned long next_tick;
-       unsigned long cycles_elapsed, ticks_elapsed;
+       unsigned long cycles_elapsed, ticks_elapsed = 1;
        unsigned long cycles_remainder;
        unsigned int cpu = smp_processor_id();
        struct cpuinfo_parisc *cpuinfo = &per_cpu(cpu_data, cpu);
@@ -71,44 +71,24 @@ irqreturn_t __irq_entry timer_interrupt(int irq, void *dev_id)
        /* Initialize next_tick to the expected tick time. */
        next_tick = cpuinfo->it_value;
 
-       /* Get current interval timer.
-        * CR16 reads as 64 bits in CPU wide mode.
-        * CR16 reads as 32 bits in CPU narrow mode.
-        */
+       /* Get current cycle counter (Control Register 16). */
        now = mfctl(16);
 
        cycles_elapsed = now - next_tick;
 
-       if ((cycles_elapsed >> 5) < cpt) {
+       if ((cycles_elapsed >> 6) < cpt) {
                /* use "cheap" math (add/subtract) instead
                 * of the more expensive div/mul method
                 */
                cycles_remainder = cycles_elapsed;
-               ticks_elapsed = 1;
                while (cycles_remainder > cpt) {
                        cycles_remainder -= cpt;
                        ticks_elapsed++;
                }
        } else {
+               /* TODO: Reduce this to one fdiv op */
                cycles_remainder = cycles_elapsed % cpt;
-               ticks_elapsed = 1 + cycles_elapsed / cpt;
-       }
-
-       /* Can we differentiate between "early CR16" (aka Scenario 1) and
-        * "long delay" (aka Scenario 3)? I don't think so.
-        *
-        * We expected timer_interrupt to be delivered at least a few hundred
-        * cycles after the IT fires. But it's arbitrary how much time passes
-        * before we call it "late". I've picked one second.
-        */
-       if (unlikely(ticks_elapsed > HZ)) {
-               /* Scenario 3: very long delay?  bad in any case */
-               printk (KERN_CRIT "timer_interrupt(CPU %d): delayed!"
-                       " cycles %lX rem %lX "
-                       " next/now %lX/%lX\n",
-                       cpu,
-                       cycles_elapsed, cycles_remainder,
-                       next_tick, now );
+               ticks_elapsed += cycles_elapsed / cpt;
        }
 
        /* convert from "division remainder" to "remainder of clock tick" */
@@ -122,18 +102,56 @@ irqreturn_t __irq_entry timer_interrupt(int irq, void *dev_id)
 
        cpuinfo->it_value = next_tick;
 
-       /* Skip one clocktick on purpose if we are likely to miss next_tick.
-        * We want to avoid the new next_tick being less than CR16.
-        * If that happened, itimer wouldn't fire until CR16 wrapped.
-        * We'll catch the tick we missed on the tick after that.
+       /* Program the IT when to deliver the next interrupt.
+        * Only bottom 32-bits of next_tick are writable in CR16!
         */
-       if (!(cycles_remainder >> 13))
-               next_tick += cpt;
-
-       /* Program the IT when to deliver the next interrupt. */
-       /* Only bottom 32-bits of next_tick are written to cr16.  */
        mtctl(next_tick, 16);
 
+       /* Skip one clocktick on purpose if we missed next_tick.
+        * The new CR16 must be "later" than current CR16 otherwise
+        * itimer would not fire until CR16 wrapped - e.g 4 seconds
+        * later on a 1Ghz processor. We'll account for the missed
+        * tick on the next timer interrupt.
+        *
+        * "next_tick - now" will always give the difference regardless
+        * if one or the other wrapped. If "now" is "bigger" we'll end up
+        * with a very large unsigned number.
+        */
+       now2 = mfctl(16);
+       if (next_tick - now2 > cpt)
+               mtctl(next_tick+cpt, 16);
+
+#if 1
+/*
+ * GGG: DEBUG code for how many cycles programming CR16 used.
+ */
+       if (unlikely(now2 - now > 0x3000))      /* 12K cycles */
+               printk (KERN_CRIT "timer_interrupt(CPU %d): SLOW! 0x%lx cycles!"
+                       " cyc %lX rem %lX "
+                       " next/now %lX/%lX\n",
+                       cpu, now2 - now, cycles_elapsed, cycles_remainder,
+                       next_tick, now );
+#endif
+
+       /* Can we differentiate between "early CR16" (aka Scenario 1) and
+        * "long delay" (aka Scenario 3)? I don't think so.
+        *
+        * Timer_interrupt will be delivered at least a few hundred cycles
+        * after the IT fires. But it's arbitrary how much time passes
+        * before we call it "late". I've picked one second.
+        *
+        * It's important NO printk's are between reading CR16 and
+        * setting up the next value. May introduce huge variance.
+        */
+       if (unlikely(ticks_elapsed > HZ)) {
+               /* Scenario 3: very long delay?  bad in any case */
+               printk (KERN_CRIT "timer_interrupt(CPU %d): delayed!"
+                       " cycles %lX rem %lX "
+                       " next/now %lX/%lX\n",
+                       cpu,
+                       cycles_elapsed, cycles_remainder,
+                       next_tick, now );
+       }
 
        /* Done mucking with unreliable delivery of interrupts.
         * Go do system house keeping.
@@ -173,7 +191,7 @@ EXPORT_SYMBOL(profile_pc);
 
 /* clock source code */
 
-static cycle_t read_cr16(void)
+static cycle_t read_cr16(struct clocksource *cs)
 {
        return get_cycles();
 }
index c32f5d6d778ec7bd10c028cf40db645af659686a..528f0ff9b2738314ab61871379b0d8c980c4b530 100644 (file)
@@ -250,15 +250,14 @@ void die_if_kernel(char *str, struct pt_regs *regs, long err)
        oops_enter();
 
        /* Amuse the user in a SPARC fashion */
-       if (err) printk(
-KERN_CRIT "      _______________________________ \n"
-KERN_CRIT "     < Your System ate a SPARC! Gah! >\n"
-KERN_CRIT "      ------------------------------- \n"
-KERN_CRIT "             \\   ^__^\n"
-KERN_CRIT "              \\  (xx)\\_______\n"
-KERN_CRIT "                 (__)\\       )\\/\\\n"
-KERN_CRIT "                  U  ||----w |\n"
-KERN_CRIT "                     ||     ||\n");
+       if (err) printk(KERN_CRIT
+                       "      _______________________________ \n"
+                       "     < Your System ate a SPARC! Gah! >\n"
+                       "      ------------------------------- \n"
+                       "             \\   ^__^\n"
+                       "                 (__)\\       )\\/\\\n"
+                       "                  U  ||----w |\n"
+                       "                     ||     ||\n");
        
        /* unlock the pdc lock if necessary */
        pdc_emergency_unlock();
@@ -797,7 +796,8 @@ void notrace handle_interruption(int code, struct pt_regs *regs)
                else
                        printk(KERN_DEBUG "User Fault (long pointer) (fault %d) ",
                               code);
-               printk("pid=%d command='%s'\n", task_pid_nr(current), current->comm);
+               printk(KERN_CONT "pid=%d command='%s'\n",
+                      task_pid_nr(current), current->comm);
                show_regs(regs);
 #endif
                si.si_signo = SIGSEGV;
index 462696d30d3bd601b366afcd4e0d0048a61050f3..ae66d31f9ecf7d713d3c995a23330980d361c067 100644 (file)
@@ -13,8 +13,6 @@
  *             modify it under the terms of the GNU General Public License
  *             as published by the Free Software Foundation; either version
  *             2 of the License, or (at your option) any later version.
- *
- * $Id: checksum.c,v 1.3 1997/12/01 17:57:34 ralf Exp $
  */
 #include <linux/module.h>
 #include <linux/types.h>
index bbda909c866e57c1327b6ccd47cf9bab8dc992d4..abf41f4632a9fca1b8df2c4ba963c2e328e553e7 100644 (file)
@@ -405,7 +405,7 @@ byte_copy:
 
 unaligned_copy:
        /* possibly we are aligned on a word, but not on a double... */
-       if (likely(t1 & (sizeof(unsigned int)-1)) == 0) {
+       if (likely((t1 & (sizeof(unsigned int)-1)) == 0)) {
                t2 = src & (sizeof(unsigned int) - 1);
 
                if (unlikely(t2 != 0)) {
index 66c8a9f6a27eba49f17798873e97419a6104c282..3ca1c61492182d3321c2fe7d2cf00d003ff5a8a5 100644 (file)
@@ -40,7 +40,7 @@
  * END_DESC
 */
 
-
+#include <linux/kernel.h>
 #include "float.h"
 #include "sgl_float.h"
 #include "dbl_float.h"
index bfb6dd6ab380c3a2b762575d28e36008900658f4..c6afbfc957703f800610a96f0caa8008f53e598e 100644 (file)
@@ -1,5 +1,4 @@
-/* $Id: fault.c,v 1.5 2000/01/26 16:20:29 jsm Exp $
- *
+/*
  * This file is subject to the terms and conditions of the GNU General Public
  * License.  See the file "COPYING" in the main directory of this archive
  * for more details.
index 4356ceb1e366d9ed010706ac21dceb8ac24ba151..b0831d9e35cba677d153af1ac7efd0583fc618aa 100644 (file)
@@ -370,34 +370,22 @@ static void __init setup_bootmem(void)
 
 void free_initmem(void)
 {
-       unsigned long addr, init_begin, init_end;
-
-       printk(KERN_INFO "Freeing unused kernel memory: ");
+       unsigned long addr;
+       unsigned long init_begin = (unsigned long)__init_begin;
+       unsigned long init_end = (unsigned long)__init_end;
 
 #ifdef CONFIG_DEBUG_KERNEL
        /* Attempt to catch anyone trying to execute code here
         * by filling the page with BRK insns.
-        * 
-        * If we disable interrupts for all CPUs, then IPI stops working.
-        * Kinda breaks the global cache flushing.
         */
-       local_irq_disable();
-
-       memset(__init_begin, 0x00,
-               (unsigned long)__init_end - (unsigned long)__init_begin);
-
-       flush_data_cache();
-       asm volatile("sync" : : );
-       flush_icache_range((unsigned long)__init_begin, (unsigned long)__init_end);
-       asm volatile("sync" : : );
-
-       local_irq_enable();
+       memset((void *)init_begin, 0x00, init_end - init_begin);
+       flush_icache_range(init_begin, init_end);
 #endif
        
        /* align __init_begin and __init_end to page size,
           ignoring linker script where we might have tried to save RAM */
-       init_begin = PAGE_ALIGN((unsigned long)(__init_begin));
-       init_end   = PAGE_ALIGN((unsigned long)(__init_end));
+       init_begin = PAGE_ALIGN(init_begin);
+       init_end = PAGE_ALIGN(init_end);
        for (addr = init_begin; addr < init_end; addr += PAGE_SIZE) {
                ClearPageReserved(virt_to_page(addr));
                init_page_count(virt_to_page(addr));
@@ -409,7 +397,8 @@ void free_initmem(void)
        /* set up a new led state on systems shipped LED State panel */
        pdc_chassis_send_status(PDC_CHASSIS_DIRECT_BCOMPLETE);
        
-       printk("%luk freed\n", (init_end - init_begin) >> 10);
+       printk(KERN_INFO "Freeing unused kernel memory: %luk freed\n",
+               (init_end - init_begin) >> 10);
 }
 
 
index bf6cedfa05dbfbef2073ec2b9d652dd21fac504d..d00131ca0835e71cb8cd25d19f9f9f43557083df 100644 (file)
@@ -62,7 +62,6 @@ config HAVE_LATENCYTOP_SUPPORT
 
 config TRACE_IRQFLAGS_SUPPORT
        bool
-       depends on PPC64
        default y
 
 config LOCKDEP_SUPPORT
index 2f50acd11a6029a82fa22c98d5fb2d30e5e47d39..3d80c3e9cf6003b2fe9bfe512c660a2961d81a32 100644 (file)
@@ -36,3 +36,13 @@ zImage.pseries
 zconf.h
 zlib.h
 zutil.h
+fdt.c
+fdt.h
+fdt_ro.c
+fdt_rw.c
+fdt_strerror.c
+fdt_sw.c
+fdt_wip.c
+libfdt.h
+libfdt_internal.h
+
index 26549fca2ed449e7dcf58a190db56c525d09d261..49ac36b16dd78d6b4e68ccfac530602d719ef20e 100644 (file)
@@ -70,8 +70,8 @@
                        devsel-speed = <0x00000001>;
                        min-grant = <0>;
                        max-latency = <0>;
-                       /* First 64k for I/O at 0x0 on PCI mapped to 0x0 on ISA. */
-                       ranges = <0x00000001 0 0x01000000 0 0x00000000 0x00010000>;
+                       /* First 4k for I/O at 0x0 on PCI mapped to 0x0 on ISA. */
+                       ranges = <0x00000001 0 0x01000000 0 0x00000000 0x00001000>;
                        interrupt-parent = <&i8259>;
                        #interrupt-cells = <2>;
                        #address-cells = <2>;
index a8dcb018c4a591425c4d0b960542830313b41f40..a680165292f24b0cd606a359e1ae9ea089a3fdb0 100644 (file)
                        /* Filled in by U-Boot */
                        clock-frequency = <0>;
                        status = "disabled";
+                       sdhci,1-bit-only;
                };
 
                crypto@30000 {
index 01bfb56bbe802a96d2c4a965df1651483d5d8ae6..31605ee4afb69444d9aa5f8c523f9eba9c5f5879 100644 (file)
                                compatible = "gpio-leds";
                                green {
                                        gpios = <&GPIO1 0 0>;
-                                       default-state = "on";
+                                       default-state = "keep";
                                };
                                red {
                                        gpios = <&GPIO1 1 0>;
+                                       default-state = "keep";
                                };
                        };
 
index 3b77f092abe12d4ef3c234d0e62a1985ce498a74..787635f23d8fd0ca3772416c4240055754c3680f 100644 (file)
@@ -1,7 +1,7 @@
 #
 # Automatically generated make config: don't edit
-# Linux kernel version: 2.6.29-rc2
-# Fri Jan 23 07:57:16 2009
+# Linux kernel version: 2.6.30
+# Tue Jun  9 23:35:36 2009
 #
 # CONFIG_PPC64 is not set
 
@@ -41,6 +41,7 @@ CONFIG_ARCH_HAS_ILOG2_U32=y
 CONFIG_GENERIC_HWEIGHT=y
 CONFIG_GENERIC_CALIBRATE_DELAY=y
 CONFIG_GENERIC_FIND_NEXT_BIT=y
+CONFIG_GENERIC_GPIO=y
 # CONFIG_ARCH_NO_VIRT_TO_BUS is not set
 CONFIG_PPC=y
 CONFIG_EARLY_PRINTK=y
@@ -53,10 +54,12 @@ CONFIG_PPC_UDBG_16550=y
 # CONFIG_GENERIC_TBSYNC is not set
 CONFIG_AUDIT_ARCH=y
 CONFIG_GENERIC_BUG=y
+CONFIG_DTC=y
 # CONFIG_DEFAULT_UIMAGE is not set
 CONFIG_PPC_DCR_NATIVE=y
 # CONFIG_PPC_DCR_MMIO is not set
 CONFIG_PPC_DCR=y
+CONFIG_ARCH_SUPPORTS_DEBUG_PAGEALLOC=y
 CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
 
 #
@@ -74,7 +77,17 @@ CONFIG_SYSVIPC_SYSCTL=y
 # CONFIG_BSD_PROCESS_ACCT is not set
 # CONFIG_TASKSTATS is not set
 # CONFIG_AUDIT is not set
-# CONFIG_IKCONFIG is not set
+
+#
+# RCU Subsystem
+#
+CONFIG_CLASSIC_RCU=y
+# CONFIG_TREE_RCU is not set
+# CONFIG_PREEMPT_RCU is not set
+# CONFIG_TREE_RCU_TRACE is not set
+# CONFIG_PREEMPT_RCU_TRACE is not set
+CONFIG_IKCONFIG=y
+CONFIG_IKCONFIG_PROC=y
 CONFIG_LOG_BUF_SHIFT=14
 CONFIG_GROUP_SCHED=y
 CONFIG_FAIR_GROUP_SCHED=y
@@ -82,27 +95,29 @@ CONFIG_FAIR_GROUP_SCHED=y
 CONFIG_USER_SCHED=y
 # CONFIG_CGROUP_SCHED is not set
 # CONFIG_CGROUPS is not set
-CONFIG_SYSFS_DEPRECATED=y
-CONFIG_SYSFS_DEPRECATED_V2=y
+# CONFIG_SYSFS_DEPRECATED_V2 is not set
 # CONFIG_RELAY is not set
 # CONFIG_NAMESPACES is not set
 CONFIG_BLK_DEV_INITRD=y
 CONFIG_INITRAMFS_SOURCE=""
+CONFIG_RD_GZIP=y
+# CONFIG_RD_BZIP2 is not set
+# CONFIG_RD_LZMA is not set
 # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
 CONFIG_SYSCTL=y
+CONFIG_ANON_INODES=y
 CONFIG_EMBEDDED=y
 CONFIG_SYSCTL_SYSCALL=y
 CONFIG_KALLSYMS=y
 # CONFIG_KALLSYMS_ALL is not set
 # CONFIG_KALLSYMS_EXTRA_PASS is not set
-# CONFIG_HOTPLUG is not set
+# CONFIG_STRIP_ASM_SYMS is not set
+CONFIG_HOTPLUG=y
 CONFIG_PRINTK=y
 CONFIG_BUG=y
 CONFIG_ELF_CORE=y
-CONFIG_COMPAT_BRK=y
 CONFIG_BASE_FULL=y
 CONFIG_FUTEX=y
-CONFIG_ANON_INODES=y
 CONFIG_EPOLL=y
 CONFIG_SIGNALFD=y
 CONFIG_TIMERFD=y
@@ -110,10 +125,13 @@ CONFIG_EVENTFD=y
 CONFIG_SHMEM=y
 CONFIG_AIO=y
 CONFIG_VM_EVENT_COUNTERS=y
-CONFIG_SLAB=y
-# CONFIG_SLUB is not set
+CONFIG_SLUB_DEBUG=y
+CONFIG_COMPAT_BRK=y
+# CONFIG_SLAB is not set
+CONFIG_SLUB=y
 # CONFIG_SLOB is not set
 # CONFIG_PROFILING is not set
+# CONFIG_MARKERS is not set
 CONFIG_HAVE_OPROFILE=y
 # CONFIG_KPROBES is not set
 CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS=y
@@ -121,6 +139,7 @@ CONFIG_HAVE_IOREMAP_PROT=y
 CONFIG_HAVE_KPROBES=y
 CONFIG_HAVE_KRETPROBES=y
 CONFIG_HAVE_ARCH_TRACEHOOK=y
+# CONFIG_SLOW_WORK is not set
 # CONFIG_HAVE_GENERIC_DMA_COHERENT is not set
 CONFIG_SLABINFO=y
 CONFIG_RT_MUTEXES=y
@@ -133,7 +152,6 @@ CONFIG_MODULE_UNLOAD=y
 # CONFIG_MODULE_SRCVERSION_ALL is not set
 CONFIG_BLOCK=y
 # CONFIG_LBD is not set
-# CONFIG_BLK_DEV_IO_TRACE is not set
 # CONFIG_BLK_DEV_BSG is not set
 # CONFIG_BLK_DEV_INTEGRITY is not set
 
@@ -149,11 +167,6 @@ CONFIG_DEFAULT_AS=y
 # CONFIG_DEFAULT_CFQ is not set
 # CONFIG_DEFAULT_NOOP is not set
 CONFIG_DEFAULT_IOSCHED="anticipatory"
-CONFIG_CLASSIC_RCU=y
-# CONFIG_TREE_RCU is not set
-# CONFIG_PREEMPT_RCU is not set
-# CONFIG_TREE_RCU_TRACE is not set
-# CONFIG_PREEMPT_RCU_TRACE is not set
 # CONFIG_FREEZER is not set
 
 #
@@ -173,10 +186,11 @@ CONFIG_WARP=y
 # CONFIG_ARCHES is not set
 # CONFIG_CANYONLANDS is not set
 # CONFIG_GLACIER is not set
+# CONFIG_REDWOOD is not set
 # CONFIG_YOSEMITE is not set
 # CONFIG_XILINX_VIRTEX440_GENERIC_BOARD is not set
 # CONFIG_PPC44x_SIMPLE is not set
-# CONFIG_PPC4xx_GPIO is not set
+CONFIG_PPC4xx_GPIO=y
 CONFIG_440EP=y
 CONFIG_IBM440EP_ERR42=y
 # CONFIG_IPIC is not set
@@ -235,9 +249,13 @@ CONFIG_ZONE_DMA_FLAG=1
 CONFIG_BOUNCE=y
 CONFIG_VIRT_TO_BUS=y
 CONFIG_UNEVICTABLE_LRU=y
+CONFIG_HAVE_MLOCK=y
+CONFIG_HAVE_MLOCKED_PAGE_BIT=y
+CONFIG_STDBINUTILS=y
 CONFIG_PPC_4K_PAGES=y
 # CONFIG_PPC_16K_PAGES is not set
 # CONFIG_PPC_64K_PAGES is not set
+# CONFIG_PPC_256K_PAGES is not set
 CONFIG_FORCE_MAX_ZONEORDER=11
 CONFIG_PROC_DEVICETREE=y
 CONFIG_CMDLINE_BOOL=y
@@ -256,6 +274,7 @@ CONFIG_PPC_PCI_CHOICE=y
 # CONFIG_PCI_DOMAINS is not set
 # CONFIG_PCI_SYSCALL is not set
 # CONFIG_ARCH_SUPPORTS_MSI is not set
+# CONFIG_PCCARD is not set
 # CONFIG_HAS_RAPIDIO is not set
 
 #
@@ -271,14 +290,12 @@ CONFIG_PAGE_OFFSET=0xc0000000
 CONFIG_KERNEL_START=0xc0000000
 CONFIG_PHYSICAL_START=0x00000000
 CONFIG_TASK_SIZE=0xc0000000
-CONFIG_CONSISTENT_START=0xff100000
 CONFIG_CONSISTENT_SIZE=0x00200000
 CONFIG_NET=y
 
 #
 # Networking options
 #
-CONFIG_COMPAT_NET_DEV_OPS=y
 CONFIG_PACKET=y
 # CONFIG_PACKET_MMAP is not set
 CONFIG_UNIX=y
@@ -353,6 +370,7 @@ CONFIG_VLAN_8021Q=y
 # CONFIG_LAPB is not set
 # CONFIG_ECONET is not set
 # CONFIG_WAN_ROUTER is not set
+# CONFIG_PHONET is not set
 # CONFIG_NET_SCHED is not set
 # CONFIG_DCB is not set
 
@@ -365,7 +383,6 @@ CONFIG_VLAN_8021Q=y
 # CONFIG_IRDA is not set
 # CONFIG_BT is not set
 # CONFIG_AF_RXRPC is not set
-# CONFIG_PHONET is not set
 # CONFIG_WIRELESS is not set
 # CONFIG_WIMAX is not set
 # CONFIG_RFKILL is not set
@@ -378,8 +395,12 @@ CONFIG_VLAN_8021Q=y
 #
 # Generic Driver Options
 #
+CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
 # CONFIG_STANDALONE is not set
 CONFIG_PREVENT_FIRMWARE_BUILD=y
+CONFIG_FW_LOADER=y
+# CONFIG_FIRMWARE_IN_KERNEL is not set
+CONFIG_EXTRA_FIRMWARE=""
 # CONFIG_DEBUG_DRIVER is not set
 # CONFIG_DEBUG_DEVRES is not set
 # CONFIG_SYS_HYPERVISOR is not set
@@ -471,13 +492,21 @@ CONFIG_MTD_NAND_NDFC=y
 # LPDDR flash memory drivers
 #
 # CONFIG_MTD_LPDDR is not set
-# CONFIG_MTD_QINFO_PROBE is not set
 
 #
 # UBI - Unsorted block images
 #
-# CONFIG_MTD_UBI is not set
+CONFIG_MTD_UBI=y
+CONFIG_MTD_UBI_WL_THRESHOLD=4096
+CONFIG_MTD_UBI_BEB_RESERVE=1
+# CONFIG_MTD_UBI_GLUEBI is not set
+
+#
+# UBI debugging options
+#
+# CONFIG_MTD_UBI_DEBUG is not set
 CONFIG_OF_DEVICE=y
+CONFIG_OF_GPIO=y
 CONFIG_OF_I2C=y
 # CONFIG_PARPORT is not set
 CONFIG_BLK_DEV=y
@@ -495,10 +524,17 @@ CONFIG_BLK_DEV_RAM_SIZE=4096
 # CONFIG_XILINX_SYSACE is not set
 # CONFIG_BLK_DEV_HD is not set
 CONFIG_MISC_DEVICES=y
-# CONFIG_EEPROM_93CX6 is not set
 # CONFIG_ICS932S401 is not set
 # CONFIG_ENCLOSURE_SERVICES is not set
+# CONFIG_ISL29003 is not set
 # CONFIG_C2PORT is not set
+
+#
+# EEPROM support
+#
+CONFIG_EEPROM_AT24=y
+# CONFIG_EEPROM_LEGACY is not set
+# CONFIG_EEPROM_93CX6 is not set
 CONFIG_HAVE_IDE=y
 # CONFIG_IDE is not set
 
@@ -529,7 +565,7 @@ CONFIG_BLK_DEV_SD=y
 # CONFIG_SCSI_CONSTANTS is not set
 # CONFIG_SCSI_LOGGING is not set
 # CONFIG_SCSI_SCAN_ASYNC is not set
-CONFIG_SCSI_WAIT_SCAN=m
+# CONFIG_SCSI_WAIT_SCAN is not set
 
 #
 # SCSI Transports
@@ -541,10 +577,12 @@ CONFIG_SCSI_SPI_ATTRS=y
 # CONFIG_SCSI_SRP_ATTRS is not set
 # CONFIG_SCSI_LOWLEVEL is not set
 # CONFIG_SCSI_DH is not set
+# CONFIG_SCSI_OSD_INITIATOR is not set
 # CONFIG_ATA is not set
 # CONFIG_MD is not set
 # CONFIG_MACINTOSH_DRIVERS is not set
 CONFIG_NETDEVICES=y
+CONFIG_COMPAT_NET_DEV_OPS=y
 # CONFIG_DUMMY is not set
 # CONFIG_BONDING is not set
 # CONFIG_MACVLAN is not set
@@ -554,6 +592,8 @@ CONFIG_NETDEVICES=y
 # CONFIG_PHYLIB is not set
 CONFIG_NET_ETHERNET=y
 CONFIG_MII=y
+# CONFIG_ETHOC is not set
+# CONFIG_DNET is not set
 CONFIG_IBM_NEW_EMAC=y
 CONFIG_IBM_NEW_EMAC_RXB=128
 CONFIG_IBM_NEW_EMAC_TXB=64
@@ -577,7 +617,6 @@ CONFIG_IBM_NEW_EMAC_ZMII=y
 #
 # CONFIG_WLAN_PRE80211 is not set
 # CONFIG_WLAN_80211 is not set
-# CONFIG_IWLWIFI_LEDS is not set
 
 #
 # Enable WiMAX (Networking options) to see the WiMAX drivers
@@ -646,6 +685,7 @@ CONFIG_LEGACY_PTY_COUNT=256
 # CONFIG_HVC_UDBG is not set
 # CONFIG_IPMI_HANDLER is not set
 CONFIG_HW_RANDOM=y
+# CONFIG_HW_RANDOM_TIMERIOMEM is not set
 # CONFIG_NVRAM is not set
 # CONFIG_GEN_RTC is not set
 # CONFIG_R3964 is not set
@@ -663,6 +703,7 @@ CONFIG_I2C_HELPER_AUTO=y
 #
 # I2C system bus drivers (mostly embedded / system-on-chip)
 #
+# CONFIG_I2C_GPIO is not set
 CONFIG_I2C_IBM_IIC=y
 # CONFIG_I2C_MPC is not set
 # CONFIG_I2C_OCORES is not set
@@ -685,12 +726,9 @@ CONFIG_I2C_IBM_IIC=y
 # Miscellaneous I2C Chip support
 #
 # CONFIG_DS1682 is not set
-CONFIG_EEPROM_AT24=y
-CONFIG_EEPROM_LEGACY=y
 # CONFIG_SENSORS_PCF8574 is not set
 # CONFIG_PCF8575 is not set
 # CONFIG_SENSORS_PCA9539 is not set
-# CONFIG_SENSORS_PCF8591 is not set
 # CONFIG_SENSORS_MAX6875 is not set
 # CONFIG_SENSORS_TSL2550 is not set
 # CONFIG_I2C_DEBUG_CORE is not set
@@ -699,7 +737,30 @@ CONFIG_EEPROM_LEGACY=y
 # CONFIG_I2C_DEBUG_CHIP is not set
 # CONFIG_SPI is not set
 CONFIG_ARCH_WANT_OPTIONAL_GPIOLIB=y
-# CONFIG_GPIOLIB is not set
+CONFIG_ARCH_REQUIRE_GPIOLIB=y
+CONFIG_GPIOLIB=y
+# CONFIG_DEBUG_GPIO is not set
+CONFIG_GPIO_SYSFS=y
+
+#
+# Memory mapped GPIO expanders:
+#
+# CONFIG_GPIO_XILINX is not set
+
+#
+# I2C GPIO expanders:
+#
+# CONFIG_GPIO_MAX732X is not set
+# CONFIG_GPIO_PCA953X is not set
+# CONFIG_GPIO_PCF857X is not set
+
+#
+# PCI GPIO expanders:
+#
+
+#
+# SPI GPIO expanders:
+#
 # CONFIG_W1 is not set
 # CONFIG_POWER_SUPPLY is not set
 CONFIG_HWMON=y
@@ -721,6 +782,7 @@ CONFIG_SENSORS_AD7414=y
 # CONFIG_SENSORS_F71805F is not set
 # CONFIG_SENSORS_F71882FG is not set
 # CONFIG_SENSORS_F75375S is not set
+# CONFIG_SENSORS_G760A is not set
 # CONFIG_SENSORS_GL518SM is not set
 # CONFIG_SENSORS_GL520SM is not set
 # CONFIG_SENSORS_IT87 is not set
@@ -735,11 +797,15 @@ CONFIG_SENSORS_AD7414=y
 # CONFIG_SENSORS_LM90 is not set
 # CONFIG_SENSORS_LM92 is not set
 # CONFIG_SENSORS_LM93 is not set
+# CONFIG_SENSORS_LTC4215 is not set
 # CONFIG_SENSORS_LTC4245 is not set
+# CONFIG_SENSORS_LM95241 is not set
 # CONFIG_SENSORS_MAX1619 is not set
 # CONFIG_SENSORS_MAX6650 is not set
 # CONFIG_SENSORS_PC87360 is not set
 # CONFIG_SENSORS_PC87427 is not set
+# CONFIG_SENSORS_PCF8591 is not set
+# CONFIG_SENSORS_SHT15 is not set
 # CONFIG_SENSORS_DME1737 is not set
 # CONFIG_SENSORS_SMSC47M1 is not set
 # CONFIG_SENSORS_SMSC47M192 is not set
@@ -785,6 +851,7 @@ CONFIG_SSB_POSSIBLE=y
 # CONFIG_MFD_CORE is not set
 # CONFIG_MFD_SM501 is not set
 # CONFIG_HTC_PASIC3 is not set
+# CONFIG_TPS65010 is not set
 # CONFIG_TWL4030_CORE is not set
 # CONFIG_MFD_TMIO is not set
 # CONFIG_PMIC_DA903X is not set
@@ -870,11 +937,11 @@ CONFIG_USB_OHCI_LITTLE_ENDIAN=y
 # CONFIG_USB_TMC is not set
 
 #
-# NOTE: USB_STORAGE depends on SCSI but BLK_DEV_SD may also be needed;
+# NOTE: USB_STORAGE depends on SCSI but BLK_DEV_SD may
 #
 
 #
-# see USB_STORAGE Help for more information
+# also be needed; see USB_STORAGE Help for more info
 #
 CONFIG_USB_STORAGE=y
 # CONFIG_USB_STORAGE_DEBUG is not set
@@ -915,7 +982,6 @@ CONFIG_USB_STORAGE=y
 # CONFIG_USB_LED is not set
 # CONFIG_USB_CYPRESS_CY7C63 is not set
 # CONFIG_USB_CYTHERM is not set
-# CONFIG_USB_PHIDGET is not set
 # CONFIG_USB_IDMOUSE is not set
 # CONFIG_USB_FTDI_ELAN is not set
 # CONFIG_USB_APPLEDISPLAY is not set
@@ -929,6 +995,8 @@ CONFIG_USB_STORAGE=y
 #
 # OTG and related infrastructure
 #
+# CONFIG_USB_GPIO_VBUS is not set
+# CONFIG_NOP_USB_XCEIV is not set
 CONFIG_MMC=y
 # CONFIG_MMC_DEBUG is not set
 # CONFIG_MMC_UNSAFE_RESUME is not set
@@ -946,6 +1014,7 @@ CONFIG_MMC_BLOCK_BOUNCE=y
 #
 # CONFIG_MMC_SDHCI is not set
 # CONFIG_MMC_WBSD is not set
+CONFIG_MMC_PIKASD=y
 # CONFIG_MEMSTICK is not set
 CONFIG_NEW_LEDS=y
 CONFIG_LEDS_CLASS=y
@@ -953,16 +1022,31 @@ CONFIG_LEDS_CLASS=y
 #
 # LED drivers
 #
+CONFIG_LEDS_GPIO=y
+# CONFIG_LEDS_GPIO_PLATFORM is not set
+CONFIG_LEDS_GPIO_OF=y
+# CONFIG_LEDS_LP5521 is not set
 # CONFIG_LEDS_PCA955X is not set
+# CONFIG_LEDS_BD2802 is not set
 
 #
 # LED Triggers
 #
-# CONFIG_LEDS_TRIGGERS is not set
+CONFIG_LEDS_TRIGGERS=y
+# CONFIG_LEDS_TRIGGER_TIMER is not set
+# CONFIG_LEDS_TRIGGER_HEARTBEAT is not set
+# CONFIG_LEDS_TRIGGER_BACKLIGHT is not set
+# CONFIG_LEDS_TRIGGER_GPIO is not set
+CONFIG_LEDS_TRIGGER_DEFAULT_ON=y
+
+#
+# iptables trigger is under Netfilter config (LED target)
+#
 # CONFIG_ACCESSIBILITY is not set
 # CONFIG_EDAC is not set
 # CONFIG_RTC_CLASS is not set
 # CONFIG_DMADEVICES is not set
+# CONFIG_AUXDISPLAY is not set
 # CONFIG_UIO is not set
 # CONFIG_STAGING is not set
 
@@ -973,6 +1057,7 @@ CONFIG_EXT2_FS=y
 # CONFIG_EXT2_FS_XATTR is not set
 # CONFIG_EXT2_FS_XIP is not set
 CONFIG_EXT3_FS=y
+# CONFIG_EXT3_DEFAULTS_TO_ORDERED is not set
 # CONFIG_EXT3_FS_XATTR is not set
 # CONFIG_EXT4_FS is not set
 CONFIG_JBD=y
@@ -992,6 +1077,11 @@ CONFIG_INOTIFY_USER=y
 # CONFIG_AUTOFS4_FS is not set
 # CONFIG_FUSE_FS is not set
 
+#
+# Caches
+#
+# CONFIG_FSCACHE is not set
+
 #
 # CD-ROM/DVD Filesystems
 #
@@ -1039,6 +1129,12 @@ CONFIG_JFFS2_ZLIB=y
 # CONFIG_JFFS2_LZO is not set
 CONFIG_JFFS2_RTIME=y
 # CONFIG_JFFS2_RUBIN is not set
+CONFIG_UBIFS_FS=y
+# CONFIG_UBIFS_FS_XATTR is not set
+# CONFIG_UBIFS_FS_ADVANCED_COMPR is not set
+CONFIG_UBIFS_FS_LZO=y
+CONFIG_UBIFS_FS_ZLIB=y
+# CONFIG_UBIFS_FS_DEBUG is not set
 CONFIG_CRAMFS=y
 # CONFIG_SQUASHFS is not set
 # CONFIG_VXFS_FS is not set
@@ -1049,6 +1145,7 @@ CONFIG_CRAMFS=y
 # CONFIG_ROMFS_FS is not set
 # CONFIG_SYSV_FS is not set
 # CONFIG_UFS_FS is not set
+# CONFIG_NILFS2_FS is not set
 CONFIG_NETWORK_FILESYSTEMS=y
 CONFIG_NFS_FS=y
 CONFIG_NFS_V3=y
@@ -1060,7 +1157,6 @@ CONFIG_LOCKD=y
 CONFIG_LOCKD_V4=y
 CONFIG_NFS_COMMON=y
 CONFIG_SUNRPC=y
-# CONFIG_SUNRPC_REGISTER_V4 is not set
 # CONFIG_RPCSEC_GSS_KRB5 is not set
 # CONFIG_RPCSEC_GSS_SPKM3 is not set
 # CONFIG_SMB_FS is not set
@@ -1115,6 +1211,7 @@ CONFIG_NLS_ISO8859_15=y
 # CONFIG_NLS_KOI8_U is not set
 CONFIG_NLS_UTF8=y
 # CONFIG_DLM is not set
+# CONFIG_BINARY_PRINTF is not set
 
 #
 # Library routines
@@ -1122,7 +1219,7 @@ CONFIG_NLS_UTF8=y
 CONFIG_BITREVERSE=y
 CONFIG_GENERIC_FIND_LAST_BIT=y
 CONFIG_CRC_CCITT=y
-# CONFIG_CRC16 is not set
+CONFIG_CRC16=y
 CONFIG_CRC_T10DIF=y
 # CONFIG_CRC_ITU_T is not set
 CONFIG_CRC32=y
@@ -1130,16 +1227,19 @@ CONFIG_CRC32=y
 # CONFIG_LIBCRC32C is not set
 CONFIG_ZLIB_INFLATE=y
 CONFIG_ZLIB_DEFLATE=y
-CONFIG_PLIST=y
+CONFIG_LZO_COMPRESS=y
+CONFIG_LZO_DECOMPRESS=y
+CONFIG_DECOMPRESS_GZIP=y
 CONFIG_HAS_IOMEM=y
 CONFIG_HAS_IOPORT=y
 CONFIG_HAS_DMA=y
 CONFIG_HAVE_LMB=y
+CONFIG_NLATTR=y
 
 #
 # Kernel hacking
 #
-# CONFIG_PRINTK_TIME is not set
+CONFIG_PRINTK_TIME=y
 CONFIG_ENABLE_WARN_DEPRECATED=y
 CONFIG_ENABLE_MUST_CHECK=y
 CONFIG_FRAME_WARN=1024
@@ -1152,11 +1252,15 @@ CONFIG_DEBUG_KERNEL=y
 CONFIG_DETECT_SOFTLOCKUP=y
 # CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC is not set
 CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC_VALUE=0
+CONFIG_DETECT_HUNG_TASK=y
+# CONFIG_BOOTPARAM_HUNG_TASK_PANIC is not set
+CONFIG_BOOTPARAM_HUNG_TASK_PANIC_VALUE=0
 # CONFIG_SCHED_DEBUG is not set
 # CONFIG_SCHEDSTATS is not set
 # CONFIG_TIMER_STATS is not set
 # CONFIG_DEBUG_OBJECTS is not set
-# CONFIG_DEBUG_SLAB is not set
+# CONFIG_SLUB_DEBUG_ON is not set
+# CONFIG_SLUB_STATS is not set
 # CONFIG_DEBUG_RT_MUTEXES is not set
 # CONFIG_RT_MUTEX_TESTER is not set
 # CONFIG_DEBUG_SPINLOCK is not set
@@ -1180,9 +1284,12 @@ CONFIG_DEBUG_INFO=y
 # CONFIG_FAULT_INJECTION is not set
 # CONFIG_LATENCYTOP is not set
 CONFIG_SYSCTL_SYSCALL_CHECK=y
+# CONFIG_DEBUG_PAGEALLOC is not set
 CONFIG_HAVE_FUNCTION_TRACER=y
+CONFIG_HAVE_FUNCTION_GRAPH_TRACER=y
 CONFIG_HAVE_DYNAMIC_FTRACE=y
 CONFIG_HAVE_FTRACE_MCOUNT_RECORD=y
+CONFIG_TRACING_SUPPORT=y
 
 #
 # Tracers
@@ -1190,24 +1297,27 @@ CONFIG_HAVE_FTRACE_MCOUNT_RECORD=y
 # CONFIG_FUNCTION_TRACER is not set
 # CONFIG_SCHED_TRACER is not set
 # CONFIG_CONTEXT_SWITCH_TRACER is not set
+# CONFIG_EVENT_TRACER is not set
 # CONFIG_BOOT_TRACER is not set
 # CONFIG_TRACE_BRANCH_PROFILING is not set
 # CONFIG_STACK_TRACER is not set
-# CONFIG_DYNAMIC_PRINTK_DEBUG is not set
+# CONFIG_KMEMTRACE is not set
+# CONFIG_WORKQUEUE_TRACER is not set
+# CONFIG_BLK_DEV_IO_TRACE is not set
+# CONFIG_DYNAMIC_DEBUG is not set
 # CONFIG_SAMPLES is not set
 CONFIG_HAVE_ARCH_KGDB=y
 # CONFIG_KGDB is not set
 CONFIG_PRINT_STACK_DEPTH=64
 # CONFIG_DEBUG_STACKOVERFLOW is not set
 # CONFIG_DEBUG_STACK_USAGE is not set
-# CONFIG_DEBUG_PAGEALLOC is not set
 # CONFIG_CODE_PATCHING_SELFTEST is not set
 # CONFIG_FTR_FIXUP_SELFTEST is not set
 # CONFIG_MSI_BITMAP_SELFTEST is not set
 # CONFIG_XMON is not set
 CONFIG_IRQSTACKS=y
 # CONFIG_VIRQ_DEBUG is not set
-CONFIG_BDI_SWITCH=y
+# CONFIG_BDI_SWITCH is not set
 # CONFIG_PPC_EARLY_DEBUG is not set
 
 #
@@ -1223,6 +1333,8 @@ CONFIG_CRYPTO=y
 # Crypto core or helper
 #
 # CONFIG_CRYPTO_FIPS is not set
+CONFIG_CRYPTO_ALGAPI=y
+CONFIG_CRYPTO_ALGAPI2=y
 # CONFIG_CRYPTO_MANAGER is not set
 # CONFIG_CRYPTO_MANAGER2 is not set
 # CONFIG_CRYPTO_GF128MUL is not set
@@ -1294,13 +1406,15 @@ CONFIG_CRYPTO=y
 #
 # Compression
 #
-# CONFIG_CRYPTO_DEFLATE is not set
-# CONFIG_CRYPTO_LZO is not set
+CONFIG_CRYPTO_DEFLATE=y
+# CONFIG_CRYPTO_ZLIB is not set
+CONFIG_CRYPTO_LZO=y
 
 #
 # Random Number Generation
 #
 # CONFIG_CRYPTO_ANSI_CPRNG is not set
 CONFIG_CRYPTO_HW=y
+# CONFIG_CRYPTO_DEV_PPC4XX is not set
 # CONFIG_PPC_CLOCK is not set
 # CONFIG_VIRTUALIZATION is not set
index 2ff798744c1d6eba3bd71a99f3875cdc71f26888..7685ffde882105fc81eba44d5a918309d5bbd66c 100644 (file)
@@ -598,8 +598,6 @@ typedef struct risc_timer_pram {
 #define CICR_IEN               ((uint)0x00000080)      /* Int. enable */
 #define CICR_SPS               ((uint)0x00000001)      /* SCC Spread */
 
-#define IMAP_ADDR              (get_immrbase())
-
 #define CPM_PIN_INPUT     0
 #define CPM_PIN_OUTPUT    1
 #define CPM_PIN_PRIMARY   0
index 1e2eb41fa0577ff8ecceb2d9711220c82ea22fab..52e4d54da2a9845d16db0773ca81310178707723 100644 (file)
@@ -63,6 +63,8 @@ extern void udelay(unsigned long usecs);
                        udelay(delay);                                         \
                else                                                           \
                        cpu_relax();                                           \
+       if (!__ret)                                                            \
+               __ret = (condition);                                           \
        __ret;                                                                 \
 })
 
index 3d9e887c3c0cfb0a970e30c6318b4b1804d08549..b44aaabdd1a685f2c52c98fe3cf7ae798c779e31 100644 (file)
@@ -309,7 +309,9 @@ static inline void dma_sync_single_for_cpu(struct device *dev,
        struct dma_mapping_ops *dma_ops = get_dma_ops(dev);
 
        BUG_ON(!dma_ops);
-       dma_ops->sync_single_range_for_cpu(dev, dma_handle, 0,
+
+       if (dma_ops->sync_single_range_for_cpu)
+               dma_ops->sync_single_range_for_cpu(dev, dma_handle, 0,
                                           size, direction);
 }
 
@@ -320,7 +322,9 @@ static inline void dma_sync_single_for_device(struct device *dev,
        struct dma_mapping_ops *dma_ops = get_dma_ops(dev);
 
        BUG_ON(!dma_ops);
-       dma_ops->sync_single_range_for_device(dev, dma_handle,
+
+       if (dma_ops->sync_single_range_for_device)
+               dma_ops->sync_single_range_for_device(dev, dma_handle,
                                              0, size, direction);
 }
 
@@ -331,7 +335,9 @@ static inline void dma_sync_sg_for_cpu(struct device *dev,
        struct dma_mapping_ops *dma_ops = get_dma_ops(dev);
 
        BUG_ON(!dma_ops);
-       dma_ops->sync_sg_for_cpu(dev, sgl, nents, direction);
+
+       if (dma_ops->sync_sg_for_cpu)
+               dma_ops->sync_sg_for_cpu(dev, sgl, nents, direction);
 }
 
 static inline void dma_sync_sg_for_device(struct device *dev,
@@ -341,7 +347,9 @@ static inline void dma_sync_sg_for_device(struct device *dev,
        struct dma_mapping_ops *dma_ops = get_dma_ops(dev);
 
        BUG_ON(!dma_ops);
-       dma_ops->sync_sg_for_device(dev, sgl, nents, direction);
+
+       if (dma_ops->sync_sg_for_device)
+               dma_ops->sync_sg_for_device(dev, sgl, nents, direction);
 }
 
 static inline void dma_sync_single_range_for_cpu(struct device *dev,
@@ -351,7 +359,9 @@ static inline void dma_sync_single_range_for_cpu(struct device *dev,
        struct dma_mapping_ops *dma_ops = get_dma_ops(dev);
 
        BUG_ON(!dma_ops);
-       dma_ops->sync_single_range_for_cpu(dev, dma_handle,
+
+       if (dma_ops->sync_single_range_for_cpu)
+               dma_ops->sync_single_range_for_cpu(dev, dma_handle,
                                           offset, size, direction);
 }
 
@@ -362,7 +372,9 @@ static inline void dma_sync_single_range_for_device(struct device *dev,
        struct dma_mapping_ops *dma_ops = get_dma_ops(dev);
 
        BUG_ON(!dma_ops);
-       dma_ops->sync_single_range_for_device(dev, dma_handle, offset,
+
+       if (dma_ops->sync_single_range_for_device)
+               dma_ops->sync_single_range_for_device(dev, dma_handle, offset,
                                              size, direction);
 }
 #else /* CONFIG_PPC_NEED_DMA_SYNC_OPS */
index 684a73f4324f4ad203c71ef4eb09b5045ab60516..a74c4ee6c0205dbad7e938ab76e012bfa6491c28 100644 (file)
@@ -22,9 +22,7 @@
 
 #ifdef __KERNEL__
 
-#include <linux/init.h>
 #include <linux/interrupt.h>
-#include <linux/highmem.h>
 #include <asm/kmap_types.h>
 #include <asm/tlbflush.h>
 #include <asm/page.h>
@@ -62,6 +60,9 @@ extern pte_t *pkmap_page_table;
 
 extern void *kmap_high(struct page *page);
 extern void kunmap_high(struct page *page);
+extern void *kmap_atomic_prot(struct page *page, enum km_type type,
+                             pgprot_t prot);
+extern void kunmap_atomic(void *kvaddr, enum km_type type);
 
 static inline void *kmap(struct page *page)
 {
@@ -79,62 +80,11 @@ static inline void kunmap(struct page *page)
        kunmap_high(page);
 }
 
-/*
- * The use of kmap_atomic/kunmap_atomic is discouraged - kmap/kunmap
- * gives a more generic (and caching) interface. But kmap_atomic can
- * be used in IRQ contexts, so in some (very limited) cases we need
- * it.
- */
-static inline void *kmap_atomic_prot(struct page *page, enum km_type type, pgprot_t prot)
-{
-       unsigned int idx;
-       unsigned long vaddr;
-
-       /* even !CONFIG_PREEMPT needs this, for in_atomic in do_page_fault */
-       pagefault_disable();
-       if (!PageHighMem(page))
-               return page_address(page);
-
-       debug_kmap_atomic(type);
-       idx = type + KM_TYPE_NR*smp_processor_id();
-       vaddr = __fix_to_virt(FIX_KMAP_BEGIN + idx);
-#ifdef CONFIG_DEBUG_HIGHMEM
-       BUG_ON(!pte_none(*(kmap_pte-idx)));
-#endif
-       __set_pte_at(&init_mm, vaddr, kmap_pte-idx, mk_pte(page, prot), 1);
-       local_flush_tlb_page(NULL, vaddr);
-
-       return (void*) vaddr;
-}
-
 static inline void *kmap_atomic(struct page *page, enum km_type type)
 {
        return kmap_atomic_prot(page, type, kmap_prot);
 }
 
-static inline void kunmap_atomic(void *kvaddr, enum km_type type)
-{
-#ifdef CONFIG_DEBUG_HIGHMEM
-       unsigned long vaddr = (unsigned long) kvaddr & PAGE_MASK;
-       enum fixed_addresses idx = type + KM_TYPE_NR*smp_processor_id();
-
-       if (vaddr < __fix_to_virt(FIX_KMAP_END)) {
-               pagefault_enable();
-               return;
-       }
-
-       BUG_ON(vaddr != __fix_to_virt(FIX_KMAP_BEGIN + idx));
-
-       /*
-        * force other mappings to Oops if they'll try to access
-        * this pte without first remap it
-        */
-       pte_clear(&init_mm, vaddr, kmap_pte-idx);
-       local_flush_tlb_page(NULL, vaddr);
-#endif
-       pagefault_enable();
-}
-
 static inline struct page *kmap_atomic_to_page(void *ptr)
 {
        unsigned long idx, vaddr = (unsigned long) ptr;
@@ -148,6 +98,7 @@ static inline struct page *kmap_atomic_to_page(void *ptr)
        return pte_page(*pte);
 }
 
+
 #define flush_cache_kmaps()    flush_cache_all()
 
 #endif /* __KERNEL__ */
index 867ab8ed69b303658a07d6c67d660eece712d5cf..8b505eaaa38a173b0f86154654879ad914d35fb7 100644 (file)
@@ -68,13 +68,13 @@ static inline int irqs_disabled_flags(unsigned long flags)
 
 #if defined(CONFIG_BOOKE)
 #define SET_MSR_EE(x)  mtmsr(x)
-#define local_irq_restore(flags)       __asm__ __volatile__("wrtee %0" : : "r" (flags) : "memory")
+#define raw_local_irq_restore(flags)   __asm__ __volatile__("wrtee %0" : : "r" (flags) : "memory")
 #else
 #define SET_MSR_EE(x)  mtmsr(x)
-#define local_irq_restore(flags)       mtmsr(flags)
+#define raw_local_irq_restore(flags)   mtmsr(flags)
 #endif
 
-static inline void local_irq_disable(void)
+static inline void raw_local_irq_disable(void)
 {
 #ifdef CONFIG_BOOKE
        __asm__ __volatile__("wrteei 0": : :"memory");
@@ -86,7 +86,7 @@ static inline void local_irq_disable(void)
 #endif
 }
 
-static inline void local_irq_enable(void)
+static inline void raw_local_irq_enable(void)
 {
 #ifdef CONFIG_BOOKE
        __asm__ __volatile__("wrteei 1": : :"memory");
@@ -98,7 +98,7 @@ static inline void local_irq_enable(void)
 #endif
 }
 
-static inline void local_irq_save_ptr(unsigned long *flags)
+static inline void raw_local_irq_save_ptr(unsigned long *flags)
 {
        unsigned long msr;
        msr = mfmsr();
@@ -110,12 +110,12 @@ static inline void local_irq_save_ptr(unsigned long *flags)
 #endif
 }
 
-#define local_save_flags(flags)        ((flags) = mfmsr())
-#define local_irq_save(flags)  local_irq_save_ptr(&flags)
-#define irqs_disabled()                ((mfmsr() & MSR_EE) == 0)
+#define raw_local_save_flags(flags)    ((flags) = mfmsr())
+#define raw_local_irq_save(flags)      raw_local_irq_save_ptr(&flags)
+#define raw_irqs_disabled()            ((mfmsr() & MSR_EE) == 0)
+#define raw_irqs_disabled_flags(flags) (((flags) & MSR_EE) == 0)
 
-#define hard_irq_enable()      local_irq_enable()
-#define hard_irq_disable()     local_irq_disable()
+#define hard_irq_disable()             raw_local_irq_disable()
 
 static inline int irqs_disabled_flags(unsigned long flags)
 {
index 8ccd4e155768fa749edf3f65fbc0c5a951ef9819..0ea0639fcf75be1c4393e4437aceaf7bb7ca87eb 100644 (file)
@@ -61,6 +61,8 @@ struct pt_regs;
 extern unsigned long perf_misc_flags(struct pt_regs *regs);
 extern unsigned long perf_instruction_pointer(struct pt_regs *regs);
 
+#define PERF_COUNTER_INDEX_OFFSET      1
+
 /*
  * Only override the default definitions in include/linux/perf_counter.h
  * if we have hardware PMU support.
index e05d26fa372fc84ae833799e072dca5a39a94d37..82b72207c51c9113600ce8b8fc5297115623142c 100644 (file)
@@ -47,7 +47,8 @@
  * generic accessors and iterators here
  */
 #define __real_pte(e,p)        ((real_pte_t) { \
-       (e), pte_val(*((p) + PTRS_PER_PTE)) })
+                       (e), ((e) & _PAGE_COMBO) ? \
+                               (pte_val(*((p) + PTRS_PER_PTE))) : 0 })
 #define __rpte_to_hidx(r,index)        ((pte_val((r).pte) & _PAGE_COMBO) ? \
         (((r).hidx >> ((index)<<2)) & 0xf) : ((pte_val((r).pte) >> 12) & 0xf))
 #define __rpte_to_pte(r)       ((r).pte)
index 01c12339b30444270d8f2a0be248f6860571d21f..168fce726201d3799fc3878e3a7620e1575a6dfd 100644 (file)
@@ -58,7 +58,7 @@ struct rtas_t {
        unsigned long entry;            /* physical address pointer */
        unsigned long base;             /* physical address pointer */
        unsigned long size;
-       spinlock_t lock;
+       raw_spinlock_t lock;
        struct rtas_args args;
        struct device_node *dev;        /* virtual address pointer */
 };
@@ -245,5 +245,8 @@ static inline u32 rtas_config_addr(int busno, int devfn, int reg)
                        (devfn << 8) | (reg & 0xff);
 }
 
+extern void __cpuinit rtas_give_timebase(void);
+extern void __cpuinit rtas_take_timebase(void);
+
 #endif /* __KERNEL__ */
 #endif /* _POWERPC_RTAS_H */
index 9aba5a38a7c4f32a011c6af5c3bd22e28e88d8a6..c8b329255678802bc34e27c85e84bf5338be25ea 100644 (file)
@@ -46,15 +46,13 @@ struct thread_info {
 
 /*
  * macros/functions for gaining access to the thread information structure
- *
- * preempt_count needs to be 1 initially, until the scheduler is functional.
  */
 #define INIT_THREAD_INFO(tsk)                  \
 {                                              \
        .task =         &tsk,                   \
        .exec_domain =  &default_exec_domain,   \
        .cpu =          0,                      \
-       .preempt_count = 1,                     \
+       .preempt_count = INIT_PREEMPT_COUNT,    \
        .restart_block = {                      \
                .fn = do_no_restart_syscall,    \
        },                                      \
index 4dd38f129153f7c90340cde840774dc11da22500..3cadba60a4b6c5ff88f964b32e1298e49c48b542 100644 (file)
@@ -191,11 +191,49 @@ transfer_to_handler_cont:
        mflr    r9
        lwz     r11,0(r9)               /* virtual address of handler */
        lwz     r9,4(r9)                /* where to go when done */
+#ifdef CONFIG_TRACE_IRQFLAGS
+       lis     r12,reenable_mmu@h
+       ori     r12,r12,reenable_mmu@l
+       mtspr   SPRN_SRR0,r12
+       mtspr   SPRN_SRR1,r10
+       SYNC
+       RFI
+reenable_mmu:                          /* re-enable mmu so we can */
+       mfmsr   r10
+       lwz     r12,_MSR(r1)
+       xor     r10,r10,r12
+       andi.   r10,r10,MSR_EE          /* Did EE change? */
+       beq     1f
+
+       /* Save handler and return address into the 2 unused words
+        * of the STACK_FRAME_OVERHEAD (sneak sneak sneak). Everything
+        * else can be recovered from the pt_regs except r3 which for
+        * normal interrupts has been set to pt_regs and for syscalls
+        * is an argument, so we temporarily use ORIG_GPR3 to save it
+        */
+       stw     r9,8(r1)
+       stw     r11,12(r1)
+       stw     r3,ORIG_GPR3(r1)
+       bl      trace_hardirqs_off
+       lwz     r0,GPR0(r1)
+       lwz     r3,ORIG_GPR3(r1)
+       lwz     r4,GPR4(r1)
+       lwz     r5,GPR5(r1)
+       lwz     r6,GPR6(r1)
+       lwz     r7,GPR7(r1)
+       lwz     r8,GPR8(r1)
+       lwz     r9,8(r1)
+       lwz     r11,12(r1)
+1:     mtctr   r11
+       mtlr    r9
+       bctr                            /* jump to handler */
+#else /* CONFIG_TRACE_IRQFLAGS */
        mtspr   SPRN_SRR0,r11
        mtspr   SPRN_SRR1,r10
        mtlr    r9
        SYNC
        RFI                             /* jump to handler, enable MMU */
+#endif /* CONFIG_TRACE_IRQFLAGS */
 
 #if defined (CONFIG_6xx) || defined(CONFIG_E500)
 4:     rlwinm  r12,r12,0,~_TLF_NAPPING
@@ -251,6 +289,31 @@ _GLOBAL(DoSyscall)
 #ifdef SHOW_SYSCALLS
        bl      do_show_syscall
 #endif /* SHOW_SYSCALLS */
+#ifdef CONFIG_TRACE_IRQFLAGS
+       /* Return from syscalls can (and generally will) hard enable
+        * interrupts. You aren't supposed to call a syscall with
+        * interrupts disabled in the first place. However, to ensure
+        * that we get it right vs. lockdep if it happens, we force
+        * that hard enable here with appropriate tracing if we see
+        * that we have been called with interrupts off
+        */
+       mfmsr   r11
+       andi.   r12,r11,MSR_EE
+       bne+    1f
+       /* We came in with interrupts disabled, we enable them now */
+       bl      trace_hardirqs_on
+       mfmsr   r11
+       lwz     r0,GPR0(r1)
+       lwz     r3,GPR3(r1)
+       lwz     r4,GPR4(r1)
+       ori     r11,r11,MSR_EE
+       lwz     r5,GPR5(r1)
+       lwz     r6,GPR6(r1)
+       lwz     r7,GPR7(r1)
+       lwz     r8,GPR8(r1)
+       mtmsr   r11
+1:
+#endif /* CONFIG_TRACE_IRQFLAGS */
        rlwinm  r10,r1,0,0,(31-THREAD_SHIFT)    /* current_thread_info() */
        lwz     r11,TI_FLAGS(r10)
        andi.   r11,r11,_TIF_SYSCALL_T_OR_A
@@ -275,6 +338,7 @@ ret_from_syscall:
        rlwinm  r12,r1,0,0,(31-THREAD_SHIFT)    /* current_thread_info() */
        /* disable interrupts so current_thread_info()->flags can't change */
        LOAD_MSR_KERNEL(r10,MSR_KERNEL) /* doesn't include MSR_EE */
+       /* Note: We don't bother telling lockdep about it */
        SYNC
        MTMSRD(r10)
        lwz     r9,TI_FLAGS(r12)
@@ -288,6 +352,19 @@ ret_from_syscall:
        oris    r11,r11,0x1000  /* Set SO bit in CR */
        stw     r11,_CCR(r1)
 syscall_exit_cont:
+       lwz     r8,_MSR(r1)
+#ifdef CONFIG_TRACE_IRQFLAGS
+       /* If we are going to return from the syscall with interrupts
+        * off, we trace that here. It shouldn't happen though but we
+        * want to catch the bugger if it does right ?
+        */
+       andi.   r10,r8,MSR_EE
+       bne+    1f
+       stw     r3,GPR3(r1)
+       bl      trace_hardirqs_off
+       lwz     r3,GPR3(r1)
+1:
+#endif /* CONFIG_TRACE_IRQFLAGS */
 #if defined(CONFIG_4xx) || defined(CONFIG_BOOKE)
        /* If the process has its own DBCR0 value, load it up.  The internal
           debug mode bit tells us that dbcr0 should be loaded. */
@@ -311,7 +388,6 @@ END_FTR_SECTION_IFSET(CPU_FTR_NEED_PAIRED_STWCX)
        mtlr    r4
        mtcr    r5
        lwz     r7,_NIP(r1)
-       lwz     r8,_MSR(r1)
        FIX_SRR1(r8, r0)
        lwz     r2,GPR2(r1)
        lwz     r1,GPR1(r1)
@@ -394,7 +470,9 @@ syscall_exit_work:
        andi.   r0,r9,(_TIF_SYSCALL_T_OR_A|_TIF_SINGLESTEP)
        beq     ret_from_except
 
-       /* Re-enable interrupts */
+       /* Re-enable interrupts. There is no need to trace that with
+        * lockdep as we are supposed to have IRQs on at this point
+        */
        ori     r10,r10,MSR_EE
        SYNC
        MTMSRD(r10)
@@ -705,6 +783,7 @@ ret_from_except:
        /* Hard-disable interrupts so that current_thread_info()->flags
         * can't change between when we test it and when we return
         * from the interrupt. */
+       /* Note: We don't bother telling lockdep about it */
        LOAD_MSR_KERNEL(r10,MSR_KERNEL)
        SYNC                    /* Some chip revs have problems here... */
        MTMSRD(r10)             /* disable interrupts */
@@ -744,11 +823,24 @@ resume_kernel:
        beq+    restore
        andi.   r0,r3,MSR_EE    /* interrupts off? */
        beq     restore         /* don't schedule if so */
+#ifdef CONFIG_TRACE_IRQFLAGS
+       /* Lockdep thinks irqs are enabled, we need to call
+        * preempt_schedule_irq with IRQs off, so we inform lockdep
+        * now that we -did- turn them off already
+        */
+       bl      trace_hardirqs_off
+#endif
 1:     bl      preempt_schedule_irq
        rlwinm  r9,r1,0,0,(31-THREAD_SHIFT)
        lwz     r3,TI_FLAGS(r9)
        andi.   r0,r3,_TIF_NEED_RESCHED
        bne-    1b
+#ifdef CONFIG_TRACE_IRQFLAGS
+       /* And now, to properly rebalance the above, we tell lockdep they
+        * are being turned back on, which will happen when we return
+        */
+       bl      trace_hardirqs_on
+#endif
 #else
 resume_kernel:
 #endif /* CONFIG_PREEMPT */
@@ -765,6 +857,28 @@ restore:
        stw     r6,icache_44x_need_flush@l(r4)
 1:
 #endif  /* CONFIG_44x */
+
+       lwz     r9,_MSR(r1)
+#ifdef CONFIG_TRACE_IRQFLAGS
+       /* Lockdep doesn't know about the fact that IRQs are temporarily turned
+        * off in this assembly code while peeking at TI_FLAGS() and such. However
+        * we need to inform it if the exception turned interrupts off, and we
+        * are about to trun them back on.
+        *
+        * The problem here sadly is that we don't know whether the exceptions was
+        * one that turned interrupts off or not. So we always tell lockdep about
+        * turning them on here when we go back to wherever we came from with EE
+        * on, even if that may meen some redudant calls being tracked. Maybe later
+        * we could encode what the exception did somewhere or test the exception
+        * type in the pt_regs but that sounds overkill
+        */
+       andi.   r10,r9,MSR_EE
+       beq     1f
+       bl      trace_hardirqs_on
+       lwz     r9,_MSR(r1)
+1:
+#endif /* CONFIG_TRACE_IRQFLAGS */
+
        lwz     r0,GPR0(r1)
        lwz     r2,GPR2(r1)
        REST_4GPRS(3, r1)
@@ -782,7 +896,6 @@ END_FTR_SECTION_IFSET(CPU_FTR_NEED_PAIRED_STWCX)
        stwcx.  r0,0,r1                 /* to clear the reservation */
 
 #if !(defined(CONFIG_4xx) || defined(CONFIG_BOOKE))
-       lwz     r9,_MSR(r1)
        andi.   r10,r9,MSR_RI           /* check if this exception occurred */
        beql    nonrecoverable          /* at a bad place (MSR:RI = 0) */
 
@@ -805,7 +918,6 @@ END_FTR_SECTION_IFSET(CPU_FTR_NEED_PAIRED_STWCX)
        MTMSRD(r10)             /* clear the RI bit */
        .globl exc_exit_restart
 exc_exit_restart:
-       lwz     r9,_MSR(r1)
        lwz     r12,_NIP(r1)
        FIX_SRR1(r9,r10)
        mtspr   SPRN_SRR0,r12
@@ -1035,11 +1147,18 @@ do_work:                        /* r10 contains MSR_KERNEL here */
        beq     do_user_signal
 
 do_resched:                    /* r10 contains MSR_KERNEL here */
+       /* Note: We don't need to inform lockdep that we are enabling
+        * interrupts here. As far as it knows, they are already enabled
+        */
        ori     r10,r10,MSR_EE
        SYNC
        MTMSRD(r10)             /* hard-enable interrupts */
        bl      schedule
 recheck:
+       /* Note: And we don't tell it we are disabling them again
+        * neither. Those disable/enable cycles used to peek at
+        * TI_FLAGS aren't advertised.
+        */
        LOAD_MSR_KERNEL(r10,MSR_KERNEL)
        SYNC
        MTMSRD(r10)             /* disable interrupts */
index 48469463f89e7a309e93e5d536da4ec1f0373f99..fc2132942754e06e09c5f6c169143da89b0b2761 100644 (file)
@@ -1124,9 +1124,8 @@ mmu_off:
        RFI
 
 /*
- * Use the first pair of BAT registers to map the 1st 16MB
- * of RAM to PAGE_OFFSET.  From this point on we can't safely
- * call OF any more.
+ * On 601, we use 3 BATs to map up to 24M of RAM at _PAGE_OFFSET
+ * (we keep one for debugging) and on others, we use one 256M BAT.
  */
 initial_bats:
        lis     r11,PAGE_OFFSET@h
@@ -1136,12 +1135,16 @@ initial_bats:
        bne     4f
        ori     r11,r11,4               /* set up BAT registers for 601 */
        li      r8,0x7f                 /* valid, block length = 8MB */
-       oris    r9,r11,0x800000@h       /* set up BAT reg for 2nd 8M */
-       oris    r10,r8,0x800000@h       /* set up BAT reg for 2nd 8M */
        mtspr   SPRN_IBAT0U,r11         /* N.B. 601 has valid bit in */
        mtspr   SPRN_IBAT0L,r8          /* lower BAT register */
-       mtspr   SPRN_IBAT1U,r9
-       mtspr   SPRN_IBAT1L,r10
+       addis   r11,r11,0x800000@h
+       addis   r8,r8,0x800000@h
+       mtspr   SPRN_IBAT1U,r11
+       mtspr   SPRN_IBAT1L,r8
+       addis   r11,r11,0x800000@h
+       addis   r8,r8,0x800000@h
+       mtspr   SPRN_IBAT2U,r11
+       mtspr   SPRN_IBAT2L,r8
        isync
        blr
 
index 75ff47fed7bfcadf9d69028297b09796c9e8a342..c244133c67a67bcdd1591b9049f7487e78974b22 100644 (file)
@@ -10,7 +10,6 @@
  */
 #include <linux/string.h>
 #include <linux/perf_counter.h>
-#include <linux/string.h>
 #include <asm/reg.h>
 #include <asm/cputable.h>
 
index fa983a59c4ce1084d939da4ea6fce17d91036f2a..a359cb08e9006168a60ba87b9e34df0c02256d51 100644 (file)
@@ -76,7 +76,7 @@ struct of_device *of_device_alloc(struct device_node *np,
        dev->dev.archdata.of_node = np;
 
        if (bus_id)
-               dev_set_name(&dev->dev, bus_id);
+               dev_set_name(&dev->dev, "%s", bus_id);
        else
                of_device_make_bus_id(dev);
 
index 5d755ef7ac8f21d97fbe5ef347b38c44a0f17e23..5a9f5cbd40a48e9c19c4afaae64e86a57fd5c18d 100644 (file)
@@ -358,6 +358,7 @@ static struct power_pmu power7_pmu = {
        .get_constraint         = power7_get_constraint,
        .get_alternatives       = power7_get_alternatives,
        .disable_pmc            = power7_disable_pmc,
+       .flags                  = PPMU_ALT_SIPR,
        .n_generic              = ARRAY_SIZE(power7_generic_events),
        .generic_events         = power7_generic_events,
        .cache_events           = &power7_cache_events,
index 6637c87fe70eb27812578d9c7d2f51a904f6f1b8..833097ac45dc4aad00e7e3e8d43b060efccada77 100644 (file)
@@ -10,7 +10,6 @@
  */
 #include <linux/string.h>
 #include <linux/perf_counter.h>
-#include <linux/string.h>
 #include <asm/reg.h>
 #include <asm/cputable.h>
 
index 3e7135bbe40f648c9a76c82b57fbd72a4e2aba95..892a9f2e6d76a40c44b7d67d5bff9a8912863020 100644 (file)
@@ -528,7 +528,7 @@ void show_regs(struct pt_regs * regs)
 
        for (i = 0;  i < 32;  i++) {
                if ((i % REGS_PER_LINE) == 0)
-                       printk("\n" KERN_INFO "GPR%02d: ", i);
+                       printk("\nGPR%02d: ", i);
                printk(REG " ", regs->gpr[i]);
                if (i == LAST_VOLATILE && !FULL_REGS(regs))
                        break;
index 9fa2c7dcd05a4501034395e6f587523cffb969d0..ef149880c145bf5d0ac639e87ba57c094b86bf51 100644 (file)
@@ -736,15 +736,16 @@ void user_disable_single_step(struct task_struct *task)
 {
        struct pt_regs *regs = task->thread.regs;
 
-
-#if defined(CONFIG_BOOKE)
-       /* If DAC then do not single step, skip */
-       if (task->thread.dabr)
-               return;
-#endif
-
        if (regs != NULL) {
-#if defined(CONFIG_40x) || defined(CONFIG_BOOKE)
+#if defined(CONFIG_BOOKE)
+               /* If DAC don't clear DBCRO_IDM or MSR_DE */
+               if (task->thread.dabr)
+                       task->thread.dbcr0 &= ~(DBCR0_IC | DBCR0_BT);
+               else {
+                       task->thread.dbcr0 &= ~(DBCR0_IC | DBCR0_BT | DBCR0_IDM);
+                       regs->msr &= ~MSR_DE;
+               }
+#elif defined(CONFIG_40x)
                task->thread.dbcr0 &= ~(DBCR0_IC | DBCR0_BT | DBCR0_IDM);
                regs->msr &= ~MSR_DE;
 #else
index 297632cba047e5ee980950059bee841217978631..8a6daf4129f67ffb143e762a3972a1419b30d0bd 100644 (file)
@@ -21,7 +21,6 @@
 #include <linux/sched.h>
 #include <linux/mm.h>
 #include <linux/smp.h>
-#include <linux/smp_lock.h>
 #include <linux/errno.h>
 #include <linux/ptrace.h>
 #include <linux/regset.h>
index ee4c7609b649e29222209cc666b0f28532844b51..c434823b8c83a02b9ccd161e2e22bea1c52a1c65 100644 (file)
 #include <asm/syscalls.h>
 #include <asm/smp.h>
 #include <asm/atomic.h>
+#include <asm/time.h>
 
 struct rtas_t rtas = {
-       .lock = SPIN_LOCK_UNLOCKED
+       .lock = __RAW_SPIN_LOCK_UNLOCKED
 };
 EXPORT_SYMBOL(rtas);
 
@@ -67,6 +68,28 @@ unsigned long rtas_rmo_buf;
 void (*rtas_flash_term_hook)(int);
 EXPORT_SYMBOL(rtas_flash_term_hook);
 
+/* RTAS use home made raw locking instead of spin_lock_irqsave
+ * because those can be called from within really nasty contexts
+ * such as having the timebase stopped which would lockup with
+ * normal locks and spinlock debugging enabled
+ */
+static unsigned long lock_rtas(void)
+{
+       unsigned long flags;
+
+       local_irq_save(flags);
+       preempt_disable();
+       __raw_spin_lock_flags(&rtas.lock, flags);
+       return flags;
+}
+
+static void unlock_rtas(unsigned long flags)
+{
+       __raw_spin_unlock(&rtas.lock);
+       local_irq_restore(flags);
+       preempt_enable();
+}
+
 /*
  * call_rtas_display_status and call_rtas_display_status_delay
  * are designed only for very early low-level debugging, which
@@ -79,7 +102,7 @@ static void call_rtas_display_status(char c)
 
        if (!rtas.base)
                return;
-       spin_lock_irqsave(&rtas.lock, s);
+       s = lock_rtas();
 
        args->token = 10;
        args->nargs = 1;
@@ -89,7 +112,7 @@ static void call_rtas_display_status(char c)
 
        enter_rtas(__pa(args));
 
-       spin_unlock_irqrestore(&rtas.lock, s);
+       unlock_rtas(s);
 }
 
 static void call_rtas_display_status_delay(char c)
@@ -411,8 +434,7 @@ int rtas_call(int token, int nargs, int nret, int *outputs, ...)
        if (!rtas.entry || token == RTAS_UNKNOWN_SERVICE)
                return -1;
 
-       /* Gotta do something different here, use global lock for now... */
-       spin_lock_irqsave(&rtas.lock, s);
+       s = lock_rtas();
        rtas_args = &rtas.args;
 
        rtas_args->token = token;
@@ -439,8 +461,7 @@ int rtas_call(int token, int nargs, int nret, int *outputs, ...)
                        outputs[i] = rtas_args->rets[i+1];
        ret = (nret > 0)? rtas_args->rets[0]: 0;
 
-       /* Gotta do something different here, use global lock for now... */
-       spin_unlock_irqrestore(&rtas.lock, s);
+       unlock_rtas(s);
 
        if (buff_copy) {
                log_error(buff_copy, ERR_TYPE_RTAS_LOG, 0);
@@ -837,7 +858,7 @@ asmlinkage int ppc_rtas(struct rtas_args __user *uargs)
 
        buff_copy = get_errorlog_buffer();
 
-       spin_lock_irqsave(&rtas.lock, flags);
+       flags = lock_rtas();
 
        rtas.args = args;
        enter_rtas(__pa(&rtas.args));
@@ -848,7 +869,7 @@ asmlinkage int ppc_rtas(struct rtas_args __user *uargs)
        if (args.rets[0] == -1)
                errbuf = __fetch_rtas_last_error(buff_copy);
 
-       spin_unlock_irqrestore(&rtas.lock, flags);
+       unlock_rtas(flags);
 
        if (buff_copy) {
                if (errbuf)
@@ -951,3 +972,33 @@ int __init early_init_dt_scan_rtas(unsigned long node,
        /* break now */
        return 1;
 }
+
+static raw_spinlock_t timebase_lock;
+static u64 timebase = 0;
+
+void __cpuinit rtas_give_timebase(void)
+{
+       unsigned long flags;
+
+       local_irq_save(flags);
+       hard_irq_disable();
+       __raw_spin_lock(&timebase_lock);
+       rtas_call(rtas_token("freeze-time-base"), 0, 1, NULL);
+       timebase = get_tb();
+       __raw_spin_unlock(&timebase_lock);
+
+       while (timebase)
+               barrier();
+       rtas_call(rtas_token("thaw-time-base"), 0, 1, NULL);
+       local_irq_restore(flags);
+}
+
+void __cpuinit rtas_take_timebase(void)
+{
+       while (!timebase)
+               barrier();
+       __raw_spin_lock(&timebase_lock);
+       set_tb(timebase >> 32, timebase & 0xffffffff);
+       timebase = 0;
+       __raw_spin_unlock(&timebase_lock);
+}
index 1d154248cf40e934aaf295d33e7ca466295ec91a..e1e3059cf34b9472ea06f1d71b1cc9114ee8ead2 100644 (file)
@@ -119,6 +119,8 @@ notrace unsigned long __init early_init(unsigned long dt_ptr)
  */
 notrace void __init machine_init(unsigned long dt_ptr)
 {
+       lockdep_init();
+
        /* Enable early debugging if any specified (see udbg.h) */
        udbg_early_init();
 
index 65484b2200b36add20b48dc38caf3f80971c4d29..0b47de07302d1306dcedf5dff3188a0a5514fd47 100644 (file)
@@ -68,7 +68,8 @@ EXPORT_PER_CPU_SYMBOL(cpu_core_map);
 /* SMP operations for this machine */
 struct smp_ops_t *smp_ops;
 
-static volatile unsigned int cpu_callin_map[NR_CPUS];
+/* Can't be static due to PowerMac hackery */
+volatile unsigned int cpu_callin_map[NR_CPUS];
 
 int smt_enabled_at_boot = 1;
 
index 0362a891e54ee3736707ae0b4066237fd529fadd..acb74a17bbbfa1bc2a916a872e8296bcd71aa0c1 100644 (file)
@@ -219,7 +219,7 @@ void udbg_init_pas_realmode(void)
 #ifdef CONFIG_PPC_EARLY_DEBUG_44x
 #include <platforms/44x/44x.h>
 
-static int udbg_44x_as1_flush(void)
+static void udbg_44x_as1_flush(void)
 {
        if (udbg_comport) {
                while ((as1_readb(&udbg_comport->lsr) & LSR_THRE) == 0)
index ef36cbbc5882281ccb26ca2c0b4fd14bf23a06d3..ea4d64644d029a283fe17e379d03be319d845b2e 100644 (file)
@@ -80,10 +80,10 @@ _GLOBAL(load_up_altivec)
        mtvscr  vr0
        REST_32VRS(0,r4,r5)
 #ifndef CONFIG_SMP
-       /* Update last_task_used_math to 'current' */
+       /* Update last_task_used_altivec to 'current' */
        subi    r4,r5,THREAD            /* Back to 'current' */
        fromreal(r4)
-       PPC_STL r4,ADDROFF(last_task_used_math)(r3)
+       PPC_STL r4,ADDROFF(last_task_used_altivec)(r3)
 #endif /* CONFIG_SMP */
        /* restore registers and return */
        blr
@@ -172,7 +172,7 @@ _GLOBAL(load_up_vsx)
        oris    r12,r12,MSR_VSX@h
        std     r12,_MSR(r1)
 #ifndef CONFIG_SMP
-       /* Update last_task_used_math to 'current' */
+       /* Update last_task_used_vsx to 'current' */
        ld      r4,PACACURRENT(r13)
        std     r4,0(r3)
 #endif /* CONFIG_SMP */
index 2d2192e48de73f18c2ea968962569b424a345978..3e68363405b79facfba31f3740afef46669fe039 100644 (file)
@@ -30,3 +30,4 @@ obj-$(CONFIG_PPC_MM_SLICES)   += slice.o
 obj-$(CONFIG_HUGETLB_PAGE)     += hugetlbpage.o
 obj-$(CONFIG_PPC_SUBPAGE_PROT) += subpage-prot.o
 obj-$(CONFIG_NOT_COHERENT_CACHE) += dma-noncoherent.o
+obj-$(CONFIG_HIGHMEM)          += highmem.o
index bc400c78c97fb4030b28cbd6c7b4794bba70b199..bc122a120bf009c7b6457e56936d5e9f47071dd6 100644 (file)
@@ -159,7 +159,7 @@ int get_user_pages_fast(unsigned long start, int nr_pages, int write,
        int psize;
 #endif
 
-       pr_debug("%s(%lx,%x,%s)\n", __func__, start, nr_pages, write ? "write" : "read");
+       pr_devel("%s(%lx,%x,%s)\n", __func__, start, nr_pages, write ? "write" : "read");
 
        start &= PAGE_MASK;
        addr = start;
@@ -170,7 +170,7 @@ int get_user_pages_fast(unsigned long start, int nr_pages, int write,
                                        start, len)))
                goto slow_irqon;
 
-       pr_debug("  aligned: %lx .. %lx\n", start, end);
+       pr_devel("  aligned: %lx .. %lx\n", start, end);
 
 #ifdef CONFIG_HUGETLB_PAGE
        /* We bail out on slice boundary crossing when hugetlb is
@@ -234,7 +234,7 @@ int get_user_pages_fast(unsigned long start, int nr_pages, int write,
                do {
                        VM_BUG_ON(shift != mmu_psize_defs[get_slice_psize(mm, a)].shift);
                        ptep = huge_pte_offset(mm, a);
-                       pr_debug(" %016lx: huge ptep %p\n", a, ptep);
+                       pr_devel(" %016lx: huge ptep %p\n", a, ptep);
                        if (!ptep || !gup_huge_pte(ptep, hstate, &a, end, write, pages,
                                                   &nr))
                                goto slow;
@@ -249,7 +249,7 @@ int get_user_pages_fast(unsigned long start, int nr_pages, int write,
 #ifdef CONFIG_PPC64
                        VM_BUG_ON(shift != mmu_psize_defs[get_slice_psize(mm, addr)].shift);
 #endif
-                       pr_debug("  %016lx: normal pgd %p\n", addr,
+                       pr_devel("  %016lx: normal pgd %p\n", addr,
                                 (void *)pgd_val(pgd));
                        next = pgd_addr_end(addr, end);
                        if (pgd_none(pgd))
@@ -269,7 +269,7 @@ int get_user_pages_fast(unsigned long start, int nr_pages, int write,
 slow:
                local_irq_enable();
 slow_irqon:
-               pr_debug("  slow path ! nr = %d\n", nr);
+               pr_devel("  slow path ! nr = %d\n", nr);
 
                /* Try to get the remaining pages with get_user_pages */
                start += nr << PAGE_SHIFT;
diff --git a/arch/powerpc/mm/highmem.c b/arch/powerpc/mm/highmem.c
new file mode 100644 (file)
index 0000000..c2186c7
--- /dev/null
@@ -0,0 +1,77 @@
+/*
+ * highmem.c: virtual kernel memory mappings for high memory
+ *
+ * PowerPC version, stolen from the i386 version.
+ *
+ * Used in CONFIG_HIGHMEM systems for memory pages which
+ * are not addressable by direct kernel virtual addresses.
+ *
+ * Copyright (C) 1999 Gerhard Wichert, Siemens AG
+ *                   Gerhard.Wichert@pdb.siemens.de
+ *
+ *
+ * Redesigned the x86 32-bit VM architecture to deal with
+ * up to 16 Terrabyte physical memory. With current x86 CPUs
+ * we now support up to 64 Gigabytes physical RAM.
+ *
+ * Copyright (C) 1999 Ingo Molnar <mingo@redhat.com>
+ *
+ * Reworked for PowerPC by various contributors. Moved from
+ * highmem.h by Benjamin Herrenschmidt (c) 2009 IBM Corp.
+ */
+
+#include <linux/highmem.h>
+#include <linux/module.h>
+
+/*
+ * The use of kmap_atomic/kunmap_atomic is discouraged - kmap/kunmap
+ * gives a more generic (and caching) interface. But kmap_atomic can
+ * be used in IRQ contexts, so in some (very limited) cases we need
+ * it.
+ */
+void *kmap_atomic_prot(struct page *page, enum km_type type, pgprot_t prot)
+{
+       unsigned int idx;
+       unsigned long vaddr;
+
+       /* even !CONFIG_PREEMPT needs this, for in_atomic in do_page_fault */
+       pagefault_disable();
+       if (!PageHighMem(page))
+               return page_address(page);
+
+       debug_kmap_atomic(type);
+       idx = type + KM_TYPE_NR*smp_processor_id();
+       vaddr = __fix_to_virt(FIX_KMAP_BEGIN + idx);
+#ifdef CONFIG_DEBUG_HIGHMEM
+       BUG_ON(!pte_none(*(kmap_pte-idx)));
+#endif
+       __set_pte_at(&init_mm, vaddr, kmap_pte-idx, mk_pte(page, prot), 1);
+       local_flush_tlb_page(NULL, vaddr);
+
+       return (void*) vaddr;
+}
+EXPORT_SYMBOL(kmap_atomic_prot);
+
+void kunmap_atomic(void *kvaddr, enum km_type type)
+{
+#ifdef CONFIG_DEBUG_HIGHMEM
+       unsigned long vaddr = (unsigned long) kvaddr & PAGE_MASK;
+       enum fixed_addresses idx = type + KM_TYPE_NR*smp_processor_id();
+
+       if (vaddr < __fix_to_virt(FIX_KMAP_END)) {
+               pagefault_enable();
+               return;
+       }
+
+       BUG_ON(vaddr != __fix_to_virt(FIX_KMAP_BEGIN + idx));
+
+       /*
+        * force other mappings to Oops if they'll try to access
+        * this pte without first remap it
+        */
+       pte_clear(&init_mm, vaddr, kmap_pte-idx);
+       local_flush_tlb_page(NULL, vaddr);
+#endif
+       pagefault_enable();
+}
+EXPORT_SYMBOL(kunmap_atomic);
index 8343986809c03fe2b3e952e411ec31a611fffe8b..92a197117d5b8012f57f83bb5d8fd56dcc055799 100644 (file)
@@ -89,7 +89,7 @@ static unsigned int steal_context_smp(unsigned int id)
                                id = first_context;
                        continue;
                }
-               pr_debug("[%d] steal context %d from mm @%p\n",
+               pr_devel("[%d] steal context %d from mm @%p\n",
                         smp_processor_id(), id, mm);
 
                /* Mark this mm has having no context anymore */
@@ -126,7 +126,7 @@ static unsigned int steal_context_up(unsigned int id)
        /* Pick up the victim mm */
        mm = context_mm[id];
 
-       pr_debug("[%d] steal context %d from mm @%p\n", cpu, id, mm);
+       pr_devel("[%d] steal context %d from mm @%p\n", cpu, id, mm);
 
        /* Flush the TLB for that context */
        local_flush_tlb_mm(mm);
@@ -180,7 +180,7 @@ void switch_mmu_context(struct mm_struct *prev, struct mm_struct *next)
        spin_lock(&context_lock);
 
 #ifndef DEBUG_STEAL_ONLY
-       pr_debug("[%d] activating context for mm @%p, active=%d, id=%d\n",
+       pr_devel("[%d] activating context for mm @%p, active=%d, id=%d\n",
                 cpu, next, next->context.active, next->context.id);
 #endif
 
@@ -189,7 +189,7 @@ void switch_mmu_context(struct mm_struct *prev, struct mm_struct *next)
        next->context.active++;
        if (prev) {
 #ifndef DEBUG_STEAL_ONLY
-               pr_debug(" old context %p active was: %d\n",
+               pr_devel(" old context %p active was: %d\n",
                         prev, prev->context.active);
 #endif
                WARN_ON(prev->context.active < 1);
@@ -236,7 +236,7 @@ void switch_mmu_context(struct mm_struct *prev, struct mm_struct *next)
        next->context.id = id;
 
 #ifndef DEBUG_STEAL_ONLY
-       pr_debug("[%d] picked up new id %d, nrf is now %d\n",
+       pr_devel("[%d] picked up new id %d, nrf is now %d\n",
                 cpu, id, nr_free_contexts);
 #endif
 
@@ -247,7 +247,7 @@ void switch_mmu_context(struct mm_struct *prev, struct mm_struct *next)
         * local TLB for it and unmark it before we use it
         */
        if (test_bit(id, stale_map[cpu])) {
-               pr_debug("[%d] flushing stale context %d for mm @%p !\n",
+               pr_devel("[%d] flushing stale context %d for mm @%p !\n",
                         cpu, id, next);
                local_flush_tlb_mm(next);
 
@@ -314,13 +314,13 @@ static int __cpuinit mmu_context_cpu_notify(struct notifier_block *self,
        switch (action) {
        case CPU_ONLINE:
        case CPU_ONLINE_FROZEN:
-               pr_debug("MMU: Allocating stale context map for CPU %d\n", cpu);
+               pr_devel("MMU: Allocating stale context map for CPU %d\n", cpu);
                stale_map[cpu] = kzalloc(CTX_MAP_SIZE, GFP_KERNEL);
                break;
 #ifdef CONFIG_HOTPLUG_CPU
        case CPU_DEAD:
        case CPU_DEAD_FROZEN:
-               pr_debug("MMU: Freeing stale context map for CPU %d\n", cpu);
+               pr_devel("MMU: Freeing stale context map for CPU %d\n", cpu);
                kfree(stale_map[cpu]);
                stale_map[cpu] = NULL;
                break;
index ae1d67cc090cfcdb4fd8cfd9ae390cf24c123a32..627767d6169bd4e4300528f4c37907693beea6a7 100644 (file)
@@ -129,12 +129,12 @@ static pte_t do_dcache_icache_coherency(pte_t pte)
        page = pfn_to_page(pfn);
 
        if (!PageReserved(page) && !test_bit(PG_arch_1, &page->flags)) {
-               pr_debug("do_dcache_icache_coherency... flushing\n");
+               pr_devel("do_dcache_icache_coherency... flushing\n");
                flush_dcache_icache_page(page);
                set_bit(PG_arch_1, &page->flags);
        }
        else
-               pr_debug("do_dcache_icache_coherency... already clean\n");
+               pr_devel("do_dcache_icache_coherency... already clean\n");
        return __pte(pte_val(pte) | _PAGE_HWEXEC);
 }
 
index 3b52c80e5e33866141630e1e4ddbe587f7dd519d..5b7038f248b60ea5b7b7d1e0f432a5dad5fa285e 100644 (file)
@@ -14,8 +14,6 @@
  *      2 of the License, or (at your option) any later version.
  */
 
-#undef DEBUG
-
 #include <asm/pgtable.h>
 #include <asm/mmu.h>
 #include <asm/mmu_context.h>
 #include <linux/compiler.h>
 #include <asm/udbg.h>
 
-#ifdef DEBUG
-#define DBG(fmt...) printk(fmt)
-#else
-#define DBG pr_debug
-#endif
 
 extern void slb_allocate_realmode(unsigned long ea);
 extern void slb_allocate_user(unsigned long ea);
@@ -285,13 +278,13 @@ void slb_initialize(void)
                patch_slb_encoding(slb_compare_rr_to_size,
                                   mmu_slb_size);
 
-               DBG("SLB: linear  LLP = %04lx\n", linear_llp);
-               DBG("SLB: io      LLP = %04lx\n", io_llp);
+               pr_devel("SLB: linear  LLP = %04lx\n", linear_llp);
+               pr_devel("SLB: io      LLP = %04lx\n", io_llp);
 
 #ifdef CONFIG_SPARSEMEM_VMEMMAP
                patch_slb_encoding(slb_miss_kernel_load_vmemmap,
                                   SLB_VSID_KERNEL | vmemmap_llp);
-               DBG("SLB: vmemmap LLP = %04lx\n", vmemmap_llp);
+               pr_devel("SLB: vmemmap LLP = %04lx\n", vmemmap_llp);
 #endif
        }
 
index 1be1b5e597962727bf41607684d6767b98548238..937eb90677d9ef658b4a2e7d9ebd982a9e0820f7 100644 (file)
@@ -72,7 +72,7 @@ void hpte_need_flush(struct mm_struct *mm, unsigned long addr,
         */
        if (huge) {
 #ifdef CONFIG_HUGETLB_PAGE
-               psize = get_slice_psize(mm, addr);;
+               psize = get_slice_psize(mm, addr);
 #else
                BUG();
                psize = pte_pagesize_index(mm, addr, pte); /* shutup gcc */
index 258fa4411e9e48dde2c9bfdffce352c49e3d9a21..c591339daf58aff5f5b721bc883baeea8928e44e 100644 (file)
@@ -185,7 +185,7 @@ struct vma_to_fileoffset_map *create_vma_map(const struct spu *aSpu,
                        goto fail;
 
                if (shdr_str.sh_type != SHT_STRTAB)
-                       goto fail;;
+                       goto fail;
 
                for (j = 0; j < shdr.sh_size / sizeof (sym); j++) {
                        if (copy_from_user(&sym, spu_elf_start +
index 42e09a9f77e264ecd0a87cd580a2254f1216de4c..e5c1b096c3e124186d9a4a4ae5c3f1cac8b06d06 100644 (file)
@@ -16,6 +16,7 @@
 #include <linux/interrupt.h>
 #include <linux/delay.h>
 #include <linux/of_gpio.h>
+#include <linux/of_i2c.h>
 
 #include <asm/machdep.h>
 #include <asm/prom.h>
@@ -63,9 +64,6 @@ define_machine(warp) {
 };
 
 
-static u32 post_info;
-
-/* I am not sure this is the best place for this... */
 static int __init warp_post_info(void)
 {
        struct device_node *np;
@@ -87,10 +85,9 @@ static int __init warp_post_info(void)
 
        iounmap(fpga);
 
-       if (post1 || post2) {
+       if (post1 || post2)
                printk(KERN_INFO "Warp POST %08x %08x\n", post1, post2);
-               post_info = 1;
-       } else
+       else
                printk(KERN_INFO "Warp POST OK\n");
 
        return 0;
@@ -166,6 +163,9 @@ static irqreturn_t temp_isr(int irq, void *context)
                value ^= 1;
                mdelay(500);
        }
+
+       /* Not reached */
+       return IRQ_HANDLED;
 }
 
 static int pika_setup_leds(void)
@@ -179,24 +179,19 @@ static int pika_setup_leds(void)
        }
 
        for_each_child_of_node(np, child)
-               if (strcmp(child->name, "green") == 0) {
+               if (strcmp(child->name, "green") == 0)
                        green_led = of_get_gpio(child, 0);
-                       /* Turn back on the green LED */
-                       gpio_set_value(green_led, 1);
-               } else if (strcmp(child->name, "red") == 0) {
+               else if (strcmp(child->name, "red") == 0)
                        red_led = of_get_gpio(child, 0);
-                       /* Set based on post */
-                       gpio_set_value(red_led, post_info);
-               }
 
        of_node_put(np);
 
        return 0;
 }
 
-static void pika_setup_critical_temp(struct i2c_client *client)
+static void pika_setup_critical_temp(struct device_node *np,
+                                    struct i2c_client *client)
 {
-       struct device_node *np;
        int irq, rc;
 
        /* Do this before enabling critical temp interrupt since we
@@ -208,14 +203,7 @@ static void pika_setup_critical_temp(struct i2c_client *client)
        i2c_smbus_write_byte_data(client, 2, 65); /* Thigh */
        i2c_smbus_write_byte_data(client, 3,  0); /* Tlow */
 
-       np = of_find_compatible_node(NULL, NULL, "adi,ad7414");
-       if (np == NULL) {
-               printk(KERN_ERR __FILE__ ": Unable to find ad7414\n");
-               return;
-       }
-
        irq = irq_of_parse_and_map(np, 0);
-       of_node_put(np);
        if (irq  == NO_IRQ) {
                printk(KERN_ERR __FILE__ ": Unable to get ad7414 irq\n");
                return;
@@ -244,32 +232,24 @@ static inline void pika_dtm_check_fan(void __iomem *fpga)
 
 static int pika_dtm_thread(void __iomem *fpga)
 {
-       struct i2c_adapter *adap;
+       struct device_node *np;
        struct i2c_client *client;
 
-       /* We loop in case either driver was compiled as a module and
-        * has not been insmoded yet.
-        */
-       while (!(adap = i2c_get_adapter(0))) {
-               set_current_state(TASK_INTERRUPTIBLE);
-               schedule_timeout(HZ);
-       }
-
-       while (1) {
-               list_for_each_entry(client, &adap->clients, list)
-                       if (client->addr == 0x4a)
-                               goto found_it;
+       np = of_find_compatible_node(NULL, NULL, "adi,ad7414");
+       if (np == NULL)
+               return -ENOENT;
 
-               set_current_state(TASK_INTERRUPTIBLE);
-               schedule_timeout(HZ);
+       client = of_find_i2c_device_by_node(np);
+       if (client == NULL) {
+               of_node_put(np);
+               return -ENOENT;
        }
 
-found_it:
-       pika_setup_critical_temp(client);
+       pika_setup_critical_temp(np, client);
 
-       i2c_put_adapter(adap);
+       of_node_put(np);
 
-       printk(KERN_INFO "PIKA DTM thread running.\n");
+       printk(KERN_INFO "Warp DTM thread running.\n");
 
        while (!kthread_should_stop()) {
                int val;
@@ -291,7 +271,6 @@ found_it:
        return 0;
 }
 
-
 static int __init pika_dtm_start(void)
 {
        struct task_struct *dtm_thread;
index ddf0bdc0fc8ba1a6845fb283a5330d21ab0701ce..7ee979f323d18c2da64e8597973bba0823ed1e8b 100644 (file)
@@ -147,7 +147,7 @@ int __init pq2ads_pci_init_irq(void)
                goto out;
        }
 
-       priv = alloc_bootmem(sizeof(struct pq2ads_pci_pic));
+       priv = kzalloc(sizeof(*priv), GFP_KERNEL);
        if (!priv) {
                of_node_put(np);
                ret = -ENOMEM;
index 77f90b35635681f818e448645fcfa9a174dd4e67..60ed9c067b1d5d2a5dd1fecb05761f789525e7e0 100644 (file)
@@ -285,6 +285,7 @@ static struct of_device_id mpc85xx_ids[] = {
        { .type = "qe", },
        { .compatible = "fsl,qe", },
        { .compatible = "gianfar", },
+       { .compatible = "fsl,rapidio-delta", },
        {},
 };
 
index cc0b0db8a6f31bc54f0fd8c483afcc8c67e68786..62c592ede641c4a374a7760fd67604cfc9b2f9de 100644 (file)
@@ -52,20 +52,19 @@ smp_85xx_kick_cpu(int nr)
 
        pr_debug("smp_85xx_kick_cpu: kick CPU #%d\n", nr);
 
-       local_irq_save(flags);
-
        np = of_get_cpu_node(nr, NULL);
        cpu_rel_addr = of_get_property(np, "cpu-release-addr", NULL);
 
        if (cpu_rel_addr == NULL) {
                printk(KERN_ERR "No cpu-release-addr for cpu %d\n", nr);
-               local_irq_restore(flags);
                return;
        }
 
        /* Map the spin table */
        bptr_vaddr = ioremap(*cpu_rel_addr, SIZE_BOOT_ENTRY);
 
+       local_irq_save(flags);
+
        out_be32(bptr_vaddr + BOOT_ENTRY_PIR, nr);
        out_be32(bptr_vaddr + BOOT_ENTRY_ADDR_LOWER, __pa(__early_start));
 
@@ -73,10 +72,10 @@ smp_85xx_kick_cpu(int nr)
        while ((__secondary_hold_acknowledge != nr) && (++n < 1000))
                mdelay(1);
 
-       iounmap(bptr_vaddr);
-
        local_irq_restore(flags);
 
+       iounmap(bptr_vaddr);
+
        pr_debug("waited %d msecs for CPU #%d.\n", n, nr);
 }
 
index d0e8443b12c6412d471c15ac1b7f8b66b9a319d9..747d8fb3ab82af2c5e26ddfd3e91966bb799bbc3 100644 (file)
@@ -102,10 +102,11 @@ static struct of_device_id __initdata socrates_of_bus_ids[] = {
        {},
 };
 
-static void __init socrates_init(void)
+static int __init socrates_publish_devices(void)
 {
-       of_platform_bus_probe(NULL, socrates_of_bus_ids, NULL);
+       return of_platform_bus_probe(NULL, socrates_of_bus_ids, NULL);
 }
+machine_device_initcall(socrates, socrates_publish_devices);
 
 /*
  * Called very early, device-tree isn't unflattened
@@ -124,7 +125,6 @@ define_machine(socrates) {
        .name                   = "Socrates",
        .probe                  = socrates_probe,
        .setup_arch             = socrates_setup_arch,
-       .init                   = socrates_init,
        .init_IRQ               = socrates_pic_init,
        .get_irq                = mpic_get_irq,
        .restart                = fsl_rstcr_restart,
index ee01532786e4e6fb897905e8438377e8cf5e0e92..1b426050a2f91952cb588f2a61388430e387780a 100644 (file)
@@ -32,7 +32,6 @@
 
 #include <sysdev/fsl_soc.h>
 #include <sysdev/fsl_pci.h>
-#include <linux/of_platform.h>
 
 /* A few bit definitions needed for fixups on some boards */
 #define MPC85xx_L2CTL_L2E              0x80000000 /* L2 enable */
index c71498dbf211780675293c205d258cd17350f987..aca5741ddc6777663dcc55c9a840d963b83128f7 100644 (file)
@@ -85,7 +85,7 @@ static inline void axon_msi_debug_setup(struct device_node *dn,
 
 static void msic_dcr_write(struct axon_msic *msic, unsigned int dcr_n, u32 val)
 {
-       pr_debug("axon_msi: dcr_write(0x%x, 0x%x)\n", val, dcr_n);
+       pr_devel("axon_msi: dcr_write(0x%x, 0x%x)\n", val, dcr_n);
 
        dcr_write(msic->dcr_host, dcr_n, val);
 }
@@ -98,7 +98,7 @@ static void axon_msi_cascade(unsigned int irq, struct irq_desc *desc)
        int retry = 0;
 
        write_offset = dcr_read(msic->dcr_host, MSIC_WRITE_OFFSET_REG);
-       pr_debug("axon_msi: original write_offset 0x%x\n", write_offset);
+       pr_devel("axon_msi: original write_offset 0x%x\n", write_offset);
 
        /* write_offset doesn't wrap properly, so we have to mask it */
        write_offset &= MSIC_FIFO_SIZE_MASK;
@@ -108,7 +108,7 @@ static void axon_msi_cascade(unsigned int irq, struct irq_desc *desc)
                msi  = le32_to_cpu(msic->fifo_virt[idx]);
                msi &= 0xFFFF;
 
-               pr_debug("axon_msi: woff %x roff %x msi %x\n",
+               pr_devel("axon_msi: woff %x roff %x msi %x\n",
                          write_offset, msic->read_offset, msi);
 
                if (msi < NR_IRQS && irq_map[msi].host == msic->irq_host) {
@@ -123,12 +123,12 @@ static void axon_msi_cascade(unsigned int irq, struct irq_desc *desc)
                         */
                        udelay(1);
                        retry++;
-                       pr_debug("axon_msi: invalid irq 0x%x!\n", msi);
+                       pr_devel("axon_msi: invalid irq 0x%x!\n", msi);
                        continue;
                }
 
                if (retry) {
-                       pr_debug("axon_msi: late irq 0x%x, retry %d\n",
+                       pr_devel("axon_msi: late irq 0x%x, retry %d\n",
                                 msi, retry);
                        retry = 0;
                }
@@ -332,7 +332,7 @@ static int axon_msi_shutdown(struct of_device *device)
        struct axon_msic *msic = dev_get_drvdata(&device->dev);
        u32 tmp;
 
-       pr_debug("axon_msi: disabling %s\n",
+       pr_devel("axon_msi: disabling %s\n",
                  msic->irq_host->of_node->full_name);
        tmp  = dcr_read(msic->dcr_host, MSIC_CTRL_REG);
        tmp &= ~MSIC_CTRL_ENABLE & ~MSIC_CTRL_IRQ_ENABLE;
@@ -349,7 +349,7 @@ static int axon_msi_probe(struct of_device *device,
        unsigned int virq;
        int dcr_base, dcr_len;
 
-       pr_debug("axon_msi: setting up dn %s\n", dn->full_name);
+       pr_devel("axon_msi: setting up dn %s\n", dn->full_name);
 
        msic = kzalloc(sizeof(struct axon_msic), GFP_KERNEL);
        if (!msic) {
@@ -403,7 +403,7 @@ static int axon_msi_probe(struct of_device *device,
 
        set_irq_data(virq, msic);
        set_irq_chained_handler(virq, axon_msi_cascade);
-       pr_debug("axon_msi: irq 0x%x setup for axon_msi\n", virq);
+       pr_devel("axon_msi: irq 0x%x setup for axon_msi\n", virq);
 
        /* Enable the MSIC hardware */
        msic_dcr_write(msic, MSIC_BASE_ADDR_HI_REG, msic->fifo_phys >> 32);
@@ -484,13 +484,13 @@ void axon_msi_debug_setup(struct device_node *dn, struct axon_msic *msic)
 
        addr = of_translate_address(dn, of_get_property(dn, "reg", NULL));
        if (addr == OF_BAD_ADDR) {
-               pr_debug("axon_msi: couldn't translate reg property\n");
+               pr_devel("axon_msi: couldn't translate reg property\n");
                return;
        }
 
        msic->trigger = ioremap(addr, 0x4);
        if (!msic->trigger) {
-               pr_debug("axon_msi: ioremap failed\n");
+               pr_devel("axon_msi: ioremap failed\n");
                return;
        }
 
@@ -498,7 +498,7 @@ void axon_msi_debug_setup(struct device_node *dn, struct axon_msic *msic)
 
        if (!debugfs_create_file(name, 0600, powerpc_debugfs_root,
                                 msic, &fops_msic)) {
-               pr_debug("axon_msi: debugfs_create_file failed!\n");
+               pr_devel("axon_msi: debugfs_create_file failed!\n");
                return;
        }
 }
index 9046803c827670a273c5b43d13cee1367ffa16fe..bc97fada48c664662ee59808c9f6424820d42f6a 100644 (file)
@@ -36,7 +36,6 @@
 #include <asm/prom.h>
 #include <asm/smp.h>
 #include <asm/paca.h>
-#include <asm/time.h>
 #include <asm/machdep.h>
 #include <asm/cputable.h>
 #include <asm/firmware.h>
@@ -140,31 +139,6 @@ static void __devinit smp_cell_setup_cpu(int cpu)
        mtspr(SPRN_DABRX, DABRX_KERNEL | DABRX_USER);
 }
 
-static DEFINE_SPINLOCK(timebase_lock);
-static unsigned long timebase = 0;
-
-static void __devinit cell_give_timebase(void)
-{
-       spin_lock(&timebase_lock);
-       rtas_call(rtas_token("freeze-time-base"), 0, 1, NULL);
-       timebase = get_tb();
-       spin_unlock(&timebase_lock);
-
-       while (timebase)
-               barrier();
-       rtas_call(rtas_token("thaw-time-base"), 0, 1, NULL);
-}
-
-static void __devinit cell_take_timebase(void)
-{
-       while (!timebase)
-               barrier();
-       spin_lock(&timebase_lock);
-       set_tb(timebase >> 32, timebase & 0xffffffff);
-       timebase = 0;
-       spin_unlock(&timebase_lock);
-}
-
 static void __devinit smp_cell_kick_cpu(int nr)
 {
        BUG_ON(nr < 0 || nr >= NR_CPUS);
@@ -224,8 +198,8 @@ void __init smp_init_cell(void)
 
        /* Non-lpar has additional take/give timebase */
        if (rtas_token("freeze-time-base") != RTAS_UNKNOWN_SERVICE) {
-               smp_ops->give_timebase = cell_give_timebase;
-               smp_ops->take_timebase = cell_take_timebase;
+               smp_ops->give_timebase = rtas_give_timebase;
+               smp_ops->take_timebase = rtas_take_timebase;
        }
 
        DBG(" <- smp_init_cell()\n");
index 10a4a4d063b6411b04db150f4bd00980aa67a6ee..02cafecc90e32b9562adf267dd689d742605abc3 100644 (file)
@@ -26,7 +26,6 @@
 #include <asm/io.h>
 #include <asm/prom.h>
 #include <asm/smp.h>
-#include <asm/time.h>
 #include <asm/machdep.h>
 #include <asm/mpic.h>
 #include <asm/rtas.h>
@@ -42,40 +41,12 @@ static void __devinit smp_chrp_setup_cpu(int cpu_nr)
        mpic_setup_this_cpu();
 }
 
-static DEFINE_SPINLOCK(timebase_lock);
-static unsigned int timebase_upper = 0, timebase_lower = 0;
-
-void __devinit smp_chrp_give_timebase(void)
-{
-       spin_lock(&timebase_lock);
-       rtas_call(rtas_token("freeze-time-base"), 0, 1, NULL);
-       timebase_upper = get_tbu();
-       timebase_lower = get_tbl();
-       spin_unlock(&timebase_lock);
-
-       while (timebase_upper || timebase_lower)
-               barrier();
-       rtas_call(rtas_token("thaw-time-base"), 0, 1, NULL);
-}
-
-void __devinit smp_chrp_take_timebase(void)
-{
-       while (!(timebase_upper || timebase_lower))
-               barrier();
-       spin_lock(&timebase_lock);
-       set_tb(timebase_upper, timebase_lower);
-       timebase_upper = 0;
-       timebase_lower = 0;
-       spin_unlock(&timebase_lock);
-       printk("CPU %i taken timebase\n", smp_processor_id());
-}
-
 /* CHRP with openpic */
 struct smp_ops_t chrp_smp_ops = {
        .message_pass = smp_mpic_message_pass,
        .probe = smp_mpic_probe,
        .kick_cpu = smp_chrp_kick_cpu,
        .setup_cpu = smp_chrp_setup_cpu,
-       .give_timebase = smp_chrp_give_timebase,
-       .take_timebase = smp_chrp_take_timebase,
+       .give_timebase = rtas_give_timebase,
+       .take_timebase = rtas_take_timebase,
 };
index 153051eb6d9330643e0c3924273a3e6d04a8921f..a4619347aa7e61a702e7a7f6c584080a31d5f4fb 100644 (file)
@@ -71,20 +71,25 @@ static void pas_restart(char *cmd)
 }
 
 #ifdef CONFIG_SMP
-static DEFINE_SPINLOCK(timebase_lock);
+static raw_spinlock_t timebase_lock;
 static unsigned long timebase;
 
 static void __devinit pas_give_timebase(void)
 {
-       spin_lock(&timebase_lock);
+       unsigned long flags;
+
+       local_irq_save(flags);
+       hard_irq_disable();
+       __raw_spin_lock(&timebase_lock);
        mtspr(SPRN_TBCTL, TBCTL_FREEZE);
        isync();
        timebase = get_tb();
-       spin_unlock(&timebase_lock);
+       __raw_spin_unlock(&timebase_lock);
 
        while (timebase)
                barrier();
        mtspr(SPRN_TBCTL, TBCTL_RESTART);
+       local_irq_restore(flags);
 }
 
 static void __devinit pas_take_timebase(void)
@@ -92,10 +97,10 @@ static void __devinit pas_take_timebase(void)
        while (!timebase)
                smp_rmb();
 
-       spin_lock(&timebase_lock);
+       __raw_spin_lock(&timebase_lock);
        set_tb(timebase >> 32, timebase & 0xffffffff);
        timebase = 0;
-       spin_unlock(&timebase_lock);
+       __raw_spin_unlock(&timebase_lock);
 }
 
 struct smp_ops_t pas_smp_ops = {
index 22ecfbe7183dec52e8f907a4ef9a8b23fdfe6a71..708c751333770b216009d1d4d112a0b0a74c08d1 100644 (file)
@@ -251,7 +251,7 @@ static void g5_pfunc_switch_volt(int speed_mode)
 static struct pmf_function *pfunc_cpu_setfreq_high;
 static struct pmf_function *pfunc_cpu_setfreq_low;
 static struct pmf_function *pfunc_cpu_getfreq;
-static struct pmf_function *pfunc_slewing_done;;
+static struct pmf_function *pfunc_slewing_done;
 
 static int g5_pfunc_switch_freq(int speed_mode)
 {
index dce736349107b3b7aa427956a610250c43709458..d212006a5b3c0d4ca5213acdf1d02e0939add083 100644 (file)
@@ -609,7 +609,7 @@ static int pmacpic_find_viaint(void)
        np = of_find_node_by_name(NULL, "via-pmu");
        if (np == NULL)
                goto not_found;
-       viaint = irq_of_parse_and_map(np, 0);;
+       viaint = irq_of_parse_and_map(np, 0);
 
 not_found:
 #endif /* CONFIG_ADB_PMU */
index 86f69a4eb49bfc669012b2681500fd5f0c29e981..c20522656367c9ecbb02f91c86fcab197f080617 100644 (file)
@@ -103,11 +103,6 @@ unsigned long smu_cmdbuf_abs;
 EXPORT_SYMBOL(smu_cmdbuf_abs);
 #endif
 
-#ifdef CONFIG_SMP
-extern struct smp_ops_t psurge_smp_ops;
-extern struct smp_ops_t core99_smp_ops;
-#endif /* CONFIG_SMP */
-
 static void pmac_show_cpuinfo(struct seq_file *m)
 {
        struct device_node *np;
@@ -341,34 +336,6 @@ static void __init pmac_setup_arch(void)
                ROOT_DEV = DEFAULT_ROOT_DEVICE;
 #endif
 
-#ifdef CONFIG_SMP
-       /* Check for Core99 */
-       ic = of_find_node_by_name(NULL, "uni-n");
-       if (!ic)
-               ic = of_find_node_by_name(NULL, "u3");
-       if (!ic)
-               ic = of_find_node_by_name(NULL, "u4");
-       if (ic) {
-               of_node_put(ic);
-               smp_ops = &core99_smp_ops;
-       }
-#ifdef CONFIG_PPC32
-       else {
-               /*
-                * We have to set bits in cpu_possible_map here since the
-                * secondary CPU(s) aren't in the device tree, and
-                * setup_per_cpu_areas only allocates per-cpu data for
-                * CPUs in the cpu_possible_map.
-                */
-               int cpu;
-
-               for (cpu = 1; cpu < 4 && cpu < NR_CPUS; ++cpu)
-                       cpu_set(cpu, cpu_possible_map);
-               smp_ops = &psurge_smp_ops;
-       }
-#endif
-#endif /* CONFIG_SMP */
-
 #ifdef CONFIG_ADB
        if (strstr(cmd_line, "adb_sync")) {
                extern int __adb_probe_sync;
@@ -512,6 +479,14 @@ static void __init pmac_init_early(void)
 #ifdef CONFIG_PPC64
        iommu_init_early_dart();
 #endif
+
+       /* SMP Init has to be done early as we need to patch up
+        * cpu_possible_map before interrupt stacks are allocated
+        * or kaboom...
+        */
+#ifdef CONFIG_SMP
+       pmac_setup_smp();
+#endif
 }
 
 static int __init pmac_declare_of_platform_devices(void)
index cf1dbe758890df60d441cfbd79421db63e40834f..6d4da7b46b419a751891e74b02554d6b7e0a89e1 100644 (file)
 extern void __secondary_start_pmac_0(void);
 extern int pmac_pfunc_base_install(void);
 
-#ifdef CONFIG_PPC32
+static void (*pmac_tb_freeze)(int freeze);
+static u64 timebase;
+static int tb_req;
 
-/* Sync flag for HW tb sync */
-static volatile int sec_tb_reset = 0;
+#ifdef CONFIG_PPC32
 
 /*
  * Powersurge (old powermac SMP) support.
@@ -294,6 +295,9 @@ static int __init smp_psurge_probe(void)
                psurge_quad_init();
                /* All released cards using this HW design have 4 CPUs */
                ncpus = 4;
+               /* No sure how timebase sync works on those, let's use SW */
+               smp_ops->give_timebase = smp_generic_give_timebase;
+               smp_ops->take_timebase = smp_generic_take_timebase;
        } else {
                iounmap(quad_base);
                if ((in_8(hhead_base + HHEAD_CONFIG) & 0x02) == 0) {
@@ -308,18 +312,15 @@ static int __init smp_psurge_probe(void)
        psurge_start = ioremap(PSURGE_START, 4);
        psurge_pri_intr = ioremap(PSURGE_PRI_INTR, 4);
 
-       /*
-        * This is necessary because OF doesn't know about the
+       /* This is necessary because OF doesn't know about the
         * secondary cpu(s), and thus there aren't nodes in the
         * device tree for them, and smp_setup_cpu_maps hasn't
-        * set their bits in cpu_possible_map and cpu_present_map.
+        * set their bits in cpu_present_map.
         */
        if (ncpus > NR_CPUS)
                ncpus = NR_CPUS;
-       for (i = 1; i < ncpus ; ++i) {
+       for (i = 1; i < ncpus ; ++i)
                cpu_set(i, cpu_present_map);
-               set_hard_smp_processor_id(i, i);
-       }
 
        if (ppc_md.progress) ppc_md.progress("smp_psurge_probe - done", 0x352);
 
@@ -329,8 +330,14 @@ static int __init smp_psurge_probe(void)
 static void __init smp_psurge_kick_cpu(int nr)
 {
        unsigned long start = __pa(__secondary_start_pmac_0) + nr * 8;
-       unsigned long a;
-       int i;
+       unsigned long a, flags;
+       int i, j;
+
+       /* Defining this here is evil ... but I prefer hiding that
+        * crap to avoid giving people ideas that they can do the
+        * same.
+        */
+       extern volatile unsigned int cpu_callin_map[NR_CPUS];
 
        /* may need to flush here if secondary bats aren't setup */
        for (a = KERNELBASE; a < KERNELBASE + 0x800000; a += 32)
@@ -339,47 +346,52 @@ static void __init smp_psurge_kick_cpu(int nr)
 
        if (ppc_md.progress) ppc_md.progress("smp_psurge_kick_cpu", 0x353);
 
+       /* This is going to freeze the timeebase, we disable interrupts */
+       local_irq_save(flags);
+
        out_be32(psurge_start, start);
        mb();
 
        psurge_set_ipi(nr);
+
        /*
         * We can't use udelay here because the timebase is now frozen.
         */
        for (i = 0; i < 2000; ++i)
-               barrier();
+               asm volatile("nop" : : : "memory");
        psurge_clr_ipi(nr);
 
-       if (ppc_md.progress) ppc_md.progress("smp_psurge_kick_cpu - done", 0x354);
-}
-
-/*
- * With the dual-cpu powersurge board, the decrementers and timebases
- * of both cpus are frozen after the secondary cpu is started up,
- * until we give the secondary cpu another interrupt.  This routine
- * uses this to get the timebases synchronized.
- *  -- paulus.
- */
-static void __init psurge_dual_sync_tb(int cpu_nr)
-{
-       int t;
-
-       set_dec(tb_ticks_per_jiffy);
-       /* XXX fixme */
-       set_tb(0, 0);
-
-       if (cpu_nr > 0) {
+       /*
+        * Also, because the timebase is frozen, we must not return to the
+        * caller which will try to do udelay's etc... Instead, we wait -here-
+        * for the CPU to callin.
+        */
+       for (i = 0; i < 100000 && !cpu_callin_map[nr]; ++i) {
+               for (j = 1; j < 10000; j++)
+                       asm volatile("nop" : : : "memory");
+               asm volatile("sync" : : : "memory");
+       }
+       if (!cpu_callin_map[nr])
+               goto stuck;
+
+       /* And we do the TB sync here too for standard dual CPU cards */
+       if (psurge_type == PSURGE_DUAL) {
+               while(!tb_req)
+                       barrier();
+               tb_req = 0;
+               mb();
+               timebase = get_tb();
+               mb();
+               while (timebase)
+                       barrier();
                mb();
-               sec_tb_reset = 1;
-               return;
        }
+ stuck:
+       /* now interrupt the secondary, restarting both TBs */
+       if (psurge_type == PSURGE_DUAL)
+               psurge_set_ipi(1);
 
-       /* wait for the secondary to have reset its TB before proceeding */
-       for (t = 10000000; t > 0 && !sec_tb_reset; --t)
-               ;
-
-       /* now interrupt the secondary, starting both TBs */
-       psurge_set_ipi(1);
+       if (ppc_md.progress) ppc_md.progress("smp_psurge_kick_cpu - done", 0x354);
 }
 
 static struct irqaction psurge_irqaction = {
@@ -390,36 +402,35 @@ static struct irqaction psurge_irqaction = {
 
 static void __init smp_psurge_setup_cpu(int cpu_nr)
 {
+       if (cpu_nr != 0)
+               return;
 
-       if (cpu_nr == 0) {
-               /* If we failed to start the second CPU, we should still
-                * send it an IPI to start the timebase & DEC or we might
-                * have them stuck.
-                */
-               if (num_online_cpus() < 2) {
-                       if (psurge_type == PSURGE_DUAL)
-                               psurge_set_ipi(1);
-                       return;
-               }
-               /* reset the entry point so if we get another intr we won't
-                * try to startup again */
-               out_be32(psurge_start, 0x100);
-               if (setup_irq(30, &psurge_irqaction))
-                       printk(KERN_ERR "Couldn't get primary IPI interrupt");
-       }
-
-       if (psurge_type == PSURGE_DUAL)
-               psurge_dual_sync_tb(cpu_nr);
+       /* reset the entry point so if we get another intr we won't
+        * try to startup again */
+       out_be32(psurge_start, 0x100);
+       if (setup_irq(30, &psurge_irqaction))
+               printk(KERN_ERR "Couldn't get primary IPI interrupt");
 }
 
 void __init smp_psurge_take_timebase(void)
 {
-       /* Dummy implementation */
+       if (psurge_type != PSURGE_DUAL)
+               return;
+
+       tb_req = 1;
+       mb();
+       while (!timebase)
+               barrier();
+       mb();
+       set_tb(timebase >> 32, timebase & 0xffffffff);
+       timebase = 0;
+       mb();
+       set_dec(tb_ticks_per_jiffy/2);
 }
 
 void __init smp_psurge_give_timebase(void)
 {
-       /* Dummy implementation */
+       /* Nothing to do here */
 }
 
 /* PowerSurge-style Macs */
@@ -437,9 +448,6 @@ struct smp_ops_t psurge_smp_ops = {
  * Core 99 and later support
  */
 
-static void (*pmac_tb_freeze)(int freeze);
-static u64 timebase;
-static int tb_req;
 
 static void smp_core99_give_timebase(void)
 {
@@ -478,7 +486,6 @@ static void __devinit smp_core99_take_timebase(void)
        set_tb(timebase >> 32, timebase & 0xffffffff);
        timebase = 0;
        mb();
-       set_dec(tb_ticks_per_jiffy/2);
 
        local_irq_restore(flags);
 }
@@ -920,3 +927,34 @@ struct smp_ops_t core99_smp_ops = {
 # endif
 #endif
 };
+
+void __init pmac_setup_smp(void)
+{
+       struct device_node *np;
+
+       /* Check for Core99 */
+       np = of_find_node_by_name(NULL, "uni-n");
+       if (!np)
+               np = of_find_node_by_name(NULL, "u3");
+       if (!np)
+               np = of_find_node_by_name(NULL, "u4");
+       if (np) {
+               of_node_put(np);
+               smp_ops = &core99_smp_ops;
+       }
+#ifdef CONFIG_PPC32
+       else {
+               /* We have to set bits in cpu_possible_map here since the
+                * secondary CPU(s) aren't in the device tree. Various
+                * things won't be initialized for CPUs not in the possible
+                * map, so we really need to fix it up here.
+                */
+               int cpu;
+
+               for (cpu = 1; cpu < 4 && cpu < NR_CPUS; ++cpu)
+                       cpu_set(cpu, cpu_possible_map);
+               smp_ops = &psurge_smp_ops;
+       }
+#endif /* CONFIG_PPC32 */
+}
+
index 9fead0faf38bbd5930fe0dd0f75fcc1f2711c296..3f763c5284acc2e682f0f9a3832159565bf3598b 100644 (file)
@@ -284,7 +284,6 @@ static int ps3_sb_free_mmio_region(struct ps3_mmio_region *r)
        int result;
 
        dump_mmio_region(r);
-;
        result = lv1_unmap_device_mmio_region(r->dev->bus_id, r->dev->dev_id,
                r->lpar_addr);
 
index e3139fa5e556e78ddcdeacc4e4850b7aeeba6ed4..903eb9eec687471628c37e30026ae6aad5c35548 100644 (file)
@@ -286,7 +286,7 @@ static long pSeries_lpar_hpte_insert(unsigned long hpte_group,
        unsigned long hpte_v, hpte_r;
 
        if (!(vflags & HPTE_V_BOLTED))
-               pr_debug("hpte_insert(group=%lx, va=%016lx, pa=%016lx, "
+               pr_devel("hpte_insert(group=%lx, va=%016lx, pa=%016lx, "
                         "rflags=%lx, vflags=%lx, psize=%d)\n",
                         hpte_group, va, pa, rflags, vflags, psize);
 
@@ -294,7 +294,7 @@ static long pSeries_lpar_hpte_insert(unsigned long hpte_group,
        hpte_r = hpte_encode_r(pa, psize) | rflags;
 
        if (!(vflags & HPTE_V_BOLTED))
-               pr_debug(" hpte_v=%016lx, hpte_r=%016lx\n", hpte_v, hpte_r);
+               pr_devel(" hpte_v=%016lx, hpte_r=%016lx\n", hpte_v, hpte_r);
 
        /* Now fill in the actual HPTE */
        /* Set CEC cookie to 0         */
@@ -311,7 +311,7 @@ static long pSeries_lpar_hpte_insert(unsigned long hpte_group,
        lpar_rc = plpar_pte_enter(flags, hpte_group, hpte_v, hpte_r, &slot);
        if (unlikely(lpar_rc == H_PTEG_FULL)) {
                if (!(vflags & HPTE_V_BOLTED))
-                       pr_debug(" full\n");
+                       pr_devel(" full\n");
                return -1;
        }
 
@@ -322,11 +322,11 @@ static long pSeries_lpar_hpte_insert(unsigned long hpte_group,
         */
        if (unlikely(lpar_rc != H_SUCCESS)) {
                if (!(vflags & HPTE_V_BOLTED))
-                       pr_debug(" lpar err %lu\n", lpar_rc);
+                       pr_devel(" lpar err %lu\n", lpar_rc);
                return -2;
        }
        if (!(vflags & HPTE_V_BOLTED))
-               pr_debug(" -> slot: %lu\n", slot & 7);
+               pr_devel(" -> slot: %lu\n", slot & 7);
 
        /* Because of iSeries, we have to pass down the secondary
         * bucket bit here as well
@@ -418,17 +418,17 @@ static long pSeries_lpar_hpte_updatepp(unsigned long slot,
 
        want_v = hpte_encode_avpn(va, psize, ssize);
 
-       pr_debug("    update: avpnv=%016lx, hash=%016lx, f=%lx, psize: %d ...",
+       pr_devel("    update: avpnv=%016lx, hash=%016lx, f=%lx, psize: %d ...",
                 want_v, slot, flags, psize);
 
        lpar_rc = plpar_pte_protect(flags, slot, want_v);
 
        if (lpar_rc == H_NOT_FOUND) {
-               pr_debug("not found !\n");
+               pr_devel("not found !\n");
                return -1;
        }
 
-       pr_debug("ok\n");
+       pr_devel("ok\n");
 
        BUG_ON(lpar_rc != H_SUCCESS);
 
@@ -503,7 +503,7 @@ static void pSeries_lpar_hpte_invalidate(unsigned long slot, unsigned long va,
        unsigned long lpar_rc;
        unsigned long dummy1, dummy2;
 
-       pr_debug("    inval : slot=%lx, va=%016lx, psize: %d, local: %d\n",
+       pr_devel("    inval : slot=%lx, va=%016lx, psize: %d, local: %d\n",
                 slot, va, psize, local);
 
        want_v = hpte_encode_avpn(va, psize, ssize);
index 1a231c389ba0122ce7f55419962af8a1bbdab25f..1f8f6cfb94f7f504b4f44f025fc02b600b392000 100644 (file)
@@ -35,7 +35,6 @@
 #include <asm/prom.h>
 #include <asm/smp.h>
 #include <asm/paca.h>
-#include <asm/time.h>
 #include <asm/machdep.h>
 #include <asm/cputable.h>
 #include <asm/firmware.h>
@@ -118,31 +117,6 @@ static void __devinit smp_xics_setup_cpu(int cpu)
 }
 #endif /* CONFIG_XICS */
 
-static DEFINE_SPINLOCK(timebase_lock);
-static unsigned long timebase = 0;
-
-static void __devinit pSeries_give_timebase(void)
-{
-       spin_lock(&timebase_lock);
-       rtas_call(rtas_token("freeze-time-base"), 0, 1, NULL);
-       timebase = get_tb();
-       spin_unlock(&timebase_lock);
-
-       while (timebase)
-               barrier();
-       rtas_call(rtas_token("thaw-time-base"), 0, 1, NULL);
-}
-
-static void __devinit pSeries_take_timebase(void)
-{
-       while (!timebase)
-               barrier();
-       spin_lock(&timebase_lock);
-       set_tb(timebase >> 32, timebase & 0xffffffff);
-       timebase = 0;
-       spin_unlock(&timebase_lock);
-}
-
 static void __devinit smp_pSeries_kick_cpu(int nr)
 {
        BUG_ON(nr < 0 || nr >= NR_CPUS);
@@ -209,8 +183,8 @@ static void __init smp_init_pseries(void)
 
        /* Non-lpar has additional take/give timebase */
        if (rtas_token("freeze-time-base") != RTAS_UNKNOWN_SERVICE) {
-               smp_ops->give_timebase = pSeries_give_timebase;
-               smp_ops->take_timebase = pSeries_take_timebase;
+               smp_ops->give_timebase = rtas_give_timebase;
+               smp_ops->take_timebase = rtas_take_timebase;
        }
 
        pr_debug(" <- smp_init_pSeries()\n");
index be3581a8c294c8de4d083b1b2c5710381a35c2d9..419f8a637ffe5b73db8c69080e118c2fdab00444 100644 (file)
@@ -190,10 +190,10 @@ static void xics_unmask_irq(unsigned int virq)
        int call_status;
        int server;
 
-       pr_debug("xics: unmask virq %d\n", virq);
+       pr_devel("xics: unmask virq %d\n", virq);
 
        irq = (unsigned int)irq_map[virq].hwirq;
-       pr_debug(" -> map to hwirq 0x%x\n", irq);
+       pr_devel(" -> map to hwirq 0x%x\n", irq);
        if (irq == XICS_IPI || irq == XICS_IRQ_SPURIOUS)
                return;
 
@@ -252,7 +252,7 @@ static void xics_mask_irq(unsigned int virq)
 {
        unsigned int irq;
 
-       pr_debug("xics: mask virq %d\n", virq);
+       pr_devel("xics: mask virq %d\n", virq);
 
        irq = (unsigned int)irq_map[virq].hwirq;
        if (irq == XICS_IPI || irq == XICS_IRQ_SPURIOUS)
@@ -414,7 +414,7 @@ static int xics_host_match(struct irq_host *h, struct device_node *node)
 static int xics_host_map(struct irq_host *h, unsigned int virq,
                         irq_hw_number_t hw)
 {
-       pr_debug("xics: map virq %d, hwirq 0x%lx\n", virq, hw);
+       pr_devel("xics: map virq %d, hwirq 0x%lx\n", virq, hw);
 
        /* Insert the interrupt mapping into the radix tree for fast lookup */
        irq_radix_revmap_insert(xics_host, virq, hw);
index 39db9d1155d27466ffe176887c7d9b2c320f288f..cbb3bed75d3c0c56a218e1a2678702d6ca0bcfd7 100644 (file)
@@ -965,7 +965,7 @@ static inline void fsl_rio_info(struct device *dev, u32 ccsr)
                        break;
                default:
                        str = "Unknown";
-                       break;;
+                       break;
                }
                dev_info(dev, "Hardware port width: %s\n", str);
 
index a86d3ce01ead98293dcb0e28a14bf943163b40a2..69e2630c90624cf40690d0ecfd7643a75e1d4bf5 100644 (file)
@@ -728,12 +728,10 @@ struct ipic * __init ipic_init(struct device_node *node, unsigned int flags)
        if (ret)
                return NULL;
 
-       ipic = alloc_bootmem(sizeof(struct ipic));
+       ipic = kzalloc(sizeof(*ipic), GFP_KERNEL);
        if (ipic == NULL)
                return NULL;
 
-       memset(ipic, 0, sizeof(struct ipic));
-
        ipic->irqhost = irq_alloc_host(node, IRQ_HOST_MAP_LINEAR,
                                       NR_IPIC_INTS,
                                       &ipic_host_ops, 0);
index 9c3af5045495bb67c0259998a39dd641c65e47ea..3981ae4cb58e7f3f41fb7ffa25e9a4757bed3d6f 100644 (file)
@@ -279,28 +279,29 @@ static void _mpic_map_mmio(struct mpic *mpic, phys_addr_t phys_addr,
 }
 
 #ifdef CONFIG_PPC_DCR
-static void _mpic_map_dcr(struct mpic *mpic, struct mpic_reg_bank *rb,
+static void _mpic_map_dcr(struct mpic *mpic, struct device_node *node,
+                         struct mpic_reg_bank *rb,
                          unsigned int offset, unsigned int size)
 {
        const u32 *dbasep;
 
-       dbasep = of_get_property(mpic->irqhost->of_node, "dcr-reg", NULL);
+       dbasep = of_get_property(node, "dcr-reg", NULL);
 
-       rb->dhost = dcr_map(mpic->irqhost->of_node, *dbasep + offset, size);
+       rb->dhost = dcr_map(node, *dbasep + offset, size);
        BUG_ON(!DCR_MAP_OK(rb->dhost));
 }
 
-static inline void mpic_map(struct mpic *mpic, phys_addr_t phys_addr,
-                           struct mpic_reg_bank *rb, unsigned int offset,
-                           unsigned int size)
+static inline void mpic_map(struct mpic *mpic, struct device_node *node,
+                           phys_addr_t phys_addr, struct mpic_reg_bank *rb,
+                           unsigned int offset, unsigned int size)
 {
        if (mpic->flags & MPIC_USES_DCR)
-               _mpic_map_dcr(mpic, rb, offset, size);
+               _mpic_map_dcr(mpic, node, rb, offset, size);
        else
                _mpic_map_mmio(mpic, phys_addr, rb, offset, size);
 }
 #else /* CONFIG_PPC_DCR */
-#define mpic_map(m,p,b,o,s)    _mpic_map_mmio(m,p,b,o,s)
+#define mpic_map(m,n,p,b,o,s)  _mpic_map_mmio(m,p,b,o,s)
 #endif /* !CONFIG_PPC_DCR */
 
 
@@ -507,9 +508,8 @@ static void __init mpic_scan_ht_pics(struct mpic *mpic)
        printk(KERN_INFO "mpic: Setting up HT PICs workarounds for U3/U4\n");
 
        /* Allocate fixups array */
-       mpic->fixups = alloc_bootmem(128 * sizeof(struct mpic_irq_fixup));
+       mpic->fixups = kzalloc(128 * sizeof(*mpic->fixups), GFP_KERNEL);
        BUG_ON(mpic->fixups == NULL);
-       memset(mpic->fixups, 0, 128 * sizeof(struct mpic_irq_fixup));
 
        /* Init spinlock */
        spin_lock_init(&mpic->fixup_lock);
@@ -1052,11 +1052,10 @@ struct mpic * __init mpic_alloc(struct device_node *node,
        int             intvec_top;
        u64             paddr = phys_addr;
 
-       mpic = alloc_bootmem(sizeof(struct mpic));
+       mpic = kzalloc(sizeof(struct mpic), GFP_KERNEL);
        if (mpic == NULL)
                return NULL;
-       
-       memset(mpic, 0, sizeof(struct mpic));
+
        mpic->name = name;
 
        mpic->hc_irq = mpic_irq_chip;
@@ -1109,9 +1108,8 @@ struct mpic * __init mpic_alloc(struct device_node *node,
                        psize /= 4;
                        bits = intvec_top + 1;
                        mapsize = BITS_TO_LONGS(bits) * sizeof(unsigned long);
-                       mpic->protected = alloc_bootmem(mapsize);
+                       mpic->protected = kzalloc(mapsize, GFP_KERNEL);
                        BUG_ON(mpic->protected == NULL);
-                       memset(mpic->protected, 0, mapsize);
                        for (i = 0; i < psize; i++) {
                                if (psrc[i] > intvec_top)
                                        continue;
@@ -1152,8 +1150,8 @@ struct mpic * __init mpic_alloc(struct device_node *node,
        }
 
        /* Map the global registers */
-       mpic_map(mpic, paddr, &mpic->gregs, MPIC_INFO(GREG_BASE), 0x1000);
-       mpic_map(mpic, paddr, &mpic->tmregs, MPIC_INFO(TIMER_BASE), 0x1000);
+       mpic_map(mpic, node, paddr, &mpic->gregs, MPIC_INFO(GREG_BASE), 0x1000);
+       mpic_map(mpic, node, paddr, &mpic->tmregs, MPIC_INFO(TIMER_BASE), 0x1000);
 
        /* Reset */
        if (flags & MPIC_WANTS_RESET) {
@@ -1194,7 +1192,7 @@ struct mpic * __init mpic_alloc(struct device_node *node,
 
        /* Map the per-CPU registers */
        for (i = 0; i < mpic->num_cpus; i++) {
-               mpic_map(mpic, paddr, &mpic->cpuregs[i],
+               mpic_map(mpic, node, paddr, &mpic->cpuregs[i],
                         MPIC_INFO(CPU_BASE) + i * MPIC_INFO(CPU_STRIDE),
                         0x1000);
        }
@@ -1202,7 +1200,7 @@ struct mpic * __init mpic_alloc(struct device_node *node,
        /* Initialize main ISU if none provided */
        if (mpic->isu_size == 0) {
                mpic->isu_size = mpic->num_sources;
-               mpic_map(mpic, paddr, &mpic->isus[0],
+               mpic_map(mpic, node, paddr, &mpic->isus[0],
                         MPIC_INFO(IRQ_BASE), MPIC_INFO(IRQ_STRIDE) * mpic->isu_size);
        }
        mpic->isu_shift = 1 + __ilog2(mpic->isu_size - 1);
@@ -1256,8 +1254,10 @@ void __init mpic_assign_isu(struct mpic *mpic, unsigned int isu_num,
 
        BUG_ON(isu_num >= MPIC_MAX_ISU);
 
-       mpic_map(mpic, paddr, &mpic->isus[isu_num], 0,
+       mpic_map(mpic, mpic->irqhost->of_node,
+                paddr, &mpic->isus[isu_num], 0,
                 MPIC_INFO(IRQ_STRIDE) * mpic->isu_size);
+
        if ((isu_first + mpic->isu_size) > mpic->num_sources)
                mpic->num_sources = isu_first + mpic->isu_size;
 }
@@ -1351,7 +1351,8 @@ void __init mpic_init(struct mpic *mpic)
 
 #ifdef CONFIG_PM
        /* allocate memory to save mpic state */
-       mpic->save_data = alloc_bootmem(mpic->num_sources * sizeof(struct mpic_irq_save));
+       mpic->save_data = kmalloc(mpic->num_sources * sizeof(*mpic->save_data),
+                                 GFP_KERNEL);
        BUG_ON(mpic->save_data == NULL);
 #endif
 }
index daefc93ddffec42eb4e15ccfb218e127ccee4032..6ff9d71b4c0d877e99aedef1fd9d3820bd424a3d 100644 (file)
@@ -1531,7 +1531,7 @@ static void __init ppc4xx_configure_pciex_PIMs(struct ppc4xx_pciex_port *port,
                 */
 
                /* Calculate window size */
-               sa = (0xffffffffffffffffull << ilog2(ep_size));;
+               sa = (0xffffffffffffffffull << ilog2(ep_size));
 
                /* Setup BAR0 */
                out_le32(mbase + PECFG_BAR0HMPA, RES_TO_U32_HIGH(sa));
@@ -1550,7 +1550,7 @@ static void __init ppc4xx_configure_pciex_PIMs(struct ppc4xx_pciex_port *port,
                out_le32(mbase + PCI_BASE_ADDRESS_1, RES_TO_U32_HIGH(ep_addr));
        } else {
                /* Calculate window size */
-               sa = (0xffffffffffffffffull << ilog2(size));;
+               sa = (0xffffffffffffffffull << ilog2(size));
                if (res->flags & IORESOURCE_PREFETCH)
                        sa |= 0x8;
 
index b28b0e512d67d91a2c1fb108f94cc9eea90e4b03..237e3654f48ca6b1059c7d2017ccd31544b215e2 100644 (file)
@@ -112,6 +112,7 @@ int qe_issue_cmd(u32 cmd, u32 device, u8 mcn_protocol, u32 cmd_input)
 {
        unsigned long flags;
        u8 mcn_shift = 0, dev_shift = 0;
+       u32 ret;
 
        spin_lock_irqsave(&qe_lock, flags);
        if (cmd == QE_RESET) {
@@ -139,11 +140,13 @@ int qe_issue_cmd(u32 cmd, u32 device, u8 mcn_protocol, u32 cmd_input)
        }
 
        /* wait for the QE_CR_FLG to clear */
-       while(in_be32(&qe_immr->cp.cecr) & QE_CR_FLG)
-               cpu_relax();
+       ret = spin_event_timeout((in_be32(&qe_immr->cp.cecr) & QE_CR_FLG) == 0,
+                          100, 0);
+       /* On timeout (e.g. failure), the expression will be false (ret == 0),
+          otherwise it will be true (ret == 1). */
        spin_unlock_irqrestore(&qe_lock, flags);
 
-       return 0;
+       return ret == 1;
 }
 EXPORT_SYMBOL(qe_issue_cmd);
 
index 63cdf9887f3672dd4e16310b591b91d564de20bd..074905c3ee5a94d80fb3e0daa86e88b8f77f9650 100644 (file)
@@ -333,12 +333,10 @@ void __init qe_ic_init(struct device_node *node, unsigned int flags,
        if (ret)
                return;
 
-       qe_ic = alloc_bootmem(sizeof(struct qe_ic));
+       qe_ic = kzalloc(sizeof(*qe_ic), GFP_KERNEL);
        if (qe_ic == NULL)
                return;
 
-       memset(qe_ic, 0, sizeof(struct qe_ic));
-
        qe_ic->irqhost = irq_alloc_host(node, IRQ_HOST_MAP_LINEAR,
                                        NR_QE_IC_INTS, &qe_ic_host_ops, 0);
        if (qe_ic->irqhost == NULL)
index d35405c5943482c86efea86739099ed8c2f3da1e..466ce9ace1270ec881a4ae2f18e92a70648af40b 100644 (file)
@@ -258,11 +258,10 @@ static struct uic * __init uic_init_one(struct device_node *node)
 
        BUG_ON(! of_device_is_compatible(node, "ibm,uic"));
 
-       uic = alloc_bootmem(sizeof(*uic));
+       uic = kzalloc(sizeof(*uic), GFP_KERNEL);
        if (! uic)
                return NULL; /* FIXME: panic? */
 
-       memset(uic, 0, sizeof(*uic));
        spin_lock_init(&uic->lock);
        indexp = of_get_property(node, "cell-index", &len);
        if (!indexp || (len != sizeof(u32))) {
index e577839f3073e5a6e5687193817ddcb6e354c423..2ae5d72f47edaad3198a030c0ee7ed09deeea6b8 100644 (file)
@@ -95,6 +95,11 @@ config S390
        select HAVE_ARCH_TRACEHOOK
        select INIT_ALL_POSSIBLE
        select HAVE_PERF_COUNTERS
+       select GENERIC_ATOMIC64 if !64BIT
+
+config SCHED_OMIT_FRAME_POINTER
+       bool
+       default y
 
 source "init/Kconfig"
 
@@ -116,6 +121,9 @@ config 32BIT
        bool
        default y if !64BIT
 
+config KTIME_SCALAR
+       def_bool 32BIT
+
 config SMP
        bool "Symmetric multi-processing support"
        ---help---
index fca9dffcc669b186f779785ae8d1ac3a9858c356..c7d0abfb0f0089a9ed9b716a31928c563abc18e2 100644 (file)
@@ -268,7 +268,12 @@ static __inline__ int atomic64_add_unless(atomic64_t *v,
 #define atomic64_inc_not_zero(v) atomic64_add_unless((v), 1, 0)
 
 #undef __CSG_LOOP
-#endif
+
+#else /* __s390x__ */
+
+#include <asm-generic/atomic64.h>
+
+#endif /* __s390x__ */
 
 #define smp_mb__before_atomic_dec()    smp_mb()
 #define smp_mb__after_atomic_dec()     smp_mb()
index a27d0d5a6f8689fa81f558686cad2f378487be42..1cd02f6073a06c0b58e8188d04eb9ebc3e4d7d7d 100644 (file)
@@ -99,7 +99,9 @@ struct kvm_s390_sie_block {
        __u8    reservedd0[48];         /* 0x00d0 */
        __u64   gcr[16];                /* 0x0100 */
        __u64   gbea;                   /* 0x0180 */
-       __u8    reserved188[120];       /* 0x0188 */
+       __u8    reserved188[24];        /* 0x0188 */
+       __u32   fac;                    /* 0x01a0 */
+       __u8    reserved1a4[92];        /* 0x01a4 */
 } __attribute__((packed));
 
 struct kvm_vcpu_stat {
index a7205a3828cb1553b89bb6730263c6549f26fbb9..7015188c2cc275b5cb86ad4ee1d4e326239f9fcc 100644 (file)
@@ -6,3 +6,5 @@
 
 static inline void set_perf_counter_pending(void) {}
 static inline void clear_perf_counter_pending(void) {}
+
+#define PERF_COUNTER_INDEX_OFFSET 0
index 925bcc6490354c3f2fa2c5dbbca8b37b553b1bd6..ba1cab9fc1f92cd19acfe34d2353cce8a0858c7e 100644 (file)
@@ -61,7 +61,7 @@ struct thread_info {
        .exec_domain    = &default_exec_domain, \
        .flags          = 0,                    \
        .cpu            = 0,                    \
-       .preempt_count  = 1,                    \
+       .preempt_count  = INIT_PREEMPT_COUNT,   \
        .restart_block  = {                     \
                .fn = do_no_restart_syscall,    \
        },                                      \
index d2f270c995d9baefa6ac75a743c4d5d165441b57..db943a7ec51331f5f471c23f838e454eb46c99b2 100644 (file)
@@ -15,7 +15,6 @@
 #include <linux/timer.h>
 #include <linux/mm.h>
 #include <linux/smp.h>
-#include <linux/smp_lock.h>
 #include <linux/init.h>
 #include <linux/interrupt.h>
 #include <linux/delay.h>
index b8bf4b140065226bbb8f48e3f4eadd07e8c04b7b..371a2d88f4ac7b6e170134b96b4924c69f8a8b99 100644 (file)
@@ -70,6 +70,7 @@ struct shutdown_action {
        char *name;
        void (*fn) (struct shutdown_trigger *trigger);
        int (*init) (void);
+       int init_rc;
 };
 
 static char *ipl_type_str(enum ipl_type type)
@@ -1486,11 +1487,13 @@ static int set_trigger(const char *buf, struct shutdown_trigger *trigger,
        int i;
 
        for (i = 0; i < SHUTDOWN_ACTIONS_COUNT; i++) {
-               if (!shutdown_actions_list[i])
-                       continue;
                if (sysfs_streq(buf, shutdown_actions_list[i]->name)) {
-                       trigger->action = shutdown_actions_list[i];
-                       return len;
+                       if (shutdown_actions_list[i]->init_rc) {
+                               return shutdown_actions_list[i]->init_rc;
+                       } else {
+                               trigger->action = shutdown_actions_list[i];
+                               return len;
+                       }
                }
        }
        return -EINVAL;
@@ -1640,8 +1643,8 @@ static void __init shutdown_actions_init(void)
        for (i = 0; i < SHUTDOWN_ACTIONS_COUNT; i++) {
                if (!shutdown_actions_list[i]->init)
                        continue;
-               if (shutdown_actions_list[i]->init())
-                       shutdown_actions_list[i] = NULL;
+               shutdown_actions_list[i]->init_rc =
+                       shutdown_actions_list[i]->init();
        }
 }
 
index 490b39934d65aa8a98cc76f5772b10f3ef9735ea..43acd73105b7f06f279776a9c96be780ae1927ce 100644 (file)
@@ -26,7 +26,6 @@
 #include <linux/sched.h>
 #include <linux/mm.h>
 #include <linux/smp.h>
-#include <linux/smp_lock.h>
 #include <linux/errno.h>
 #include <linux/ptrace.h>
 #include <linux/user.h>
index c18b21d6991cebacdb8dfb4358017db75782eb44..90d9d1ba258b0458b23df8892a20a792523f1b14 100644 (file)
@@ -25,6 +25,7 @@
 #include <asm/lowcore.h>
 #include <asm/pgtable.h>
 #include <asm/nmi.h>
+#include <asm/system.h>
 #include "kvm-s390.h"
 #include "gaccess.h"
 
@@ -69,6 +70,7 @@ struct kvm_stats_debugfs_item debugfs_entries[] = {
        { NULL }
 };
 
+static unsigned long long *facilities;
 
 /* Section: not file related */
 void kvm_arch_hardware_enable(void *garbage)
@@ -288,6 +290,7 @@ int kvm_arch_vcpu_setup(struct kvm_vcpu *vcpu)
        vcpu->arch.sie_block->gmsor = vcpu->kvm->arch.guest_origin;
        vcpu->arch.sie_block->ecb   = 2;
        vcpu->arch.sie_block->eca   = 0xC1002001U;
+       vcpu->arch.sie_block->fac   = (int) (long) facilities;
        hrtimer_init(&vcpu->arch.ckc_timer, CLOCK_REALTIME, HRTIMER_MODE_ABS);
        tasklet_init(&vcpu->arch.tasklet, kvm_s390_tasklet,
                     (unsigned long) vcpu);
@@ -739,11 +742,29 @@ gfn_t unalias_gfn(struct kvm *kvm, gfn_t gfn)
 
 static int __init kvm_s390_init(void)
 {
-       return kvm_init(NULL, sizeof(struct kvm_vcpu), THIS_MODULE);
+       int ret;
+       ret = kvm_init(NULL, sizeof(struct kvm_vcpu), THIS_MODULE);
+       if (ret)
+               return ret;
+
+       /*
+        * guests can ask for up to 255+1 double words, we need a full page
+        * to hold the maximum amount of facilites. On the other hand, we
+        * only set facilities that are known to work in KVM.
+        */
+       facilities = (unsigned long long *) get_zeroed_page(GFP_DMA);
+       if (!facilities) {
+               kvm_exit();
+               return -ENOMEM;
+       }
+       stfle(facilities, 1);
+       facilities[0] &= 0xff00fff3f0700000ULL;
+       return 0;
 }
 
 static void __exit kvm_s390_exit(void)
 {
+       free_page((unsigned long) facilities);
        kvm_exit();
 }
 
index 93ecd06e1a749fc866177c5bd5c6bcdd6ae82e81..d426aac8095de3552177158bc88fa72e1ef9a82e 100644 (file)
@@ -158,7 +158,7 @@ static int handle_stfl(struct kvm_vcpu *vcpu)
 
        vcpu->stat.instruction_stfl++;
        /* only pass the facility bits, which we can handle */
-       facility_list &= 0xfe00fff3;
+       facility_list &= 0xff00fff3;
 
        rc = copy_to_guest(vcpu, offsetof(struct _lowcore, stfl_fac_list),
                           &facility_list, sizeof(facility_list));
index ab6735df2d2155b2755170048701f979272e6f03..97975ec7a27471253a8da274af72d14a16e9f171 100644 (file)
@@ -3,6 +3,6 @@
 #
 
 lib-y += delay.o string.o uaccess_std.o uaccess_pt.o
-obj-$(CONFIG_32BIT) += div64.o qrnnd.o
+obj-$(CONFIG_32BIT) += div64.o qrnnd.o ucmpdi2.o
 lib-$(CONFIG_64BIT) += uaccess_mvcos.o
 lib-$(CONFIG_SMP) += spinlock.o
index 3f5f680726ed1e03bc74cc40a4217a93ab89e837..97c1eca83cc24274e796c491f60d5851252de150 100644 (file)
@@ -36,9 +36,11 @@ static void __udelay_disabled(unsigned long usecs)
        cr0 = (cr0_saved & 0xffff00e0) | 0x00000800;
        __ctl_load(cr0 , 0, 0);
        mask = psw_kernel_bits | PSW_MASK_WAIT | PSW_MASK_EXT;
+       lockdep_off();
        trace_hardirqs_on();
        __load_psw_mask(mask);
        local_irq_disable();
+       lockdep_on();
        __ctl_load(cr0_saved, 0, 0);
        local_tick_enable(clock_saved);
        set_clock_comparator(S390_lowcore.clock_comparator);
diff --git a/arch/s390/lib/ucmpdi2.c b/arch/s390/lib/ucmpdi2.c
new file mode 100644 (file)
index 0000000..3e05ff5
--- /dev/null
@@ -0,0 +1,26 @@
+#include <linux/module.h>
+
+union ull_union {
+       unsigned long long ull;
+       struct {
+               unsigned int high;
+               unsigned int low;
+       } ui;
+};
+
+int __ucmpdi2(unsigned long long a, unsigned long long b)
+{
+       union ull_union au = {.ull = a};
+       union ull_union bu = {.ull = b};
+
+       if (au.ui.high < bu.ui.high)
+               return 0;
+       else if (au.ui.high > bu.ui.high)
+               return 2;
+       if (au.ui.low < bu.ui.low)
+               return 0;
+       else if (au.ui.low > bu.ui.low)
+               return 2;
+       return 1;
+}
+EXPORT_SYMBOL(__ucmpdi2);
index 74eb26bf1970ee4f92bf3d6f34e3036471a6302d..e5e119fe03b2c18b0664c4ed48653889380aa7ac 100644 (file)
@@ -22,7 +22,6 @@
 #include <linux/compat.h>
 #include <linux/smp.h>
 #include <linux/kdebug.h>
-#include <linux/smp_lock.h>
 #include <linux/init.h>
 #include <linux/console.h>
 #include <linux/module.h>
index 8ece0b5bd0282495f872bc71f0ad56227d312b12..39224b57c6efe5ae5d37a45c68d34811fbc0f047 100644 (file)
@@ -61,10 +61,6 @@ config EARLY_PRINTK
          select both the EARLY_SCIF_CONSOLE and SH_STANDARD_BIOS, using
          the kernel command line option to toggle back and forth.
 
-config DEBUG_BOOTMEM
-       depends on DEBUG_KERNEL
-       bool "Debug BOOTMEM initialization"
-
 config DEBUG_STACKOVERFLOW
        bool "Check for stack overflows"
        depends on DEBUG_KERNEL && SUPERH32
index 9c3a33210d61750a71a2ae55d8fc7a7c5936403d..180455642a432ce08bd639f02b06826209cd9ac5 100644 (file)
@@ -50,7 +50,7 @@ unsigned char se7206_inb_p(unsigned long port)
 
 unsigned short se7206_inw(unsigned long port)
 {
-       return *port2adr(port);;
+       return *port2adr(port);
 }
 
 void se7206_outb(unsigned char value, unsigned long port)
index 9cd04bd558b88930583774a29837d5aa8424518d..8fed45a2fb8550dd4cf09f3f8844269194d613cd 100644 (file)
 #include <linux/smc91x.h>
 #include <linux/gpio.h>
 #include <linux/input.h>
+#include <linux/usb/r8a66597.h>
 #include <video/sh_mobile_lcdc.h>
 #include <media/sh_mobile_ceu.h>
 #include <asm/io.h>
 #include <asm/heartbeat.h>
+#include <asm/sh_eth.h>
+#include <asm/clock.h>
 #include <asm/sh_keysc.h>
 #include <cpu/sh7724.h>
 #include <mach-se/mach/se7724.h>
@@ -272,6 +275,62 @@ static struct platform_device keysc_device = {
        },
 };
 
+/* SH Eth */
+static struct resource sh_eth_resources[] = {
+       [0] = {
+               .start = SH_ETH_ADDR,
+               .end   = SH_ETH_ADDR + 0x1FC,
+               .flags = IORESOURCE_MEM,
+       },
+       [1] = {
+               .start = 91,
+               .flags = IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHLEVEL,
+       },
+};
+
+struct sh_eth_plat_data sh_eth_plat = {
+       .phy = 0x1f, /* SMSC LAN8187 */
+       .edmac_endian = EDMAC_LITTLE_ENDIAN,
+};
+
+static struct platform_device sh_eth_device = {
+       .name = "sh-eth",
+       .id     = 0,
+       .dev = {
+               .platform_data = &sh_eth_plat,
+       },
+       .num_resources = ARRAY_SIZE(sh_eth_resources),
+       .resource = sh_eth_resources,
+};
+
+static struct r8a66597_platdata sh7724_usb0_host_data = {
+};
+
+static struct resource sh7724_usb0_host_resources[] = {
+       [0] = {
+               .start  = 0xa4d80000,
+               .end    = 0xa4d800ff,
+               .flags  = IORESOURCE_MEM,
+       },
+       [1] = {
+               .start  = 65,
+               .end    = 65,
+               .flags  = IORESOURCE_IRQ | IRQF_TRIGGER_LOW,
+       },
+};
+
+static struct platform_device sh7724_usb0_host_device = {
+       .name           = "r8a66597_hcd",
+       .id             = 0,
+       .dev = {
+               .dma_mask               = NULL,         /*  not use dma */
+               .coherent_dma_mask      = 0xffffffff,
+               .platform_data          = &sh7724_usb0_host_data,
+       },
+       .num_resources  = ARRAY_SIZE(sh7724_usb0_host_resources),
+       .resource       = sh7724_usb0_host_resources,
+};
+
 static struct platform_device *ms7724se_devices[] __initdata = {
        &heartbeat_device,
        &smc91x_eth_device,
@@ -280,11 +339,62 @@ static struct platform_device *ms7724se_devices[] __initdata = {
        &ceu0_device,
        &ceu1_device,
        &keysc_device,
+       &sh_eth_device,
+       &sh7724_usb0_host_device,
 };
 
+#define EEPROM_OP   0xBA206000
+#define EEPROM_ADR  0xBA206004
+#define EEPROM_DATA 0xBA20600C
+#define EEPROM_STAT 0xBA206010
+#define EEPROM_STRT 0xBA206014
+static int __init sh_eth_is_eeprom_ready(void)
+{
+       int t = 10000;
+
+       while (t--) {
+               if (!ctrl_inw(EEPROM_STAT))
+                       return 1;
+               cpu_relax();
+       }
+
+       printk(KERN_ERR "ms7724se can not access to eeprom\n");
+       return 0;
+}
+
+static void __init sh_eth_init(void)
+{
+       int i;
+       u16 mac[3];
+
+       /* check EEPROM status */
+       if (!sh_eth_is_eeprom_ready())
+               return;
+
+       /* read MAC addr from EEPROM */
+       for (i = 0 ; i < 3 ; i++) {
+               ctrl_outw(0x0, EEPROM_OP); /* read */
+               ctrl_outw(i*2, EEPROM_ADR);
+               ctrl_outw(0x1, EEPROM_STRT);
+               if (!sh_eth_is_eeprom_ready())
+                       return;
+
+               mac[i] = ctrl_inw(EEPROM_DATA);
+               mac[i] = ((mac[i] & 0xFF) << 8) | (mac[i] >> 8); /* swap */
+       }
+
+       /* reset sh-eth */
+       ctrl_outl(0x1, SH_ETH_ADDR + 0x0);
+
+       /* set MAC addr */
+       ctrl_outl(((mac[0] << 16) | (mac[1])), SH_ETH_MAHR);
+       ctrl_outl((mac[2]), SH_ETH_MALR);
+}
+
 #define SW4140    0xBA201000
 #define FPGA_OUT  0xBA200400
 #define PORT_HIZA 0xA4050158
+#define PORT_MSELCRB 0xA4050182
 
 #define SW41_A    0x0100
 #define SW41_B    0x0200
@@ -294,6 +404,7 @@ static struct platform_device *ms7724se_devices[] __initdata = {
 #define SW41_F    0x2000
 #define SW41_G    0x4000
 #define SW41_H    0x8000
+
 static int __init devices_setup(void)
 {
        u16 sw = ctrl_inw(SW4140); /* select camera, monitor */
@@ -302,9 +413,16 @@ static int __init devices_setup(void)
        ctrl_outw(ctrl_inw(FPGA_OUT) &
                  ~((1 << 1)  | /* LAN */
                    (1 << 6)  | /* VIDEO DAC */
-                   (1 << 12)), /* USB0 */
+                   (1 << 12) | /* USB0 */
+                   (1 << 14)), /* RMII */
                  FPGA_OUT);
 
+       /* turn on USB clocks, use external clock */
+       ctrl_outw((ctrl_inw(PORT_MSELCRB) & ~0xc000) | 0x8000, PORT_MSELCRB);
+
+       /* enable USB0 port */
+       ctrl_outw(0x0600, 0xa40501d4);
+
        /* enable IRQ 0,1,2 */
        gpio_request(GPIO_FN_INTC_IRQ0, NULL);
        gpio_request(GPIO_FN_INTC_IRQ1, NULL);
@@ -374,7 +492,7 @@ static int __init devices_setup(void)
        gpio_request(GPIO_FN_VIO0_CLK, NULL);
        gpio_request(GPIO_FN_VIO0_FLD, NULL);
        gpio_request(GPIO_FN_VIO0_HD,  NULL);
-       platform_resource_setup_memory(&ceu0_device, "ceu", 4 << 20);
+       platform_resource_setup_memory(&ceu0_device, "ceu0", 4 << 20);
 
        /* enable CEU1 */
        gpio_request(GPIO_FN_VIO1_D7,  NULL);
@@ -389,7 +507,7 @@ static int __init devices_setup(void)
        gpio_request(GPIO_FN_VIO1_HD,  NULL);
        gpio_request(GPIO_FN_VIO1_VD,  NULL);
        gpio_request(GPIO_FN_VIO1_CLK, NULL);
-       platform_resource_setup_memory(&ceu1_device, "ceu", 4 << 20);
+       platform_resource_setup_memory(&ceu1_device, "ceu1", 4 << 20);
 
        /* KEYSC */
        gpio_request(GPIO_FN_KEYOUT5_IN5, NULL);
@@ -404,6 +522,28 @@ static int __init devices_setup(void)
        gpio_request(GPIO_FN_KEYOUT1,     NULL);
        gpio_request(GPIO_FN_KEYOUT0,     NULL);
 
+       /*
+        * enable SH-Eth
+        *
+        * please remove J33 pin from your board !!
+        *
+        * ms7724 board should not use GPIO_FN_LNKSTA pin
+        * So, This time PTX5 is set to input pin
+        */
+       gpio_request(GPIO_FN_RMII_RXD0,    NULL);
+       gpio_request(GPIO_FN_RMII_RXD1,    NULL);
+       gpio_request(GPIO_FN_RMII_TXD0,    NULL);
+       gpio_request(GPIO_FN_RMII_TXD1,    NULL);
+       gpio_request(GPIO_FN_RMII_REF_CLK, NULL);
+       gpio_request(GPIO_FN_RMII_TX_EN,   NULL);
+       gpio_request(GPIO_FN_RMII_RX_ER,   NULL);
+       gpio_request(GPIO_FN_RMII_CRS_DV,  NULL);
+       gpio_request(GPIO_FN_MDIO,         NULL);
+       gpio_request(GPIO_FN_MDC,          NULL);
+       gpio_request(GPIO_PTX5, NULL);
+       gpio_direction_input(GPIO_PTX5);
+       sh_eth_init();
+
        if (sw & SW41_B) {
                /* SVGA */
                lcdc_info.ch[0].lcd_cfg.xres         = 800;
@@ -437,7 +577,7 @@ static int __init devices_setup(void)
        }
 
        return platform_add_devices(ms7724se_devices,
-                               ARRAY_SIZE(ms7724se_devices));
+                                   ARRAY_SIZE(ms7724se_devices));
 }
 device_initcall(devices_setup);
 
index da627d22c009ceaab56bdb09359d56c4773406ee..b18cfd39cac6082a7aa4088f0996d88e86f82f6a 100644 (file)
@@ -309,7 +309,7 @@ CONFIG_ZERO_PAGE_OFFSET=0x00001000
 CONFIG_BOOT_LINK_OFFSET=0x00800000
 CONFIG_ENTRY_OFFSET=0x00001000
 CONFIG_CMDLINE_BOOL=y
-CONFIG_CMDLINE="console=ttySC0,115200 earlyprintk=serial ip=on root=/dev/nfs ip=dhcp"
+CONFIG_CMDLINE="console=tty0 console=ttySC0,115200 earlyprintk=serial ip=on root=/dev/nfs ip=dhcp"
 
 #
 # Bus options
@@ -858,7 +858,35 @@ CONFIG_VIDEO_SH_MOBILE_CEU=y
 #
 # CONFIG_VGASTATE is not set
 # CONFIG_VIDEO_OUTPUT_CONTROL is not set
-# CONFIG_FB is not set
+CONFIG_FB=y
+# CONFIG_FIRMWARE_EDID is not set
+# CONFIG_FB_DDC is not set
+# CONFIG_FB_BOOT_VESA_SUPPORT is not set
+# CONFIG_FB_CFB_FILLRECT is not set
+# CONFIG_FB_CFB_COPYAREA is not set
+# CONFIG_FB_CFB_IMAGEBLIT is not set
+# CONFIG_FB_CFB_REV_PIXELS_IN_BYTE is not set
+CONFIG_FB_SYS_FILLRECT=y
+CONFIG_FB_SYS_COPYAREA=y
+CONFIG_FB_SYS_IMAGEBLIT=y
+# CONFIG_FB_FOREIGN_ENDIAN is not set
+CONFIG_FB_SYS_FOPS=y
+CONFIG_FB_DEFERRED_IO=y
+# CONFIG_FB_SVGALIB is not set
+# CONFIG_FB_MACMODES is not set
+# CONFIG_FB_BACKLIGHT is not set
+# CONFIG_FB_MODE_HELPERS is not set
+# CONFIG_FB_TILEBLITTING is not set
+
+#
+# Frame buffer hardware drivers
+#
+# CONFIG_FB_S1D13XXX is not set
+CONFIG_FB_SH_MOBILE_LCDC=y
+# CONFIG_FB_VIRTUAL is not set
+# CONFIG_FB_METRONOME is not set
+# CONFIG_FB_MB862XX is not set
+# CONFIG_FB_BROADSHEET is not set
 # CONFIG_BACKLIGHT_LCD_SUPPORT is not set
 
 #
@@ -870,6 +898,27 @@ CONFIG_VIDEO_SH_MOBILE_CEU=y
 # Console display driver support
 #
 CONFIG_DUMMY_CONSOLE=y
+CONFIG_FRAMEBUFFER_CONSOLE=y
+CONFIG_FRAMEBUFFER_CONSOLE_DETECT_PRIMARY=y
+# CONFIG_FRAMEBUFFER_CONSOLE_ROTATION is not set
+CONFIG_FONTS=y
+# CONFIG_FONT_8x8 is not set
+# CONFIG_FONT_8x16 is not set
+# CONFIG_FONT_6x11 is not set
+# CONFIG_FONT_7x14 is not set
+# CONFIG_FONT_PEARL_8x8 is not set
+# CONFIG_FONT_ACORN_8x8 is not set
+CONFIG_FONT_MINI_4x6=y
+# CONFIG_FONT_SUN8x16 is not set
+# CONFIG_FONT_SUN12x22 is not set
+# CONFIG_FONT_10x18 is not set
+CONFIG_LOGO=y
+# CONFIG_LOGO_LINUX_MONO is not set
+# CONFIG_LOGO_LINUX_VGA16 is not set
+# CONFIG_LOGO_LINUX_CLUT224 is not set
+# CONFIG_LOGO_SUPERH_MONO is not set
+CONFIG_LOGO_SUPERH_VGA16=y
+# CONFIG_LOGO_SUPERH_CLUT224 is not set
 # CONFIG_SOUND is not set
 CONFIG_HID_SUPPORT=y
 CONFIG_HID=y
index 3840270283e4416a74e348bac24430cf0b58298b..3ee783a0a075c306d08941b94371792567eac4dd 100644 (file)
@@ -1,7 +1,7 @@
 #
 # Automatically generated make config: don't edit
 # Linux kernel version: 2.6.30
-# Thu Jun 18 16:09:05 2009
+# Mon Jun 29 16:28:43 2009
 #
 CONFIG_SUPERH=y
 CONFIG_SUPERH32=y
@@ -14,6 +14,7 @@ CONFIG_GENERIC_HWEIGHT=y
 CONFIG_GENERIC_HARDIRQS=y
 CONFIG_GENERIC_HARDIRQS_NO__DO_IRQ=y
 CONFIG_GENERIC_IRQ_PROBE=y
+CONFIG_IRQ_PER_CPU=y
 CONFIG_GENERIC_GPIO=y
 CONFIG_GENERIC_TIME=y
 CONFIG_GENERIC_CLOCKEVENTS=y
@@ -28,7 +29,9 @@ CONFIG_HAVE_LATENCYTOP_SUPPORT=y
 # CONFIG_ARCH_HAS_ILOG2_U64 is not set
 CONFIG_ARCH_NO_VIRT_TO_BUS=y
 CONFIG_ARCH_HAS_DEFAULT_IDLE=y
+CONFIG_ARCH_HAS_CPU_IDLE_WAIT=y
 CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+CONFIG_CONSTRUCTORS=y
 
 #
 # General setup
@@ -88,10 +91,12 @@ CONFIG_TIMERFD=y
 CONFIG_EVENTFD=y
 CONFIG_SHMEM=y
 CONFIG_AIO=y
+CONFIG_HAVE_PERF_COUNTERS=y
 
 #
 # Performance Counters
 #
+# CONFIG_PERF_COUNTERS is not set
 CONFIG_VM_EVENT_COUNTERS=y
 # CONFIG_STRIP_ASM_SYMS is not set
 CONFIG_COMPAT_BRK=y
@@ -107,6 +112,10 @@ CONFIG_HAVE_KRETPROBES=y
 CONFIG_HAVE_ARCH_TRACEHOOK=y
 CONFIG_HAVE_CLK=y
 CONFIG_HAVE_DMA_API_DEBUG=y
+
+#
+# GCOV-based kernel profiling
+#
 # CONFIG_SLOW_WORK is not set
 CONFIG_HAVE_GENERIC_DMA_COHERENT=y
 CONFIG_SLABINFO=y
@@ -119,7 +128,7 @@ CONFIG_MODULE_UNLOAD=y
 # CONFIG_MODVERSIONS is not set
 # CONFIG_MODULE_SRCVERSION_ALL is not set
 CONFIG_BLOCK=y
-# CONFIG_LBD is not set
+CONFIG_LBDAF=y
 # CONFIG_BLK_DEV_BSG is not set
 # CONFIG_BLK_DEV_INTEGRITY is not set
 
@@ -584,7 +593,6 @@ CONFIG_SCSI_WAIT_SCAN=m
 # CONFIG_SCSI_SRP_ATTRS is not set
 CONFIG_SCSI_LOWLEVEL=y
 # CONFIG_ISCSI_TCP is not set
-# CONFIG_SCSI_BNX2_ISCSI is not set
 # CONFIG_LIBFC is not set
 # CONFIG_LIBFCOE is not set
 # CONFIG_SCSI_DEBUG is not set
@@ -624,7 +632,7 @@ CONFIG_NET_ETHERNET=y
 CONFIG_MII=y
 # CONFIG_AX88796 is not set
 # CONFIG_STNIC is not set
-# CONFIG_SH_ETH is not set
+CONFIG_SH_ETH=y
 CONFIG_SMC91X=y
 # CONFIG_ENC28J60 is not set
 # CONFIG_ETHOC is not set
@@ -801,6 +809,11 @@ CONFIG_SPI_BITBANG=y
 #
 # CONFIG_SPI_SPIDEV is not set
 # CONFIG_SPI_TLE62X0 is not set
+
+#
+# PPS support
+#
+# CONFIG_PPS is not set
 CONFIG_ARCH_REQUIRE_GPIOLIB=y
 CONFIG_GPIOLIB=y
 # CONFIG_GPIO_SYSFS is not set
@@ -851,6 +864,8 @@ CONFIG_SSB_POSSIBLE=y
 # CONFIG_MFD_WM8400 is not set
 # CONFIG_MFD_WM8350_I2C is not set
 # CONFIG_MFD_PCF50633 is not set
+# CONFIG_AB3100_CORE is not set
+# CONFIG_EZX_PCAP is not set
 # CONFIG_REGULATOR is not set
 CONFIG_MEDIA_SUPPORT=y
 
@@ -1196,6 +1211,7 @@ CONFIG_RTC_DRV_PCF8563=y
 # CONFIG_RTC_DRV_S35390A is not set
 # CONFIG_RTC_DRV_FM3130 is not set
 # CONFIG_RTC_DRV_RX8581 is not set
+# CONFIG_RTC_DRV_RX8025 is not set
 
 #
 # SPI RTC drivers
@@ -1260,6 +1276,7 @@ CONFIG_FS_MBCACHE=y
 # CONFIG_JFS_FS is not set
 CONFIG_FS_POSIX_ACL=y
 # CONFIG_XFS_FS is not set
+# CONFIG_GFS2_FS is not set
 # CONFIG_OCFS2_FS is not set
 # CONFIG_BTRFS_FS is not set
 CONFIG_FILE_LOCKING=y
index a8153c2aa6faf20db8fd1ef661218536d046362c..d8e6bb9c0ccc75bee14438cd767630002f6400fa 100644 (file)
@@ -2,6 +2,8 @@
 #define __ASM_SH_PERF_COUNTER_H
 
 /* SH only supports software counters through this interface. */
-#define set_perf_counter_pending()     do { } while (0)
+static inline void set_perf_counter_pending(void) {}
+
+#define PERF_COUNTER_INDEX_OFFSET      0
 
 #endif /* __ASM_SH_PERF_COUNTER_H */
index 5bc34681d99451ae8485a75e4c92b1c24285acbb..6f83f2cc45c16887e126cbffa5e14a28f9b63104 100644 (file)
@@ -3,6 +3,7 @@
 
 #include <linux/kernel.h>
 #include <linux/sched.h>
+#include <linux/err.h>
 #include <asm/ptrace.h>
 
 /* The system call number is given by the user in R3 */
index f09ac4806294007a883b0a472ed2d6654a7ef19f..d570ac2e5cb99838b486c0f65cf120ba710e20e5 100644 (file)
@@ -51,7 +51,7 @@ struct thread_info {
        .exec_domain    = &default_exec_domain, \
        .flags          = 0,                    \
        .cpu            = 0,                    \
-       .preempt_count  = 1,                    \
+       .preempt_count  = INIT_PREEMPT_COUNT,   \
        .addr_limit     = KERNEL_DS,            \
        .restart_block  = {                     \
                .fn = do_no_restart_syscall,    \
index 74164b60d0dbb43872ee74df4dffcb43ac239577..29514a39d0f5135afe8ba400a262e2ec77f72f49 100644 (file)
  */
 #include <asm/addrspace.h>
 
+/* SH Eth */
+#define SH_ETH_ADDR    (0xA4600000)
+#define SH_ETH_MAHR    (SH_ETH_ADDR + 0x1C0)
+#define SH_ETH_MALR    (SH_ETH_ADDR + 0x1C8)
+
 #define PA_LED         (0xba203000)    /* 8bit LED */
 #define IRQ_MODE       (0xba200010)
 #define IRQ0_SR                (0xba200014)
index cc8ddbdf3d7a75005c2c9590fe386d20bb79050c..71925946f1e16d6294301581ade0bb6f0fda050a 100644 (file)
 #include <linux/mm.h>
 #include <linux/hardirq.h>
 #include <linux/kprobes.h>
-#include <linux/marker.h>
+#include <linux/perf_counter.h>
 #include <asm/io_trapped.h>
 #include <asm/system.h>
 #include <asm/mmu_context.h>
 #include <asm/tlbflush.h>
 
+static inline int notify_page_fault(struct pt_regs *regs, int trap)
+{
+       int ret = 0;
+
+#ifdef CONFIG_KPROBES
+       if (!user_mode(regs)) {
+               preempt_disable();
+               if (kprobe_running() && kprobe_fault_handler(regs, trap))
+                       ret = 1;
+               preempt_enable();
+       }
+#endif
+
+       return ret;
+}
+
 /*
  * This routine handles page faults.  It determines the address,
  * and the problem, and then passes it off to one of the appropriate
@@ -87,13 +103,16 @@ asmlinkage void __kprobes do_page_fault(struct pt_regs *regs,
                return;
        }
 
+       mm = tsk->mm;
+
+       if (unlikely(notify_page_fault(regs, lookup_exception_vector())))
+               return;
+
        /* Only enable interrupts if they were on before the fault */
-       if ((regs->sr & SR_IMASK) != SR_IMASK) {
-               trace_hardirqs_on();
+       if ((regs->sr & SR_IMASK) != SR_IMASK)
                local_irq_enable();
-       }
 
-       mm = tsk->mm;
+       perf_swcounter_event(PERF_COUNT_SW_PAGE_FAULTS, 1, 0, regs, address);
 
        /*
         * If we're in an interrupt or have no user
@@ -141,10 +160,15 @@ survive:
                        goto do_sigbus;
                BUG();
        }
-       if (fault & VM_FAULT_MAJOR)
+       if (fault & VM_FAULT_MAJOR) {
                tsk->maj_flt++;
-       else
+               perf_swcounter_event(PERF_COUNT_SW_PAGE_FAULTS_MAJ, 1, 0,
+                                    regs, address);
+       } else {
                tsk->min_flt++;
+               perf_swcounter_event(PERF_COUNT_SW_PAGE_FAULTS_MIN, 1, 0,
+                                    regs, address);
+       }
 
        up_read(&mm->mmap_sem);
        return;
@@ -245,22 +269,6 @@ do_sigbus:
                goto no_context;
 }
 
-static inline int notify_page_fault(struct pt_regs *regs, int trap)
-{
-       int ret = 0;
-
-#ifdef CONFIG_KPROBES
-       if (!user_mode(regs)) {
-               preempt_disable();
-               if (kprobe_running() && kprobe_fault_handler(regs, trap))
-                       ret = 1;
-               preempt_enable();
-       }
-#endif
-
-       return ret;
-}
-
 /*
  * Called with interrupts disabled.
  */
@@ -273,12 +281,7 @@ asmlinkage int __kprobes __do_page_fault(struct pt_regs *regs,
        pmd_t *pmd;
        pte_t *pte;
        pte_t entry;
-       int ret = 0;
-
-       if (notify_page_fault(regs, lookup_exception_vector()))
-               goto out;
-
-       ret = 1;
+       int ret = 1;
 
        /*
         * We don't take page faults for P1, P2, and parts of P4, these
index 7fbfd5a11ffae73860c64941240dff7ecbc03e51..17cb7c3adf2256b0206ea3d920578c47b9a0dbfc 100644 (file)
@@ -18,7 +18,6 @@
 #include <linux/mman.h>
 #include <linux/mm.h>
 #include <linux/smp.h>
-#include <linux/smp_lock.h>
 #include <linux/interrupt.h>
 
 #include <asm/system.h>
index fcbb6e135cef319ee30c5d27a12fb75b234608e1..3ce40ea34824914f6ad30ad2abb38a0d8ca9d401 100644 (file)
@@ -3,7 +3,7 @@
  *
  * Copyright (C) 2000, 2001  Paolo Alberelli
  * Copyright (C) 2003  Richard Curnow (/proc/tlb, bug fixes)
- * Copyright (C) 2003  Paul Mundt
+ * Copyright (C) 2003 - 2009 Paul Mundt
  *
  * This file is subject to the terms and conditions of the GNU General Public
  * License.  See the file "COPYING" in the main directory of this archive
@@ -20,6 +20,7 @@
 #include <linux/mman.h>
 #include <linux/mm.h>
 #include <linux/smp.h>
+#include <linux/perf_counter.h>
 #include <linux/interrupt.h>
 #include <asm/system.h>
 #include <asm/io.h>
@@ -115,6 +116,8 @@ asmlinkage void do_page_fault(struct pt_regs *regs, unsigned long writeaccess,
        /* Not an IO address, so reenable interrupts */
        local_irq_enable();
 
+       perf_swcounter_event(PERF_COUNT_SW_PAGE_FAULTS, 1, 0, regs, address);
+
        /*
         * If we're in an interrupt or have no user
         * context, we must not take the fault..
@@ -195,10 +198,16 @@ survive:
                        goto do_sigbus;
                BUG();
        }
-       if (fault & VM_FAULT_MAJOR)
+
+       if (fault & VM_FAULT_MAJOR) {
                tsk->maj_flt++;
-       else
+               perf_swcounter_event(PERF_COUNT_SW_PAGE_FAULTS_MAJ, 1, 0,
+                                    regs, address);
+       } else {
                tsk->min_flt++;
+               perf_swcounter_event(PERF_COUNT_SW_PAGE_FAULTS_MIN, 1, 0,
+                                    regs, address);
+       }
 
        /* If we get here, the page fault has been handled.  Do the TLB refill
           now from the newly-setup PTE, to avoid having to fault again right
index 96041a8d39e8cf2e01695c0536502440e43e0f0d..1ff0fd92475655ca551e11961a19b8c76e8777b3 100644 (file)
@@ -15,7 +15,7 @@ quiet_cmd_elftoaout   = ELFTOAOUT $@
 
 ifeq ($(CONFIG_SPARC32),y)
 quiet_cmd_piggy                = PIGGY   $@
-      cmd_piggy                = $(obj)/piggyback_32 $@ $(obj)/System.map $(ROOT_IMG)
+      cmd_piggy                = $(obj)/piggyback_32 $@ System.map $(ROOT_IMG)
 quiet_cmd_btfix                = BTFIX   $@
       cmd_btfix                = $(OBJDUMP) -x vmlinux | $(obj)/btfixupprep > $@
 quiet_cmd_sysmap        = SYSMAP  $(obj)/System.map
@@ -58,7 +58,7 @@ $(obj)/image: $(obj)/btfix.o FORCE
 $(obj)/zImage: $(obj)/image
        $(call if_changed,strip)
 
-$(obj)/tftpboot.img: $(obj)/piggyback $(obj)/System.map $(obj)/image FORCE
+$(obj)/tftpboot.img: $(obj)/image $(obj)/piggyback_32 System.map $(ROOT_IMG) FORCE
        $(call if_changed,elftoaout)
        $(call if_changed,piggy)
 
@@ -79,7 +79,7 @@ $(obj)/image: vmlinux FORCE
        $(call if_changed,strip)
        @echo '  kernel: $@ is ready'
 
-$(obj)/tftpboot.img: vmlinux $(obj)/piggyback_64 System.map $(ROOT_IMG) FORCE
+$(obj)/tftpboot.img: $(obj)/image $(obj)/piggyback_64 System.map $(ROOT_IMG) FORCE
        $(call if_changed,elftoaout)
        $(call if_changed,piggy)
        @echo '  kernel: $@ is ready'
index c9f500c1a8b23b9253213baaa58a9e53aaaa9af6..e8dc9adfcd61db8a05ae092407b53a01f2efac2b 100644 (file)
@@ -70,7 +70,7 @@ void die(char *str)
 int main(int argc,char **argv)
 {
        static char aout_magic[] = { 0x01, 0x03, 0x01, 0x07 };
-       unsigned char buffer[1024], *q, *r;
+       char buffer[1024], *q, *r;
        unsigned int i, j, k, start, end, offset;
        FILE *map;
        struct stat s;
@@ -84,7 +84,7 @@ int main(int argc,char **argv)
        while (fgets (buffer, 1024, map)) {
                if (!strcmp (buffer + 8, " T start\n") || !strcmp (buffer + 16, " T start\n"))
                        start = strtoul (buffer, NULL, 16);
-               else if (!strcmp (buffer + 8, " A end\n") || !strcmp (buffer + 16, " A end\n"))
+               else if (!strcmp (buffer + 8, " A _end\n") || !strcmp (buffer + 16, " A _end\n"))
                        end = strtoul (buffer, NULL, 16);
        }
        fclose (map);
index de364bfed0bbfc3405104a3046cbbdd4d099c588..c63fd1b6bdd4f036617c7740619db05dbe6d8e7d 100644 (file)
@@ -46,6 +46,7 @@ int main(int argc,char **argv)
        struct stat s;
        int image, tail;
        
+       start = end = 0;
        if (stat (argv[3], &s) < 0) die (argv[3]);
        map = fopen (argv[2], "r");
        if (!map) die(argv[2]);
index 0f7b0e5fb1c79ce1233437a5744a5736d6f91152..844d73a0340cd9c002a5399a10b943b8b60ce92d 100644 (file)
@@ -54,8 +54,6 @@ struct thread_info {
 
 /*
  * macros/functions for gaining access to the thread information structure
- *
- * preempt_count needs to be 1 initially, until the scheduler is functional.
  */
 #define INIT_THREAD_INFO(tsk)                          \
 {                                                      \
@@ -64,7 +62,7 @@ struct thread_info {
        .exec_domain    =       &default_exec_domain,   \
        .flags          =       0,                      \
        .cpu            =       0,                      \
-       .preempt_count  =       1,                      \
+       .preempt_count  =       INIT_PREEMPT_COUNT,     \
        .restart_block  = {                             \
                .fn     =       do_no_restart_syscall,  \
        },                                              \
index 65865726b28319238b16f109a032510a14b624e5..1b45a7bbe40751a210f748759fac6c0e3fc3b879 100644 (file)
@@ -125,8 +125,6 @@ struct thread_info {
 
 /*
  * macros/functions for gaining access to the thread information structure
- *
- * preempt_count needs to be 1 initially, until the scheduler is functional.
  */
 #ifndef __ASSEMBLY__
 
@@ -135,7 +133,7 @@ struct thread_info {
        .task           =       &tsk,                   \
        .flags          = ((unsigned long)ASI_P) << TI_FLAG_CURRENT_DS_SHIFT,   \
        .exec_domain    =       &default_exec_domain,   \
-       .preempt_count  =       1,                      \
+       .preempt_count  =       INIT_PREEMPT_COUNT,     \
        .restart_block  = {                             \
                .fn     =       do_no_restart_syscall,  \
        },                                              \
index bd075054942bd900fecb66516b40d02c95becd0e..f0ee79055409d34f02947e3ca6915f0e71fe9dc1 100644 (file)
@@ -20,7 +20,6 @@
 #include <linux/delay.h>
 #include <linux/proc_fs.h>
 #include <linux/seq_file.h>
-#include <linux/bootmem.h>
 #include <linux/irq.h>
 
 #include <asm/ptrace.h>
@@ -914,25 +913,19 @@ void __cpuinit notrace sun4v_register_mondo_queues(int this_cpu)
                           tb->nonresum_qmask);
 }
 
-static void __init alloc_one_mondo(unsigned long *pa_ptr, unsigned long qmask)
-{
-       unsigned long size = PAGE_ALIGN(qmask + 1);
-       void *p = __alloc_bootmem(size, size, 0);
-       if (!p) {
-               prom_printf("SUN4V: Error, cannot allocate mondo queue.\n");
-               prom_halt();
-       }
-
-       *pa_ptr = __pa(p);
-}
-
-static void __init alloc_one_kbuf(unsigned long *pa_ptr, unsigned long qmask)
+/* Each queue region must be a power of 2 multiple of 64 bytes in
+ * size.  The base real address must be aligned to the size of the
+ * region.  Thus, an 8KB queue must be 8KB aligned, for example.
+ */
+static void __init alloc_one_queue(unsigned long *pa_ptr, unsigned long qmask)
 {
        unsigned long size = PAGE_ALIGN(qmask + 1);
-       void *p = __alloc_bootmem(size, size, 0);
+       unsigned long order = get_order(size);
+       unsigned long p;
 
+       p = __get_free_pages(GFP_KERNEL, order);
        if (!p) {
-               prom_printf("SUN4V: Error, cannot allocate kbuf page.\n");
+               prom_printf("SUN4V: Error, cannot allocate queue.\n");
                prom_halt();
        }
 
@@ -942,11 +935,11 @@ static void __init alloc_one_kbuf(unsigned long *pa_ptr, unsigned long qmask)
 static void __init init_cpu_send_mondo_info(struct trap_per_cpu *tb)
 {
 #ifdef CONFIG_SMP
-       void *page;
+       unsigned long page;
 
        BUILD_BUG_ON((NR_CPUS * sizeof(u16)) > (PAGE_SIZE - 64));
 
-       page = alloc_bootmem_pages(PAGE_SIZE);
+       page = get_zeroed_page(GFP_KERNEL);
        if (!page) {
                prom_printf("SUN4V: Error, cannot allocate cpu mondo page.\n");
                prom_halt();
@@ -965,13 +958,13 @@ static void __init sun4v_init_mondo_queues(void)
        for_each_possible_cpu(cpu) {
                struct trap_per_cpu *tb = &trap_block[cpu];
 
-               alloc_one_mondo(&tb->cpu_mondo_pa, tb->cpu_mondo_qmask);
-               alloc_one_mondo(&tb->dev_mondo_pa, tb->dev_mondo_qmask);
-               alloc_one_mondo(&tb->resum_mondo_pa, tb->resum_qmask);
-               alloc_one_kbuf(&tb->resum_kernel_buf_pa, tb->resum_qmask);
-               alloc_one_mondo(&tb->nonresum_mondo_pa, tb->nonresum_qmask);
-               alloc_one_kbuf(&tb->nonresum_kernel_buf_pa,
-                              tb->nonresum_qmask);
+               alloc_one_queue(&tb->cpu_mondo_pa, tb->cpu_mondo_qmask);
+               alloc_one_queue(&tb->dev_mondo_pa, tb->dev_mondo_qmask);
+               alloc_one_queue(&tb->resum_mondo_pa, tb->resum_qmask);
+               alloc_one_queue(&tb->resum_kernel_buf_pa, tb->resum_qmask);
+               alloc_one_queue(&tb->nonresum_mondo_pa, tb->nonresum_qmask);
+               alloc_one_queue(&tb->nonresum_kernel_buf_pa,
+                               tb->nonresum_qmask);
        }
 }
 
@@ -999,7 +992,7 @@ void __init init_IRQ(void)
        kill_prom_timer();
 
        size = sizeof(struct ino_bucket) * NUM_IVECS;
-       ivector_table = alloc_bootmem(size);
+       ivector_table = kzalloc(size, GFP_KERNEL);
        if (!ivector_table) {
                prom_printf("Fatal error, cannot allocate ivector_table\n");
                prom_halt();
index 8ce6285a06d55794b7a0ea68035ba65a0b39861e..7e3dfd9bb97ed677715adc641dc530e2c0d63c9b 100644 (file)
@@ -16,7 +16,6 @@
 #include <linux/ptrace.h>
 #include <linux/user.h>
 #include <linux/smp.h>
-#include <linux/smp_lock.h>
 #include <linux/security.h>
 #include <linux/signal.h>
 #include <linux/regset.h>
index a941c610e7ce0cdf8c38c38c5e3d46c32419114f..4ae91dc2feb9697c3a659aa7b993ca0636aadfb7 100644 (file)
@@ -17,7 +17,6 @@
 #include <linux/ptrace.h>
 #include <linux/user.h>
 #include <linux/smp.h>
-#include <linux/smp_lock.h>
 #include <linux/security.h>
 #include <linux/seccomp.h>
 #include <linux/audit.h>
index 5c12e79b4bdfe5ac1840e8e3fb30c911154f6476..da1218e8ee87a2beea896d93ec67401922623450 100644 (file)
@@ -11,7 +11,6 @@
 #include <linux/errno.h>
 #include <linux/module.h>
 #include <linux/sched.h>
-#include <linux/smp_lock.h>
 #include <linux/kernel.h>
 #include <linux/param.h>
 #include <linux/string.h>
index 358283341b4792945036fed4e32822733dd25227..c0490c7bbde0ffd187c6f0b1838108cbf9e5cd2e 100644 (file)
@@ -13,7 +13,6 @@
 #include <linux/kernel.h>
 #include <linux/signal.h>
 #include <linux/smp.h>
-#include <linux/smp_lock.h>
 #include <linux/kdebug.h>
 
 #include <asm/delay.h>
index 753d128ed15885ce6143d3c167859d00a5a3627f..c28c71449a6c72652706e49cf1897c639e2f441b 100644 (file)
@@ -224,7 +224,12 @@ static struct vio_dev *vio_create_one(struct mdesc_handle *hp, u64 mp,
        if (!strcmp(type, "domain-services-port"))
                bus_id_name = "ds";
 
-       if (strlen(bus_id_name) >= BUS_ID_SIZE - 4) {
+       /*
+        * 20 char is the old driver-core name size limit, which is no more.
+        * This check can probably be removed after review and possible
+        * adaption of the vio users name length handling.
+        */
+       if (strlen(bus_id_name) >= 20 - 4) {
                printk(KERN_ERR "VIO: bus_id_name [%s] is too long.\n",
                       bus_id_name);
                return NULL;
index 5ec17563142e22cc6f6ff1e3ec76db23666d3ec9..dd2aadc14af0ab6768723bc8fbade09e6c3203b3 100644 (file)
@@ -30,7 +30,6 @@ static void slip_init(struct net_device *dev, void *data)
 
        slip_proto_init(&spri->slip);
 
-       dev->init = NULL;
        dev->hard_header_len = 0;
        dev->header_ops = NULL;
        dev->addr_len = 0;
index f15a6e7654f36fdf17af6388172d8273ebb11f71..e376284f0fb7fdc42e1d1e026abe52408501f4d1 100644 (file)
@@ -32,7 +32,6 @@ void slirp_init(struct net_device *dev, void *data)
 
        slip_proto_init(&spri->slip);
 
-       dev->init = NULL;
        dev->hard_header_len = 0;
        dev->header_ops = NULL;
        dev->addr_len = 0;
index 90fc708b320e4c2a54425981bfb2d73b12a90ffe..378de4bbf49ff50486848893ad2a5454df69dd52 100644 (file)
@@ -79,14 +79,14 @@ dma_unmap_sg(struct device *dev, struct scatterlist *sg, int nhwentries,
 }
 
 static inline void
-dma_sync_single(struct device *dev, dma_addr_t dma_handle, size_t size,
+dma_sync_single_for_cpu(struct device *dev, dma_addr_t dma_handle, size_t size,
                enum dma_data_direction direction)
 {
        BUG();
 }
 
 static inline void
-dma_sync_sg(struct device *dev, struct scatterlist *sg, int nelems,
+dma_sync_sg_for_cpu(struct device *dev, struct scatterlist *sg, int nelems,
            enum dma_data_direction direction)
 {
        BUG();
index 62274ab9471fe6f8eb0de14368acf05b65e17691..fd911f855367a2d55506d7b002fce51cd2039ec2 100644 (file)
@@ -32,7 +32,7 @@ struct thread_info {
        .exec_domain =  &default_exec_domain,   \
        .flags =                0,              \
        .cpu =          0,                      \
-       .preempt_count =        1,              \
+       .preempt_count = INIT_PREEMPT_COUNT,    \
        .addr_limit =   KERNEL_DS,              \
        .restart_block =  {                     \
                .fn =  do_no_restart_syscall,   \
index 56d43d0a39602b140d458f2f989779bc9512b66a..0960de54495abf48e7f290c024cb3877f70e1c69 100644 (file)
@@ -70,8 +70,8 @@ void show_stack(struct task_struct *task, unsigned long *esp)
                if (kstack_end(stack))
                        break;
                if (i && ((i % 8) == 0))
-                       printk("\n" KERN_INFO "       ");
-               printk("%08lx ", *stack++);
+                       printk(KERN_INFO "       ");
+               printk(KERN_CONT "%08lx ", *stack++);
        }
 
        show_trace(task, esp);
index d1430ef6b4f9a463c7ddc3b7be49754f5fa883bd..738bdc6b0f8b8dcd938eddefa79beb4ed77e16f2 100644 (file)
@@ -1913,25 +1913,26 @@ config DMAR_DEFAULT_ON
          recommended you say N here while the DMAR code remains
          experimental.
 
-config DMAR_GFX_WA
-       def_bool y
-       prompt "Support for Graphics workaround"
+config DMAR_BROKEN_GFX_WA
+       def_bool n
+       prompt "Workaround broken graphics drivers (going away soon)"
        depends on DMAR
        ---help---
          Current Graphics drivers tend to use physical address
          for DMA and avoid using DMA APIs. Setting this config
          option permits the IOMMU driver to set a unity map for
          all the OS-visible memory. Hence the driver can continue
-         to use physical addresses for DMA.
+         to use physical addresses for DMA, at least until this
+         option is removed in the 2.6.32 kernel.
 
 config DMAR_FLOPPY_WA
        def_bool y
        depends on DMAR
        ---help---
-         Floppy disk drivers are know to bypass DMA API calls
+         Floppy disk drivers are known to bypass DMA API calls
          thereby failing to work when IOMMU is enabled. This
          workaround will setup a 1:1 mapping for the first
-         16M to make floppy (an ISA device) work.
+         16MiB to make floppy (an ISA device) work.
 
 config INTR_REMAP
        bool "Support for Interrupt Remapping (EXPERIMENTAL)"
index d660be4923634ebfc0160b468a569289c02bce90..49e0c18833e0d23361f218e3c67a51e171f600ed 100644 (file)
@@ -37,14 +37,13 @@ static int set_bios_mode(u8 mode)
        ireg.al = mode;         /* AH=0x00 Set Video Mode */
        intcall(0x10, &ireg, NULL);
 
-
        ireg.ah = 0x0f;         /* Get Current Video Mode */
        intcall(0x10, &ireg, &oreg);
 
        do_restore = 1;         /* Assume video contents were lost */
 
        /* Not all BIOSes are clean with the top bit */
-       new_mode = ireg.al & 0x7f;
+       new_mode = oreg.al & 0x7f;
 
        if (new_mode == mode)
                return 0;       /* Mode change OK */
index c700147d6ffb24b72fbbf43ff954d4cfd268f137..275dd177f1985719f239c10a148306c9c5995572 100644 (file)
@@ -45,7 +45,7 @@ static int vesa_probe(void)
        ireg.di = (size_t)&vginfo;
        intcall(0x10, &ireg, &oreg);
 
-       if (ireg.ax != 0x004f ||
+       if (oreg.ax != 0x004f ||
            vginfo.signature != VESA_MAGIC ||
            vginfo.version < 0x0102)
                return 0;       /* Not present */
@@ -70,7 +70,7 @@ static int vesa_probe(void)
                ireg.di = (size_t)&vminfo;
                intcall(0x10, &ireg, &oreg);
 
-               if (ireg.ax != 0x004f)
+               if (oreg.ax != 0x004f)
                        continue;
 
                if ((vminfo.mode_attr & 0x15) == 0x05) {
index 4518dc50090380b6676074b3f2466709ddea5a4b..20d1465a2ab046d8956eec43d5f5d4d36a3bd6bb 100644 (file)
@@ -144,6 +144,7 @@ static inline unsigned int acpi_processor_cstate_check(unsigned int max_cstate)
 
 #else /* !CONFIG_ACPI */
 
+#define acpi_disabled 1
 #define acpi_lapic 0
 #define acpi_ioapic 0
 static inline void acpi_noirq_set(void) { }
index 2503d4e64c2a79a2aab7618e9c325aadb428e74d..dc5a667ff791388074804ee547b92370c07f59c6 100644 (file)
  *
  * Atomically reads the value of @v.
  */
-#define atomic_read(v)         ((v)->counter)
+static inline int atomic_read(const atomic_t *v)
+{
+       return v->counter;
+}
 
 /**
  * atomic_set - set atomic variable
  *
  * Atomically sets the value of @v to @i.
  */
-#define atomic_set(v, i)       (((v)->counter) = (i))
+static inline void atomic_set(atomic_t *v, int i)
+{
+       v->counter = i;
+}
 
 /**
  * atomic_add - add integer to atomic variable
@@ -200,8 +206,15 @@ static inline int atomic_sub_return(int i, atomic_t *v)
        return atomic_add_return(-i, v);
 }
 
-#define atomic_cmpxchg(v, old, new) (cmpxchg(&((v)->counter), (old), (new)))
-#define atomic_xchg(v, new) (xchg(&((v)->counter), (new)))
+static inline int atomic_cmpxchg(atomic_t *v, int old, int new)
+{
+       return cmpxchg(&v->counter, old, new);
+}
+
+static inline int atomic_xchg(atomic_t *v, int new)
+{
+       return xchg(&v->counter, new);
+}
 
 /**
  * atomic_add_unless - add unless the number is already a given value
@@ -250,45 +263,12 @@ static inline int atomic_add_unless(atomic_t *v, int a, int u)
 /* An 64bit atomic type */
 
 typedef struct {
-       unsigned long long counter;
+       u64 __aligned(8) counter;
 } atomic64_t;
 
 #define ATOMIC64_INIT(val)     { (val) }
 
-/**
- * atomic64_read - read atomic64 variable
- * @ptr: pointer of type atomic64_t
- *
- * Atomically reads the value of @v.
- * Doesn't imply a read memory barrier.
- */
-#define __atomic64_read(ptr)           ((ptr)->counter)
-
-static inline unsigned long long
-cmpxchg8b(unsigned long long *ptr, unsigned long long old, unsigned long long new)
-{
-       asm volatile(
-
-               LOCK_PREFIX "cmpxchg8b (%[ptr])\n"
-
-                    :          "=A" (old)
-
-                    : [ptr]    "D" (ptr),
-                               "A" (old),
-                               "b" (ll_low(new)),
-                               "c" (ll_high(new))
-
-                    : "memory");
-
-       return old;
-}
-
-static inline unsigned long long
-atomic64_cmpxchg(atomic64_t *ptr, unsigned long long old_val,
-                unsigned long long new_val)
-{
-       return cmpxchg8b(&ptr->counter, old_val, new_val);
-}
+extern u64 atomic64_cmpxchg(atomic64_t *ptr, u64 old_val, u64 new_val);
 
 /**
  * atomic64_xchg - xchg atomic64 variable
@@ -298,18 +278,7 @@ atomic64_cmpxchg(atomic64_t *ptr, unsigned long long old_val,
  * Atomically xchgs the value of @ptr to @new_val and returns
  * the old value.
  */
-
-static inline unsigned long long
-atomic64_xchg(atomic64_t *ptr, unsigned long long new_val)
-{
-       unsigned long long old_val;
-
-       do {
-               old_val = atomic_read(ptr);
-       } while (atomic64_cmpxchg(ptr, old_val, new_val) != old_val);
-
-       return old_val;
-}
+extern u64 atomic64_xchg(atomic64_t *ptr, u64 new_val);
 
 /**
  * atomic64_set - set atomic64 variable
@@ -318,10 +287,7 @@ atomic64_xchg(atomic64_t *ptr, unsigned long long new_val)
  *
  * Atomically sets the value of @ptr to @new_val.
  */
-static inline void atomic64_set(atomic64_t *ptr, unsigned long long new_val)
-{
-       atomic64_xchg(ptr, new_val);
-}
+extern void atomic64_set(atomic64_t *ptr, u64 new_val);
 
 /**
  * atomic64_read - read atomic64 variable
@@ -329,17 +295,30 @@ static inline void atomic64_set(atomic64_t *ptr, unsigned long long new_val)
  *
  * Atomically reads the value of @ptr and returns it.
  */
-static inline unsigned long long atomic64_read(atomic64_t *ptr)
+static inline u64 atomic64_read(atomic64_t *ptr)
 {
-       unsigned long long curr_val;
-
-       do {
-               curr_val = __atomic64_read(ptr);
-       } while (atomic64_cmpxchg(ptr, curr_val, curr_val) != curr_val);
-
-       return curr_val;
+       u64 res;
+
+       /*
+        * Note, we inline this atomic64_t primitive because
+        * it only clobbers EAX/EDX and leaves the others
+        * untouched. We also (somewhat subtly) rely on the
+        * fact that cmpxchg8b returns the current 64-bit value
+        * of the memory location we are touching:
+        */
+       asm volatile(
+               "mov %%ebx, %%eax\n\t"
+               "mov %%ecx, %%edx\n\t"
+               LOCK_PREFIX "cmpxchg8b %1\n"
+                       : "=&A" (res)
+                       : "m" (*ptr)
+               );
+
+       return res;
 }
 
+extern u64 atomic64_read(atomic64_t *ptr);
+
 /**
  * atomic64_add_return - add and return
  * @delta: integer value to add
@@ -347,34 +326,14 @@ static inline unsigned long long atomic64_read(atomic64_t *ptr)
  *
  * Atomically adds @delta to @ptr and returns @delta + *@ptr
  */
-static inline unsigned long long
-atomic64_add_return(unsigned long long delta, atomic64_t *ptr)
-{
-       unsigned long long old_val, new_val;
-
-       do {
-               old_val = atomic_read(ptr);
-               new_val = old_val + delta;
-
-       } while (atomic64_cmpxchg(ptr, old_val, new_val) != old_val);
-
-       return new_val;
-}
-
-static inline long atomic64_sub_return(unsigned long long delta, atomic64_t *ptr)
-{
-       return atomic64_add_return(-delta, ptr);
-}
+extern u64 atomic64_add_return(u64 delta, atomic64_t *ptr);
 
-static inline long atomic64_inc_return(atomic64_t *ptr)
-{
-       return atomic64_add_return(1, ptr);
-}
-
-static inline long atomic64_dec_return(atomic64_t *ptr)
-{
-       return atomic64_sub_return(1, ptr);
-}
+/*
+ * Other variants with different arithmetic operators:
+ */
+extern u64 atomic64_sub_return(u64 delta, atomic64_t *ptr);
+extern u64 atomic64_inc_return(atomic64_t *ptr);
+extern u64 atomic64_dec_return(atomic64_t *ptr);
 
 /**
  * atomic64_add - add integer to atomic64 variable
@@ -383,10 +342,7 @@ static inline long atomic64_dec_return(atomic64_t *ptr)
  *
  * Atomically adds @delta to @ptr.
  */
-static inline void atomic64_add(unsigned long long delta, atomic64_t *ptr)
-{
-       atomic64_add_return(delta, ptr);
-}
+extern void atomic64_add(u64 delta, atomic64_t *ptr);
 
 /**
  * atomic64_sub - subtract the atomic64 variable
@@ -395,10 +351,7 @@ static inline void atomic64_add(unsigned long long delta, atomic64_t *ptr)
  *
  * Atomically subtracts @delta from @ptr.
  */
-static inline void atomic64_sub(unsigned long long delta, atomic64_t *ptr)
-{
-       atomic64_add(-delta, ptr);
-}
+extern void atomic64_sub(u64 delta, atomic64_t *ptr);
 
 /**
  * atomic64_sub_and_test - subtract value from variable and test result
@@ -409,13 +362,7 @@ static inline void atomic64_sub(unsigned long long delta, atomic64_t *ptr)
  * true if the result is zero, or false for all
  * other cases.
  */
-static inline int
-atomic64_sub_and_test(unsigned long long delta, atomic64_t *ptr)
-{
-       unsigned long long old_val = atomic64_sub_return(delta, ptr);
-
-       return old_val == 0;
-}
+extern int atomic64_sub_and_test(u64 delta, atomic64_t *ptr);
 
 /**
  * atomic64_inc - increment atomic64 variable
@@ -423,10 +370,7 @@ atomic64_sub_and_test(unsigned long long delta, atomic64_t *ptr)
  *
  * Atomically increments @ptr by 1.
  */
-static inline void atomic64_inc(atomic64_t *ptr)
-{
-       atomic64_add(1, ptr);
-}
+extern void atomic64_inc(atomic64_t *ptr);
 
 /**
  * atomic64_dec - decrement atomic64 variable
@@ -434,10 +378,7 @@ static inline void atomic64_inc(atomic64_t *ptr)
  *
  * Atomically decrements @ptr by 1.
  */
-static inline void atomic64_dec(atomic64_t *ptr)
-{
-       atomic64_sub(1, ptr);
-}
+extern void atomic64_dec(atomic64_t *ptr);
 
 /**
  * atomic64_dec_and_test - decrement and test
@@ -447,10 +388,7 @@ static inline void atomic64_dec(atomic64_t *ptr)
  * returns true if the result is 0, or false for all other
  * cases.
  */
-static inline int atomic64_dec_and_test(atomic64_t *ptr)
-{
-       return atomic64_sub_and_test(1, ptr);
-}
+extern int atomic64_dec_and_test(atomic64_t *ptr);
 
 /**
  * atomic64_inc_and_test - increment and test
@@ -460,10 +398,7 @@ static inline int atomic64_dec_and_test(atomic64_t *ptr)
  * and returns true if the result is zero, or false for all
  * other cases.
  */
-static inline int atomic64_inc_and_test(atomic64_t *ptr)
-{
-       return atomic64_sub_and_test(-1, ptr);
-}
+extern int atomic64_inc_and_test(atomic64_t *ptr);
 
 /**
  * atomic64_add_negative - add and test if negative
@@ -474,13 +409,7 @@ static inline int atomic64_inc_and_test(atomic64_t *ptr)
  * if the result is negative, or false when
  * result is greater than or equal to zero.
  */
-static inline int
-atomic64_add_negative(unsigned long long delta, atomic64_t *ptr)
-{
-       long long old_val = atomic64_add_return(delta, ptr);
-
-       return old_val < 0;
-}
+extern int atomic64_add_negative(u64 delta, atomic64_t *ptr);
 
 #include <asm-generic/atomic-long.h>
 #endif /* _ASM_X86_ATOMIC_32_H */
index 0d6360220007b2bc3a35952a7fa4830c837ad4af..d605dc268e798b5bb9e0a5df36de3e5aa88d0e5f 100644 (file)
  *
  * Atomically reads the value of @v.
  */
-#define atomic_read(v)         ((v)->counter)
+static inline int atomic_read(const atomic_t *v)
+{
+       return v->counter;
+}
 
 /**
  * atomic_set - set atomic variable
  *
  * Atomically sets the value of @v to @i.
  */
-#define atomic_set(v, i)               (((v)->counter) = (i))
+static inline void atomic_set(atomic_t *v, int i)
+{
+       v->counter = i;
+}
 
 /**
  * atomic_add - add integer to atomic variable
@@ -192,7 +198,10 @@ static inline int atomic_sub_return(int i, atomic_t *v)
  * Atomically reads the value of @v.
  * Doesn't imply a read memory barrier.
  */
-#define atomic64_read(v)               ((v)->counter)
+static inline long atomic64_read(const atomic64_t *v)
+{
+       return v->counter;
+}
 
 /**
  * atomic64_set - set atomic64 variable
@@ -201,7 +210,10 @@ static inline int atomic_sub_return(int i, atomic_t *v)
  *
  * Atomically sets the value of @v to @i.
  */
-#define atomic64_set(v, i)             (((v)->counter) = (i))
+static inline void atomic64_set(atomic64_t *v, long i)
+{
+       v->counter = i;
+}
 
 /**
  * atomic64_add - add integer to atomic64 variable
@@ -355,11 +367,25 @@ static inline long atomic64_sub_return(long i, atomic64_t *v)
 #define atomic64_inc_return(v)  (atomic64_add_return(1, (v)))
 #define atomic64_dec_return(v)  (atomic64_sub_return(1, (v)))
 
-#define atomic64_cmpxchg(v, old, new) (cmpxchg(&((v)->counter), (old), (new)))
-#define atomic64_xchg(v, new) (xchg(&((v)->counter), new))
+static inline long atomic64_cmpxchg(atomic64_t *v, long old, long new)
+{
+       return cmpxchg(&v->counter, old, new);
+}
+
+static inline long atomic64_xchg(atomic64_t *v, long new)
+{
+       return xchg(&v->counter, new);
+}
 
-#define atomic_cmpxchg(v, old, new) (cmpxchg(&((v)->counter), (old), (new)))
-#define atomic_xchg(v, new) (xchg(&((v)->counter), (new)))
+static inline long atomic_cmpxchg(atomic_t *v, int old, int new)
+{
+       return cmpxchg(&v->counter, old, new);
+}
+
+static inline long atomic_xchg(atomic_t *v, int new)
+{
+       return xchg(&v->counter, new);
+}
 
 /**
  * atomic_add_unless - add unless the number is a given value
index 418e632d4a801aa8e86f565afeae59659d6500a0..7a1065958ba9d3f1c5a26b9862864e4707418916 100644 (file)
@@ -8,7 +8,7 @@
 
 #ifdef __KERNEL__
 
-#include <asm/page_types.h>
+#include <asm/pgtable_types.h>
 
 /* Physical address where kernel should be loaded. */
 #define LOAD_PHYSICAL_ADDR ((CONFIG_PHYSICAL_START \
                                & ~(CONFIG_PHYSICAL_ALIGN - 1))
 
 /* Minimum kernel alignment, as a power of two */
-#ifdef CONFIG_x86_64
+#ifdef CONFIG_X86_64
 #define MIN_KERNEL_ALIGN_LG2   PMD_SHIFT
 #else
-#define MIN_KERNEL_ALIGN_LG2   (PAGE_SHIFT+1)
+#define MIN_KERNEL_ALIGN_LG2   (PAGE_SHIFT + THREAD_ORDER)
 #endif
 #define MIN_KERNEL_ALIGN       (_AC(1, UL) << MIN_KERNEL_ALIGN_LG2)
 
index 2d81af3974a070185ca672eb4bebf246d7eeaaa5..7b2d71df39a6ac42fc631628239f4f41c1be243b 100644 (file)
@@ -111,12 +111,9 @@ enum fixed_addresses {
 #ifdef CONFIG_PARAVIRT
        FIX_PARAVIRT_BOOTMAP,
 #endif
-       FIX_TEXT_POKE0, /* reserve 2 pages for text_poke() */
-       FIX_TEXT_POKE1,
+       FIX_TEXT_POKE1, /* reserve 2 pages for text_poke() */
+       FIX_TEXT_POKE0, /* first page is last, because allocation is backward */
        __end_of_permanent_fixed_addresses,
-#ifdef CONFIG_PROVIDE_OHCI1394_DMA_INIT
-       FIX_OHCI1394_BASE,
-#endif
        /*
         * 256 temporary boot-time mappings, used by early_ioremap(),
         * before ioremap() is functional.
@@ -129,6 +126,9 @@ enum fixed_addresses {
        FIX_BTMAP_END = __end_of_permanent_fixed_addresses + 256 -
                        (__end_of_permanent_fixed_addresses & 255),
        FIX_BTMAP_BEGIN = FIX_BTMAP_END + NR_FIX_BTMAPS*FIX_BTMAPS_SLOTS - 1,
+#ifdef CONFIG_PROVIDE_OHCI1394_DMA_INIT
+       FIX_OHCI1394_BASE,
+#endif
 #ifdef CONFIG_X86_32
        FIX_WP_TEST,
 #endif
index daf866ed0612413f3781cdf6f863e8038daebe85..330ee807f89e7e007a93d093c08b9108b3af22d0 100644 (file)
@@ -161,6 +161,7 @@ extern int io_apic_set_pci_routing(struct device *dev, int irq,
                 struct io_apic_irq_attr *irq_attr);
 extern int (*ioapic_renumber_irq)(int ioapic, int irq);
 extern void ioapic_init_mappings(void);
+extern void ioapic_insert_resources(void);
 
 extern struct IO_APIC_route_entry **alloc_ioapic_entries(void);
 extern void free_ioapic_entries(struct IO_APIC_route_entry **ioapic_entries);
@@ -180,6 +181,7 @@ extern void ioapic_write_entry(int apic, int pin,
 #define io_apic_assign_pci_irqs 0
 static const int timer_through_8259 = 0;
 static inline void ioapic_init_mappings(void)  { }
+static inline void ioapic_insert_resources(void) { }
 
 static inline void probe_nr_irqs_gsi(void)     { }
 #endif
index d31c4a684078080ebe48fbc4d90ebd7f67dce568..33600a66755ff9e8931695c1e5eada1e7bb530ac 100644 (file)
@@ -30,7 +30,7 @@
 #include <asm/hw_irq.h>
 #include <asm/kvm_para.h>
 
-/*G:031 But first, how does our Guest contact the Host to ask for privileged
+/*G:030 But first, how does our Guest contact the Host to ask for privileged
  * operations?  There are two ways: the direct way is to make a "hypercall",
  * to make requests of the Host Itself.
  *
index 1692fb5050e35e010e904c54043576ff83cff746..6be7fc254b599160e33c94112d37935fe3783d55 100644 (file)
 #define MSR_IA32_MISC_ENABLE_TURBO_DISABLE     (1ULL << 38)
 #define MSR_IA32_MISC_ENABLE_IP_PREF_DISABLE   (1ULL << 39)
 
-/* Intel Model 6 */
-#define MSR_P6_EVNTSEL0                        0x00000186
-#define MSR_P6_EVNTSEL1                        0x00000187
-
 /* P4/Xeon+ specific */
 #define MSR_IA32_MCG_EAX               0x00000180
 #define MSR_IA32_MCG_EBX               0x00000181
index c97264409934be915d24d35395c1c0af5956aa7b..c86e5ed4af51dc0802291eb4b4af1af9793b938b 100644 (file)
@@ -72,7 +72,6 @@ void lapic_watchdog_stop(void);
 int lapic_watchdog_init(unsigned nmi_hz);
 int lapic_wd_event(unsigned nmi_hz);
 unsigned lapic_adjust_nmi_hz(unsigned hz);
-int lapic_watchdog_ok(void);
 void disable_lapic_nmi_watchdog(void);
 void enable_lapic_nmi_watchdog(void);
 void stop_nmi(void);
index 927958d13c1967114ebba7ac6bd8bacc9ddbd56c..1ff685ca221ceec7fd324f6409393984aec4c399 100644 (file)
@@ -91,7 +91,7 @@ extern void pci_iommu_alloc(void);
 
 #define PCI_DMA_BUS_IS_PHYS (dma_ops->is_phys)
 
-#if defined(CONFIG_X86_64) || defined(CONFIG_DMA_API_DEBUG)
+#if defined(CONFIG_X86_64) || defined(CONFIG_DMAR) || defined(CONFIG_DMA_API_DEBUG)
 
 #define DECLARE_PCI_UNMAP_ADDR(ADDR_NAME)       \
                dma_addr_t ADDR_NAME;
index cb739cc0a08063729fb239d4d6a254f6aee08625..b399988eee3a3105e60be5fe760089d6cf57d3f0 100644 (file)
@@ -25,7 +25,7 @@
 #define PCI_BIOS_IRQ_SCAN      0x2000
 #define PCI_ASSIGN_ALL_BUSSES  0x4000
 #define PCI_CAN_SKIP_ISA_ALIGN 0x8000
-#define PCI_NO_ROOT_CRS                0x10000
+#define PCI_USE__CRS           0x10000
 #define PCI_CHECK_ENABLE_AMD_MMCONF    0x20000
 #define PCI_HAS_IO_ECS         0x40000
 #define PCI_NOASSIGN_ROMS      0x80000
@@ -121,6 +121,9 @@ extern int __init pcibios_init(void);
 extern int __init pci_mmcfg_arch_init(void);
 extern void __init pci_mmcfg_arch_free(void);
 
+extern struct acpi_mcfg_allocation *pci_mmcfg_config;
+extern int pci_mmcfg_config_num;
+
 /*
  * AMD Fam10h CPUs are buggy, and cannot access MMIO config space
  * on their northbrige except through the * %eax register. As such, you MUST
index 02ecb30982a3a61d5e655b70d3599b9a2540dd3b..103f1ddb0d85b342498beef4153267a3af93f0a0 100644 (file)
@@ -42,6 +42,7 @@
 
 #else /* ...!ASSEMBLY */
 
+#include <linux/kernel.h>
 #include <linux/stringify.h>
 
 #ifdef CONFIG_SMP
@@ -155,6 +156,15 @@ do {                                                       \
 /* We can use this directly for local CPU (faster). */
 DECLARE_PER_CPU(unsigned long, this_cpu_off);
 
+#ifdef CONFIG_NEED_MULTIPLE_NODES
+void *pcpu_lpage_remapped(void *kaddr);
+#else
+static inline void *pcpu_lpage_remapped(void *kaddr)
+{
+       return NULL;
+}
+#endif
+
 #endif /* !__ASSEMBLY__ */
 
 #ifdef CONFIG_SMP
index 5fb33e160ea0b585b065b726ede5a855bfa22df7..fa64e401589d4ed9089c908f06c3bef2261c4d9f 100644 (file)
@@ -87,6 +87,9 @@ union cpuid10_edx {
 #ifdef CONFIG_PERF_COUNTERS
 extern void init_hw_perf_counters(void);
 extern void perf_counters_lapic_init(void);
+
+#define PERF_COUNTER_INDEX_OFFSET                      0
+
 #else
 static inline void init_hw_perf_counters(void)         { }
 static inline void perf_counters_lapic_init(void)      { }
index 49fb3ecf3bb341208a45935203d121ef60eba4d0..621f56d731212748902e2ba2f3436d84985395e2 100644 (file)
@@ -22,7 +22,14 @@ extern int reboot_force;
 
 long do_arch_prctl(struct task_struct *task, int code, unsigned long addr);
 
-#define round_up(x, y) (((x) + (y) - 1) & ~((y) - 1))
-#define round_down(x, y) ((x) & ~((y) - 1))
+/*
+ * This looks more complex than it should be. But we need to
+ * get the type for the ~ right in round_down (it needs to be
+ * as wide as the result!), and we want to evaluate the macro
+ * arguments just once each.
+ */
+#define __round_mask(x,y) ((__typeof__(x))((y)-1))
+#define round_up(x,y) ((((x)-1) | __round_mask(x,y))+1)
+#define round_down(x,y) ((x) & ~__round_mask(x,y))
 
 #endif /* _ASM_X86_PROTO_H */
index b7e5db8763994cf3164ecf8273f7ec725be9215c..4e77853321dbcca412c52cf35c437bbff2442af8 100644 (file)
@@ -302,4 +302,8 @@ static inline void __raw_write_unlock(raw_rwlock_t *rw)
 #define _raw_read_relax(lock)  cpu_relax()
 #define _raw_write_relax(lock) cpu_relax()
 
+/* The {read|write|spin}_lock() on x86 are full memory barriers. */
+static inline void smp_mb__after_lock(void) { }
+#define ARCH_HAS_SMP_MB_AFTER_LOCK
+
 #endif /* _ASM_X86_SPINLOCK_H */
index f517944b2b176618f51d9791adb9fed4f08864ae..cf86a5e73815dde6fb2e0fa997b8628555584063 100644 (file)
@@ -3,6 +3,8 @@
 
 extern int kstack_depth_to_print;
 
+int x86_is_stack_id(int id, char *name);
+
 /* Generic stack tracer with callbacks */
 
 struct stacktrace_ops {
index b0783520988b8bba544ad79dc38d4ea4580876f6..fad7d40b75f898e8a3651265f573c313a479c4ea 100644 (file)
@@ -49,7 +49,7 @@ struct thread_info {
        .exec_domain    = &default_exec_domain, \
        .flags          = 0,                    \
        .cpu            = 0,                    \
-       .preempt_count  = 1,                    \
+       .preempt_count  = INIT_PREEMPT_COUNT,   \
        .addr_limit     = KERNEL_DS,            \
        .restart_block = {                      \
                .fn = do_no_restart_syscall,    \
index 6c327b852e23b528963dc4f23e59ffa13761463d..430d5b24af7b210faf695f0c3619a1d66ae8acf5 100644 (file)
@@ -26,6 +26,8 @@ CFLAGS_tsc.o          := $(nostackp)
 CFLAGS_paravirt.o      := $(nostackp)
 GCOV_PROFILE_vsyscall_64.o     := n
 GCOV_PROFILE_hpet.o            := n
+GCOV_PROFILE_tsc.o             := n
+GCOV_PROFILE_paravirt.o                := n
 
 obj-y                  := process_$(BITS).o signal.o entry_$(BITS).o
 obj-y                  += traps.o irq.o irq_$(BITS).o dumpstack_$(BITS).o
index 631086159c53b0be5f28df92d3e2ed976cffa7a8..6b8ca3a0285d77512219724750bca449fa3a8a67 100644 (file)
 
 static int __initdata acpi_force = 0;
 u32 acpi_rsdt_forced;
-#ifdef CONFIG_ACPI
-int acpi_disabled = 0;
-#else
-int acpi_disabled = 1;
-#endif
+int acpi_disabled;
 EXPORT_SYMBOL(acpi_disabled);
 
 #ifdef CONFIG_X86_64
@@ -122,72 +118,6 @@ void __init __acpi_unmap_table(char *map, unsigned long size)
        early_iounmap(map, size);
 }
 
-#ifdef CONFIG_PCI_MMCONFIG
-
-static int acpi_mcfg_64bit_base_addr __initdata = FALSE;
-
-/* The physical address of the MMCONFIG aperture.  Set from ACPI tables. */
-struct acpi_mcfg_allocation *pci_mmcfg_config;
-int pci_mmcfg_config_num;
-
-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;
-}
-
-int __init acpi_parse_mcfg(struct acpi_table_header *header)
-{
-       struct acpi_table_mcfg *mcfg;
-       unsigned long i;
-       int config_size;
-
-       if (!header)
-               return -EINVAL;
-
-       mcfg = (struct acpi_table_mcfg *)header;
-
-       /* how many config structures do we have */
-       pci_mmcfg_config_num = 0;
-       i = header->length - sizeof(struct acpi_table_mcfg);
-       while (i >= sizeof(struct acpi_mcfg_allocation)) {
-               ++pci_mmcfg_config_num;
-               i -= sizeof(struct acpi_mcfg_allocation);
-       };
-       if (pci_mmcfg_config_num == 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;
-                       return -ENODEV;
-               }
-       }
-
-       return 0;
-}
-#endif                         /* CONFIG_PCI_MMCONFIG */
-
 #ifdef CONFIG_X86_LOCAL_APIC
 static int __init acpi_parse_madt(struct acpi_table_header *table)
 {
@@ -1517,14 +1447,6 @@ static struct dmi_system_id __initdata acpi_dmi_table[] = {
                     DMI_MATCH(DMI_PRODUCT_NAME, "Workstation W8000"),
                     },
         },
-       {
-        .callback = force_acpi_ht,
-        .ident = "ASUS P4B266",
-        .matches = {
-                    DMI_MATCH(DMI_BOARD_VENDOR, "ASUSTeK Computer INC."),
-                    DMI_MATCH(DMI_BOARD_NAME, "P4B266"),
-                    },
-        },
        {
         .callback = force_acpi_ht,
         .ident = "ASUS P2B-DS",
index bbbe4bbb6f34b7ed8bf60cf849faa32963e93d90..8c44c232efcb9f2b1150b4f58a0942bf9dd3ac0a 100644 (file)
@@ -34,12 +34,22 @@ void acpi_processor_power_init_bm_check(struct acpi_processor_flags *flags,
                flags->bm_check = 1;
        else if (c->x86_vendor == X86_VENDOR_INTEL) {
                /*
-                * Today all CPUs that support C3 share cache.
-                * TBD: This needs to look at cache shared map, once
-                * multi-core detection patch makes to the base.
+                * Today all MP CPUs that support C3 share cache.
+                * And caches should not be flushed by software while
+                * entering C3 type state.
                 */
                flags->bm_check = 1;
        }
+
+       /*
+        * On all recent Intel platforms, ARB_DISABLE is a nop.
+        * So, set bm_control to zero to indicate that ARB_DISABLE
+        * is not required while entering C3 type state on
+        * P4, Core and beyond CPUs
+        */
+       if (c->x86_vendor == X86_VENDOR_INTEL &&
+           (c->x86 > 0x6 || (c->x86 == 6 && c->x86_model >= 14)))
+                       flags->bm_control = 0;
 }
 EXPORT_SYMBOL(acpi_processor_power_init_bm_check);
 
index 7c074eec39fb56ebff16c26f3351b6eae79cca50..d296f4a195c916d8d454c144396ecc1f71af91d2 100644 (file)
@@ -72,6 +72,7 @@ static void init_intel_pdc(struct acpi_processor *pr, struct cpuinfo_x86 *c)
        return;
 }
 
+
 /* Initialize _PDC data based on the CPU vendor */
 void arch_acpi_processor_init_pdc(struct acpi_processor *pr)
 {
@@ -85,3 +86,15 @@ void arch_acpi_processor_init_pdc(struct acpi_processor *pr)
 }
 
 EXPORT_SYMBOL(arch_acpi_processor_init_pdc);
+
+void arch_acpi_processor_cleanup_pdc(struct acpi_processor *pr)
+{
+       if (pr->pdc) {
+               kfree(pr->pdc->pointer->buffer.pointer);
+               kfree(pr->pdc->pointer);
+               kfree(pr->pdc);
+               pr->pdc = NULL;
+       }
+}
+
+EXPORT_SYMBOL(arch_acpi_processor_cleanup_pdc);
index 9372f0406ad4a51d654ce2a1dae5c41f7b3bf48e..6c99f5037801302fc60da447ce414a3179fad3eb 100644 (file)
@@ -1192,7 +1192,7 @@ out:
        return 0;
 }
 
-struct notifier_block device_nb = {
+static struct notifier_block device_nb = {
        .notifier_call = device_change_notifier,
 };
 
@@ -1763,7 +1763,7 @@ static void *alloc_coherent(struct device *dev, size_t size,
        flag |= __GFP_ZERO;
        virt_addr = (void *)__get_free_pages(flag, get_order(size));
        if (!virt_addr)
-               return 0;
+               return NULL;
 
        paddr = virt_to_phys(virt_addr);
 
index 10b2accd12ea5983d917b0646cf445f9c8fe8b93..c1b17e97252e08f89f2221c2228642e0ff3dad81 100644 (file)
@@ -472,6 +472,8 @@ static u8 * __init alloc_event_buffer(struct amd_iommu *iommu)
        if (iommu->evt_buf == NULL)
                return NULL;
 
+       iommu->evt_buf_size = EVT_BUFFER_SIZE;
+
        return iommu->evt_buf;
 }
 
@@ -691,6 +693,7 @@ static void __init init_iommu_from_acpi(struct amd_iommu *iommu,
 
                        devid = e->devid;
                        devid_to = e->ext >> 8;
+                       set_dev_entry_from_acpi(iommu, devid   , e->flags, 0);
                        set_dev_entry_from_acpi(iommu, devid_to, e->flags, 0);
                        amd_iommu_alias_table[devid] = devid_to;
                        break;
@@ -749,11 +752,13 @@ static void __init init_iommu_from_acpi(struct amd_iommu *iommu,
 
                        devid = e->devid;
                        for (dev_i = devid_start; dev_i <= devid; ++dev_i) {
-                               if (alias)
+                               if (alias) {
                                        amd_iommu_alias_table[dev_i] = devid_to;
-                               set_dev_entry_from_acpi(iommu,
-                                               amd_iommu_alias_table[dev_i],
-                                               flags, ext_flags);
+                                       set_dev_entry_from_acpi(iommu,
+                                               devid_to, flags, ext_flags);
+                               }
+                               set_dev_entry_from_acpi(iommu, dev_i,
+                                                       flags, ext_flags);
                        }
                        break;
                default:
index 8c7c042ecad1eeb406caa0b5fa6605f7d6c7a04a..0a1c2830ec662168a72c1e6780b4f4c8c10075ed 100644 (file)
@@ -140,7 +140,6 @@ int x2apic_mode;
 #ifdef CONFIG_X86_X2APIC
 /* x2apic enabled before OS handover */
 static int x2apic_preenabled;
-static int disable_x2apic;
 static __init int setup_nox2apic(char *str)
 {
        if (x2apic_enabled()) {
@@ -149,7 +148,6 @@ static __init int setup_nox2apic(char *str)
                return 0;
        }
 
-       disable_x2apic = 1;
        setup_clear_cpu_cap(X86_FEATURE_X2APIC);
        return 0;
 }
index 69328ac8de9c86e106d30af1337a80ab0d4488b1..8952a5890281cc363094cc2f67fed1159e6d7674 100644 (file)
@@ -652,7 +652,8 @@ static int es7000_mps_oem_check_cluster(struct mpc_table *mpc, char *oem,
        return ret && es7000_apic_is_cluster();
 }
 
-struct apic apic_es7000_cluster = {
+/* We've been warned by a false positive warning.Use __refdata to keep calm. */
+struct apic __refdata apic_es7000_cluster = {
 
        .name                           = "es7000",
        .probe                          = probe_es7000,
index b7a79207295ee05e0f4ecb34e3863d96e330cd1d..2284a4812b68cfb83ab987388d058004ccb5ee55 100644 (file)
@@ -1414,6 +1414,9 @@ int setup_ioapic_entry(int apic_id, int irq,
                irte.vector = vector;
                irte.dest_id = IRTE_DEST(destination);
 
+               /* Set source-id of interrupt request */
+               set_ioapic_sid(&irte, apic_id);
+
                modify_irte(irq, &irte);
 
                ir_entry->index2 = (index >> 15) & 0x1;
@@ -1713,25 +1716,19 @@ __apicdebuginit(void) print_IO_APIC(void)
        return;
 }
 
-__apicdebuginit(void) print_APIC_bitfield(int base)
+__apicdebuginit(void) print_APIC_field(int base)
 {
-       unsigned int v;
-       int i, j;
+       int i;
 
        if (apic_verbosity == APIC_QUIET)
                return;
 
-       printk(KERN_DEBUG "0123456789abcdef0123456789abcdef\n" KERN_DEBUG);
-       for (i = 0; i < 8; i++) {
-               v = apic_read(base + i*0x10);
-               for (j = 0; j < 32; j++) {
-                       if (v & (1<<j))
-                               printk("1");
-                       else
-                               printk("0");
-               }
-               printk("\n");
-       }
+       printk(KERN_DEBUG);
+
+       for (i = 0; i < 8; i++)
+               printk(KERN_CONT "%08x", apic_read(base + i*0x10));
+
+       printk(KERN_CONT "\n");
 }
 
 __apicdebuginit(void) print_local_APIC(void *dummy)
@@ -1742,7 +1739,7 @@ __apicdebuginit(void) print_local_APIC(void *dummy)
        if (apic_verbosity == APIC_QUIET)
                return;
 
-       printk("\n" KERN_DEBUG "printing local APIC contents on CPU#%d/%d:\n",
+       printk(KERN_DEBUG "printing local APIC contents on CPU#%d/%d:\n",
                smp_processor_id(), hard_smp_processor_id());
        v = apic_read(APIC_ID);
        printk(KERN_INFO "... APIC ID:      %08x (%01x)\n", v, read_apic_id());
@@ -1783,11 +1780,11 @@ __apicdebuginit(void) print_local_APIC(void *dummy)
        printk(KERN_DEBUG "... APIC SPIV: %08x\n", v);
 
        printk(KERN_DEBUG "... APIC ISR field:\n");
-       print_APIC_bitfield(APIC_ISR);
+       print_APIC_field(APIC_ISR);
        printk(KERN_DEBUG "... APIC TMR field:\n");
-       print_APIC_bitfield(APIC_TMR);
+       print_APIC_field(APIC_TMR);
        printk(KERN_DEBUG "... APIC IRR field:\n");
-       print_APIC_bitfield(APIC_IRR);
+       print_APIC_field(APIC_IRR);
 
        if (APIC_INTEGRATED(ver)) {             /* !82489DX */
                if (maxlvt > 3)         /* Due to the Pentium erratum 3AP. */
@@ -3290,6 +3287,9 @@ static int msi_compose_msg(struct pci_dev *pdev, unsigned int irq, struct msi_ms
                irte.vector = cfg->vector;
                irte.dest_id = IRTE_DEST(dest);
 
+               /* Set source-id of interrupt request */
+               set_msi_sid(&irte, pdev);
+
                modify_irte(irq, &irte);
 
                msg->address_hi = MSI_ADDR_BASE_HI;
@@ -4181,28 +4181,20 @@ fake_ioapic_page:
        }
 }
 
-static int __init ioapic_insert_resources(void)
+void __init ioapic_insert_resources(void)
 {
        int i;
        struct resource *r = ioapic_resources;
 
        if (!r) {
-               if (nr_ioapics > 0) {
+               if (nr_ioapics > 0)
                        printk(KERN_ERR
                                "IO APIC resources couldn't be allocated.\n");
-                       return -1;
-               }
-               return 0;
+               return;
        }
 
        for (i = 0; i < nr_ioapics; i++) {
                insert_resource(&iomem_resource, r);
                r++;
        }
-
-       return 0;
 }
-
-/* Insert the IO APIC resources after PCI initialization has occured to handle
- * IO APICS that are mapped in on a BAR in PCI space. */
-late_initcall(ioapic_insert_resources);
index 533e59c6fc823a7bb3813cedb74f921765b5d434..ca96e68f0d23230efb4aa74e3227d9d584d4a237 100644 (file)
@@ -493,7 +493,8 @@ static void numaq_setup_portio_remap(void)
                (u_long) xquad_portio, (u_long) num_quads*XQUAD_PORTIO_QUAD);
 }
 
-struct apic apic_numaq = {
+/* Use __refdata to keep false positive warning calm.  */
+struct apic __refdata apic_numaq = {
 
        .name                           = "NUMAQ",
        .probe                          = probe_numaq,
index e5b27d8f1b47395fda285d867b776e82454ae61a..28e5f59560429a7bb754a1dca7cb93935d481e07 100644 (file)
@@ -258,13 +258,15 @@ static void __cpuinit amd_detect_cmp(struct cpuinfo_x86 *c)
 {
 #ifdef CONFIG_X86_HT
        unsigned bits;
+       int cpu = smp_processor_id();
 
        bits = c->x86_coreid_bits;
-
        /* Low order bits define the core id (index of core in socket) */
        c->cpu_core_id = c->initial_apicid & ((1 << bits)-1);
        /* Convert the initial APIC ID into the socket ID */
        c->phys_proc_id = c->initial_apicid >> bits;
+       /* use socket ID also for last level cache */
+       per_cpu(cpu_llc_id, cpu) = c->phys_proc_id;
 #endif
 }
 
index 6b26d4deada0ce19917e393badd4e8e785259df7..f1961c07af9a684b0fd15ad1636ef21dbf1d31ac 100644 (file)
@@ -848,9 +848,6 @@ static void __cpuinit identify_cpu(struct cpuinfo_x86 *c)
 #if defined(CONFIG_NUMA) && defined(CONFIG_X86_64)
        numa_add_cpu(smp_processor_id());
 #endif
-
-       /* Cap the iomem address space to what is addressable on all CPUs */
-       iomem_resource.end &= (1ULL << c->x86_phys_bits) - 1;
 }
 
 #ifdef CONFIG_X86_64
index 81cbe64ed6b49a79e8e3aa8b339a6a8b4cf2d202..2a50ef891000f3c114374c1a28bdbf4f26a36d67 100644 (file)
@@ -299,7 +299,7 @@ static int transition_pstate(struct powernow_k8_data *data, u32 pstate)
 static int transition_fid_vid(struct powernow_k8_data *data,
                u32 reqfid, u32 reqvid)
 {
-       if (core_voltage_pre_transition(data, reqvid))
+       if (core_voltage_pre_transition(data, reqvid, reqfid))
                return 1;
 
        if (core_frequency_transition(data, reqfid))
@@ -327,17 +327,20 @@ static int transition_fid_vid(struct powernow_k8_data *data,
 
 /* Phase 1 - core voltage transition ... setup voltage */
 static int core_voltage_pre_transition(struct powernow_k8_data *data,
-               u32 reqvid)
+               u32 reqvid, u32 reqfid)
 {
        u32 rvosteps = data->rvo;
        u32 savefid = data->currfid;
-       u32 maxvid, lo;
+       u32 maxvid, lo, rvomult = 1;
 
        dprintk("ph1 (cpu%d): start, currfid 0x%x, currvid 0x%x, "
                "reqvid 0x%x, rvo 0x%x\n",
                smp_processor_id(),
                data->currfid, data->currvid, reqvid, data->rvo);
 
+       if ((savefid < LO_FID_TABLE_TOP) && (reqfid < LO_FID_TABLE_TOP))
+               rvomult = 2;
+       rvosteps *= rvomult;
        rdmsr(MSR_FIDVID_STATUS, lo, maxvid);
        maxvid = 0x1f & (maxvid >> 16);
        dprintk("ph1 maxvid=0x%x\n", maxvid);
@@ -351,7 +354,8 @@ static int core_voltage_pre_transition(struct powernow_k8_data *data,
                        return 1;
        }
 
-       while ((rvosteps > 0) && ((data->rvo + data->currvid) > reqvid)) {
+       while ((rvosteps > 0) &&
+                       ((rvomult * data->rvo + data->currvid) > reqvid)) {
                if (data->currvid == maxvid) {
                        rvosteps = 0;
                } else {
@@ -384,13 +388,6 @@ static int core_frequency_transition(struct powernow_k8_data *data, u32 reqfid)
        u32 vcoreqfid, vcocurrfid, vcofiddiff;
        u32 fid_interval, savevid = data->currvid;
 
-       if ((reqfid < HI_FID_TABLE_BOTTOM) &&
-           (data->currfid < HI_FID_TABLE_BOTTOM)) {
-               printk(KERN_ERR PFX "ph2: illegal lo-lo transition "
-                               "0x%x 0x%x\n", reqfid, data->currfid);
-               return 1;
-       }
-
        if (data->currfid == reqfid) {
                printk(KERN_ERR PFX "ph2 null fid transition 0x%x\n",
                                data->currfid);
@@ -407,6 +404,9 @@ static int core_frequency_transition(struct powernow_k8_data *data, u32 reqfid)
        vcofiddiff = vcocurrfid > vcoreqfid ? vcocurrfid - vcoreqfid
            : vcoreqfid - vcocurrfid;
 
+       if ((reqfid <= LO_FID_TABLE_TOP) && (data->currfid <= LO_FID_TABLE_TOP))
+               vcofiddiff = 0;
+
        while (vcofiddiff > 2) {
                (data->currfid & 1) ? (fid_interval = 1) : (fid_interval = 2);
 
@@ -1081,14 +1081,6 @@ static int transition_frequency_fidvid(struct powernow_k8_data *data,
                return 0;
        }
 
-       if ((fid < HI_FID_TABLE_BOTTOM) &&
-           (data->currfid < HI_FID_TABLE_BOTTOM)) {
-               printk(KERN_ERR PFX
-                      "ignoring illegal change in lo freq table-%x to 0x%x\n",
-                      data->currfid, fid);
-               return 1;
-       }
-
        dprintk("cpu %d, changing to fid 0x%x, vid 0x%x\n",
                smp_processor_id(), fid, vid);
        freqs.old = find_khz_freq_from_fid(data->currfid);
@@ -1267,7 +1259,7 @@ static int __cpuinit powernowk8_cpu_init(struct cpufreq_policy *pol)
 {
        static const char ACPI_PSS_BIOS_BUG_MSG[] =
                KERN_ERR FW_BUG PFX "No compatible ACPI _PSS objects found.\n"
-               KERN_ERR FW_BUG PFX "Try again with latest BIOS.\n";
+               FW_BUG PFX "Try again with latest BIOS.\n";
        struct powernow_k8_data *data;
        struct init_on_cpu init_on_cpu;
        int rc;
index c9c1190b5e1f057fb30652132225443c2ba2da58..02ce824073cb9463e33e0fb5a32d7f7e60814b2f 100644 (file)
@@ -215,7 +215,8 @@ struct pst_s {
 
 #define dprintk(msg...) cpufreq_debug_printk(CPUFREQ_DEBUG_DRIVER, "powernow-k8", msg)
 
-static int core_voltage_pre_transition(struct powernow_k8_data *data, u32 reqvid);
+static int core_voltage_pre_transition(struct powernow_k8_data *data,
+       u32 reqvid, u32 regfid);
 static int core_voltage_post_transition(struct powernow_k8_data *data, u32 reqvid);
 static int core_frequency_transition(struct powernow_k8_data *data, u32 reqfid);
 
index 284d1de968bc3e1f2867eb2f3ca8cedf9338e1f6..484c1e5f658e6b5d932566cd41f7813c44d00b71 100644 (file)
@@ -194,14 +194,14 @@ static void print_mce(struct mce *m)
                       m->cs, m->ip);
                if (m->cs == __KERNEL_CS)
                        print_symbol("{%s}", m->ip);
-               printk("\n");
+               printk(KERN_CONT "\n");
        }
        printk(KERN_EMERG "TSC %llx ", m->tsc);
        if (m->addr)
-               printk("ADDR %llx ", m->addr);
+               printk(KERN_CONT "ADDR %llx ", m->addr);
        if (m->misc)
-               printk("MISC %llx ", m->misc);
-       printk("\n");
+               printk(KERN_CONT "MISC %llx ", m->misc);
+       printk(KERN_CONT "\n");
        printk(KERN_EMERG "PROCESSOR %u:%x TIME %llu SOCKET %u APIC %x\n",
                        m->cpuvendor, m->cpuid, m->time, m->socketid,
                        m->apicid);
@@ -209,13 +209,13 @@ static void print_mce(struct mce *m)
 
 static void print_mce_head(void)
 {
-       printk(KERN_EMERG "\n" KERN_EMERG "HARDWARE ERROR\n");
+       printk(KERN_EMERG "\nHARDWARE ERROR\n");
 }
 
 static void print_mce_tail(void)
 {
        printk(KERN_EMERG "This is not a software problem!\n"
-              KERN_EMERG "Run through mcelog --ascii to decode and contact your hardware vendor\n");
+              "Run through mcelog --ascii to decode and contact your hardware vendor\n");
 }
 
 #define PANIC_TIMEOUT 5 /* 5 seconds */
@@ -1117,7 +1117,7 @@ static void mcheck_timer(unsigned long data)
                *n = min(*n*2, (int)round_jiffies_relative(check_interval*HZ));
 
        t->expires = jiffies + *n;
-       add_timer(t);
+       add_timer_on(t, smp_processor_id());
 }
 
 static void mce_do_trigger(struct work_struct *work)
@@ -1321,7 +1321,7 @@ static void mce_init_timer(void)
                return;
        setup_timer(t, mcheck_timer, smp_processor_id());
        t->expires = round_jiffies(jiffies + *n);
-       add_timer(t);
+       add_timer_on(t, smp_processor_id());
 }
 
 /*
index 76dfef23f78957aa4e17d3337d5dc5221bd18ade..36c3dc7b8991d4a5b7ea8709c9003b161c058d6f 100644 (file)
@@ -401,7 +401,7 @@ static const u64 amd_hw_cache_event_ids
                [ C(RESULT_MISS)   ] = 0x0041, /* Data Cache Misses          */
        },
        [ C(OP_WRITE) ] = {
-               [ C(RESULT_ACCESS) ] = 0x0042, /* Data Cache Refills from L2 */
+               [ C(RESULT_ACCESS) ] = 0x0142, /* Data Cache Refills :system */
                [ C(RESULT_MISS)   ] = 0,
        },
        [ C(OP_PREFETCH) ] = {
@@ -912,6 +912,8 @@ x86_perf_counter_set_period(struct perf_counter *counter,
        err = checking_wrmsrl(hwc->counter_base + idx,
                             (u64)(-left) & x86_pmu.counter_mask);
 
+       perf_counter_update_userpage(counter);
+
        return ret;
 }
 
@@ -969,13 +971,6 @@ fixed_mode_idx(struct perf_counter *counter, struct hw_perf_counter *hwc)
        if (!x86_pmu.num_counters_fixed)
                return -1;
 
-       /*
-        * Quirk, IA32_FIXED_CTRs do not work on current Atom processors:
-        */
-       if (boot_cpu_data.x86_vendor == X86_VENDOR_INTEL &&
-                                       boot_cpu_data.x86_model == 28)
-               return -1;
-
        event = hwc->config & ARCH_PERFMON_EVENT_MASK;
 
        if (unlikely(event == x86_pmu.event_map(PERF_COUNT_HW_INSTRUCTIONS)))
@@ -1041,6 +1036,8 @@ try_generic:
        x86_perf_counter_set_period(counter, hwc, idx);
        x86_pmu.enable(hwc, idx);
 
+       perf_counter_update_userpage(counter);
+
        return 0;
 }
 
@@ -1133,6 +1130,8 @@ static void x86_pmu_disable(struct perf_counter *counter)
        x86_perf_counter_update(counter, hwc, idx);
        cpuc->counters[idx] = NULL;
        clear_bit(idx, cpuc->used_mask);
+
+       perf_counter_update_userpage(counter);
 }
 
 /*
@@ -1428,8 +1427,6 @@ static int intel_pmu_init(void)
         */
        x86_pmu.num_counters_fixed      = max((int)edx.split.num_counters_fixed, 3);
 
-       rdmsrl(MSR_CORE_PERF_GLOBAL_CTRL, x86_pmu.intel_ctrl);
-
        /*
         * Install the hw-cache-events table:
         */
@@ -1499,21 +1496,22 @@ void __init init_hw_perf_counters(void)
        pr_cont("%s PMU driver.\n", x86_pmu.name);
 
        if (x86_pmu.num_counters > X86_PMC_MAX_GENERIC) {
-               x86_pmu.num_counters = X86_PMC_MAX_GENERIC;
                WARN(1, KERN_ERR "hw perf counters %d > max(%d), clipping!",
                     x86_pmu.num_counters, X86_PMC_MAX_GENERIC);
+               x86_pmu.num_counters = X86_PMC_MAX_GENERIC;
        }
        perf_counter_mask = (1 << x86_pmu.num_counters) - 1;
        perf_max_counters = x86_pmu.num_counters;
 
        if (x86_pmu.num_counters_fixed > X86_PMC_MAX_FIXED) {
-               x86_pmu.num_counters_fixed = X86_PMC_MAX_FIXED;
                WARN(1, KERN_ERR "hw perf counters fixed %d > max(%d), clipping!",
                     x86_pmu.num_counters_fixed, X86_PMC_MAX_FIXED);
+               x86_pmu.num_counters_fixed = X86_PMC_MAX_FIXED;
        }
 
        perf_counter_mask |=
                ((1LL << x86_pmu.num_counters_fixed)-1) << X86_PMC_IDX_FIXED;
+       x86_pmu.intel_ctrl = perf_counter_mask;
 
        perf_counters_lapic_init();
        register_die_notifier(&perf_counter_nmi_notifier);
@@ -1563,6 +1561,7 @@ void callchain_store(struct perf_callchain_entry *entry, u64 ip)
 
 static DEFINE_PER_CPU(struct perf_callchain_entry, irq_entry);
 static DEFINE_PER_CPU(struct perf_callchain_entry, nmi_entry);
+static DEFINE_PER_CPU(int, in_nmi_frame);
 
 
 static void
@@ -1578,7 +1577,9 @@ static void backtrace_warning(void *data, char *msg)
 
 static int backtrace_stack(void *data, char *name)
 {
-       /* Process all stacks: */
+       per_cpu(in_nmi_frame, smp_processor_id()) =
+                       x86_is_stack_id(NMI_STACK, name);
+
        return 0;
 }
 
@@ -1586,6 +1587,9 @@ static void backtrace_address(void *data, unsigned long addr, int reliable)
 {
        struct perf_callchain_entry *entry = data;
 
+       if (per_cpu(in_nmi_frame, smp_processor_id()))
+               return;
+
        if (reliable)
                callchain_store(entry, addr);
 }
index 5c481f6205bfc3f591d32f3ef4b4cd850ba2d37a..e60ed740d2b3f4aa49412b47a97656eef07e8952 100644 (file)
@@ -803,8 +803,3 @@ int __kprobes lapic_wd_event(unsigned nmi_hz)
        wd_ops->rearm(wd, nmi_hz);
        return 1;
 }
-
-int lapic_watchdog_ok(void)
-{
-       return wd_ops != NULL;
-}
index 95ea5fa7d4445540c67bdb28ad13102df4248143..c8405718a4c3be91cab8948e95937c7c0bc568b9 100644 (file)
@@ -22,6 +22,7 @@
 #include "dumpstack.h"
 
 int panic_on_unrecovered_nmi;
+int panic_on_io_nmi;
 unsigned int code_bytes = 64;
 int kstack_depth_to_print = 3 * STACKSLOTS_PER_LINE;
 static int die_counter;
index d593cd1f58dcca22925f10e2b3669435a4a25557..bca5fba91c9ea3d62eed95643cacdb90e2a32770 100644 (file)
 
 #include "dumpstack.h"
 
+/* Just a stub for now */
+int x86_is_stack_id(int id, char *name)
+{
+       return 0;
+}
+
 void dump_trace(struct task_struct *task, struct pt_regs *regs,
                unsigned long *stack, unsigned long bp,
                const struct stacktrace_ops *ops, void *data)
index d35db5993fd68e3a740ee36ade60edf78d14fae8..54b0a3276766c3ac5180d7d6c11469a2c5f00979 100644 (file)
 
 #include "dumpstack.h"
 
-static unsigned long *in_exception_stack(unsigned cpu, unsigned long stack,
-                                       unsigned *usedp, char **idp)
-{
-       static char ids[][8] = {
+
+static char x86_stack_ids[][8] = {
                [DEBUG_STACK - 1] = "#DB",
                [NMI_STACK - 1] = "NMI",
                [DOUBLEFAULT_STACK - 1] = "#DF",
@@ -33,6 +31,15 @@ static unsigned long *in_exception_stack(unsigned cpu, unsigned long stack,
                        N_EXCEPTION_STACKS + DEBUG_STKSZ / EXCEPTION_STKSZ - 2] = "#DB[?]"
 #endif
        };
+
+int x86_is_stack_id(int id, char *name)
+{
+       return x86_stack_ids[id - 1] == name;
+}
+
+static unsigned long *in_exception_stack(unsigned cpu, unsigned long stack,
+                                       unsigned *usedp, char **idp)
+{
        unsigned k;
 
        /*
@@ -61,7 +68,7 @@ static unsigned long *in_exception_stack(unsigned cpu, unsigned long stack,
                        if (*usedp & (1U << k))
                                break;
                        *usedp |= 1U << k;
-                       *idp = ids[k];
+                       *idp = x86_stack_ids[k];
                        return (unsigned long *)end;
                }
                /*
@@ -81,12 +88,13 @@ static unsigned long *in_exception_stack(unsigned cpu, unsigned long stack,
                        do {
                                ++j;
                                end -= EXCEPTION_STKSZ;
-                               ids[j][4] = '1' + (j - N_EXCEPTION_STACKS);
+                               x86_stack_ids[j][4] = '1' +
+                                               (j - N_EXCEPTION_STACKS);
                        } while (stack < end - EXCEPTION_STKSZ);
                        if (*usedp & (1U << j))
                                break;
                        *usedp |= 1U << j;
-                       *idp = ids[j];
+                       *idp = x86_stack_ids[j];
                        return (unsigned long *)end;
                }
 #endif
index 7271fa33d79135edd790f854d7c0c91d05d0c20b..5cb5725b2bae26b97ab1f080599a13ab09cc9770 100644 (file)
@@ -627,10 +627,9 @@ __init void e820_setup_gap(void)
 #ifdef CONFIG_X86_64
        if (!found) {
                gapstart = (max_pfn << PAGE_SHIFT) + 1024*1024;
-               printk(KERN_ERR "PCI: Warning: Cannot find a gap in the 32bit "
-                      "address range\n"
-                      KERN_ERR "PCI: Unassigned devices with 32bit resource "
-                      "registers may break!\n");
+               printk(KERN_ERR
+       "PCI: Warning: Cannot find a gap in the 32bit address range\n"
+       "PCI: Unassigned devices with 32bit resource registers may break!\n");
        }
 #endif
 
@@ -1383,6 +1382,8 @@ static unsigned long ram_alignment(resource_size_t pos)
        return 32*1024*1024;
 }
 
+#define MAX_RESOURCE_SIZE ((resource_size_t)-1)
+
 void __init e820_reserve_resources_late(void)
 {
        int i;
@@ -1400,17 +1401,19 @@ void __init e820_reserve_resources_late(void)
         * avoid stolen RAM:
         */
        for (i = 0; i < e820.nr_map; i++) {
-               struct e820entry *entry = &e820_saved.map[i];
-               resource_size_t start, end;
+               struct e820entry *entry = &e820.map[i];
+               u64 start, end;
 
                if (entry->type != E820_RAM)
                        continue;
                start = entry->addr + entry->size;
-               end = round_up(start, ram_alignment(start));
-               if (start == end)
+               end = round_up(start, ram_alignment(start)) - 1;
+               if (end > MAX_RESOURCE_SIZE)
+                       end = MAX_RESOURCE_SIZE;
+               if (start >= end)
                        continue;
-               reserve_region_with_split(&iomem_resource, start,
-                                                 end - 1, "RAM buffer");
+               reserve_region_with_split(&iomem_resource, start, end,
+                                         "RAM buffer");
        }
 }
 
index a78ecad0c900ff646b8c826c08cd54b094815b5a..c664d515f613576c7ccd1168afcc47bf897a0855 100644 (file)
@@ -200,7 +200,7 @@ static void kvm_leave_lazy_mmu(void)
        state->mode = paravirt_get_lazy_mode();
 }
 
-static void paravirt_ops_setup(void)
+static void __init paravirt_ops_setup(void)
 {
        pv_info.name = "KVM";
        pv_info.paravirt_enabled = 1;
index 47630479b0677e3cb51ee3fb473a584fdd4dfa8e..1a041bcf506bd8efd0d27a4e99e2003e07ff6445 100644 (file)
@@ -211,11 +211,11 @@ static __init int iommu_setup(char *p)
 #ifdef CONFIG_SWIOTLB
                if (!strncmp(p, "soft", 4))
                        swiotlb = 1;
+#endif
                if (!strncmp(p, "pt", 2)) {
                        iommu_pass_through = 1;
                        return 1;
                }
-#endif
 
                gart_parse_options(p);
 
index cfd9f90638967e03277ad510625905213322bfd4..d2e56b8f48e708032e9504e8cd13f6cd29437f5e 100644 (file)
@@ -675,7 +675,7 @@ static __init int init_k8_gatt(struct agp_kern_info *info)
  nommu:
        /* Should not happen anymore */
        printk(KERN_WARNING "PCI-DMA: More than 4GB of RAM and no IOMMU\n"
-              KERN_WARNING "falling back to iommu=soft.\n");
+              "falling back to iommu=soft.\n");
        return -1;
 }
 
index 4f9c55f3a7c0f7e2590a5e248428bd19aa0d5c37..03801f2f761fc312ba80353425c1cc7243a0105f 100644 (file)
@@ -60,7 +60,7 @@ static inline u64 scale_delta(u64 delta, u32 mul_frac, int shift)
                "adc  %5,%%edx ; "
                : "=A" (product), "=r" (tmp1), "=r" (tmp2)
                : "a" ((u32)delta), "1" ((u32)(delta >> 32)), "2" (mul_frac) );
-#elif __x86_64__
+#elif defined(__x86_64__)
        __asm__ (
                "mul %%rdx ; shrd $32,%%rdx,%%rax"
                : "=a" (product) : "0" (delta), "d" ((u64)mul_frac) );
index be5ae80f897fb58f68f353fcd65c9346b3834d39..de2cab13284495da052984e093508f5884af3de1 100644 (file)
@@ -289,6 +289,20 @@ void * __init extend_brk(size_t size, size_t align)
        return ret;
 }
 
+#ifdef CONFIG_X86_64
+static void __init init_gbpages(void)
+{
+       if (direct_gbpages && cpu_has_gbpages)
+               printk(KERN_INFO "Using GB pages for direct mapping\n");
+       else
+               direct_gbpages = 0;
+}
+#else
+static inline void init_gbpages(void)
+{
+}
+#endif
+
 static void __init reserve_brk(void)
 {
        if (_brk_end > _brk_start)
@@ -871,6 +885,8 @@ void __init setup_arch(char **cmdline_p)
 
        reserve_brk();
 
+       init_gbpages();
+
        /* max_pfn_mapped is updated here */
        max_low_pfn_mapped = init_memory_mapping(0, max_low_pfn<<PAGE_SHIFT);
        max_pfn_mapped = max_low_pfn_mapped;
index 9c3f0823e6aa00ea93bec0babdfd2c0b19971d13..29a3eef7cf4affdb6f21a463af6e98a320605f52 100644 (file)
@@ -124,7 +124,7 @@ static void * __init pcpu_alloc_bootmem(unsigned int cpu, unsigned long size,
 }
 
 /*
- * Remap allocator
+ * Large page remap allocator
  *
  * This allocator uses PMD page as unit.  A PMD page is allocated for
  * each cpu and each is remapped into vmalloc area using PMD mapping.
@@ -137,105 +137,185 @@ static void * __init pcpu_alloc_bootmem(unsigned int cpu, unsigned long size,
  * better than only using 4k mappings while still being NUMA friendly.
  */
 #ifdef CONFIG_NEED_MULTIPLE_NODES
-static size_t pcpur_size __initdata;
-static void **pcpur_ptrs __initdata;
+struct pcpul_ent {
+       unsigned int    cpu;
+       void            *ptr;
+};
+
+static size_t pcpul_size;
+static struct pcpul_ent *pcpul_map;
+static struct vm_struct pcpul_vm;
 
-static struct page * __init pcpur_get_page(unsigned int cpu, int pageno)
+static struct page * __init pcpul_get_page(unsigned int cpu, int pageno)
 {
        size_t off = (size_t)pageno << PAGE_SHIFT;
 
-       if (off >= pcpur_size)
+       if (off >= pcpul_size)
                return NULL;
 
-       return virt_to_page(pcpur_ptrs[cpu] + off);
+       return virt_to_page(pcpul_map[cpu].ptr + off);
 }
 
-static ssize_t __init setup_pcpu_remap(size_t static_size)
+static ssize_t __init setup_pcpu_lpage(size_t static_size, bool chosen)
 {
-       static struct vm_struct vm;
-       size_t ptrs_size, dyn_size;
+       size_t map_size, dyn_size;
        unsigned int cpu;
+       int i, j;
        ssize_t ret;
 
-       /*
-        * If large page isn't supported, there's no benefit in doing
-        * this.  Also, on non-NUMA, embedding is better.
-        *
-        * NOTE: disabled for now.
-        */
-       if (true || !cpu_has_pse || !pcpu_need_numa())
+       if (!chosen) {
+               size_t vm_size = VMALLOC_END - VMALLOC_START;
+               size_t tot_size = num_possible_cpus() * PMD_SIZE;
+
+               /* on non-NUMA, embedding is better */
+               if (!pcpu_need_numa())
+                       return -EINVAL;
+
+               /* don't consume more than 20% of vmalloc area */
+               if (tot_size > vm_size / 5) {
+                       pr_info("PERCPU: too large chunk size %zuMB for "
+                               "large page remap\n", tot_size >> 20);
+                       return -EINVAL;
+               }
+       }
+
+       /* need PSE */
+       if (!cpu_has_pse) {
+               pr_warning("PERCPU: lpage allocator requires PSE\n");
                return -EINVAL;
+       }
 
        /*
         * Currently supports only single page.  Supporting multiple
         * pages won't be too difficult if it ever becomes necessary.
         */
-       pcpur_size = PFN_ALIGN(static_size + PERCPU_MODULE_RESERVE +
+       pcpul_size = PFN_ALIGN(static_size + PERCPU_MODULE_RESERVE +
                               PERCPU_DYNAMIC_RESERVE);
-       if (pcpur_size > PMD_SIZE) {
+       if (pcpul_size > PMD_SIZE) {
                pr_warning("PERCPU: static data is larger than large page, "
                           "can't use large page\n");
                return -EINVAL;
        }
-       dyn_size = pcpur_size - static_size - PERCPU_FIRST_CHUNK_RESERVE;
+       dyn_size = pcpul_size - static_size - PERCPU_FIRST_CHUNK_RESERVE;
 
        /* allocate pointer array and alloc large pages */
-       ptrs_size = PFN_ALIGN(num_possible_cpus() * sizeof(pcpur_ptrs[0]));
-       pcpur_ptrs = alloc_bootmem(ptrs_size);
+       map_size = PFN_ALIGN(num_possible_cpus() * sizeof(pcpul_map[0]));
+       pcpul_map = alloc_bootmem(map_size);
 
        for_each_possible_cpu(cpu) {
-               pcpur_ptrs[cpu] = pcpu_alloc_bootmem(cpu, PMD_SIZE, PMD_SIZE);
-               if (!pcpur_ptrs[cpu])
+               pcpul_map[cpu].cpu = cpu;
+               pcpul_map[cpu].ptr = pcpu_alloc_bootmem(cpu, PMD_SIZE,
+                                                       PMD_SIZE);
+               if (!pcpul_map[cpu].ptr) {
+                       pr_warning("PERCPU: failed to allocate large page "
+                                  "for cpu%u\n", cpu);
                        goto enomem;
+               }
 
                /*
-                * Only use pcpur_size bytes and give back the rest.
+                * Only use pcpul_size bytes and give back the rest.
                 *
                 * Ingo: The 2MB up-rounding bootmem is needed to make
                 * sure the partial 2MB page is still fully RAM - it's
                 * not well-specified to have a PAT-incompatible area
                 * (unmapped RAM, device memory, etc.) in that hole.
                 */
-               free_bootmem(__pa(pcpur_ptrs[cpu] + pcpur_size),
-                            PMD_SIZE - pcpur_size);
+               free_bootmem(__pa(pcpul_map[cpu].ptr + pcpul_size),
+                            PMD_SIZE - pcpul_size);
 
-               memcpy(pcpur_ptrs[cpu], __per_cpu_load, static_size);
+               memcpy(pcpul_map[cpu].ptr, __per_cpu_load, static_size);
        }
 
        /* allocate address and map */
-       vm.flags = VM_ALLOC;
-       vm.size = num_possible_cpus() * PMD_SIZE;
-       vm_area_register_early(&vm, PMD_SIZE);
+       pcpul_vm.flags = VM_ALLOC;
+       pcpul_vm.size = num_possible_cpus() * PMD_SIZE;
+       vm_area_register_early(&pcpul_vm, PMD_SIZE);
 
        for_each_possible_cpu(cpu) {
-               pmd_t *pmd;
+               pmd_t *pmd, pmd_v;
 
-               pmd = populate_extra_pmd((unsigned long)vm.addr
-                                        + cpu * PMD_SIZE);
-               set_pmd(pmd, pfn_pmd(page_to_pfn(virt_to_page(pcpur_ptrs[cpu])),
-                                    PAGE_KERNEL_LARGE));
+               pmd = populate_extra_pmd((unsigned long)pcpul_vm.addr +
+                                        cpu * PMD_SIZE);
+               pmd_v = pfn_pmd(page_to_pfn(virt_to_page(pcpul_map[cpu].ptr)),
+                               PAGE_KERNEL_LARGE);
+               set_pmd(pmd, pmd_v);
        }
 
        /* we're ready, commit */
        pr_info("PERCPU: Remapped at %p with large pages, static data "
-               "%zu bytes\n", vm.addr, static_size);
+               "%zu bytes\n", pcpul_vm.addr, static_size);
 
-       ret = pcpu_setup_first_chunk(pcpur_get_page, static_size,
+       ret = pcpu_setup_first_chunk(pcpul_get_page, static_size,
                                     PERCPU_FIRST_CHUNK_RESERVE, dyn_size,
-                                    PMD_SIZE, vm.addr, NULL);
-       goto out_free_ar;
+                                    PMD_SIZE, pcpul_vm.addr, NULL);
+
+       /* sort pcpul_map array for pcpu_lpage_remapped() */
+       for (i = 0; i < num_possible_cpus() - 1; i++)
+               for (j = i + 1; j < num_possible_cpus(); j++)
+                       if (pcpul_map[i].ptr > pcpul_map[j].ptr) {
+                               struct pcpul_ent tmp = pcpul_map[i];
+                               pcpul_map[i] = pcpul_map[j];
+                               pcpul_map[j] = tmp;
+                       }
+
+       return ret;
 
 enomem:
        for_each_possible_cpu(cpu)
-               if (pcpur_ptrs[cpu])
-                       free_bootmem(__pa(pcpur_ptrs[cpu]), PMD_SIZE);
-       ret = -ENOMEM;
-out_free_ar:
-       free_bootmem(__pa(pcpur_ptrs), ptrs_size);
-       return ret;
+               if (pcpul_map[cpu].ptr)
+                       free_bootmem(__pa(pcpul_map[cpu].ptr), pcpul_size);
+       free_bootmem(__pa(pcpul_map), map_size);
+       return -ENOMEM;
+}
+
+/**
+ * pcpu_lpage_remapped - determine whether a kaddr is in pcpul recycled area
+ * @kaddr: the kernel address in question
+ *
+ * Determine whether @kaddr falls in the pcpul recycled area.  This is
+ * used by pageattr to detect VM aliases and break up the pcpu PMD
+ * mapping such that the same physical page is not mapped under
+ * different attributes.
+ *
+ * The recycled area is always at the tail of a partially used PMD
+ * page.
+ *
+ * RETURNS:
+ * Address of corresponding remapped pcpu address if match is found;
+ * otherwise, NULL.
+ */
+void *pcpu_lpage_remapped(void *kaddr)
+{
+       void *pmd_addr = (void *)((unsigned long)kaddr & PMD_MASK);
+       unsigned long offset = (unsigned long)kaddr & ~PMD_MASK;
+       int left = 0, right = num_possible_cpus() - 1;
+       int pos;
+
+       /* pcpul in use at all? */
+       if (!pcpul_map)
+               return NULL;
+
+       /* okay, perform binary search */
+       while (left <= right) {
+               pos = (left + right) / 2;
+
+               if (pcpul_map[pos].ptr < pmd_addr)
+                       left = pos + 1;
+               else if (pcpul_map[pos].ptr > pmd_addr)
+                       right = pos - 1;
+               else {
+                       /* it shouldn't be in the area for the first chunk */
+                       WARN_ON(offset < pcpul_size);
+
+                       return pcpul_vm.addr +
+                               pcpul_map[pos].cpu * PMD_SIZE + offset;
+               }
+       }
+
+       return NULL;
 }
 #else
-static ssize_t __init setup_pcpu_remap(size_t static_size)
+static ssize_t __init setup_pcpu_lpage(size_t static_size, bool chosen)
 {
        return -EINVAL;
 }
@@ -249,7 +329,7 @@ static ssize_t __init setup_pcpu_remap(size_t static_size)
  * mapping so that it can use PMD mapping without additional TLB
  * pressure.
  */
-static ssize_t __init setup_pcpu_embed(size_t static_size)
+static ssize_t __init setup_pcpu_embed(size_t static_size, bool chosen)
 {
        size_t reserve = PERCPU_MODULE_RESERVE + PERCPU_DYNAMIC_RESERVE;
 
@@ -258,7 +338,7 @@ static ssize_t __init setup_pcpu_embed(size_t static_size)
         * this.  Also, embedding allocation doesn't play well with
         * NUMA.
         */
-       if (!cpu_has_pse || pcpu_need_numa())
+       if (!chosen && (!cpu_has_pse || pcpu_need_numa()))
                return -EINVAL;
 
        return pcpu_embed_first_chunk(static_size, PERCPU_FIRST_CHUNK_RESERVE,
@@ -308,8 +388,11 @@ static ssize_t __init setup_pcpu_4k(size_t static_size)
                        void *ptr;
 
                        ptr = pcpu_alloc_bootmem(cpu, PAGE_SIZE, PAGE_SIZE);
-                       if (!ptr)
+                       if (!ptr) {
+                               pr_warning("PERCPU: failed to allocate "
+                                          "4k page for cpu%u\n", cpu);
                                goto enomem;
+                       }
 
                        memcpy(ptr, __per_cpu_load + i * PAGE_SIZE, PAGE_SIZE);
                        pcpu4k_pages[j++] = virt_to_page(ptr);
@@ -333,6 +416,16 @@ out_free_ar:
        return ret;
 }
 
+/* for explicit first chunk allocator selection */
+static char pcpu_chosen_alloc[16] __initdata;
+
+static int __init percpu_alloc_setup(char *str)
+{
+       strncpy(pcpu_chosen_alloc, str, sizeof(pcpu_chosen_alloc) - 1);
+       return 0;
+}
+early_param("percpu_alloc", percpu_alloc_setup);
+
 static inline void setup_percpu_segment(int cpu)
 {
 #ifdef CONFIG_X86_32
@@ -346,11 +439,6 @@ static inline void setup_percpu_segment(int cpu)
 #endif
 }
 
-/*
- * Great future plan:
- * Declare PDA itself and support (irqstack,tss,pgd) as per cpu data.
- * Always point %gs to its beginning
- */
 void __init setup_per_cpu_areas(void)
 {
        size_t static_size = __per_cpu_end - __per_cpu_start;
@@ -367,9 +455,26 @@ void __init setup_per_cpu_areas(void)
         * of large page mappings.  Please read comments on top of
         * each allocator for details.
         */
-       ret = setup_pcpu_remap(static_size);
-       if (ret < 0)
-               ret = setup_pcpu_embed(static_size);
+       ret = -EINVAL;
+       if (strlen(pcpu_chosen_alloc)) {
+               if (strcmp(pcpu_chosen_alloc, "4k")) {
+                       if (!strcmp(pcpu_chosen_alloc, "lpage"))
+                               ret = setup_pcpu_lpage(static_size, true);
+                       else if (!strcmp(pcpu_chosen_alloc, "embed"))
+                               ret = setup_pcpu_embed(static_size, true);
+                       else
+                               pr_warning("PERCPU: unknown allocator %s "
+                                          "specified\n", pcpu_chosen_alloc);
+                       if (ret < 0)
+                               pr_warning("PERCPU: %s allocator failed (%zd), "
+                                          "falling back to 4k\n",
+                                          pcpu_chosen_alloc, ret);
+               }
+       } else {
+               ret = setup_pcpu_lpage(static_size, false);
+               if (ret < 0)
+                       ret = setup_pcpu_embed(static_size, false);
+       }
        if (ret < 0)
                ret = setup_pcpu_4k(static_size);
        if (ret < 0)
index 124d40c575df376e989d5b00229fda865f0bb682..8ccabb8a2f6a617ba512574ec2272e1d5ed5b622 100644 (file)
@@ -711,7 +711,6 @@ uv_activation_descriptor_init(int node, int pnode)
        unsigned long pa;
        unsigned long m;
        unsigned long n;
-       unsigned long mmr_image;
        struct bau_desc *adp;
        struct bau_desc *ad2;
 
@@ -727,12 +726,8 @@ uv_activation_descriptor_init(int node, int pnode)
        n = pa >> uv_nshift;
        m = pa & uv_mmask;
 
-       mmr_image = uv_read_global_mmr64(pnode, UVH_LB_BAU_SB_DESCRIPTOR_BASE);
-       if (mmr_image) {
-               uv_write_global_mmr64(pnode, (unsigned long)
-                                     UVH_LB_BAU_SB_DESCRIPTOR_BASE,
-                                     (n << UV_DESC_BASE_PNODE_SHIFT | m));
-       }
+       uv_write_global_mmr64(pnode, UVH_LB_BAU_SB_DESCRIPTOR_BASE,
+                             (n << UV_DESC_BASE_PNODE_SHIFT | m));
 
        /*
         * initializing all 8 (UV_ITEMS_PER_DESCRIPTOR) descriptors for each
index a0f48f5671c076fdde9bbccf10300c3724c840a9..5204332f475d86e1caa1ede6bb39fcc28b78d13f 100644 (file)
@@ -346,6 +346,9 @@ io_check_error(unsigned char reason, struct pt_regs *regs)
        printk(KERN_EMERG "NMI: IOCK error (debug interrupt?)\n");
        show_registers(regs);
 
+       if (panic_on_io_nmi)
+               panic("NMI IOCK error: Not continuing");
+
        /* Re-enable the IOCK line, wait for a few seconds */
        reason = (reason & 0xf) | 8;
        outb(reason, 0x61);
index 5c3d6e81a7dc61ec0b5ad6d952b77b96acb23b8f..7030b5f911bff0df9019a1c080bf3b5561086780 100644 (file)
@@ -2157,7 +2157,7 @@ static void reset_rsvds_bits_mask(struct kvm_vcpu *vcpu, int level)
                else
                        /* 32 bits PSE 4MB page */
                        context->rsvd_bits_mask[1][1] = rsvd_bits(13, 21);
-               context->rsvd_bits_mask[1][0] = ~0ull;
+               context->rsvd_bits_mask[1][0] = context->rsvd_bits_mask[1][0];
                break;
        case PT32E_ROOT_LEVEL:
                context->rsvd_bits_mask[0][2] =
@@ -2170,7 +2170,7 @@ static void reset_rsvds_bits_mask(struct kvm_vcpu *vcpu, int level)
                context->rsvd_bits_mask[1][1] = exb_bit_rsvd |
                        rsvd_bits(maxphyaddr, 62) |
                        rsvd_bits(13, 20);              /* large page */
-               context->rsvd_bits_mask[1][0] = ~0ull;
+               context->rsvd_bits_mask[1][0] = context->rsvd_bits_mask[1][0];
                break;
        case PT64_ROOT_LEVEL:
                context->rsvd_bits_mask[0][3] = exb_bit_rsvd |
@@ -2186,7 +2186,7 @@ static void reset_rsvds_bits_mask(struct kvm_vcpu *vcpu, int level)
                context->rsvd_bits_mask[1][1] = exb_bit_rsvd |
                        rsvd_bits(maxphyaddr, 51) |
                        rsvd_bits(13, 20);              /* large page */
-               context->rsvd_bits_mask[1][0] = ~0ull;
+               context->rsvd_bits_mask[1][0] = context->rsvd_bits_mask[1][0];
                break;
        }
 }
index 258e4591e1ca02246801fc380ae19472b2375b0a..67785f635399fdf26e09528589e41c41a1202a7a 100644 (file)
@@ -281,7 +281,7 @@ static u64 *FNAME(fetch)(struct kvm_vcpu *vcpu, gva_t addr,
 {
        unsigned access = gw->pt_access;
        struct kvm_mmu_page *shadow_page;
-       u64 spte, *sptep;
+       u64 spte, *sptep = NULL;
        int direct;
        gfn_t table_gfn;
        int r;
index e770bf349ec4f7f473f8639dabf4068188a4b3b5..356a0ce85c68d92427260f8478b88a9036f41ef2 100644 (file)
@@ -3012,6 +3012,12 @@ static int handle_vmcall(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
        return 1;
 }
 
+static int handle_vmx_insn(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
+{
+       kvm_queue_exception(vcpu, UD_VECTOR);
+       return 1;
+}
+
 static int handle_invlpg(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
 {
        unsigned long exit_qualification = vmcs_readl(EXIT_QUALIFICATION);
@@ -3198,6 +3204,15 @@ static int (*kvm_vmx_exit_handlers[])(struct kvm_vcpu *vcpu,
        [EXIT_REASON_HLT]                     = handle_halt,
        [EXIT_REASON_INVLPG]                  = handle_invlpg,
        [EXIT_REASON_VMCALL]                  = handle_vmcall,
+       [EXIT_REASON_VMCLEAR]                 = handle_vmx_insn,
+       [EXIT_REASON_VMLAUNCH]                = handle_vmx_insn,
+       [EXIT_REASON_VMPTRLD]                 = handle_vmx_insn,
+       [EXIT_REASON_VMPTRST]                 = handle_vmx_insn,
+       [EXIT_REASON_VMREAD]                  = handle_vmx_insn,
+       [EXIT_REASON_VMRESUME]                = handle_vmx_insn,
+       [EXIT_REASON_VMWRITE]                 = handle_vmx_insn,
+       [EXIT_REASON_VMOFF]                   = handle_vmx_insn,
+       [EXIT_REASON_VMON]                    = handle_vmx_insn,
        [EXIT_REASON_TPR_BELOW_THRESHOLD]     = handle_tpr_below_threshold,
        [EXIT_REASON_APIC_ACCESS]             = handle_apic_access,
        [EXIT_REASON_WBINVD]                  = handle_wbinvd,
index 249540f985132f79922736a8dd49f8febeb71bdf..fe5474aec41a0c399711f978aeeccab9a970ac13 100644 (file)
@@ -898,6 +898,7 @@ int kvm_get_msr_common(struct kvm_vcpu *vcpu, u32 msr, u64 *pdata)
        case MSR_VM_HSAVE_PA:
        case MSR_P6_EVNTSEL0:
        case MSR_P6_EVNTSEL1:
+       case MSR_K7_EVNTSEL0:
                data = 0;
                break;
        case MSR_MTRRcap:
index c1b6c232e02b180287e7b0e91a41ddb34c699689..616de4628d60d4e8aea197284a637ceced25dd73 100644 (file)
@@ -1361,7 +1361,7 @@ static inline int writeback(struct x86_emulate_ctxt *ctxt,
        return 0;
 }
 
-void toggle_interruptibility(struct x86_emulate_ctxt *ctxt, u32 mask)
+static void toggle_interruptibility(struct x86_emulate_ctxt *ctxt, u32 mask)
 {
        u32 int_shadow = kvm_x86_ops->get_interrupt_shadow(ctxt->vcpu, mask);
        /*
index 7bc65f0f62c4fc51607dd443641d1273cb4ebb03..f2bf1f73d468942590d5c914e874d24fa23d22b0 100644 (file)
@@ -379,6 +379,11 @@ static void lguest_cpuid(unsigned int *ax, unsigned int *bx,
 
        native_cpuid(ax, bx, cx, dx);
        switch (function) {
+       case 0: /* ID and highest CPUID.  Futureproof a little by sticking to
+                * older ones. */
+               if (*ax > 5)
+                       *ax = 5;
+               break;
        case 1: /* Basic feature request. */
                /* We only allow kernel to see SSE3, CMPXCHG16B and SSSE3 */
                *cx &= 0x00002201;
@@ -1079,7 +1084,7 @@ static unsigned lguest_patch(u8 type, u16 clobber, void *ibuf,
        return insn_len;
 }
 
-/*G:030 Once we get to lguest_init(), we know we're a Guest.  The various
+/*G:029 Once we get to lguest_init(), we know we're a Guest.  The various
  * pv_ops structures in the kernel provide points for (almost) every routine we
  * have to override to avoid privileged instructions. */
 __init void lguest_init(void)
index f9d35632666b06bb0b9bf072176777dbd94c39cc..07c31899c9c24b8f59d0d9c8bacf9c3dd56444da 100644 (file)
@@ -10,6 +10,7 @@ lib-y += usercopy_$(BITS).o getuser.o putuser.o
 lib-y += memcpy_$(BITS).o
 
 ifeq ($(CONFIG_X86_32),y)
+        obj-y += atomic64_32.o
         lib-y += checksum_32.o
         lib-y += strstr_32.o
         lib-y += semaphore_32.o string_32.o
diff --git a/arch/x86/lib/atomic64_32.c b/arch/x86/lib/atomic64_32.c
new file mode 100644 (file)
index 0000000..824fa0b
--- /dev/null
@@ -0,0 +1,230 @@
+#include <linux/compiler.h>
+#include <linux/module.h>
+#include <linux/types.h>
+
+#include <asm/processor.h>
+#include <asm/cmpxchg.h>
+#include <asm/atomic.h>
+
+static noinline u64 cmpxchg8b(u64 *ptr, u64 old, u64 new)
+{
+       u32 low = new;
+       u32 high = new >> 32;
+
+       asm volatile(
+               LOCK_PREFIX "cmpxchg8b %1\n"
+                    : "+A" (old), "+m" (*ptr)
+                    :  "b" (low),  "c" (high)
+                    );
+       return old;
+}
+
+u64 atomic64_cmpxchg(atomic64_t *ptr, u64 old_val, u64 new_val)
+{
+       return cmpxchg8b(&ptr->counter, old_val, new_val);
+}
+EXPORT_SYMBOL(atomic64_cmpxchg);
+
+/**
+ * atomic64_xchg - xchg atomic64 variable
+ * @ptr:      pointer to type atomic64_t
+ * @new_val:  value to assign
+ *
+ * Atomically xchgs the value of @ptr to @new_val and returns
+ * the old value.
+ */
+u64 atomic64_xchg(atomic64_t *ptr, u64 new_val)
+{
+       /*
+        * Try first with a (possibly incorrect) assumption about
+        * what we have there. We'll do two loops most likely,
+        * but we'll get an ownership MESI transaction straight away
+        * instead of a read transaction followed by a
+        * flush-for-ownership transaction:
+        */
+       u64 old_val, real_val = 0;
+
+       do {
+               old_val = real_val;
+
+               real_val = atomic64_cmpxchg(ptr, old_val, new_val);
+
+       } while (real_val != old_val);
+
+       return old_val;
+}
+EXPORT_SYMBOL(atomic64_xchg);
+
+/**
+ * atomic64_set - set atomic64 variable
+ * @ptr:      pointer to type atomic64_t
+ * @new_val:  value to assign
+ *
+ * Atomically sets the value of @ptr to @new_val.
+ */
+void atomic64_set(atomic64_t *ptr, u64 new_val)
+{
+       atomic64_xchg(ptr, new_val);
+}
+EXPORT_SYMBOL(atomic64_set);
+
+/**
+EXPORT_SYMBOL(atomic64_read);
+ * atomic64_add_return - add and return
+ * @delta: integer value to add
+ * @ptr:   pointer to type atomic64_t
+ *
+ * Atomically adds @delta to @ptr and returns @delta + *@ptr
+ */
+noinline u64 atomic64_add_return(u64 delta, atomic64_t *ptr)
+{
+       /*
+        * Try first with a (possibly incorrect) assumption about
+        * what we have there. We'll do two loops most likely,
+        * but we'll get an ownership MESI transaction straight away
+        * instead of a read transaction followed by a
+        * flush-for-ownership transaction:
+        */
+       u64 old_val, new_val, real_val = 0;
+
+       do {
+               old_val = real_val;
+               new_val = old_val + delta;
+
+               real_val = atomic64_cmpxchg(ptr, old_val, new_val);
+
+       } while (real_val != old_val);
+
+       return new_val;
+}
+EXPORT_SYMBOL(atomic64_add_return);
+
+u64 atomic64_sub_return(u64 delta, atomic64_t *ptr)
+{
+       return atomic64_add_return(-delta, ptr);
+}
+EXPORT_SYMBOL(atomic64_sub_return);
+
+u64 atomic64_inc_return(atomic64_t *ptr)
+{
+       return atomic64_add_return(1, ptr);
+}
+EXPORT_SYMBOL(atomic64_inc_return);
+
+u64 atomic64_dec_return(atomic64_t *ptr)
+{
+       return atomic64_sub_return(1, ptr);
+}
+EXPORT_SYMBOL(atomic64_dec_return);
+
+/**
+ * atomic64_add - add integer to atomic64 variable
+ * @delta: integer value to add
+ * @ptr:   pointer to type atomic64_t
+ *
+ * Atomically adds @delta to @ptr.
+ */
+void atomic64_add(u64 delta, atomic64_t *ptr)
+{
+       atomic64_add_return(delta, ptr);
+}
+EXPORT_SYMBOL(atomic64_add);
+
+/**
+ * atomic64_sub - subtract the atomic64 variable
+ * @delta: integer value to subtract
+ * @ptr:   pointer to type atomic64_t
+ *
+ * Atomically subtracts @delta from @ptr.
+ */
+void atomic64_sub(u64 delta, atomic64_t *ptr)
+{
+       atomic64_add(-delta, ptr);
+}
+EXPORT_SYMBOL(atomic64_sub);
+
+/**
+ * atomic64_sub_and_test - subtract value from variable and test result
+ * @delta: integer value to subtract
+ * @ptr:   pointer to type atomic64_t
+ *
+ * Atomically subtracts @delta from @ptr and returns
+ * true if the result is zero, or false for all
+ * other cases.
+ */
+int atomic64_sub_and_test(u64 delta, atomic64_t *ptr)
+{
+       u64 new_val = atomic64_sub_return(delta, ptr);
+
+       return new_val == 0;
+}
+EXPORT_SYMBOL(atomic64_sub_and_test);
+
+/**
+ * atomic64_inc - increment atomic64 variable
+ * @ptr: pointer to type atomic64_t
+ *
+ * Atomically increments @ptr by 1.
+ */
+void atomic64_inc(atomic64_t *ptr)
+{
+       atomic64_add(1, ptr);
+}
+EXPORT_SYMBOL(atomic64_inc);
+
+/**
+ * atomic64_dec - decrement atomic64 variable
+ * @ptr: pointer to type atomic64_t
+ *
+ * Atomically decrements @ptr by 1.
+ */
+void atomic64_dec(atomic64_t *ptr)
+{
+       atomic64_sub(1, ptr);
+}
+EXPORT_SYMBOL(atomic64_dec);
+
+/**
+ * atomic64_dec_and_test - decrement and test
+ * @ptr: pointer to type atomic64_t
+ *
+ * Atomically decrements @ptr by 1 and
+ * returns true if the result is 0, or false for all other
+ * cases.
+ */
+int atomic64_dec_and_test(atomic64_t *ptr)
+{
+       return atomic64_sub_and_test(1, ptr);
+}
+EXPORT_SYMBOL(atomic64_dec_and_test);
+
+/**
+ * atomic64_inc_and_test - increment and test
+ * @ptr: pointer to type atomic64_t
+ *
+ * Atomically increments @ptr by 1
+ * and returns true if the result is zero, or false for all
+ * other cases.
+ */
+int atomic64_inc_and_test(atomic64_t *ptr)
+{
+       return atomic64_sub_and_test(-1, ptr);
+}
+EXPORT_SYMBOL(atomic64_inc_and_test);
+
+/**
+ * atomic64_add_negative - add and test if negative
+ * @delta: integer value to add
+ * @ptr:   pointer to type atomic64_t
+ *
+ * Atomically adds @delta to @ptr and returns true
+ * if the result is negative, or false when
+ * result is greater than or equal to zero.
+ */
+int atomic64_add_negative(u64 delta, atomic64_t *ptr)
+{
+       s64 new_val = atomic64_add_return(delta, ptr);
+
+       return new_val < 0;
+}
+EXPORT_SYMBOL(atomic64_add_negative);
index 9a10a78bb4a414867fa68099996c6cfb66f26d2e..ebeafcce04a9bd595b645af6941429fe8fc26c62 100644 (file)
@@ -5,15 +5,14 @@
  * Zero a page.        
  * rdi page
  */                    
-       ALIGN
-clear_page_c:
+ENTRY(clear_page_c)
        CFI_STARTPROC
        movl $4096/8,%ecx
        xorl %eax,%eax
        rep stosq
        ret
        CFI_ENDPROC
-ENDPROC(clear_page)
+ENDPROC(clear_page_c)
 
 ENTRY(clear_page)
        CFI_STARTPROC
index f118c110af32f66b5a2208ecc864d86e2f249981..6ba0f7bb85eadaeebffde0d428dd8af7f932d2c9 100644 (file)
@@ -75,6 +75,7 @@ ENTRY(copy_to_user)
        jae bad_to_user
        ALTERNATIVE_JUMP X86_FEATURE_REP_GOOD,copy_user_generic_unrolled,copy_user_generic_string
        CFI_ENDPROC
+ENDPROC(copy_to_user)
 
 /* Standard copy_from_user with segment limit checking */
 ENTRY(copy_from_user)
index f4568605d7d5c9fa7281bebfc6d8f5e2b122c8df..ff485d361182f814624e238e1ebc418c28c05e79 100644 (file)
@@ -55,8 +55,10 @@ static void delay_tsc(unsigned long loops)
 
        preempt_disable();
        cpu = smp_processor_id();
+       rdtsc_barrier();
        rdtscl(bclock);
        for (;;) {
+               rdtsc_barrier();
                rdtscl(now);
                if ((now - bclock) >= loops)
                        break;
@@ -78,6 +80,7 @@ static void delay_tsc(unsigned long loops)
                if (unlikely(cpu != smp_processor_id())) {
                        loops -= (now - bclock);
                        cpu = smp_processor_id();
+                       rdtsc_barrier();
                        rdtscl(bclock);
                }
        }
index 7c8ca91bb9ecbacbccc42df711222e7abdc32310..1f118d462acc242990eb7a796b6832d8d90bc442 100644 (file)
@@ -751,7 +751,7 @@ survive:
 
                        if (retval == -ENOMEM && is_global_init(current)) {
                                up_read(&current->mm->mmap_sem);
-                               congestion_wait(WRITE, HZ/50);
+                               congestion_wait(BLK_RW_ASYNC, HZ/50);
                                goto survive;
                        }
 
index 78a5fff857bea0906cb6748baf6ef450b259b538..bfae139182ffbf0d2c5098d824f9d9ed7d8b6827 100644 (file)
@@ -426,10 +426,11 @@ static noinline int vmalloc_fault(unsigned long address)
 }
 
 static const char errata93_warning[] =
-KERN_ERR "******* Your BIOS seems to not contain a fix for K8 errata #93\n"
-KERN_ERR "******* Working around it, but it may cause SEGVs or burn power.\n"
-KERN_ERR "******* Please consider a BIOS update.\n"
-KERN_ERR "******* Disabling USB legacy in the BIOS may also help.\n";
+KERN_ERR 
+"******* Your BIOS seems to not contain a fix for K8 errata #93\n"
+"******* Working around it, but it may cause SEGVs or burn power.\n"
+"******* Please consider a BIOS update.\n"
+"******* Disabling USB legacy in the BIOS may also help.\n";
 
 /*
  * No vm86 mode in 64-bit mode:
@@ -696,7 +697,7 @@ show_signal_msg(struct pt_regs *regs, unsigned long error_code,
        if (!printk_ratelimit())
                return;
 
-       printk(KERN_CONT "%s%s[%d]: segfault at %lx ip %p sp %p error %lx",
+       printk("%s%s[%d]: segfault at %lx ip %p sp %p error %lx",
                task_pid_nr(tsk) > 1 ? KERN_INFO : KERN_EMERG,
                tsk->comm, task_pid_nr(tsk), address,
                (void *)regs->ip, (void *)regs->sp, error_code);
index f53b57e4086fffde114e8c153c67b76a7a857554..0607119cef94f2321ead2e46d467d1900a7014fb 100644 (file)
@@ -12,6 +12,7 @@
 #include <asm/system.h>
 #include <asm/tlbflush.h>
 #include <asm/tlb.h>
+#include <asm/proto.h>
 
 DEFINE_PER_CPU(struct mmu_gather, mmu_gathers);
 
@@ -177,20 +178,6 @@ static int __meminit save_mr(struct map_range *mr, int nr_range,
        return nr_range;
 }
 
-#ifdef CONFIG_X86_64
-static void __init init_gbpages(void)
-{
-       if (direct_gbpages && cpu_has_gbpages)
-               printk(KERN_INFO "Using GB pages for direct mapping\n");
-       else
-               direct_gbpages = 0;
-}
-#else
-static inline void init_gbpages(void)
-{
-}
-#endif
-
 /*
  * Setup the direct mapping of the physical memory at PAGE_OFFSET.
  * This runs before bootmem is initialized and gets pages directly from
@@ -210,9 +197,6 @@ unsigned long __init_refok init_memory_mapping(unsigned long start,
 
        printk(KERN_INFO "init_memory_mapping: %016lx-%016lx\n", start, end);
 
-       if (!after_bootmem)
-               init_gbpages();
-
 #if defined(CONFIG_DEBUG_PAGEALLOC) || defined(CONFIG_KMEMCHECK)
        /*
         * For CONFIG_DEBUG_PAGEALLOC, identity mapping will use small pages.
index c4378f4fd4a5e240125cfa60d2f1430a0bb35145..6176fe8f29e0138ec1cb6742f65b177010846aab 100644 (file)
@@ -598,6 +598,15 @@ void __init paging_init(void)
 
        sparse_memory_present_with_active_regions(MAX_NUMNODES);
        sparse_init();
+
+       /*
+        * clear the default setting with node 0
+        * note: don't use nodes_clear here, that is really clearing when
+        *       numa support is not compiled in, and later node_set_state
+        *       will not set it back.
+        */
+       node_clear_state(0, N_NORMAL_MEMORY);
+
        free_area_init_nodes(max_zone_pfns);
 }
 
index 3cfe9ced8a4c6e500b6df519dceadc7534a5730a..1b734d7a896685123a0f95a3778b39a3ec891a6f 100644 (file)
@@ -11,6 +11,7 @@
 #include <linux/interrupt.h>
 #include <linux/seq_file.h>
 #include <linux/debugfs.h>
+#include <linux/pfn.h>
 
 #include <asm/e820.h>
 #include <asm/processor.h>
@@ -681,8 +682,9 @@ static int __change_page_attr_set_clr(struct cpa_data *cpa, int checkalias);
 static int cpa_process_alias(struct cpa_data *cpa)
 {
        struct cpa_data alias_cpa;
-       int ret = 0;
-       unsigned long temp_cpa_vaddr, vaddr;
+       unsigned long laddr = (unsigned long)__va(cpa->pfn << PAGE_SHIFT);
+       unsigned long vaddr, remapped;
+       int ret;
 
        if (cpa->pfn >= max_pfn_mapped)
                return 0;
@@ -706,42 +708,55 @@ static int cpa_process_alias(struct cpa_data *cpa)
                    PAGE_OFFSET + (max_pfn_mapped << PAGE_SHIFT)))) {
 
                alias_cpa = *cpa;
-               temp_cpa_vaddr = (unsigned long) __va(cpa->pfn << PAGE_SHIFT);
-               alias_cpa.vaddr = &temp_cpa_vaddr;
+               alias_cpa.vaddr = &laddr;
                alias_cpa.flags &= ~(CPA_PAGES_ARRAY | CPA_ARRAY);
 
-
                ret = __change_page_attr_set_clr(&alias_cpa, 0);
+               if (ret)
+                       return ret;
        }
 
 #ifdef CONFIG_X86_64
-       if (ret)
-               return ret;
        /*
-        * No need to redo, when the primary call touched the high
-        * mapping already:
-        */
-       if (within(vaddr, (unsigned long) _text, _brk_end))
-               return 0;
-
-       /*
-        * If the physical address is inside the kernel map, we need
+        * If the primary call didn't touch the high mapping already
+        * and the physical address is inside the kernel map, we need
         * to touch the high mapped kernel as well:
         */
-       if (!within(cpa->pfn, highmap_start_pfn(), highmap_end_pfn()))
-               return 0;
+       if (!within(vaddr, (unsigned long)_text, _brk_end) &&
+           within(cpa->pfn, highmap_start_pfn(), highmap_end_pfn())) {
+               unsigned long temp_cpa_vaddr = (cpa->pfn << PAGE_SHIFT) +
+                                              __START_KERNEL_map - phys_base;
+               alias_cpa = *cpa;
+               alias_cpa.vaddr = &temp_cpa_vaddr;
+               alias_cpa.flags &= ~(CPA_PAGES_ARRAY | CPA_ARRAY);
 
-       alias_cpa = *cpa;
-       temp_cpa_vaddr = (cpa->pfn << PAGE_SHIFT) + __START_KERNEL_map - phys_base;
-       alias_cpa.vaddr = &temp_cpa_vaddr;
-       alias_cpa.flags &= ~(CPA_PAGES_ARRAY | CPA_ARRAY);
+               /*
+                * The high mapping range is imprecise, so ignore the
+                * return value.
+                */
+               __change_page_attr_set_clr(&alias_cpa, 0);
+       }
+#endif
 
        /*
-        * The high mapping range is imprecise, so ignore the return value.
+        * If the PMD page was partially used for per-cpu remapping,
+        * the recycled area needs to be split and modified.  Because
+        * the area is always proper subset of a PMD page
+        * cpa->numpages is guaranteed to be 1 for these areas, so
+        * there's no need to loop over and check for further remaps.
         */
-       __change_page_attr_set_clr(&alias_cpa, 0);
-#endif
-       return ret;
+       remapped = (unsigned long)pcpu_lpage_remapped((void *)laddr);
+       if (remapped) {
+               WARN_ON(cpa->numpages > 1);
+               alias_cpa = *cpa;
+               alias_cpa.vaddr = &remapped;
+               alias_cpa.flags &= ~(CPA_PAGES_ARRAY | CPA_ARRAY);
+               ret = __change_page_attr_set_clr(&alias_cpa, 0);
+               if (ret)
+                       return ret;
+       }
+
+       return 0;
 }
 
 static int __change_page_attr_set_clr(struct cpa_data *cpa, int checkalias)
index b07dd8d0b321d9e04fd94b307c0f51befdc20933..89b9a5cd63da1d52900a47dd0b269476dd09fb2c 100644 (file)
@@ -390,7 +390,7 @@ static int __init p4_init(char **cpu_type)
 static int force_arch_perfmon;
 static int force_cpu_type(const char *str, struct kernel_param *kp)
 {
-       if (!strcmp(str, "archperfmon")) {
+       if (!strcmp(str, "arch_perfmon")) {
                force_arch_perfmon = 1;
                printk(KERN_INFO "oprofile: forcing architectural perfmon\n");
        }
index 16c3fda85bbad502317bafedc37159bf9847b278..1014eb4bfc37ac15cec9e3b24b3f980a1a52e7d9 100644 (file)
@@ -68,6 +68,10 @@ setup_resource(struct acpi_resource *acpi_res, void *data)
        unsigned long flags;
        struct resource *root;
        int max_root_bus_resources = PCI_BUS_NUM_RESOURCES;
+       u64 start, end;
+
+       if (bus_has_transparent_bridge(info->bus))
+               max_root_bus_resources -= 3;
 
        status = resource_to_addr(acpi_res, &addr);
        if (!ACPI_SUCCESS(status))
@@ -84,25 +88,24 @@ setup_resource(struct acpi_resource *acpi_res, void *data)
        } else
                return AE_OK;
 
-       res = &info->res[info->res_num];
-       res->name = info->name;
-       res->flags = flags;
-       res->start = addr.minimum + addr.translation_offset;
-       res->end = res->start + addr.address_length - 1;
-       res->child = NULL;
-
-       if (bus_has_transparent_bridge(info->bus))
-               max_root_bus_resources -= 3;
+       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) res->start,
-                       (unsigned long) res->end, root->name, info->name,
+                       "%d resource descriptors\n", (unsigned long) start,
+                       (unsigned long) end, root->name, info->name,
                        max_root_bus_resources);
-               info->res_num++;
                return AE_OK;
        }
 
+       res = &info->res[info->res_num];
+       res->name = info->name;
+       res->flags = flags;
+       res->start = start;
+       res->end = end;
+       res->child = NULL;
+
        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,
@@ -114,23 +117,6 @@ setup_resource(struct acpi_resource *acpi_res, void *data)
        return AE_OK;
 }
 
-static void
-adjust_transparent_bridge_resources(struct pci_bus *bus)
-{
-       struct pci_dev *dev;
-
-       list_for_each_entry(dev, &bus->devices, bus_list) {
-               int i;
-               u16 class = dev->class >> 8;
-
-               if (class == PCI_CLASS_BRIDGE_PCI && dev->transparent) {
-                       for(i = 3; i < PCI_BUS_NUM_RESOURCES; i++)
-                               dev->subordinate->resource[i] =
-                                               dev->bus->resource[i - 3];
-               }
-       }
-}
-
 static void
 get_current_resources(struct acpi_device *device, int busnum,
                        int domain, struct pci_bus *bus)
@@ -158,8 +144,6 @@ get_current_resources(struct acpi_device *device, int busnum,
        info.res_num = 0;
        acpi_walk_resources(device->handle, METHOD_NAME__CRS, setup_resource,
                                &info);
-       if (info.res_num)
-               adjust_transparent_bridge_resources(bus);
 
        return;
 
@@ -222,8 +206,15 @@ struct pci_bus * __devinit pci_acpi_scan_root(struct acpi_device *device, int do
                 */
                memcpy(bus->sysdata, sd, sizeof(*sd));
                kfree(sd);
-       } else
-               bus = pci_scan_bus_parented(NULL, busnum, &pci_root_ops, sd);
+       } 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);
+                       bus->subordinate = pci_scan_child_bus(bus);
+               }
+       }
 
        if (!bus)
                kfree(sd);
@@ -238,8 +229,6 @@ struct pci_bus * __devinit pci_acpi_scan_root(struct acpi_device *device, int do
 #endif
        }
 
-       if (bus && !(pci_probe & PCI_NO_ROOT_CRS))
-               get_current_resources(device, busnum, domain, bus);
        return bus;
 }
 
index 2255f880678bb198af08f8fd43452c2e3370167a..3ffa10df20b9f2dc6ccbcf6380926a73fda79026 100644 (file)
@@ -100,8 +100,9 @@ void x86_pci_root_bus_res_quirks(struct pci_bus *b)
        int j;
        struct pci_root_info *info;
 
-       /* don't go for it if _CRS is used */
-       if (!(pci_probe & PCI_NO_ROOT_CRS))
+       /* 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 */
@@ -116,6 +117,9 @@ void x86_pci_root_bus_res_quirks(struct pci_bus *b)
        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;
index 4740119e4bb73389e66ff08ed47e30c7d12c56c6..2202b6257b82b84bb9ef17f33630ca7dac929610 100644 (file)
@@ -515,8 +515,8 @@ char * __devinit  pcibios_setup(char *str)
        } else if (!strcmp(str, "assign-busses")) {
                pci_probe |= PCI_ASSIGN_ALL_BUSSES;
                return NULL;
-       } else if (!strcmp(str, "nocrs")) {
-               pci_probe |= PCI_NO_ROOT_CRS;
+       } else if (!strcmp(str, "use_crs")) {
+               pci_probe |= PCI_USE__CRS;
                return NULL;
        } else if (!strcmp(str, "earlydump")) {
                pci_early_dump_regs = 1;
index 0fb56db16d1813897b7f7fea6df2af75a20fd2a0..52e62e57fedd53a385147cf1399cd84f89f7bc4b 100644 (file)
@@ -35,6 +35,7 @@
 #include <asm/pat.h>
 #include <asm/e820.h>
 #include <asm/pci_x86.h>
+#include <asm/io_apic.h>
 
 
 static int
@@ -227,6 +228,12 @@ void __init pcibios_resource_survey(void)
        pcibios_allocate_resources(1);
 
        e820_reserve_resources_late();
+       /*
+        * Insert the IO APIC resources after PCI initialization has
+        * occured to handle IO APICS that are mapped in on a BAR in
+        * PCI space, but before trying to assign unassigned pci res.
+        */
+       ioapic_insert_resources();
 }
 
 /**
index 8766b0e216c5f1a139a7094630933670dd3f1cc4..712443ec6d43b46aaf05d75e04f2c249f44d20da 100644 (file)
@@ -523,6 +523,69 @@ reject:
 
 static int __initdata known_bridge;
 
+static int acpi_mcfg_64bit_base_addr __initdata = FALSE;
+
+/* The physical address of the MMCONFIG aperture.  Set from ACPI tables. */
+struct acpi_mcfg_allocation *pci_mmcfg_config;
+int pci_mmcfg_config_num;
+
+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;
+}
+
+static int __init pci_parse_mcfg(struct acpi_table_header *header)
+{
+       struct acpi_table_mcfg *mcfg;
+       unsigned long i;
+       int config_size;
+
+       if (!header)
+               return -EINVAL;
+
+       mcfg = (struct acpi_table_mcfg *)header;
+
+       /* how many config structures do we have */
+       pci_mmcfg_config_num = 0;
+       i = header->length - sizeof(struct acpi_table_mcfg);
+       while (i >= sizeof(struct acpi_mcfg_allocation)) {
+               ++pci_mmcfg_config_num;
+               i -= sizeof(struct acpi_mcfg_allocation);
+       };
+       if (pci_mmcfg_config_num == 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;
+                       return -ENODEV;
+               }
+       }
+
+       return 0;
+}
+
 static void __init __pci_mmcfg_init(int early)
 {
        /* MMCONFIG disabled */
@@ -543,7 +606,7 @@ static void __init __pci_mmcfg_init(int early)
        }
 
        if (!known_bridge)
-               acpi_table_parse(ACPI_SIG_MCFG, acpi_parse_mcfg);
+               acpi_table_parse(ACPI_SIG_MCFG, pci_parse_mcfg);
 
        pci_mmcfg_reject_broken(early);
 
index de2abbd0754481d0528ee527077d668d7b3e422b..a6a198c336238f63a2c0962fe2f94212ee6712e2 100644 (file)
@@ -1,7 +1,7 @@
 # __restore_processor_state() restores %gs after S3 resume and so should not
 # itself be stack-protected
 nostackp := $(call cc-option, -fno-stack-protector)
-CFLAGS_cpu_$(BITS).o   := $(nostackp)
+CFLAGS_cpu.o   := $(nostackp)
 
 obj-$(CONFIG_PM_SLEEP)         += cpu.o
 obj-$(CONFIG_HIBERNATION)      += hibernate_$(BITS).o hibernate_asm_$(BITS).o
index d277ef1eea511c1047b2dfb06ea784496c42a0f1..b3d20b9cac6366922d189572396d7c805c6680b2 100644 (file)
@@ -244,7 +244,7 @@ static void __restore_processor_state(struct saved_context *ctxt)
        do_fpu_end();
        mtrr_ap_init();
 
-#ifdef CONFIG_X86_32
+#ifdef CONFIG_X86_OLD_MCE
        mcheck_init(&boot_cpu_data);
 #endif
 }
index 0f4fe1faf9ba46fed7f9c689f2bb2652fe25923b..13165641cc5153bb9990a634042262f2c120085a 100644 (file)
@@ -80,8 +80,6 @@ struct thread_info {
 
 /*
  * macros/functions for gaining access to the thread information structure
- *
- * preempt_count needs to be 1 initially, until the scheduler is functional.
  */
 
 #ifndef __ASSEMBLY__
@@ -92,7 +90,7 @@ struct thread_info {
        .exec_domain    = &default_exec_domain, \
        .flags          = 0,                    \
        .cpu            = 0,                    \
-       .preempt_count  = 1,                    \
+       .preempt_count  = INIT_PREEMPT_COUNT,   \
        .addr_limit     = KERNEL_DS,            \
        .restart_block = {                      \
                .fn = do_no_restart_syscall,    \
index ba9ab9349782d3ffbf364d500f03005c433d2798..e64efac3b9db43e7383127ec56ee31030ec36ff3 100644 (file)
@@ -354,10 +354,10 @@ void show_regs(struct pt_regs * regs)
 
        for (i = 0; i < 16; i++) {
                if ((i % 8) == 0)
-                       printk ("\n" KERN_INFO "a%02d: ", i);
-               printk("%08lx ", regs->areg[i]);
+                       printk(KERN_INFO "a%02d:", i);
+               printk(KERN_CONT " %08lx", regs->areg[i]);
        }
-       printk("\n");
+       printk(KERN_CONT "\n");
 
        printk("pc: %08lx, ps: %08lx, depc: %08lx, excvaddr: %08lx\n",
               regs->pc, regs->ps, regs->depc, regs->excvaddr);
index e9fa4dd690f238e51c4a830bf3ccdfec0703c4d8..6c54ed0ff755b6507fb89884524111b429cff3e0 100644 (file)
@@ -5,7 +5,7 @@
 obj-$(CONFIG_BLOCK) := elevator.o blk-core.o blk-tag.o blk-sysfs.o \
                        blk-barrier.o blk-settings.o blk-ioc.o blk-map.o \
                        blk-exec.o blk-merge.o blk-softirq.o blk-timeout.o \
-                       ioctl.o genhd.o scsi_ioctl.o cmd-filter.o
+                       ioctl.o genhd.o scsi_ioctl.o
 
 obj-$(CONFIG_BLK_DEV_BSG)      += bsg.o
 obj-$(CONFIG_IOSCHED_NOOP)     += noop-iosched.o
index b06cf5c2a829c49a17dc4a23ab4421d8933b3401..4b45435c6eaf2b3b714f2ce50606a0b053ee63f3 100644 (file)
@@ -595,8 +595,6 @@ blk_init_queue_node(request_fn_proc *rfn, spinlock_t *lock, int node_id)
 
        q->sg_reserved_size = INT_MAX;
 
-       blk_set_cmd_filter_defaults(&q->cmd_filter);
-
        /*
         * all done
         */
@@ -1172,6 +1170,11 @@ static int __make_request(struct request_queue *q, struct bio *bio)
        const int unplug = bio_unplug(bio);
        int rw_flags;
 
+       if (bio_barrier(bio) && bio_has_data(bio) &&
+           (q->next_ordered == QUEUE_ORDERED_NONE)) {
+               bio_endio(bio, -EOPNOTSUPP);
+               return 0;
+       }
        /*
         * low level driver can indicate that it wants pages above a
         * certain limit bounced to low memory (ie for highmem, or even
@@ -1472,11 +1475,6 @@ static inline void __generic_make_request(struct bio *bio)
                        err = -EOPNOTSUPP;
                        goto end_io;
                }
-               if (bio_barrier(bio) && bio_has_data(bio) &&
-                   (q->next_ordered == QUEUE_ORDERED_NONE)) {
-                       err = -EOPNOTSUPP;
-                       goto end_io;
-               }
 
                ret = q->make_request_fn(q, bio);
        } while (ret);
@@ -2365,7 +2363,7 @@ int blk_rq_prep_clone(struct request *rq, struct request *rq_src,
                __bio_clone(bio, bio_src);
 
                if (bio_integrity(bio_src) &&
-                   bio_integrity_clone(bio, bio_src, gfp_mask))
+                   bio_integrity_clone(bio, bio_src, gfp_mask, bs))
                        goto free_and_out;
 
                if (bio_ctr && bio_ctr(bio, bio_src, data))
index 39ce64432ba6d4cdcff6427851fe19aac172a2d7..e1999679a4d5156b967729c5e2b6b229a8747954 100644 (file)
@@ -350,6 +350,12 @@ static int attempt_merge(struct request_queue *q, struct request *req,
        if (blk_integrity_rq(req) != blk_integrity_rq(next))
                return 0;
 
+       /* don't merge requests of different failfast settings */
+       if (blk_failfast_dev(req)       != blk_failfast_dev(next)       ||
+           blk_failfast_transport(req) != blk_failfast_transport(next) ||
+           blk_failfast_driver(req)    != blk_failfast_driver(next))
+               return 0;
+
        /*
         * If we are allowed to merge, then append bio list
         * from next to rq and release next. merge_requests_fn
index e7d47525424890e24057b7ef4199eeff2322da5a..5f184bb3ff9e12a13a0e01060c77bdc6e6bdc5e9 100644 (file)
@@ -186,7 +186,7 @@ static int blk_fill_sgv4_hdr_rq(struct request_queue *q, struct request *rq,
                return -EFAULT;
 
        if (hdr->subprotocol == BSG_SUB_PROTOCOL_SCSI_CMD) {
-               if (blk_verify_command(&q->cmd_filter, rq->cmd, has_write_perm))
+               if (blk_verify_command(rq->cmd, has_write_perm))
                        return -EPERM;
        } else if (!capable(CAP_SYS_RAWIO))
                return -EPERM;
index 833ec18eaa63e2a20b847797c99511e41314b474..fd7080ed793599127647baafbed009d8e11ef1af 100644 (file)
@@ -70,6 +70,51 @@ struct cfq_rb_root {
 };
 #define CFQ_RB_ROOT    (struct cfq_rb_root) { RB_ROOT, NULL, }
 
+/*
+ * Per process-grouping structure
+ */
+struct cfq_queue {
+       /* reference count */
+       atomic_t ref;
+       /* various state flags, see below */
+       unsigned int flags;
+       /* parent cfq_data */
+       struct cfq_data *cfqd;
+       /* service_tree member */
+       struct rb_node rb_node;
+       /* service_tree key */
+       unsigned long rb_key;
+       /* prio tree member */
+       struct rb_node p_node;
+       /* prio tree root we belong to, if any */
+       struct rb_root *p_root;
+       /* sorted list of pending requests */
+       struct rb_root sort_list;
+       /* if fifo isn't expired, next request to serve */
+       struct request *next_rq;
+       /* requests queued in sort_list */
+       int queued[2];
+       /* currently allocated requests */
+       int allocated[2];
+       /* fifo list of requests in sort_list */
+       struct list_head fifo;
+
+       unsigned long slice_end;
+       long slice_resid;
+       unsigned int slice_dispatch;
+
+       /* pending metadata requests */
+       int meta_pending;
+       /* number of requests that are on the dispatch list or inside driver */
+       int dispatched;
+
+       /* io prio of this group */
+       unsigned short ioprio, org_ioprio;
+       unsigned short ioprio_class, org_ioprio_class;
+
+       pid_t pid;
+};
+
 /*
  * Per block device queue structure
  */
@@ -135,51 +180,11 @@ struct cfq_data {
        unsigned int cfq_slice_idle;
 
        struct list_head cic_list;
-};
 
-/*
- * Per process-grouping structure
- */
-struct cfq_queue {
-       /* reference count */
-       atomic_t ref;
-       /* various state flags, see below */
-       unsigned int flags;
-       /* parent cfq_data */
-       struct cfq_data *cfqd;
-       /* service_tree member */
-       struct rb_node rb_node;
-       /* service_tree key */
-       unsigned long rb_key;
-       /* prio tree member */
-       struct rb_node p_node;
-       /* prio tree root we belong to, if any */
-       struct rb_root *p_root;
-       /* sorted list of pending requests */
-       struct rb_root sort_list;
-       /* if fifo isn't expired, next request to serve */
-       struct request *next_rq;
-       /* requests queued in sort_list */
-       int queued[2];
-       /* currently allocated requests */
-       int allocated[2];
-       /* fifo list of requests in sort_list */
-       struct list_head fifo;
-
-       unsigned long slice_end;
-       long slice_resid;
-       unsigned int slice_dispatch;
-
-       /* pending metadata requests */
-       int meta_pending;
-       /* number of requests that are on the dispatch list or inside driver */
-       int dispatched;
-
-       /* io prio of this group */
-       unsigned short ioprio, org_ioprio;
-       unsigned short ioprio_class, org_ioprio_class;
-
-       pid_t pid;
+       /*
+        * Fallback dummy cfqq for extreme OOM conditions
+        */
+       struct cfq_queue oom_cfqq;
 };
 
 enum cfqq_state_flags {
@@ -1641,6 +1646,26 @@ static void cfq_ioc_set_ioprio(struct io_context *ioc)
        ioc->ioprio_changed = 0;
 }
 
+static void cfq_init_cfqq(struct cfq_data *cfqd, struct cfq_queue *cfqq,
+                         pid_t pid, int is_sync)
+{
+       RB_CLEAR_NODE(&cfqq->rb_node);
+       RB_CLEAR_NODE(&cfqq->p_node);
+       INIT_LIST_HEAD(&cfqq->fifo);
+
+       atomic_set(&cfqq->ref, 0);
+       cfqq->cfqd = cfqd;
+
+       cfq_mark_cfqq_prio_changed(cfqq);
+
+       if (is_sync) {
+               if (!cfq_class_idle(cfqq))
+                       cfq_mark_cfqq_idle_window(cfqq);
+               cfq_mark_cfqq_sync(cfqq);
+       }
+       cfqq->pid = pid;
+}
+
 static struct cfq_queue *
 cfq_find_alloc_queue(struct cfq_data *cfqd, int is_sync,
                     struct io_context *ioc, gfp_t gfp_mask)
@@ -1653,56 +1678,40 @@ retry:
        /* cic always exists here */
        cfqq = cic_to_cfqq(cic, is_sync);
 
-       if (!cfqq) {
+       /*
+        * Always try a new alloc if we fell back to the OOM cfqq
+        * originally, since it should just be a temporary situation.
+        */
+       if (!cfqq || cfqq == &cfqd->oom_cfqq) {
+               cfqq = NULL;
                if (new_cfqq) {
                        cfqq = new_cfqq;
                        new_cfqq = NULL;
                } else if (gfp_mask & __GFP_WAIT) {
-                       /*
-                        * Inform the allocator of the fact that we will
-                        * just repeat this allocation if it fails, to allow
-                        * the allocator to do whatever it needs to attempt to
-                        * free memory.
-                        */
                        spin_unlock_irq(cfqd->queue->queue_lock);
                        new_cfqq = kmem_cache_alloc_node(cfq_pool,
-                                       gfp_mask | __GFP_NOFAIL | __GFP_ZERO,
+                                       gfp_mask | __GFP_ZERO,
                                        cfqd->queue->node);
                        spin_lock_irq(cfqd->queue->queue_lock);
-                       goto retry;
+                       if (new_cfqq)
+                               goto retry;
                } else {
                        cfqq = kmem_cache_alloc_node(cfq_pool,
                                        gfp_mask | __GFP_ZERO,
                                        cfqd->queue->node);
-                       if (!cfqq)
-                               goto out;
                }
 
-               RB_CLEAR_NODE(&cfqq->rb_node);
-               RB_CLEAR_NODE(&cfqq->p_node);
-               INIT_LIST_HEAD(&cfqq->fifo);
-
-               atomic_set(&cfqq->ref, 0);
-               cfqq->cfqd = cfqd;
-
-               cfq_mark_cfqq_prio_changed(cfqq);
-
-               cfq_init_prio_data(cfqq, ioc);
-
-               if (is_sync) {
-                       if (!cfq_class_idle(cfqq))
-                               cfq_mark_cfqq_idle_window(cfqq);
-                       cfq_mark_cfqq_sync(cfqq);
-               }
-               cfqq->pid = current->pid;
-               cfq_log_cfqq(cfqd, cfqq, "alloced");
+               if (cfqq) {
+                       cfq_init_cfqq(cfqd, cfqq, current->pid, is_sync);
+                       cfq_init_prio_data(cfqq, ioc);
+                       cfq_log_cfqq(cfqd, cfqq, "alloced");
+               } else
+                       cfqq = &cfqd->oom_cfqq;
        }
 
        if (new_cfqq)
                kmem_cache_free(cfq_pool, new_cfqq);
 
-out:
-       WARN_ON((gfp_mask & __GFP_WAIT) && !cfqq);
        return cfqq;
 }
 
@@ -1735,11 +1744,8 @@ cfq_get_queue(struct cfq_data *cfqd, int is_sync, struct io_context *ioc,
                cfqq = *async_cfqq;
        }
 
-       if (!cfqq) {
+       if (!cfqq)
                cfqq = cfq_find_alloc_queue(cfqd, is_sync, ioc, gfp_mask);
-               if (!cfqq)
-                       return NULL;
-       }
 
        /*
         * pin the queue now that it's allocated, scheduler exit will prune it
@@ -2305,12 +2311,8 @@ cfq_set_request(struct request_queue *q, struct request *rq, gfp_t gfp_mask)
                goto queue_fail;
 
        cfqq = cic_to_cfqq(cic, is_sync);
-       if (!cfqq) {
+       if (!cfqq || cfqq == &cfqd->oom_cfqq) {
                cfqq = cfq_get_queue(cfqd, is_sync, cic->ioc, gfp_mask);
-
-               if (!cfqq)
-                       goto queue_fail;
-
                cic_set_cfqq(cic, cfqq, is_sync);
        }
 
@@ -2465,6 +2467,14 @@ static void *cfq_init_queue(struct request_queue *q)
        for (i = 0; i < CFQ_PRIO_LISTS; i++)
                cfqd->prio_trees[i] = RB_ROOT;
 
+       /*
+        * Our fallback cfqq if cfq_find_alloc_queue() runs into OOM issues.
+        * Grab a permanent reference to it, so that the normal code flow
+        * will not attempt to free it.
+        */
+       cfq_init_cfqq(cfqd, &cfqd->oom_cfqq, 1, 0);
+       atomic_inc(&cfqd->oom_cfqq.ref);
+
        INIT_LIST_HEAD(&cfqd->cic_list);
 
        cfqd->queue = q;
diff --git a/block/cmd-filter.c b/block/cmd-filter.c
deleted file mode 100644 (file)
index 572bbc2..0000000
+++ /dev/null
@@ -1,233 +0,0 @@
-/*
- * Copyright 2004 Peter M. Jones <pjones@redhat.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- *
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public Licens
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-
- *
- */
-
-#include <linux/list.h>
-#include <linux/genhd.h>
-#include <linux/spinlock.h>
-#include <linux/capability.h>
-#include <linux/bitops.h>
-#include <linux/blkdev.h>
-
-#include <scsi/scsi.h>
-#include <linux/cdrom.h>
-
-int blk_verify_command(struct blk_cmd_filter *filter,
-                      unsigned char *cmd, fmode_t has_write_perm)
-{
-       /* root can do any command. */
-       if (capable(CAP_SYS_RAWIO))
-               return 0;
-
-       /* if there's no filter set, assume we're filtering everything out */
-       if (!filter)
-               return -EPERM;
-
-       /* Anybody who can open the device can do a read-safe command */
-       if (test_bit(cmd[0], filter->read_ok))
-               return 0;
-
-       /* Write-safe commands require a writable open */
-       if (test_bit(cmd[0], filter->write_ok) && has_write_perm)
-               return 0;
-
-       return -EPERM;
-}
-EXPORT_SYMBOL(blk_verify_command);
-
-#if 0
-/* and now, the sysfs stuff */
-static ssize_t rcf_cmds_show(struct blk_cmd_filter *filter, char *page,
-                            int rw)
-{
-       char *npage = page;
-       unsigned long *okbits;
-       int i;
-
-       if (rw == READ)
-               okbits = filter->read_ok;
-       else
-               okbits = filter->write_ok;
-
-       for (i = 0; i < BLK_SCSI_MAX_CMDS; i++) {
-               if (test_bit(i, okbits)) {
-                       npage += sprintf(npage, "0x%02x", i);
-                       if (i < BLK_SCSI_MAX_CMDS - 1)
-                               sprintf(npage++, " ");
-               }
-       }
-
-       if (npage != page)
-               npage += sprintf(npage, "\n");
-
-       return npage - page;
-}
-
-static ssize_t rcf_readcmds_show(struct blk_cmd_filter *filter, char *page)
-{
-       return rcf_cmds_show(filter, page, READ);
-}
-
-static ssize_t rcf_writecmds_show(struct blk_cmd_filter *filter,
-                                char *page)
-{
-       return rcf_cmds_show(filter, page, WRITE);
-}
-
-static ssize_t rcf_cmds_store(struct blk_cmd_filter *filter,
-                             const char *page, size_t count, int rw)
-{
-       unsigned long okbits[BLK_SCSI_CMD_PER_LONG], *target_okbits;
-       int cmd, set;
-       char *p, *status;
-
-       if (rw == READ) {
-               memcpy(&okbits, filter->read_ok, sizeof(okbits));
-               target_okbits = filter->read_ok;
-       } else {
-               memcpy(&okbits, filter->write_ok, sizeof(okbits));
-               target_okbits = filter->write_ok;
-       }
-
-       while ((p = strsep((char **)&page, " ")) != NULL) {
-               set = 1;
-
-               if (p[0] == '+') {
-                       p++;
-               } else if (p[0] == '-') {
-                       set = 0;
-                       p++;
-               }
-
-               cmd = simple_strtol(p, &status, 16);
-
-               /* either of these cases means invalid input, so do nothing. */
-               if ((status == p) || cmd >= BLK_SCSI_MAX_CMDS)
-                       return -EINVAL;
-
-               if (set)
-                       __set_bit(cmd, okbits);
-               else
-                       __clear_bit(cmd, okbits);
-       }
-
-       memcpy(target_okbits, okbits, sizeof(okbits));
-       return count;
-}
-
-static ssize_t rcf_readcmds_store(struct blk_cmd_filter *filter,
-                                 const char *page, size_t count)
-{
-       return rcf_cmds_store(filter, page, count, READ);
-}
-
-static ssize_t rcf_writecmds_store(struct blk_cmd_filter *filter,
-                                  const char *page, size_t count)
-{
-       return rcf_cmds_store(filter, page, count, WRITE);
-}
-
-struct rcf_sysfs_entry {
-       struct attribute attr;
-       ssize_t (*show)(struct blk_cmd_filter *, char *);
-       ssize_t (*store)(struct blk_cmd_filter *, const char *, size_t);
-};
-
-static struct rcf_sysfs_entry rcf_readcmds_entry = {
-       .attr = { .name = "read_table", .mode = S_IRUGO | S_IWUSR },
-       .show = rcf_readcmds_show,
-       .store = rcf_readcmds_store,
-};
-
-static struct rcf_sysfs_entry rcf_writecmds_entry = {
-       .attr = {.name = "write_table", .mode = S_IRUGO | S_IWUSR },
-       .show = rcf_writecmds_show,
-       .store = rcf_writecmds_store,
-};
-
-static struct attribute *default_attrs[] = {
-       &rcf_readcmds_entry.attr,
-       &rcf_writecmds_entry.attr,
-       NULL,
-};
-
-#define to_rcf(atr) container_of((atr), struct rcf_sysfs_entry, attr)
-
-static ssize_t
-rcf_attr_show(struct kobject *kobj, struct attribute *attr, char *page)
-{
-       struct rcf_sysfs_entry *entry = to_rcf(attr);
-       struct blk_cmd_filter *filter;
-
-       filter = container_of(kobj, struct blk_cmd_filter, kobj);
-       if (entry->show)
-               return entry->show(filter, page);
-
-       return 0;
-}
-
-static ssize_t
-rcf_attr_store(struct kobject *kobj, struct attribute *attr,
-                       const char *page, size_t length)
-{
-       struct rcf_sysfs_entry *entry = to_rcf(attr);
-       struct blk_cmd_filter *filter;
-
-       if (!capable(CAP_SYS_RAWIO))
-               return -EPERM;
-
-       if (!entry->store)
-               return -EINVAL;
-
-       filter = container_of(kobj, struct blk_cmd_filter, kobj);
-       return entry->store(filter, page, length);
-}
-
-static struct sysfs_ops rcf_sysfs_ops = {
-       .show = rcf_attr_show,
-       .store = rcf_attr_store,
-};
-
-static struct kobj_type rcf_ktype = {
-       .sysfs_ops = &rcf_sysfs_ops,
-       .default_attrs = default_attrs,
-};
-
-int blk_register_filter(struct gendisk *disk)
-{
-       int ret;
-       struct blk_cmd_filter *filter = &disk->queue->cmd_filter;
-
-       ret = kobject_init_and_add(&filter->kobj, &rcf_ktype,
-                                  &disk_to_dev(disk)->kobj,
-                                  "%s", "cmd_filter");
-       if (ret < 0)
-               return ret;
-
-       return 0;
-}
-EXPORT_SYMBOL(blk_register_filter);
-
-void blk_unregister_filter(struct gendisk *disk)
-{
-       struct blk_cmd_filter *filter = &disk->queue->cmd_filter;
-
-       kobject_put(&filter->kobj);
-}
-EXPORT_SYMBOL(blk_unregister_filter);
-#endif
index ca861927ba41b2dfc9ff80c139f6c8cc162fc251..6f2375339a996a794c17c96d0f32aa724fd1fae2 100644 (file)
@@ -100,6 +100,14 @@ int elv_rq_merge_ok(struct request *rq, struct bio *bio)
        if (bio_integrity(bio) != blk_integrity_rq(rq))
                return 0;
 
+       /*
+        * Don't merge if failfast settings don't match
+        */
+       if (bio_failfast_dev(bio)       != blk_failfast_dev(rq)         ||
+           bio_failfast_transport(bio) != blk_failfast_transport(rq)   ||
+           bio_failfast_driver(bio)    != blk_failfast_driver(rq))
+               return 0;
+
        if (!elv_iosched_allow_merge(rq, bio))
                return 0;
 
index 5f8e798ede4ee6d7c479bce1ee36f5488b717cc9..e5b10017a50b121a9288d6d0354bfe9ebb15e499 100644 (file)
 #include <scsi/scsi_ioctl.h>
 #include <scsi/scsi_cmnd.h>
 
+struct blk_cmd_filter {
+       unsigned long read_ok[BLK_SCSI_CMD_PER_LONG];
+       unsigned long write_ok[BLK_SCSI_CMD_PER_LONG];
+} blk_default_cmd_filter;
+
 /* Command group 3 is reserved and should never be used.  */
 const unsigned char scsi_command_size_tbl[8] =
 {
@@ -105,7 +110,7 @@ static int sg_emulated_host(struct request_queue *q, int __user *p)
        return put_user(1, p);
 }
 
-void blk_set_cmd_filter_defaults(struct blk_cmd_filter *filter)
+static void blk_set_cmd_filter_defaults(struct blk_cmd_filter *filter)
 {
        /* Basic read-only commands */
        __set_bit(TEST_UNIT_READY, filter->read_ok);
@@ -187,14 +192,37 @@ void blk_set_cmd_filter_defaults(struct blk_cmd_filter *filter)
        __set_bit(GPCMD_SET_STREAMING, filter->write_ok);
        __set_bit(GPCMD_SET_READ_AHEAD, filter->write_ok);
 }
-EXPORT_SYMBOL_GPL(blk_set_cmd_filter_defaults);
+
+int blk_verify_command(unsigned char *cmd, fmode_t has_write_perm)
+{
+       struct blk_cmd_filter *filter = &blk_default_cmd_filter;
+
+       /* root can do any command. */
+       if (capable(CAP_SYS_RAWIO))
+               return 0;
+
+       /* if there's no filter set, assume we're filtering everything out */
+       if (!filter)
+               return -EPERM;
+
+       /* Anybody who can open the device can do a read-safe command */
+       if (test_bit(cmd[0], filter->read_ok))
+               return 0;
+
+       /* Write-safe commands require a writable open */
+       if (test_bit(cmd[0], filter->write_ok) && has_write_perm)
+               return 0;
+
+       return -EPERM;
+}
+EXPORT_SYMBOL(blk_verify_command);
 
 static int blk_fill_sghdr_rq(struct request_queue *q, struct request *rq,
                             struct sg_io_hdr *hdr, fmode_t mode)
 {
        if (copy_from_user(rq->cmd, hdr->cmdp, hdr->cmd_len))
                return -EFAULT;
-       if (blk_verify_command(&q->cmd_filter, rq->cmd, mode & FMODE_WRITE))
+       if (blk_verify_command(rq->cmd, mode & FMODE_WRITE))
                return -EPERM;
 
        /*
@@ -427,7 +455,7 @@ int sg_scsi_ioctl(struct request_queue *q, struct gendisk *disk, fmode_t mode,
        if (in_len && copy_from_user(buffer, sic->data + cmdlen, in_len))
                goto error;
 
-       err = blk_verify_command(&q->cmd_filter, rq->cmd, mode & FMODE_WRITE);
+       err = blk_verify_command(rq->cmd, mode & FMODE_WRITE);
        if (err)
                goto error;
 
@@ -645,5 +673,11 @@ int scsi_cmd_ioctl(struct request_queue *q, struct gendisk *bd_disk, fmode_t mod
        blk_put_queue(q);
        return err;
 }
-
 EXPORT_SYMBOL(scsi_cmd_ioctl);
+
+int __init blk_scsi_ioctl_init(void)
+{
+       blk_set_cmd_filter_defaults(&blk_default_cmd_filter);
+       return 0;
+}
+fs_initcall(blk_scsi_ioctl_init);
index 88e42abf5d881b8bf443ecc4f58e3b4e76b3ecd3..0df8fcb687d6f00ce400c1b4677019a34af236a1 100644 (file)
@@ -61,6 +61,7 @@ static int acpi_ac_open_fs(struct inode *inode, struct file *file);
 static int acpi_ac_add(struct acpi_device *device);
 static int acpi_ac_remove(struct acpi_device *device, int type);
 static int acpi_ac_resume(struct acpi_device *device);
+static void acpi_ac_notify(struct acpi_device *device, u32 event);
 
 static const struct acpi_device_id ac_device_ids[] = {
        {"ACPI0003", 0},
@@ -72,10 +73,12 @@ static struct acpi_driver acpi_ac_driver = {
        .name = "ac",
        .class = ACPI_AC_CLASS,
        .ids = ac_device_ids,
+       .flags = ACPI_DRIVER_ALL_NOTIFY_EVENTS,
        .ops = {
                .add = acpi_ac_add,
                .remove = acpi_ac_remove,
                .resume = acpi_ac_resume,
+               .notify = acpi_ac_notify,
                },
 };
 
@@ -220,16 +223,14 @@ static int acpi_ac_remove_fs(struct acpi_device *device)
                                    Driver Model
    -------------------------------------------------------------------------- */
 
-static void acpi_ac_notify(acpi_handle handle, u32 event, void *data)
+static void acpi_ac_notify(struct acpi_device *device, u32 event)
 {
-       struct acpi_ac *ac = data;
-       struct acpi_device *device = NULL;
+       struct acpi_ac *ac = acpi_driver_data(device);
 
 
        if (!ac)
                return;
 
-       device = ac->device;
        switch (event) {
        default:
                ACPI_DEBUG_PRINT((ACPI_DB_INFO,
@@ -253,7 +254,6 @@ static void acpi_ac_notify(acpi_handle handle, u32 event, void *data)
 static int acpi_ac_add(struct acpi_device *device)
 {
        int result = 0;
-       acpi_status status = AE_OK;
        struct acpi_ac *ac = NULL;
 
 
@@ -286,13 +286,6 @@ static int acpi_ac_add(struct acpi_device *device)
        ac->charger.get_property = get_ac_property;
        power_supply_register(&ac->device->dev, &ac->charger);
 #endif
-       status = acpi_install_notify_handler(device->handle,
-                                            ACPI_ALL_NOTIFY, acpi_ac_notify,
-                                            ac);
-       if (ACPI_FAILURE(status)) {
-               result = -ENODEV;
-               goto end;
-       }
 
        printk(KERN_INFO PREFIX "%s [%s] (%s)\n",
               acpi_device_name(device), acpi_device_bid(device),
@@ -328,7 +321,6 @@ static int acpi_ac_resume(struct acpi_device *device)
 
 static int acpi_ac_remove(struct acpi_device *device, int type)
 {
-       acpi_status status = AE_OK;
        struct acpi_ac *ac = NULL;
 
 
@@ -337,8 +329,6 @@ static int acpi_ac_remove(struct acpi_device *device, int type)
 
        ac = acpi_driver_data(device);
 
-       status = acpi_remove_notify_handler(device->handle,
-                                           ACPI_ALL_NOTIFY, acpi_ac_notify);
 #ifdef CONFIG_ACPI_SYSFS_POWER
        if (ac->charger.dev)
                power_supply_unregister(&ac->charger);
index b0de6312919a82a455f20f8d06dddd8f1b672d80..58b4517ce71277b2d7c533d0cc43b0052a58f975 100644 (file)
@@ -796,13 +796,12 @@ static void acpi_battery_remove_fs(struct acpi_device *device)
                                  Driver Interface
    -------------------------------------------------------------------------- */
 
-static void acpi_battery_notify(acpi_handle handle, u32 event, void *data)
+static void acpi_battery_notify(struct acpi_device *device, u32 event)
 {
-       struct acpi_battery *battery = data;
-       struct acpi_device *device;
+       struct acpi_battery *battery = acpi_driver_data(device);
+
        if (!battery)
                return;
-       device = battery->device;
        acpi_battery_update(battery);
        acpi_bus_generate_proc_event(device, event,
                                     acpi_battery_present(battery));
@@ -819,7 +818,6 @@ static void acpi_battery_notify(acpi_handle handle, u32 event, void *data)
 static int acpi_battery_add(struct acpi_device *device)
 {
        int result = 0;
-       acpi_status status = 0;
        struct acpi_battery *battery = NULL;
        if (!device)
                return -EINVAL;
@@ -834,22 +832,12 @@ static int acpi_battery_add(struct acpi_device *device)
        acpi_battery_update(battery);
 #ifdef CONFIG_ACPI_PROCFS_POWER
        result = acpi_battery_add_fs(device);
-       if (result)
-               goto end;
 #endif
-       status = acpi_install_notify_handler(device->handle,
-                                            ACPI_ALL_NOTIFY,
-                                            acpi_battery_notify, battery);
-       if (ACPI_FAILURE(status)) {
-               ACPI_EXCEPTION((AE_INFO, status, "Installing notify handler"));
-               result = -ENODEV;
-               goto end;
-       }
-       printk(KERN_INFO PREFIX "%s Slot [%s] (battery %s)\n",
-              ACPI_BATTERY_DEVICE_NAME, acpi_device_bid(device),
-              device->status.battery_present ? "present" : "absent");
-      end:
-       if (result) {
+       if (!result) {
+               printk(KERN_INFO PREFIX "%s Slot [%s] (battery %s)\n",
+                       ACPI_BATTERY_DEVICE_NAME, acpi_device_bid(device),
+                       device->status.battery_present ? "present" : "absent");
+       } else {
 #ifdef CONFIG_ACPI_PROCFS_POWER
                acpi_battery_remove_fs(device);
 #endif
@@ -860,15 +848,11 @@ static int acpi_battery_add(struct acpi_device *device)
 
 static int acpi_battery_remove(struct acpi_device *device, int type)
 {
-       acpi_status status = 0;
        struct acpi_battery *battery = NULL;
 
        if (!device || !acpi_driver_data(device))
                return -EINVAL;
        battery = acpi_driver_data(device);
-       status = acpi_remove_notify_handler(device->handle,
-                                           ACPI_ALL_NOTIFY,
-                                           acpi_battery_notify);
 #ifdef CONFIG_ACPI_PROCFS_POWER
        acpi_battery_remove_fs(device);
 #endif
@@ -896,10 +880,12 @@ static struct acpi_driver acpi_battery_driver = {
        .name = "battery",
        .class = ACPI_BATTERY_CLASS,
        .ids = battery_device_ids,
+       .flags = ACPI_DRIVER_ALL_NOTIFY_EVENTS,
        .ops = {
                .add = acpi_battery_add,
                .resume = acpi_battery_resume,
                .remove = acpi_battery_remove,
+               .notify = acpi_battery_notify,
                },
 };
 
index 09c69806c1fc7693f91268ce86d0a8030dc2df59..f6baa77deefbd6d0743e92fc4a593b66a93c64c5 100644 (file)
@@ -192,6 +192,22 @@ static struct dmi_system_id acpi_osi_dmi_table[] __initdata = {
                     DMI_MATCH(DMI_PRODUCT_NAME, "ESPRIMO Mobile V5505"),
                },
        },
+       {
+       .callback = dmi_disable_osi_vista,
+       .ident = "Sony VGN-NS10J_S",
+       .matches = {
+                    DMI_MATCH(DMI_SYS_VENDOR, "Sony Corporation"),
+                    DMI_MATCH(DMI_PRODUCT_NAME, "VGN-NS10J_S"),
+               },
+       },
+       {
+       .callback = dmi_disable_osi_vista,
+       .ident = "Sony VGN-SR290J",
+       .matches = {
+                    DMI_MATCH(DMI_SYS_VENDOR, "Sony Corporation"),
+                    DMI_MATCH(DMI_PRODUCT_NAME, "Sony VGN-SR290J"),
+               },
+       },
 
        /*
         * BIOS invocation of _OSI(Linux) is almost always a BIOS bug.
index ae862f1798dc9d59d1b1e7479a6252dec22a185c..2876fc70c3a9b71915ef016f1ade1fa235c8db3f 100644 (file)
@@ -450,18 +450,16 @@ int acpi_bus_receive_event(struct acpi_bus_event *event)
                              Notification Handling
    -------------------------------------------------------------------------- */
 
-static int
-acpi_bus_check_device(struct acpi_device *device, int *status_changed)
+static void acpi_bus_check_device(acpi_handle handle)
 {
-       acpi_status status = 0;
+       struct acpi_device *device;
+       acpi_status status;
        struct acpi_device_status old_status;
 
-
+       if (acpi_bus_get_device(handle, &device))
+               return;
        if (!device)
-               return -EINVAL;
-
-       if (status_changed)
-               *status_changed = 0;
+               return;
 
        old_status = device->status;
 
@@ -471,22 +469,15 @@ acpi_bus_check_device(struct acpi_device *device, int *status_changed)
         */
        if (device->parent && !device->parent->status.present) {
                device->status = device->parent->status;
-               if (STRUCT_TO_INT(old_status) != STRUCT_TO_INT(device->status)) {
-                       if (status_changed)
-                               *status_changed = 1;
-               }
-               return 0;
+               return;
        }
 
        status = acpi_bus_get_status(device);
        if (ACPI_FAILURE(status))
-               return -ENODEV;
+               return;
 
        if (STRUCT_TO_INT(old_status) == STRUCT_TO_INT(device->status))
-               return 0;
-
-       if (status_changed)
-               *status_changed = 1;
+               return;
 
        /*
         * Device Insertion/Removal
@@ -498,33 +489,17 @@ acpi_bus_check_device(struct acpi_device *device, int *status_changed)
                ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Device removal detected\n"));
                /* TBD: Handle device removal */
        }
-
-       return 0;
 }
 
-static int acpi_bus_check_scope(struct acpi_device *device)
+static void acpi_bus_check_scope(acpi_handle handle)
 {
-       int result = 0;
-       int status_changed = 0;
-
-
-       if (!device)
-               return -EINVAL;
-
        /* Status Change? */
-       result = acpi_bus_check_device(device, &status_changed);
-       if (result)
-               return result;
-
-       if (!status_changed)
-               return 0;
+       acpi_bus_check_device(handle);
 
        /*
         * TBD: Enumerate child devices within this device's scope and
         *       run acpi_bus_check_device()'s on them.
         */
-
-       return 0;
 }
 
 static BLOCKING_NOTIFIER_HEAD(acpi_bus_notify_list);
@@ -547,22 +522,19 @@ EXPORT_SYMBOL_GPL(unregister_acpi_bus_notifier);
  */
 static void acpi_bus_notify(acpi_handle handle, u32 type, void *data)
 {
-       int result = 0;
        struct acpi_device *device = NULL;
+       struct acpi_driver *driver;
+
+       ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Notification %#02x to handle %p\n",
+                         type, handle));
 
        blocking_notifier_call_chain(&acpi_bus_notify_list,
                type, (void *)handle);
 
-       if (acpi_bus_get_device(handle, &device))
-               return;
-
        switch (type) {
 
        case ACPI_NOTIFY_BUS_CHECK:
-               ACPI_DEBUG_PRINT((ACPI_DB_INFO,
-                                 "Received BUS CHECK notification for device [%s]\n",
-                                 device->pnp.bus_id));
-               result = acpi_bus_check_scope(device);
+               acpi_bus_check_scope(handle);
                /*
                 * TBD: We'll need to outsource certain events to non-ACPI
                 *      drivers via the device manager (device.c).
@@ -570,10 +542,7 @@ static void acpi_bus_notify(acpi_handle handle, u32 type, void *data)
                break;
 
        case ACPI_NOTIFY_DEVICE_CHECK:
-               ACPI_DEBUG_PRINT((ACPI_DB_INFO,
-                                 "Received DEVICE CHECK notification for device [%s]\n",
-                                 device->pnp.bus_id));
-               result = acpi_bus_check_device(device, NULL);
+               acpi_bus_check_device(handle);
                /*
                 * TBD: We'll need to outsource certain events to non-ACPI
                 *      drivers via the device manager (device.c).
@@ -581,44 +550,26 @@ static void acpi_bus_notify(acpi_handle handle, u32 type, void *data)
                break;
 
        case ACPI_NOTIFY_DEVICE_WAKE:
-               ACPI_DEBUG_PRINT((ACPI_DB_INFO,
-                                 "Received DEVICE WAKE notification for device [%s]\n",
-                                 device->pnp.bus_id));
                /* TBD */
                break;
 
        case ACPI_NOTIFY_EJECT_REQUEST:
-               ACPI_DEBUG_PRINT((ACPI_DB_INFO,
-                                 "Received EJECT REQUEST notification for device [%s]\n",
-                                 device->pnp.bus_id));
                /* TBD */
                break;
 
        case ACPI_NOTIFY_DEVICE_CHECK_LIGHT:
-               ACPI_DEBUG_PRINT((ACPI_DB_INFO,
-                                 "Received DEVICE CHECK LIGHT notification for device [%s]\n",
-                                 device->pnp.bus_id));
                /* TBD: Exactly what does 'light' mean? */
                break;
 
        case ACPI_NOTIFY_FREQUENCY_MISMATCH:
-               ACPI_DEBUG_PRINT((ACPI_DB_INFO,
-                                 "Received FREQUENCY MISMATCH notification for device [%s]\n",
-                                 device->pnp.bus_id));
                /* TBD */
                break;
 
        case ACPI_NOTIFY_BUS_MODE_MISMATCH:
-               ACPI_DEBUG_PRINT((ACPI_DB_INFO,
-                                 "Received BUS MODE MISMATCH notification for device [%s]\n",
-                                 device->pnp.bus_id));
                /* TBD */
                break;
 
        case ACPI_NOTIFY_POWER_FAULT:
-               ACPI_DEBUG_PRINT((ACPI_DB_INFO,
-                                 "Received POWER FAULT notification for device [%s]\n",
-                                 device->pnp.bus_id));
                /* TBD */
                break;
 
@@ -629,7 +580,13 @@ static void acpi_bus_notify(acpi_handle handle, u32 type, void *data)
                break;
        }
 
-       return;
+       acpi_bus_get_device(handle, &device);
+       if (device) {
+               driver = device->driver;
+               if (driver && driver->ops.notify &&
+                   (driver->flags & ACPI_DRIVER_ALL_NOTIFY_EVENTS))
+                       driver->ops.notify(device, type);
+       }
 }
 
 /* --------------------------------------------------------------------------
index 8bd2c2a6884d5ce550ff336775e87844331e0e69..a8a5c29958c81faaea6b007626e40ee225ec0275 100644 (file)
@@ -140,46 +140,6 @@ struct device *acpi_get_physical_device(acpi_handle handle)
 
 EXPORT_SYMBOL(acpi_get_physical_device);
 
-/* ToDo: When a PCI bridge is found, return the PCI device behind the bridge
- *       This should work in general, but did not on a Lenovo T61 for the
- *      graphics card. But this must be fixed when the PCI device is
- *       bound and the kernel device struct is attached to the acpi device
- * Note: A success call will increase reference count by one
- *       Do call put_device(dev) on the returned device then
- */
-struct device *acpi_get_physical_pci_device(acpi_handle handle)
-{
-       struct device *dev;
-       long long device_id;
-       acpi_status status;
-
-       status =
-               acpi_evaluate_integer(handle, "_ADR", NULL, &device_id);
-
-       if (ACPI_FAILURE(status))
-               return NULL;
-
-       /* We need to attempt to determine whether the _ADR refers to a
-          PCI device or not. There's no terribly good way to do this,
-          so the best we can hope for is to assume that there'll never
-          be a device in the host bridge */
-       if (device_id >= 0x10000) {
-               /* It looks like a PCI device. Does it exist? */
-               dev = acpi_get_physical_device(handle);
-       } else {
-               /* It doesn't look like a PCI device. Does its parent
-                  exist? */
-               acpi_handle phandle;
-               if (acpi_get_parent(handle, &phandle))
-                       return NULL;
-               dev = acpi_get_physical_device(phandle);
-       }
-       if (!dev)
-               return NULL;
-       return dev;
-}
-EXPORT_SYMBOL(acpi_get_physical_pci_device);
-
 static int acpi_bind_one(struct device *dev, acpi_handle handle)
 {
        struct acpi_device *acpi_dev;
index d916bea729f1dfac4e81f020d581eee296ab42e0..71670719d61a6fec442792189fa0beac85e0324d 100644 (file)
@@ -79,6 +79,7 @@ static acpi_osd_handler acpi_irq_handler;
 static void *acpi_irq_context;
 static struct workqueue_struct *kacpid_wq;
 static struct workqueue_struct *kacpi_notify_wq;
+static struct workqueue_struct *kacpi_hotplug_wq;
 
 struct acpi_res_list {
        resource_size_t start;
@@ -192,8 +193,10 @@ acpi_status acpi_os_initialize1(void)
 {
        kacpid_wq = create_singlethread_workqueue("kacpid");
        kacpi_notify_wq = create_singlethread_workqueue("kacpi_notify");
+       kacpi_hotplug_wq = create_singlethread_workqueue("kacpi_hotplug");
        BUG_ON(!kacpid_wq);
        BUG_ON(!kacpi_notify_wq);
+       BUG_ON(!kacpi_hotplug_wq);
        return AE_OK;
 }
 
@@ -206,6 +209,7 @@ acpi_status acpi_os_terminate(void)
 
        destroy_workqueue(kacpid_wq);
        destroy_workqueue(kacpi_notify_wq);
+       destroy_workqueue(kacpi_hotplug_wq);
 
        return AE_OK;
 }
@@ -716,6 +720,7 @@ static acpi_status __acpi_os_execute(acpi_execute_type type,
        acpi_status status = AE_OK;
        struct acpi_os_dpc *dpc;
        struct workqueue_struct *queue;
+       work_func_t func;
        int ret;
        ACPI_DEBUG_PRINT((ACPI_DB_EXEC,
                          "Scheduling function [%p(%p)] for deferred execution.\n",
@@ -740,15 +745,17 @@ static acpi_status __acpi_os_execute(acpi_execute_type type,
        dpc->function = function;
        dpc->context = context;
 
-       if (!hp) {
-               INIT_WORK(&dpc->work, acpi_os_execute_deferred);
-               queue = (type == OSL_NOTIFY_HANDLER) ?
-                       kacpi_notify_wq : kacpid_wq;
-               ret = queue_work(queue, &dpc->work);
-       } else {
-               INIT_WORK(&dpc->work, acpi_os_execute_hp_deferred);
-               ret = schedule_work(&dpc->work);
-       }
+       /*
+        * We can't run hotplug code in keventd_wq/kacpid_wq/kacpid_notify_wq
+        * because the hotplug code may call driver .remove() functions,
+        * which invoke flush_scheduled_work/acpi_os_wait_events_complete
+        * to flush these workqueues.
+        */
+       queue = hp ? kacpi_hotplug_wq :
+               (type == OSL_NOTIFY_HANDLER ? kacpi_notify_wq : kacpid_wq);
+       func = hp ? acpi_os_execute_hp_deferred : acpi_os_execute_deferred;
+       INIT_WORK(&dpc->work, func);
+       ret = queue_work(queue, &dpc->work);
 
        if (!ret) {
                printk(KERN_ERR PREFIX
index bc46de3d967f62904962e06bf9beef26095a9a78..a5a77b78a7237cbbb6e77a707f73a0861426718d 100644 (file)
  */
 
 #include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/init.h>
 #include <linux/types.h>
-#include <linux/proc_fs.h>
-#include <linux/spinlock.h>
-#include <linux/pm.h>
 #include <linux/pci.h>
 #include <linux/acpi.h>
 #include <acpi/acpi_bus.h>
 #define _COMPONENT             ACPI_PCI_COMPONENT
 ACPI_MODULE_NAME("pci_bind");
 
-struct acpi_pci_data {
-       struct acpi_pci_id id;
-       struct pci_bus *bus;
-       struct pci_dev *dev;
-};
-
-static int acpi_pci_unbind(struct acpi_device *device);
-
-static void acpi_pci_data_handler(acpi_handle handle, u32 function,
-                                 void *context)
-{
-
-       /* TBD: Anything we need to do here? */
-
-       return;
-}
-
-/**
- * acpi_get_pci_id
- * ------------------
- * This function is used by the ACPI Interpreter (a.k.a. Core Subsystem)
- * to resolve PCI information for ACPI-PCI devices defined in the namespace.
- * This typically occurs when resolving PCI operation region information.
- */
-acpi_status acpi_get_pci_id(acpi_handle handle, struct acpi_pci_id *id)
+static int acpi_pci_unbind(struct acpi_device *device)
 {
-       int result = 0;
-       acpi_status status = AE_OK;
-       struct acpi_device *device = NULL;
-       struct acpi_pci_data *data = NULL;
-
-
-       if (!id)
-               return AE_BAD_PARAMETER;
-
-       result = acpi_bus_get_device(handle, &device);
-       if (result) {
-               printk(KERN_ERR PREFIX
-                           "Invalid ACPI Bus context for device %s\n",
-                           acpi_device_bid(device));
-               return AE_NOT_EXIST;
-       }
-
-       status = acpi_get_data(handle, acpi_pci_data_handler, (void **)&data);
-       if (ACPI_FAILURE(status) || !data) {
-               ACPI_EXCEPTION((AE_INFO, status,
-                               "Invalid ACPI-PCI context for device %s",
-                               acpi_device_bid(device)));
-               return status;
-       }
+       struct pci_dev *dev;
 
-       *id = data->id;
+       dev = acpi_get_pci_dev(device->handle);
+       if (!dev || !dev->subordinate)
+               goto out;
 
-       /*
-          id->segment = data->id.segment;
-          id->bus = data->id.bus;
-          id->device = data->id.device;
-          id->function = data->id.function;
-        */
+       acpi_pci_irq_del_prt(dev->subordinate);
 
-       ACPI_DEBUG_PRINT((ACPI_DB_INFO,
-                         "Device %s has PCI address %04x:%02x:%02x.%d\n",
-                         acpi_device_bid(device), id->segment, id->bus,
-                         id->device, id->function));
+       device->ops.bind = NULL;
+       device->ops.unbind = NULL;
 
-       return AE_OK;
+out:
+       pci_dev_put(dev);
+       return 0;
 }
 
-EXPORT_SYMBOL(acpi_get_pci_id);
-
-int acpi_pci_bind(struct acpi_device *device)
+static int acpi_pci_bind(struct acpi_device *device)
 {
-       int result = 0;
        acpi_status status;
-       struct acpi_pci_data *data;
-       struct acpi_pci_data *pdata;
-       struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
        acpi_handle handle;
+       struct pci_bus *bus;
+       struct pci_dev *dev;
 
-       if (!device || !device->parent)
-               return -EINVAL;
-
-       data = kzalloc(sizeof(struct acpi_pci_data), GFP_KERNEL);
-       if (!data)
-               return -ENOMEM;
-
-       status = acpi_get_name(device->handle, ACPI_FULL_PATHNAME, &buffer);
-       if (ACPI_FAILURE(status)) {
-               kfree(data);
-               return -ENODEV;
-       }
-
-       ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Binding PCI device [%s]...\n",
-                         (char *)buffer.pointer));
-
-       /* 
-        * Segment & Bus
-        * -------------
-        * These are obtained via the parent device's ACPI-PCI context.
-        */
-       status = acpi_get_data(device->parent->handle, acpi_pci_data_handler,
-                              (void **)&pdata);
-       if (ACPI_FAILURE(status) || !pdata || !pdata->bus) {
-               ACPI_EXCEPTION((AE_INFO, status,
-                               "Invalid ACPI-PCI context for parent device %s",
-                               acpi_device_bid(device->parent)));
-               result = -ENODEV;
-               goto end;
-       }
-       data->id.segment = pdata->id.segment;
-       data->id.bus = pdata->bus->number;
-
-       /*
-        * Device & Function
-        * -----------------
-        * These are simply obtained from the device's _ADR method.  Note
-        * that a value of zero is valid.
-        */
-       data->id.device = device->pnp.bus_address >> 16;
-       data->id.function = device->pnp.bus_address & 0xFFFF;
-
-       ACPI_DEBUG_PRINT((ACPI_DB_INFO, "...to %04x:%02x:%02x.%d\n",
-                         data->id.segment, data->id.bus, data->id.device,
-                         data->id.function));
-
-       /*
-        * TBD: Support slot devices (e.g. function=0xFFFF).
-        */
-
-       /* 
-        * Locate PCI Device
-        * -----------------
-        * Locate matching device in PCI namespace.  If it doesn't exist
-        * this typically means that the device isn't currently inserted
-        * (e.g. docking station, port replicator, etc.).
-        */
-       data->dev = pci_get_slot(pdata->bus,
-                               PCI_DEVFN(data->id.device, data->id.function));
-       if (!data->dev) {
-               ACPI_DEBUG_PRINT((ACPI_DB_INFO,
-                                 "Device %04x:%02x:%02x.%d not present in PCI namespace\n",
-                                 data->id.segment, data->id.bus,
-                                 data->id.device, data->id.function));
-               result = -ENODEV;
-               goto end;
-       }
-       if (!data->dev->bus) {
-               printk(KERN_ERR PREFIX
-                           "Device %04x:%02x:%02x.%d has invalid 'bus' field\n",
-                           data->id.segment, data->id.bus,
-                           data->id.device, data->id.function);
-               result = -ENODEV;
-               goto end;
-       }
+       dev = acpi_get_pci_dev(device->handle);
+       if (!dev)
+               return 0;
 
        /*
-        * PCI Bridge?
-        * -----------
-        * If so, set the 'bus' field and install the 'bind' function to 
-        * facilitate callbacks for all of its children.
+        * Install the 'bind' function to facilitate callbacks for
+        * children of the P2P bridge.
         */
-       if (data->dev->subordinate) {
+       if (dev->subordinate) {
                ACPI_DEBUG_PRINT((ACPI_DB_INFO,
                                  "Device %04x:%02x:%02x.%d is a PCI bridge\n",
-                                 data->id.segment, data->id.bus,
-                                 data->id.device, data->id.function));
-               data->bus = data->dev->subordinate;
+                                 pci_domain_nr(dev->bus), dev->bus->number,
+                                 PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn)));
                device->ops.bind = acpi_pci_bind;
                device->ops.unbind = acpi_pci_unbind;
        }
 
        /*
-        * Attach ACPI-PCI Context
-        * -----------------------
-        * Thus binding the ACPI and PCI devices.
-        */
-       status = acpi_attach_data(device->handle, acpi_pci_data_handler, data);
-       if (ACPI_FAILURE(status)) {
-               ACPI_EXCEPTION((AE_INFO, status,
-                               "Unable to attach ACPI-PCI context to device %s",
-                               acpi_device_bid(device)));
-               result = -ENODEV;
-               goto end;
-       }
-
-       /*
-        * PCI Routing Table
-        * -----------------
-        * Evaluate and parse _PRT, if exists.  This code is independent of 
-        * PCI bridges (above) to allow parsing of _PRT objects within the
-        * scope of non-bridge devices.  Note that _PRTs within the scope of
-        * a PCI bridge assume the bridge's subordinate bus number.
+        * Evaluate and parse _PRT, if exists.  This code allows parsing of
+        * _PRT objects within the scope of non-bridge devices.  Note that
+        * _PRTs within the scope of a PCI bridge assume the bridge's
+        * subordinate bus number.
         *
         * TBD: Can _PRTs exist within the scope of non-bridge PCI devices?
         */
        status = acpi_get_handle(device->handle, METHOD_NAME__PRT, &handle);
-       if (ACPI_SUCCESS(status)) {
-               if (data->bus)  /* PCI-PCI bridge */
-                       acpi_pci_irq_add_prt(device->handle, data->id.segment,
-                                            data->bus->number);
-               else            /* non-bridge PCI device */
-                       acpi_pci_irq_add_prt(device->handle, data->id.segment,
-                                            data->id.bus);
-       }
-
-      end:
-       kfree(buffer.pointer);
-       if (result) {
-               pci_dev_put(data->dev);
-               kfree(data);
-       }
-       return result;
-}
-
-static int acpi_pci_unbind(struct acpi_device *device)
-{
-       int result = 0;
-       acpi_status status;
-       struct acpi_pci_data *data;
-       struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
-
-
-       if (!device || !device->parent)
-               return -EINVAL;
-
-       status = acpi_get_name(device->handle, ACPI_FULL_PATHNAME, &buffer);
        if (ACPI_FAILURE(status))
-               return -ENODEV;
+               goto out;
 
-       ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Unbinding PCI device [%s]...\n",
-                         (char *) buffer.pointer));
-       kfree(buffer.pointer);
+       if (dev->subordinate)
+               bus = dev->subordinate;
+       else
+               bus = dev->bus;
 
-       status =
-           acpi_get_data(device->handle, acpi_pci_data_handler,
-                         (void **)&data);
-       if (ACPI_FAILURE(status)) {
-               result = -ENODEV;
-               goto end;
-       }
+       acpi_pci_irq_add_prt(device->handle, bus);
 
-       status = acpi_detach_data(device->handle, acpi_pci_data_handler);
-       if (ACPI_FAILURE(status)) {
-               ACPI_EXCEPTION((AE_INFO, status,
-                               "Unable to detach data from device %s",
-                               acpi_device_bid(device)));
-               result = -ENODEV;
-               goto end;
-       }
-       if (data->dev->subordinate) {
-               acpi_pci_irq_del_prt(data->id.segment, data->bus->number);
-       }
-       pci_dev_put(data->dev);
-       kfree(data);
-
-      end:
-       return result;
+out:
+       pci_dev_put(dev);
+       return 0;
 }
 
-int
-acpi_pci_bind_root(struct acpi_device *device,
-                  struct acpi_pci_id *id, struct pci_bus *bus)
+int acpi_pci_bind_root(struct acpi_device *device)
 {
-       int result = 0;
-       acpi_status status;
-       struct acpi_pci_data *data = NULL;
-       struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
-
-       if (!device || !id || !bus) {
-               return -EINVAL;
-       }
-
-       data = kzalloc(sizeof(struct acpi_pci_data), GFP_KERNEL);
-       if (!data)
-               return -ENOMEM;
-
-       data->id = *id;
-       data->bus = bus;
        device->ops.bind = acpi_pci_bind;
        device->ops.unbind = acpi_pci_unbind;
 
-       status = acpi_get_name(device->handle, ACPI_FULL_PATHNAME, &buffer);
-       if (ACPI_FAILURE(status)) {
-               kfree (data);
-               return -ENODEV;
-       }
-
-       ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Binding PCI root bridge [%s] to "
-                       "%04x:%02x\n", (char *)buffer.pointer,
-                       id->segment, id->bus));
-
-       status = acpi_attach_data(device->handle, acpi_pci_data_handler, data);
-       if (ACPI_FAILURE(status)) {
-               ACPI_EXCEPTION((AE_INFO, status,
-                               "Unable to attach ACPI-PCI context to device %s",
-                               (char *)buffer.pointer));
-               result = -ENODEV;
-               goto end;
-       }
-
-      end:
-       kfree(buffer.pointer);
-       if (result != 0)
-               kfree(data);
-
-       return result;
+       return 0;
 }
index 2faa9e2ac89331b9c46c1de0de560a0225ce88e2..b794eb88ab9030506873ab6879ab05860cc083b8 100644 (file)
@@ -182,7 +182,7 @@ static void do_prt_fixups(struct acpi_prt_entry *entry,
        }
 }
 
-static int acpi_pci_irq_add_entry(acpi_handle handle, int segment, int bus,
+static int acpi_pci_irq_add_entry(acpi_handle handle, struct pci_bus *bus,
                                  struct acpi_pci_routing_table *prt)
 {
        struct acpi_prt_entry *entry;
@@ -196,8 +196,8 @@ static int acpi_pci_irq_add_entry(acpi_handle handle, int segment, int bus,
         * 1=INTA, 2=INTB.  We use the PCI encoding throughout, so convert
         * it here.
         */
-       entry->id.segment = segment;
-       entry->id.bus = bus;
+       entry->id.segment = pci_domain_nr(bus);
+       entry->id.bus = bus->number;
        entry->id.device = (prt->address >> 16) & 0xFFFF;
        entry->pin = prt->pin + 1;
 
@@ -242,7 +242,7 @@ static int acpi_pci_irq_add_entry(acpi_handle handle, int segment, int bus,
        return 0;
 }
 
-int acpi_pci_irq_add_prt(acpi_handle handle, int segment, int bus)
+int acpi_pci_irq_add_prt(acpi_handle handle, struct pci_bus *bus)
 {
        acpi_status status;
        struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
@@ -271,7 +271,7 @@ int acpi_pci_irq_add_prt(acpi_handle handle, int segment, int bus)
 
        entry = buffer.pointer;
        while (entry && (entry->length > 0)) {
-               acpi_pci_irq_add_entry(handle, segment, bus, entry);
+               acpi_pci_irq_add_entry(handle, bus, entry);
                entry = (struct acpi_pci_routing_table *)
                    ((unsigned long)entry + entry->length);
        }
@@ -280,16 +280,17 @@ int acpi_pci_irq_add_prt(acpi_handle handle, int segment, int bus)
        return 0;
 }
 
-void acpi_pci_irq_del_prt(int segment, int bus)
+void acpi_pci_irq_del_prt(struct pci_bus *bus)
 {
        struct acpi_prt_entry *entry, *tmp;
 
        printk(KERN_DEBUG
               "ACPI: Delete PCI Interrupt Routing Table for %04x:%02x\n",
-              segment, bus);
+              pci_domain_nr(bus), bus->number);
        spin_lock(&acpi_prt_lock);
        list_for_each_entry_safe(entry, tmp, &acpi_prt_list, list) {
-               if (segment == entry->id.segment && bus == entry->id.bus) {
+               if (pci_domain_nr(bus) == entry->id.segment
+                       && bus->number == entry->id.bus) {
                        list_del(&entry->list);
                        kfree(entry);
                }
index 196f97d00956aa379b95b8fbe8e5a6cb6ddd10eb..55b5b90c2a44288f786d266a7cc5810b215ba227 100644 (file)
@@ -63,9 +63,10 @@ static struct acpi_driver acpi_pci_root_driver = {
 
 struct acpi_pci_root {
        struct list_head node;
-       struct acpi_device * device;
-       struct acpi_pci_id id;
+       struct acpi_device *device;
        struct pci_bus *bus;
+       u16 segment;
+       u8 bus_nr;
 
        u32 osc_support_set;    /* _OSC state of support bits */
        u32 osc_control_set;    /* _OSC state of control bits */
@@ -82,7 +83,7 @@ static DEFINE_MUTEX(osc_lock);
 int acpi_pci_register_driver(struct acpi_pci_driver *driver)
 {
        int n = 0;
-       struct list_head *entry;
+       struct acpi_pci_root *root;
 
        struct acpi_pci_driver **pptr = &sub_driver;
        while (*pptr)
@@ -92,9 +93,7 @@ int acpi_pci_register_driver(struct acpi_pci_driver *driver)
        if (!driver->add)
                return 0;
 
-       list_for_each(entry, &acpi_pci_roots) {
-               struct acpi_pci_root *root;
-               root = list_entry(entry, struct acpi_pci_root, node);
+       list_for_each_entry(root, &acpi_pci_roots, node) {
                driver->add(root->device->handle);
                n++;
        }
@@ -106,7 +105,7 @@ EXPORT_SYMBOL(acpi_pci_register_driver);
 
 void acpi_pci_unregister_driver(struct acpi_pci_driver *driver)
 {
-       struct list_head *entry;
+       struct acpi_pci_root *root;
 
        struct acpi_pci_driver **pptr = &sub_driver;
        while (*pptr) {
@@ -120,28 +119,48 @@ void acpi_pci_unregister_driver(struct acpi_pci_driver *driver)
        if (!driver->remove)
                return;
 
-       list_for_each(entry, &acpi_pci_roots) {
-               struct acpi_pci_root *root;
-               root = list_entry(entry, struct acpi_pci_root, node);
+       list_for_each_entry(root, &acpi_pci_roots, node)
                driver->remove(root->device->handle);
-       }
 }
 
 EXPORT_SYMBOL(acpi_pci_unregister_driver);
 
 acpi_handle acpi_get_pci_rootbridge_handle(unsigned int seg, unsigned int bus)
 {
-       struct acpi_pci_root *tmp;
+       struct acpi_pci_root *root;
        
-       list_for_each_entry(tmp, &acpi_pci_roots, node) {
-               if ((tmp->id.segment == (u16) seg) && (tmp->id.bus == (u16) bus))
-                       return tmp->device->handle;
-       }
+       list_for_each_entry(root, &acpi_pci_roots, node)
+               if ((root->segment == (u16) seg) && (root->bus_nr == (u16) bus))
+                       return root->device->handle;
        return NULL;            
 }
 
 EXPORT_SYMBOL_GPL(acpi_get_pci_rootbridge_handle);
 
+/**
+ * acpi_is_root_bridge - determine whether an ACPI CA node is a PCI root bridge
+ * @handle - the ACPI CA node in question.
+ *
+ * Note: we could make this API take a struct acpi_device * instead, but
+ * for now, it's more convenient to operate on an acpi_handle.
+ */
+int acpi_is_root_bridge(acpi_handle handle)
+{
+       int ret;
+       struct acpi_device *device;
+
+       ret = acpi_bus_get_device(handle, &device);
+       if (ret)
+               return 0;
+
+       ret = acpi_match_device_ids(device, root_device_ids);
+       if (ret)
+               return 0;
+       else
+               return 1;
+}
+EXPORT_SYMBOL_GPL(acpi_is_root_bridge);
+
 static acpi_status
 get_root_bridge_busnr_callback(struct acpi_resource *resource, void *data)
 {
@@ -161,19 +180,22 @@ get_root_bridge_busnr_callback(struct acpi_resource *resource, void *data)
        return AE_OK;
 }
 
-static acpi_status try_get_root_bridge_busnr(acpi_handle handle, int *busnum)
+static acpi_status try_get_root_bridge_busnr(acpi_handle handle,
+                                            unsigned long long *bus)
 {
        acpi_status status;
+       int busnum;
 
-       *busnum = -1;
+       busnum = -1;
        status =
            acpi_walk_resources(handle, METHOD_NAME__CRS,
-                               get_root_bridge_busnr_callback, busnum);
+                               get_root_bridge_busnr_callback, &busnum);
        if (ACPI_FAILURE(status))
                return status;
        /* Check if we really get a bus number from _CRS */
-       if (*busnum == -1)
+       if (busnum == -1)
                return AE_ERROR;
+       *bus = busnum;
        return AE_OK;
 }
 
@@ -298,6 +320,7 @@ static acpi_status acpi_pci_osc_support(struct acpi_pci_root *root, u32 flags)
 static struct acpi_pci_root *acpi_pci_find_root(acpi_handle handle)
 {
        struct acpi_pci_root *root;
+
        list_for_each_entry(root, &acpi_pci_roots, node) {
                if (root->device->handle == handle)
                        return root;
@@ -305,6 +328,87 @@ static struct acpi_pci_root *acpi_pci_find_root(acpi_handle handle)
        return NULL;
 }
 
+struct acpi_handle_node {
+       struct list_head node;
+       acpi_handle handle;
+};
+
+/**
+ * acpi_get_pci_dev - convert ACPI CA handle to struct pci_dev
+ * @handle: the handle in question
+ *
+ * Given an ACPI CA handle, the desired PCI device is located in the
+ * list of PCI devices.
+ *
+ * If the device is found, its reference count is increased and this
+ * function returns a pointer to its data structure.  The caller must
+ * decrement the reference count by calling pci_dev_put().
+ * If no device is found, %NULL is returned.
+ */
+struct pci_dev *acpi_get_pci_dev(acpi_handle handle)
+{
+       int dev, fn;
+       unsigned long long adr;
+       acpi_status status;
+       acpi_handle phandle;
+       struct pci_bus *pbus;
+       struct pci_dev *pdev = NULL;
+       struct acpi_handle_node *node, *tmp;
+       struct acpi_pci_root *root;
+       LIST_HEAD(device_list);
+
+       /*
+        * Walk up the ACPI CA namespace until we reach a PCI root bridge.
+        */
+       phandle = handle;
+       while (!acpi_is_root_bridge(phandle)) {
+               node = kzalloc(sizeof(struct acpi_handle_node), GFP_KERNEL);
+               if (!node)
+                       goto out;
+
+               INIT_LIST_HEAD(&node->node);
+               node->handle = phandle;
+               list_add(&node->node, &device_list);
+
+               status = acpi_get_parent(phandle, &phandle);
+               if (ACPI_FAILURE(status))
+                       goto out;
+       }
+
+       root = acpi_pci_find_root(phandle);
+       if (!root)
+               goto out;
+
+       pbus = root->bus;
+
+       /*
+        * Now, walk back down the PCI device tree until we return to our
+        * original handle. Assumes that everything between the PCI root
+        * bridge and the device we're looking for must be a P2P bridge.
+        */
+       list_for_each_entry(node, &device_list, node) {
+               acpi_handle hnd = node->handle;
+               status = acpi_evaluate_integer(hnd, "_ADR", NULL, &adr);
+               if (ACPI_FAILURE(status))
+                       goto out;
+               dev = (adr >> 16) & 0xffff;
+               fn  = adr & 0xffff;
+
+               pdev = pci_get_slot(pbus, PCI_DEVFN(dev, fn));
+               if (!pdev || hnd == handle)
+                       break;
+
+               pbus = pdev->subordinate;
+               pci_dev_put(pdev);
+       }
+out:
+       list_for_each_entry_safe(node, tmp, &device_list, node)
+               kfree(node);
+
+       return pdev;
+}
+EXPORT_SYMBOL_GPL(acpi_get_pci_dev);
+
 /**
  * acpi_pci_osc_control_set - commit requested control to Firmware
  * @handle: acpi_handle for the target ACPI object
@@ -363,31 +467,46 @@ EXPORT_SYMBOL(acpi_pci_osc_control_set);
 
 static int __devinit acpi_pci_root_add(struct acpi_device *device)
 {
-       int result = 0;
-       struct acpi_pci_root *root = NULL;
-       struct acpi_pci_root *tmp;
-       acpi_status status = AE_OK;
-       unsigned long long value = 0;
-       acpi_handle handle = NULL;
+       unsigned long long segment, bus;
+       acpi_status status;
+       int result;
+       struct acpi_pci_root *root;
+       acpi_handle handle;
        struct acpi_device *child;
        u32 flags, base_flags;
 
+       segment = 0;
+       status = acpi_evaluate_integer(device->handle, METHOD_NAME__SEG, NULL,
+                                      &segment);
+       if (ACPI_FAILURE(status) && status != AE_NOT_FOUND) {
+               printk(KERN_ERR PREFIX "can't evaluate _SEG\n");
+               return -ENODEV;
+       }
 
-       if (!device)
-               return -EINVAL;
+       /* Check _CRS first, then _BBN.  If no _BBN, default to zero. */
+       bus = 0;
+       status = try_get_root_bridge_busnr(device->handle, &bus);
+       if (ACPI_FAILURE(status)) {
+               status = acpi_evaluate_integer(device->handle, METHOD_NAME__BBN,                                               NULL, &bus);
+               if (ACPI_FAILURE(status) && status != AE_NOT_FOUND) {
+                       printk(KERN_ERR PREFIX
+                            "no bus number in _CRS and can't evaluate _BBN\n");
+                       return -ENODEV;
+               }
+       }
 
        root = kzalloc(sizeof(struct acpi_pci_root), GFP_KERNEL);
        if (!root)
                return -ENOMEM;
-       INIT_LIST_HEAD(&root->node);
 
+       INIT_LIST_HEAD(&root->node);
        root->device = device;
+       root->segment = segment & 0xFFFF;
+       root->bus_nr = bus & 0xFF;
        strcpy(acpi_device_name(device), ACPI_PCI_ROOT_DEVICE_NAME);
        strcpy(acpi_device_class(device), ACPI_PCI_ROOT_CLASS);
        device->driver_data = root;
 
-       device->ops.bind = acpi_pci_bind;
-
        /*
         * All supported architectures that use ACPI have support for
         * PCI domains, so we indicate this in _OSC support capabilities.
@@ -395,79 +514,6 @@ static int __devinit acpi_pci_root_add(struct acpi_device *device)
        flags = base_flags = OSC_PCI_SEGMENT_GROUPS_SUPPORT;
        acpi_pci_osc_support(root, flags);
 
-       /* 
-        * Segment
-        * -------
-        * Obtained via _SEG, if exists, otherwise assumed to be zero (0).
-        */
-       status = acpi_evaluate_integer(device->handle, METHOD_NAME__SEG, NULL,
-                                      &value);
-       switch (status) {
-       case AE_OK:
-               root->id.segment = (u16) value;
-               break;
-       case AE_NOT_FOUND:
-               ACPI_DEBUG_PRINT((ACPI_DB_INFO,
-                                 "Assuming segment 0 (no _SEG)\n"));
-               root->id.segment = 0;
-               break;
-       default:
-               ACPI_EXCEPTION((AE_INFO, status, "Evaluating _SEG"));
-               result = -ENODEV;
-               goto end;
-       }
-
-       /* 
-        * Bus
-        * ---
-        * Obtained via _BBN, if exists, otherwise assumed to be zero (0).
-        */
-       status = acpi_evaluate_integer(device->handle, METHOD_NAME__BBN, NULL,
-                                      &value);
-       switch (status) {
-       case AE_OK:
-               root->id.bus = (u16) value;
-               break;
-       case AE_NOT_FOUND:
-               ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Assuming bus 0 (no _BBN)\n"));
-               root->id.bus = 0;
-               break;
-       default:
-               ACPI_EXCEPTION((AE_INFO, status, "Evaluating _BBN"));
-               result = -ENODEV;
-               goto end;
-       }
-
-       /* Some systems have wrong _BBN */
-       list_for_each_entry(tmp, &acpi_pci_roots, node) {
-               if ((tmp->id.segment == root->id.segment)
-                   && (tmp->id.bus == root->id.bus)) {
-                       int bus = 0;
-                       acpi_status status;
-
-                       printk(KERN_ERR PREFIX
-                                   "Wrong _BBN value, reboot"
-                                   " and use option 'pci=noacpi'\n");
-
-                       status = try_get_root_bridge_busnr(device->handle, &bus);
-                       if (ACPI_FAILURE(status))
-                               break;
-                       if (bus != root->id.bus) {
-                               printk(KERN_INFO PREFIX
-                                      "PCI _CRS %d overrides _BBN 0\n", bus);
-                               root->id.bus = bus;
-                       }
-                       break;
-               }
-       }
-       /*
-        * Device & Function
-        * -----------------
-        * Obtained from _ADR (which has already been evaluated for us).
-        */
-       root->id.device = device->pnp.bus_address >> 16;
-       root->id.function = device->pnp.bus_address & 0xFFFF;
-
        /*
         * TBD: Need PCI interface for enumeration/configuration of roots.
         */
@@ -477,7 +523,7 @@ static int __devinit acpi_pci_root_add(struct acpi_device *device)
 
        printk(KERN_INFO PREFIX "%s [%s] (%04x:%02x)\n",
               acpi_device_name(device), acpi_device_bid(device),
-              root->id.segment, root->id.bus);
+              root->segment, root->bus_nr);
 
        /*
         * Scan the Root Bridge
@@ -486,11 +532,11 @@ static int __devinit acpi_pci_root_add(struct acpi_device *device)
         * PCI namespace does not get created until this call is made (and 
         * thus the root bridge's pci_dev does not exist).
         */
-       root->bus = pci_acpi_scan_root(device, root->id.segment, root->id.bus);
+       root->bus = pci_acpi_scan_root(device, segment, bus);
        if (!root->bus) {
                printk(KERN_ERR PREFIX
                            "Bus %04x:%02x not present in PCI namespace\n",
-                           root->id.segment, root->id.bus);
+                           root->segment, root->bus_nr);
                result = -ENODEV;
                goto end;
        }
@@ -500,7 +546,7 @@ static int __devinit acpi_pci_root_add(struct acpi_device *device)
         * -----------------------
         * Thus binding the ACPI and PCI devices.
         */
-       result = acpi_pci_bind_root(device, &root->id, root->bus);
+       result = acpi_pci_bind_root(device);
        if (result)
                goto end;
 
@@ -511,8 +557,7 @@ static int __devinit acpi_pci_root_add(struct acpi_device *device)
         */
        status = acpi_get_handle(device->handle, METHOD_NAME__PRT, &handle);
        if (ACPI_SUCCESS(status))
-               result = acpi_pci_irq_add_prt(device->handle, root->id.segment,
-                                             root->id.bus);
+               result = acpi_pci_irq_add_prt(device->handle, root->bus);
 
        /*
         * Scan and bind all _ADR-Based Devices
@@ -531,42 +576,28 @@ static int __devinit acpi_pci_root_add(struct acpi_device *device)
        if (flags != base_flags)
                acpi_pci_osc_support(root, flags);
 
-      end:
-       if (result) {
-               if (!list_empty(&root->node))
-                       list_del(&root->node);
-               kfree(root);
-       }
+       return 0;
 
+end:
+       if (!list_empty(&root->node))
+               list_del(&root->node);
+       kfree(root);
        return result;
 }
 
 static int acpi_pci_root_start(struct acpi_device *device)
 {
-       struct acpi_pci_root *root;
+       struct acpi_pci_root *root = acpi_driver_data(device);
 
-
-       list_for_each_entry(root, &acpi_pci_roots, node) {
-               if (root->device == device) {
-                       pci_bus_add_devices(root->bus);
-                       return 0;
-               }
-       }
-       return -ENODEV;
+       pci_bus_add_devices(root->bus);
+       return 0;
 }
 
 static int acpi_pci_root_remove(struct acpi_device *device, int type)
 {
-       struct acpi_pci_root *root = NULL;
-
-
-       if (!device || !acpi_driver_data(device))
-               return -EINVAL;
-
-       root = acpi_driver_data(device);
+       struct acpi_pci_root *root = acpi_driver_data(device);
 
        kfree(root);
-
        return 0;
 }
 
index 56665a63bf19b29f86c4088f02cd0ff8c7ad9faa..d74365d4a6e7d03f781954663301c50d30ac77da 100644 (file)
@@ -194,7 +194,7 @@ static int acpi_power_get_list_state(struct acpi_handle_list *list, int *state)
 
 static int acpi_power_on(acpi_handle handle, struct acpi_device *dev)
 {
-       int result = 0, state;
+       int result = 0;
        int found = 0;
        acpi_status status = AE_OK;
        struct acpi_power_resource *resource = NULL;
@@ -236,18 +236,6 @@ static int acpi_power_on(acpi_handle handle, struct acpi_device *dev)
        if (ACPI_FAILURE(status))
                return -ENODEV;
 
-       if (!acpi_power_nocheck) {
-               /*
-                * If acpi_power_nocheck is set, it is unnecessary to check
-                * the power state after power transition.
-                */
-               result = acpi_power_get_state(resource->device->handle,
-                               &state);
-               if (result)
-                       return result;
-               if (state != ACPI_POWER_RESOURCE_STATE_ON)
-                       return -ENOEXEC;
-       }
        /* Update the power resource's _device_ power state */
        resource->device->power.state = ACPI_STATE_D0;
 
@@ -258,7 +246,7 @@ static int acpi_power_on(acpi_handle handle, struct acpi_device *dev)
 
 static int acpi_power_off_device(acpi_handle handle, struct acpi_device *dev)
 {
-       int result = 0, state;
+       int result = 0;
        acpi_status status = AE_OK;
        struct acpi_power_resource *resource = NULL;
        struct list_head *node, *next;
@@ -293,18 +281,6 @@ static int acpi_power_off_device(acpi_handle handle, struct acpi_device *dev)
        if (ACPI_FAILURE(status))
                return -ENODEV;
 
-       if (!acpi_power_nocheck) {
-               /*
-                * If acpi_power_nocheck is set, it is unnecessary to check
-                * the power state after power transition.
-                */
-               result = acpi_power_get_state(handle, &state);
-               if (result)
-                       return result;
-               if (state != ACPI_POWER_RESOURCE_STATE_OFF)
-                       return -ENOEXEC;
-       }
-
        /* Update the power resource's _device_ power state */
        resource->device->power.state = ACPI_STATE_D3;
 
index 23f0fb84f1c1104538efe624c5824937e069c191..84e0f3c0744270b4c8474f92239b64255a27985b 100644 (file)
@@ -89,7 +89,7 @@ static int acpi_processor_handle_eject(struct acpi_processor *pr);
 
 static const struct acpi_device_id processor_device_ids[] = {
        {ACPI_PROCESSOR_OBJECT_HID, 0},
-       {ACPI_PROCESSOR_HID, 0},
+       {"ACPI0007", 0},
        {"", 0},
 };
 MODULE_DEVICE_TABLE(acpi, processor_device_ids);
@@ -596,7 +596,21 @@ static int acpi_processor_get_info(struct acpi_device *device)
                ACPI_DEBUG_PRINT((ACPI_DB_INFO,
                                  "No bus mastering arbitration control\n"));
 
-       if (!strcmp(acpi_device_hid(device), ACPI_PROCESSOR_HID)) {
+       if (!strcmp(acpi_device_hid(device), ACPI_PROCESSOR_OBJECT_HID)) {
+               /* Declared with "Processor" statement; match ProcessorID */
+               status = acpi_evaluate_object(pr->handle, NULL, NULL, &buffer);
+               if (ACPI_FAILURE(status)) {
+                       printk(KERN_ERR PREFIX "Evaluating processor object\n");
+                       return -ENODEV;
+               }
+
+               /*
+                * TBD: Synch processor ID (via LAPIC/LSAPIC structures) on SMP.
+                *      >>> 'acpi_get_processor_id(acpi_id, &id)' in
+                *      arch/xxx/acpi.c
+                */
+               pr->acpi_id = object.processor.proc_id;
+       } else {
                /*
                 * Declared with "Device" statement; match _UID.
                 * Note that we don't handle string _UIDs yet.
@@ -611,20 +625,6 @@ static int acpi_processor_get_info(struct acpi_device *device)
                }
                device_declaration = 1;
                pr->acpi_id = value;
-       } else {
-               /* Declared with "Processor" statement; match ProcessorID */
-               status = acpi_evaluate_object(pr->handle, NULL, NULL, &buffer);
-               if (ACPI_FAILURE(status)) {
-                       printk(KERN_ERR PREFIX "Evaluating processor object\n");
-                       return -ENODEV;
-               }
-
-               /*
-                * TBD: Synch processor ID (via LAPIC/LSAPIC structures) on SMP.
-                *      >>> 'acpi_get_processor_id(acpi_id, &id)' in
-                *      arch/xxx/acpi.c
-                */
-               pr->acpi_id = object.processor.proc_id;
        }
        cpu_index = get_cpu_id(pr->handle, device_declaration, pr->acpi_id);
 
@@ -649,7 +649,16 @@ static int acpi_processor_get_info(struct acpi_device *device)
                        return -ENODEV;
                }
        }
-
+       /*
+        * On some boxes several processors use the same processor bus id.
+        * But they are located in different scope. For example:
+        * \_SB.SCK0.CPU0
+        * \_SB.SCK1.CPU0
+        * Rename the processor device bus id. And the new bus id will be
+        * generated as the following format:
+        * CPU+CPU ID.
+        */
+       sprintf(acpi_device_bid(device), "CPU%X", pr->id);
        ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Processor [%d:%d]\n", pr->id,
                          pr->acpi_id));
 
@@ -731,6 +740,8 @@ static int __cpuinit acpi_processor_start(struct acpi_device *device)
        /* _PDC call should be done before doing anything else (if reqd.). */
        arch_acpi_processor_init_pdc(pr);
        acpi_processor_set_pdc(pr);
+       arch_acpi_processor_cleanup_pdc(pr);
+
 #ifdef CONFIG_CPU_FREQ
        acpi_processor_ppc_has_changed(pr);
 #endif
index 10a2d913635a99d76502309efb55895d7a92c5e4..0efa59e7e3afd16095fa538f333f11f37ca7a9d4 100644 (file)
@@ -139,7 +139,7 @@ static void acpi_safe_halt(void)
  * are affected too. We pick the most conservative approach: we assume
  * that the local APIC stops in both C2 and C3.
  */
-static void acpi_timer_check_state(int state, struct acpi_processor *pr,
+static void lapic_timer_check_state(int state, struct acpi_processor *pr,
                                   struct acpi_processor_cx *cx)
 {
        struct acpi_processor_power *pwr = &pr->power;
@@ -162,7 +162,7 @@ static void acpi_timer_check_state(int state, struct acpi_processor *pr,
                pr->power.timer_broadcast_on_state = state;
 }
 
-static void acpi_propagate_timer_broadcast(struct acpi_processor *pr)
+static void lapic_timer_propagate_broadcast(struct acpi_processor *pr)
 {
        unsigned long reason;
 
@@ -173,7 +173,7 @@ static void acpi_propagate_timer_broadcast(struct acpi_processor *pr)
 }
 
 /* Power(C) State timer broadcast control */
-static void acpi_state_timer_broadcast(struct acpi_processor *pr,
+static void lapic_timer_state_broadcast(struct acpi_processor *pr,
                                       struct acpi_processor_cx *cx,
                                       int broadcast)
 {
@@ -190,10 +190,10 @@ static void acpi_state_timer_broadcast(struct acpi_processor *pr,
 
 #else
 
-static void acpi_timer_check_state(int state, struct acpi_processor *pr,
+static void lapic_timer_check_state(int state, struct acpi_processor *pr,
                                   struct acpi_processor_cx *cstate) { }
-static void acpi_propagate_timer_broadcast(struct acpi_processor *pr) { }
-static void acpi_state_timer_broadcast(struct acpi_processor *pr,
+static void lapic_timer_propagate_broadcast(struct acpi_processor *pr) { }
+static void lapic_timer_state_broadcast(struct acpi_processor *pr,
                                       struct acpi_processor_cx *cx,
                                       int broadcast)
 {
@@ -515,7 +515,8 @@ static void acpi_processor_power_verify_c2(struct acpi_processor_cx *cx)
 static void acpi_processor_power_verify_c3(struct acpi_processor *pr,
                                           struct acpi_processor_cx *cx)
 {
-       static int bm_check_flag;
+       static int bm_check_flag = -1;
+       static int bm_control_flag = -1;
 
 
        if (!cx->address)
@@ -545,12 +546,14 @@ static void acpi_processor_power_verify_c3(struct acpi_processor *pr,
        }
 
        /* All the logic here assumes flags.bm_check is same across all CPUs */
-       if (!bm_check_flag) {
+       if (bm_check_flag == -1) {
                /* Determine whether bm_check is needed based on CPU  */
                acpi_processor_power_init_bm_check(&(pr->flags), pr->id);
                bm_check_flag = pr->flags.bm_check;
+               bm_control_flag = pr->flags.bm_control;
        } else {
                pr->flags.bm_check = bm_check_flag;
+               pr->flags.bm_control = bm_control_flag;
        }
 
        if (pr->flags.bm_check) {
@@ -614,29 +617,25 @@ static int acpi_processor_power_verify(struct acpi_processor *pr)
                switch (cx->type) {
                case ACPI_STATE_C1:
                        cx->valid = 1;
-                       acpi_timer_check_state(i, pr, cx);
                        break;
 
                case ACPI_STATE_C2:
                        acpi_processor_power_verify_c2(cx);
-                       if (cx->valid)
-                               acpi_timer_check_state(i, pr, cx);
                        break;
 
                case ACPI_STATE_C3:
                        acpi_processor_power_verify_c3(pr, cx);
-                       if (cx->valid)
-                               acpi_timer_check_state(i, pr, cx);
                        break;
                }
-               if (cx->valid)
-                       tsc_check_state(cx->type);
+               if (!cx->valid)
+                       continue;
 
-               if (cx->valid)
-                       working++;
+               lapic_timer_check_state(i, pr, cx);
+               tsc_check_state(cx->type);
+               working++;
        }
 
-       acpi_propagate_timer_broadcast(pr);
+       lapic_timer_propagate_broadcast(pr);
 
        return (working);
 }
@@ -839,7 +838,7 @@ static int acpi_idle_enter_c1(struct cpuidle_device *dev,
                return 0;
        }
 
-       acpi_state_timer_broadcast(pr, cx, 1);
+       lapic_timer_state_broadcast(pr, cx, 1);
        kt1 = ktime_get_real();
        acpi_idle_do_entry(cx);
        kt2 = ktime_get_real();
@@ -847,7 +846,7 @@ static int acpi_idle_enter_c1(struct cpuidle_device *dev,
 
        local_irq_enable();
        cx->usage++;
-       acpi_state_timer_broadcast(pr, cx, 0);
+       lapic_timer_state_broadcast(pr, cx, 0);
 
        return idle_time;
 }
@@ -892,7 +891,7 @@ static int acpi_idle_enter_simple(struct cpuidle_device *dev,
         * Must be done before busmaster disable as we might need to
         * access HPET !
         */
-       acpi_state_timer_broadcast(pr, cx, 1);
+       lapic_timer_state_broadcast(pr, cx, 1);
 
        if (cx->type == ACPI_STATE_C3)
                ACPI_FLUSH_CPU_CACHE();
@@ -914,7 +913,7 @@ static int acpi_idle_enter_simple(struct cpuidle_device *dev,
 
        cx->usage++;
 
-       acpi_state_timer_broadcast(pr, cx, 0);
+       lapic_timer_state_broadcast(pr, cx, 0);
        cx->time += sleep_ticks;
        return idle_time;
 }
@@ -981,7 +980,7 @@ static int acpi_idle_enter_bm(struct cpuidle_device *dev,
         * Must be done before busmaster disable as we might need to
         * access HPET !
         */
-       acpi_state_timer_broadcast(pr, cx, 1);
+       lapic_timer_state_broadcast(pr, cx, 1);
 
        kt1 = ktime_get_real();
        /*
@@ -1026,7 +1025,7 @@ static int acpi_idle_enter_bm(struct cpuidle_device *dev,
 
        cx->usage++;
 
-       acpi_state_timer_broadcast(pr, cx, 0);
+       lapic_timer_state_broadcast(pr, cx, 0);
        cx->time += sleep_ticks;
        return idle_time;
 }
index 8ff510b91d88f4f38e473afab76425a9cf392477..781435d7e3692026d81cb6f112e7e422aa00a7dc 100644 (file)
@@ -95,7 +95,7 @@ acpi_device_modalias_show(struct device *dev, struct device_attribute *attr, cha
 }
 static DEVICE_ATTR(modalias, 0444, acpi_device_modalias_show, NULL);
 
-static int acpi_bus_hot_remove_device(void *context)
+static void acpi_bus_hot_remove_device(void *context)
 {
        struct acpi_device *device;
        acpi_handle handle = context;
@@ -104,10 +104,10 @@ static int acpi_bus_hot_remove_device(void *context)
        acpi_status status = AE_OK;
 
        if (acpi_bus_get_device(handle, &device))
-               return 0;
+               return;
 
        if (!device)
-               return 0;
+               return;
 
        ACPI_DEBUG_PRINT((ACPI_DB_INFO,
                "Hot-removing device %s...\n", dev_name(&device->dev)));
@@ -115,7 +115,7 @@ static int acpi_bus_hot_remove_device(void *context)
        if (acpi_bus_trim(device, 1)) {
                printk(KERN_ERR PREFIX
                                "Removing device failed\n");
-               return -1;
+               return;
        }
 
        /* power off device */
@@ -142,9 +142,10 @@ static int acpi_bus_hot_remove_device(void *context)
         */
        status = acpi_evaluate_object(handle, "_EJ0", &arg_list, NULL);
        if (ACPI_FAILURE(status))
-               return -ENODEV;
+               printk(KERN_WARNING PREFIX
+                               "Eject device failed\n");
 
-       return 0;
+       return;
 }
 
 static ssize_t
@@ -155,7 +156,6 @@ acpi_eject_store(struct device *d, struct device_attribute *attr,
        acpi_status status;
        acpi_object_type type = 0;
        struct acpi_device *acpi_device = to_acpi_device(d);
-       struct task_struct *task;
 
        if ((!count) || (buf[0] != '1')) {
                return -EINVAL;
@@ -172,11 +172,7 @@ acpi_eject_store(struct device *d, struct device_attribute *attr,
                goto err;
        }
 
-       /* remove the device in another thread to fix the deadlock issue */
-       task = kthread_run(acpi_bus_hot_remove_device,
-                               acpi_device->handle, "acpi_hot_remove_device");
-       if (IS_ERR(task))
-               ret = PTR_ERR(task);
+       acpi_os_hotplug_execute(acpi_bus_hot_remove_device, acpi_device->handle);
 err:
        return ret;
 }
@@ -198,12 +194,12 @@ acpi_device_path_show(struct device *dev, struct device_attribute *attr, char *b
        int result;
 
        result = acpi_get_name(acpi_dev->handle, ACPI_FULL_PATHNAME, &path);
-       if(result)
+       if (result)
                goto end;
 
        result = sprintf(buf, "%s\n", (char*)path.pointer);
        kfree(path.pointer);
-  end:
+end:
        return result;
 }
 static DEVICE_ATTR(path, 0444, acpi_device_path_show, NULL);
@@ -217,21 +213,21 @@ static int acpi_device_setup_files(struct acpi_device *dev)
        /*
         * Devices gotten from FADT don't have a "path" attribute
         */
-       if(dev->handle) {
+       if (dev->handle) {
                result = device_create_file(&dev->dev, &dev_attr_path);
-               if(result)
+               if (result)
                        goto end;
        }
 
-       if(dev->flags.hardware_id) {
+       if (dev->flags.hardware_id) {
                result = device_create_file(&dev->dev, &dev_attr_hid);
-               if(result)
+               if (result)
                        goto end;
        }
 
-       if (dev->flags.hardware_id || dev->flags.compatible_ids){
+       if (dev->flags.hardware_id || dev->flags.compatible_ids) {
                result = device_create_file(&dev->dev, &dev_attr_modalias);
-               if(result)
+               if (result)
                        goto end;
        }
 
@@ -242,7 +238,7 @@ static int acpi_device_setup_files(struct acpi_device *dev)
        status = acpi_get_handle(dev->handle, "_EJ0", &temp);
        if (ACPI_SUCCESS(status))
                result = device_create_file(&dev->dev, &dev_attr_eject);
-  end:
+end:
        return result;
 }
 
@@ -262,9 +258,9 @@ static void acpi_device_remove_files(struct acpi_device *dev)
        if (dev->flags.hardware_id || dev->flags.compatible_ids)
                device_remove_file(&dev->dev, &dev_attr_modalias);
 
-       if(dev->flags.hardware_id)
+       if (dev->flags.hardware_id)
                device_remove_file(&dev->dev, &dev_attr_hid);
-       if(dev->handle)
+       if (dev->handle)
                device_remove_file(&dev->dev, &dev_attr_path);
 }
 /* --------------------------------------------------------------------------
@@ -512,7 +508,7 @@ static int acpi_device_register(struct acpi_device *device,
                        break;
                }
        }
-       if(!found) {
+       if (!found) {
                acpi_device_bus_id = new_bus_id;
                strcpy(acpi_device_bus_id->bus_id, device->flags.hardware_id ? device->pnp.hardware_id : "device");
                acpi_device_bus_id->instance_no = 0;
@@ -530,22 +526,21 @@ static int acpi_device_register(struct acpi_device *device,
        if (device->parent)
                device->dev.parent = &parent->dev;
        device->dev.bus = &acpi_bus_type;
-       device_initialize(&device->dev);
        device->dev.release = &acpi_device_release;
-       result = device_add(&device->dev);
-       if(result) {
-               dev_err(&device->dev, "Error adding device\n");
+       result = device_register(&device->dev);
+       if (result) {
+               dev_err(&device->dev, "Error registering device\n");
                goto end;
        }
 
        result = acpi_device_setup_files(device);
-       if(result)
+       if (result)
                printk(KERN_ERR PREFIX "Error creating sysfs interface for device %s\n",
                       dev_name(&device->dev));
 
        device->removal_type = ACPI_BUS_REMOVAL_NORMAL;
        return 0;
-  end:
+end:
        mutex_lock(&acpi_device_lock);
        if (device->parent)
                list_del(&device->node);
@@ -577,7 +572,7 @@ static void acpi_device_unregister(struct acpi_device *device, int type)
  * @device: the device to add and initialize
  * @driver: driver for the device
  *
- * Used to initialize a device via its device driver.  Called whenever a 
+ * Used to initialize a device via its device driver.  Called whenever a
  * driver is bound to a device.  Invokes the driver's add() ops.
  */
 static int
@@ -585,7 +580,6 @@ acpi_bus_driver_init(struct acpi_device *device, struct acpi_driver *driver)
 {
        int result = 0;
 
-
        if (!device || !driver)
                return -EINVAL;
 
@@ -802,7 +796,7 @@ static int acpi_bus_get_wakeup_device_flags(struct acpi_device *device)
        if (!acpi_match_device_ids(device, button_device_ids))
                device->wakeup.flags.run_wake = 1;
 
-      end:
+end:
        if (ACPI_FAILURE(status))
                device->flags.wake_capable = 0;
        return 0;
@@ -1070,7 +1064,7 @@ static void acpi_device_set_id(struct acpi_device *device,
                break;
        }
 
-       /* 
+       /*
         * \_SB
         * ----
         * Fix for the system root bus device -- the only root-level device.
@@ -1320,7 +1314,7 @@ acpi_add_single_object(struct acpi_device **child,
                        device->parent->ops.bind(device);
        }
 
-      end:
+end:
        if (!result)
                *child = device;
        else {
@@ -1464,7 +1458,6 @@ acpi_bus_add(struct acpi_device **child,
 
        return result;
 }
-
 EXPORT_SYMBOL(acpi_bus_add);
 
 int acpi_bus_start(struct acpi_device *device)
@@ -1484,7 +1477,6 @@ int acpi_bus_start(struct acpi_device *device)
        }
        return result;
 }
-
 EXPORT_SYMBOL(acpi_bus_start);
 
 int acpi_bus_trim(struct acpi_device *start, int rmdevice)
@@ -1542,7 +1534,6 @@ int acpi_bus_trim(struct acpi_device *start, int rmdevice)
 }
 EXPORT_SYMBOL_GPL(acpi_bus_trim);
 
-
 static int acpi_bus_scan_fixed(struct acpi_device *root)
 {
        int result = 0;
@@ -1610,6 +1601,6 @@ int __init acpi_scan_init(void)
        if (result)
                acpi_device_unregister(acpi_root, ACPI_BUS_REMOVAL_NORMAL);
 
-      Done:
+Done:
        return result;
 }
index 1bdfb37377e32d58bcd1f3e35e858c1cc681aa5c..8851315ce858a2e2eb1e4ffd2d2b6b695fa8bfb8 100644 (file)
@@ -76,6 +76,7 @@ MODULE_LICENSE("GPL");
 static int brightness_switch_enabled = 1;
 module_param(brightness_switch_enabled, bool, 0644);
 
+static int register_count = 0;
 static int acpi_video_bus_add(struct acpi_device *device);
 static int acpi_video_bus_remove(struct acpi_device *device, int type);
 static int acpi_video_resume(struct acpi_device *device);
@@ -586,6 +587,14 @@ static struct dmi_system_id video_dmi_table[] __initdata = {
                DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 5315"),
                },
        },
+       {
+        .callback = video_set_bqc_offset,
+        .ident = "Acer Aspire 7720",
+        .matches = {
+               DMI_MATCH(DMI_BOARD_VENDOR, "Acer"),
+               DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 7720"),
+               },
+       },
        {}
 };
 
@@ -976,6 +985,11 @@ static void acpi_video_device_find_cap(struct acpi_video_device *device)
                device->backlight->props.max_brightness = device->brightness->count-3;
                kfree(name);
 
+               result = sysfs_create_link(&device->backlight->dev.kobj,
+                                          &device->dev->dev.kobj, "device");
+               if (result)
+                       printk(KERN_ERR PREFIX "Create sysfs link\n");
+
                device->cdev = thermal_cooling_device_register("LCD",
                                        device->dev, &video_cooling_ops);
                if (IS_ERR(device->cdev))
@@ -1054,15 +1068,15 @@ static void acpi_video_bus_find_cap(struct acpi_video_bus *video)
 static int acpi_video_bus_check(struct acpi_video_bus *video)
 {
        acpi_status status = -ENOENT;
-       struct device *dev;
+       struct pci_dev *dev;
 
        if (!video)
                return -EINVAL;
 
-       dev = acpi_get_physical_pci_device(video->device->handle);
+       dev = acpi_get_pci_dev(video->device->handle);
        if (!dev)
                return -ENODEV;
-       put_device(dev);
+       pci_dev_put(dev);
 
        /* Since there is no HID, CID and so on for VGA driver, we have
         * to check well known required nodes.
@@ -1990,6 +2004,7 @@ static int acpi_video_bus_put_one_device(struct acpi_video_device *device)
        status = acpi_remove_notify_handler(device->dev->handle,
                                            ACPI_DEVICE_NOTIFY,
                                            acpi_video_device_notify);
+       sysfs_remove_link(&device->backlight->dev.kobj, "device");
        backlight_device_unregister(device->backlight);
        if (device->cdev) {
                sysfs_remove_link(&device->dev->dev.kobj,
@@ -2318,6 +2333,13 @@ static int __init intel_opregion_present(void)
 int acpi_video_register(void)
 {
        int result = 0;
+       if (register_count) {
+               /*
+                * if the function of acpi_video_register is already called,
+                * don't register the acpi_vide_bus again and return no error.
+                */
+               return 0;
+       }
 
        acpi_video_dir = proc_mkdir(ACPI_VIDEO_CLASS, acpi_root_dir);
        if (!acpi_video_dir)
@@ -2329,10 +2351,35 @@ int acpi_video_register(void)
                return -ENODEV;
        }
 
+       /*
+        * When the acpi_video_bus is loaded successfully, increase
+        * the counter reference.
+        */
+       register_count = 1;
+
        return 0;
 }
 EXPORT_SYMBOL(acpi_video_register);
 
+void acpi_video_unregister(void)
+{
+       if (!register_count) {
+               /*
+                * If the acpi video bus is already unloaded, don't
+                * unload it again and return directly.
+                */
+               return;
+       }
+       acpi_bus_unregister_driver(&acpi_video_bus);
+
+       remove_proc_entry(ACPI_VIDEO_CLASS, acpi_root_dir);
+
+       register_count = 0;
+
+       return;
+}
+EXPORT_SYMBOL(acpi_video_unregister);
+
 /*
  * This is kind of nasty. Hardware using Intel chipsets may require
  * the video opregion code to be run first in order to initialise
@@ -2350,16 +2397,12 @@ static int __init acpi_video_init(void)
        return acpi_video_register();
 }
 
-void acpi_video_exit(void)
+static void __exit acpi_video_exit(void)
 {
-
-       acpi_bus_unregister_driver(&acpi_video_bus);
-
-       remove_proc_entry(ACPI_VIDEO_CLASS, acpi_root_dir);
+       acpi_video_unregister();
 
        return;
 }
-EXPORT_SYMBOL(acpi_video_exit);
 
 module_init(acpi_video_init);
 module_exit(acpi_video_exit);
index 09737275e25fd94990d7e250f7acfcc09d2e10af..7cd2b63435ea1bf1464d2a8dbac17650cbd12dc4 100644 (file)
@@ -10,7 +10,7 @@
  * assinged
  *
  * After PCI devices are glued with ACPI devices
- * acpi_get_physical_pci_device() can be called to identify ACPI graphics
+ * acpi_get_pci_dev() can be called to identify ACPI graphics
  * devices for which a real graphics card is plugged in
  *
  * Now acpi_video_get_capabilities() can be called to check which
@@ -36,6 +36,7 @@
 
 #include <linux/acpi.h>
 #include <linux/dmi.h>
+#include <linux/pci.h>
 
 ACPI_MODULE_NAME("video");
 #define _COMPONENT             ACPI_VIDEO_COMPONENT
@@ -109,7 +110,7 @@ static acpi_status
 find_video(acpi_handle handle, u32 lvl, void *context, void **rv)
 {
        long *cap = context;
-       struct device *dev;
+       struct pci_dev *dev;
        struct acpi_device *acpi_dev;
 
        const struct acpi_device_id video_ids[] = {
@@ -120,10 +121,10 @@ find_video(acpi_handle handle, u32 lvl, void *context, void **rv)
                return AE_OK;
 
        if (!acpi_match_device_ids(acpi_dev, video_ids)) {
-               dev = acpi_get_physical_pci_device(handle);
+               dev = acpi_get_pci_dev(handle);
                if (!dev)
                        return AE_OK;
-               put_device(dev);
+               pci_dev_put(dev);
                *cap |= acpi_is_video_device(acpi_dev);
        }
        return AE_OK;
index 3d763fdf99b7d2409f8dbf425822ace5f1063cea..246650673010594d08c139551da1973318f78685 100644 (file)
@@ -207,6 +207,16 @@ int amba_device_register(struct amba_device *dev, struct resource *parent)
        void __iomem *tmp;
        int i, ret;
 
+       device_initialize(&dev->dev);
+
+       /*
+        * Copy from device_add
+        */
+       if (dev->dev.init_name) {
+               dev_set_name(&dev->dev, "%s", dev->dev.init_name);
+               dev->dev.init_name = NULL;
+       }
+
        dev->dev.release = amba_device_release;
        dev->dev.bus = &amba_bustype;
        dev->dev.dma_mask = &dev->dma_mask;
@@ -240,7 +250,7 @@ int amba_device_register(struct amba_device *dev, struct resource *parent)
                goto err_release;
        }
 
-       ret = device_register(&dev->dev);
+       ret = device_add(&dev->dev);
        if (ret)
                goto err_release;
 
index 15a23031833f46e921957c48578723caf9b2446e..336eb1ed73cc3e9dd858ab0bf9cade009498f78b 100644 (file)
@@ -513,6 +513,7 @@ static const struct pci_device_id ahci_pci_tbl[] = {
        { PCI_VDEVICE(INTEL, 0x502a), board_ahci }, /* Tolapai */
        { PCI_VDEVICE(INTEL, 0x502b), board_ahci }, /* Tolapai */
        { PCI_VDEVICE(INTEL, 0x3a05), board_ahci }, /* ICH10 */
+       { PCI_VDEVICE(INTEL, 0x3a22), board_ahci }, /* ICH10 */
        { PCI_VDEVICE(INTEL, 0x3a25), board_ahci }, /* ICH10 */
        { PCI_VDEVICE(INTEL, 0x3b24), board_ahci }, /* PCH RAID */
        { PCI_VDEVICE(INTEL, 0x3b25), board_ahci }, /* PCH RAID */
index 045a486a09eae25a16174a7c697e52796dcbc503..2c6aedaef7185e649f506b7c656ce8eb042c3e9e 100644 (file)
@@ -3392,17 +3392,27 @@ int ata_down_xfermask_limit(struct ata_device *dev, unsigned int sel)
 
 static int ata_dev_set_mode(struct ata_device *dev)
 {
+       struct ata_port *ap = dev->link->ap;
        struct ata_eh_context *ehc = &dev->link->eh_context;
+       const bool nosetxfer = dev->horkage & ATA_HORKAGE_NOSETXFER;
        const char *dev_err_whine = "";
        int ign_dev_err = 0;
-       unsigned int err_mask;
+       unsigned int err_mask = 0;
        int rc;
 
        dev->flags &= ~ATA_DFLAG_PIO;
        if (dev->xfer_shift == ATA_SHIFT_PIO)
                dev->flags |= ATA_DFLAG_PIO;
 
-       err_mask = ata_dev_set_xfermode(dev);
+       if (nosetxfer && ap->flags & ATA_FLAG_SATA && ata_id_is_sata(dev->id))
+               dev_err_whine = " (SET_XFERMODE skipped)";
+       else {
+               if (nosetxfer)
+                       ata_dev_printk(dev, KERN_WARNING,
+                                      "NOSETXFER but PATA detected - can't "
+                                      "skip SETXFER, might malfunction\n");
+               err_mask = ata_dev_set_xfermode(dev);
+       }
 
        if (err_mask & ~AC_ERR_DEV)
                goto fail;
@@ -4297,6 +4307,12 @@ static const struct ata_blacklist_entry ata_device_blacklist [] = {
        /* Devices which aren't very happy with higher link speeds */
        { "WD My Book",                 NULL,   ATA_HORKAGE_1_5_GBPS, },
 
+       /*
+        * Devices which choke on SETXFER.  Applies only if both the
+        * device and controller are SATA.
+        */
+       { "PIONEER DVD-RW  DVRTD08",    "1.00", ATA_HORKAGE_NOSETXFER },
+
        /* End Marker */
        { }
 };
index fa22f94ca4150247b39a0e26fa7541d4cbee4ba4..1a07c061f644f37d76e7efe831a028ff6b8c1953 100644 (file)
@@ -2517,6 +2517,10 @@ int ata_eh_reset(struct ata_link *link, int classify,
 
                        ata_eh_about_to_do(link, NULL, ATA_EH_RESET);
                        rc = ata_do_reset(link, reset, classes, deadline, true);
+                       if (rc) {
+                               failed_link = link;
+                               goto fail;
+                       }
                }
        } else {
                if (verbose)
index 4b27617be26da7ecfadd5ac53476237348559310..8561a9f195c11ed9dd2a49979da8970a7a70e633 100644 (file)
@@ -312,11 +312,12 @@ err_ide_ioremap:
 static int __devexit pata_at91_remove(struct platform_device *pdev)
 {
        struct ata_host *host = dev_get_drvdata(&pdev->dev);
-       struct at91_ide_info *info = host->private_data;
+       struct at91_ide_info *info;
        struct device *dev = &pdev->dev;
 
        if (!host)
                return 0;
+       info = host->private_data;
 
        ata_host_detach(host);
 
index e8beb8e5b6264232dbfc0ea2dc7ae95d76f5af64..05dd307e8f024038bfe6e9d762e3dff1dd6281ee 100644 (file)
@@ -428,6 +428,9 @@ int devres_release_all(struct device *dev)
 {
        unsigned long flags;
 
+       /* Looks like an uninitialized device structure */
+       if (WARN_ON(dev->devres_head.next == NULL))
+               return -ENODEV;
        spin_lock_irqsave(&dev->devres_lock, flags);
        return release_nodes(dev, dev->devres_head.next, &dev->devres_head,
                             flags);
index ddeb819c8f878a3cf07c18ed9d6d2c3ffe082e46..f285f441fab9d20dbf050d61e4360759b0fbe1fb 100644 (file)
@@ -217,8 +217,10 @@ firmware_data_read(struct kobject *kobj, struct bin_attribute *bin_attr,
                ret_count = -ENODEV;
                goto out;
        }
-       if (offset > fw->size)
-               return 0;
+       if (offset > fw->size) {
+               ret_count = 0;
+               goto out;
+       }
        if (count > fw->size - offset)
                count = fw->size - offset;
 
@@ -357,7 +359,7 @@ static void fw_dev_release(struct device *dev)
        kfree(fw_priv->pages);
        kfree(fw_priv->fw_id);
        kfree(fw_priv);
-       put_device(dev);
+       kfree(dev);
 
        module_put(THIS_MODULE);
 }
@@ -408,13 +410,11 @@ static int fw_register_device(struct device **dev_p, const char *fw_name,
        if (retval) {
                dev_err(device, "%s: device_register failed\n", __func__);
                put_device(f_dev);
-               goto error_kfree_fw_id;
+               return retval;
        }
        *dev_p = f_dev;
        return 0;
 
-error_kfree_fw_id:
-       kfree(fw_priv->fw_id);
 error_kfree:
        kfree(f_dev);
        kfree(fw_priv);
index fae725458981793649bf3e339a20394ac9859448..58a3e572f2c903ff81bfe75a51730257c49daf37 100644 (file)
@@ -762,6 +762,7 @@ static int dpm_prepare(pm_message_t state)
                        dev->power.status = DPM_ON;
                        if (error == -EAGAIN) {
                                put_device(dev);
+                               error = 0;
                                continue;
                        }
                        printk(KERN_ERR "PM: Failed to prepare device %s "
index 668dc234b8e22d5b09950950914398d6f1f61766..1e6b7c14f697c58b7ad5f551e6f947d2fe7719a2 100644 (file)
@@ -36,6 +36,7 @@
 #include <linux/ioport.h>
 #include <linux/mm.h>
 #include <linux/slab.h>
+#include <linux/smp_lock.h>
 #include <linux/proc_fs.h>
 #include <linux/reboot.h>
 #include <linux/spinlock.h>
index bb72ada9f074588e49796267b59600f848a615be..1d886e079c588e70951965b7a67192b962967c16 100644 (file)
@@ -298,6 +298,22 @@ config BLK_DEV_NBD
 
          If unsure, say N.
 
+config BLK_DEV_OSD
+       tristate "OSD object-as-blkdev support"
+       depends on SCSI_OSD_ULD
+       ---help---
+         Saying Y or M here will allow the exporting of a single SCSI
+         OSD (object-based storage) object as a Linux block device.
+
+         For example, if you create a 2G object on an OSD device,
+         you can then use this module to present that 2G object as
+         a Linux block device.
+
+         To compile this driver as a module, choose M here: the
+         module will be called osdblk.
+
+         If unsure, say N.
+
 config BLK_DEV_SX8
        tristate "Promise SATA SX8 support"
        depends on PCI
index 7755a5e2a85e3b5a7ffcfe1544ce507df050764d..cdaa3f8fddf03f324bfe72b92b2ad884e5e1af0a 100644 (file)
@@ -23,6 +23,7 @@ obj-$(CONFIG_XILINX_SYSACE)   += xsysace.o
 obj-$(CONFIG_CDROM_PKTCDVD)    += pktcdvd.o
 obj-$(CONFIG_MG_DISK)          += mg_disk.o
 obj-$(CONFIG_SUNVDC)           += sunvdc.o
+obj-$(CONFIG_BLK_DEV_OSD)      += osdblk.o
 
 obj-$(CONFIG_BLK_DEV_UMEM)     += umem.o
 obj-$(CONFIG_BLK_DEV_NBD)      += nbd.o
index 9c6e5b0fe894f9e6af94a50b87a2ec2b2f04a470..2f07b7c99a95b5046b121572f956c1048dc29894 100644 (file)
@@ -1645,7 +1645,7 @@ static int __init fd_probe_drives(void)
 {
        int drive,drives,nomem;
 
-       printk(KERN_INFO "FD: probing units\n" KERN_INFO "found ");
+       printk(KERN_INFO "FD: probing units\nfound ");
        drives=0;
        nomem=0;
        for(drive=0;drive<FD_MAX_UNITS;drive++) {
index c7a527c08a0980d542c1fffbd30687bbc95289d0..a52cc7fe45ea12d4e3d7742615ed9904013e0f10 100644 (file)
@@ -26,6 +26,7 @@
 #include <linux/pci.h>
 #include <linux/kernel.h>
 #include <linux/slab.h>
+#include <linux/smp_lock.h>
 #include <linux/delay.h>
 #include <linux/major.h>
 #include <linux/fs.h>
@@ -226,8 +227,18 @@ static inline void addQ(struct hlist_head *list, CommandList_struct *c)
 
 static inline void removeQ(CommandList_struct *c)
 {
-       if (WARN_ON(hlist_unhashed(&c->list)))
+       /*
+        * After kexec/dump some commands might still
+        * be in flight, which the firmware will try
+        * to complete. Resetting the firmware doesn't work
+        * with old fw revisions, so we have to mark
+        * them off as 'stale' to prevent the driver from
+        * falling over.
+        */
+       if (WARN_ON(hlist_unhashed(&c->list))) {
+               c->cmd_type = CMD_MSG_STALE;
                return;
+       }
 
        hlist_del_init(&c->list);
 }
@@ -4246,7 +4257,8 @@ static void fail_all_cmds(unsigned long ctlr)
        while (!hlist_empty(&h->cmpQ)) {
                c = hlist_entry(h->cmpQ.first, CommandList_struct, list);
                removeQ(c);
-               c->err_info->CommandStatus = CMD_HARDWARE_ERR;
+               if (c->cmd_type != CMD_MSG_STALE)
+                       c->err_info->CommandStatus = CMD_HARDWARE_ERR;
                if (c->cmd_type == CMD_RWREQ) {
                        complete_command(h, c, 0);
                } else if (c->cmd_type == CMD_IOCTL_PEND)
index cd665b00c7c5b333176e160102fc25f5b6f998e5..dbaed1ea0da3c9c2ba71993dfec116d291a87770 100644 (file)
@@ -274,6 +274,7 @@ typedef struct _ErrorInfo_struct {
 #define CMD_SCSI       0x03
 #define CMD_MSG_DONE   0x04
 #define CMD_MSG_TIMEOUT 0x05
+#define CMD_MSG_STALE  0xff
 
 /* This structure needs to be divisible by 8 for new
  * indexing method.
index 862b40c90181b008f91f22aef61e69e87c681123..91b753013780f8a1bcb113159970abde34f4e127 100644 (file)
@@ -3327,7 +3327,10 @@ static inline int set_geometry(unsigned int cmd, struct floppy_struct *g,
                if (!capable(CAP_SYS_ADMIN))
                        return -EPERM;
                mutex_lock(&open_lock);
-               LOCK_FDC(drive, 1);
+               if (lock_fdc(drive, 1)) {
+                       mutex_unlock(&open_lock);
+                       return -EINTR;
+               }
                floppy_type[type] = *g;
                floppy_type[type].name = "user format";
                for (cnt = type << 2; cnt < (type << 2) + 4; cnt++)
index 801f4ab83302556e9b48f1ddf139201a05e8c304..5757188cd1fb33393e830adf89313857146ce752 100644 (file)
@@ -61,7 +61,6 @@
 #include <linux/blkdev.h>
 #include <linux/blkpg.h>
 #include <linux/init.h>
-#include <linux/smp_lock.h>
 #include <linux/swap.h>
 #include <linux/slab.h>
 #include <linux/loop.h>
diff --git a/drivers/block/osdblk.c b/drivers/block/osdblk.c
new file mode 100644 (file)
index 0000000..13c1aee
--- /dev/null
@@ -0,0 +1,701 @@
+
+/*
+   osdblk.c -- Export a single SCSI OSD object as a Linux block device
+
+
+   Copyright 2009 Red Hat, Inc.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; see the file COPYING.  If not, write to
+   the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+
+
+   Instructions for use
+   --------------------
+
+   1) Map a Linux block device to an existing OSD object.
+
+      In this example, we will use partition id 1234, object id 5678,
+      OSD device /dev/osd1.
+
+      $ echo "1234 5678 /dev/osd1" > /sys/class/osdblk/add
+
+
+   2) List all active blkdev<->object mappings.
+
+      In this example, we have performed step #1 twice, creating two blkdevs,
+      mapped to two separate OSD objects.
+
+      $ cat /sys/class/osdblk/list
+      0 174 1234 5678 /dev/osd1
+      1 179 1994 897123 /dev/osd0
+
+      The columns, in order, are:
+      - blkdev unique id
+      - blkdev assigned major
+      - OSD object partition id
+      - OSD object id
+      - OSD device
+
+
+   3) Remove an active blkdev<->object mapping.
+
+      In this example, we remove the mapping with blkdev unique id 1.
+
+      $ echo 1 > /sys/class/osdblk/remove
+
+
+   NOTE:  The actual creation and deletion of OSD objects is outside the scope
+   of this driver.
+
+ */
+
+#include <linux/kernel.h>
+#include <linux/device.h>
+#include <linux/module.h>
+#include <linux/fs.h>
+#include <scsi/osd_initiator.h>
+#include <scsi/osd_attributes.h>
+#include <scsi/osd_sec.h>
+#include <scsi/scsi_device.h>
+
+#define DRV_NAME "osdblk"
+#define PFX DRV_NAME ": "
+
+/* #define _OSDBLK_DEBUG */
+#ifdef _OSDBLK_DEBUG
+#define OSDBLK_DEBUG(fmt, a...) \
+       printk(KERN_NOTICE "osdblk @%s:%d: " fmt, __func__, __LINE__, ##a)
+#else
+#define OSDBLK_DEBUG(fmt, a...) \
+       do { if (0) printk(fmt, ##a); } while (0)
+#endif
+
+MODULE_AUTHOR("Jeff Garzik <jeff@garzik.org>");
+MODULE_DESCRIPTION("block device inside an OSD object osdblk.ko");
+MODULE_LICENSE("GPL");
+
+struct osdblk_device;
+
+enum {
+       OSDBLK_MINORS_PER_MAJOR = 256,          /* max minors per blkdev */
+       OSDBLK_MAX_REQ          = 32,           /* max parallel requests */
+       OSDBLK_OP_TIMEOUT       = 4 * 60,       /* sync OSD req timeout */
+};
+
+struct osdblk_request {
+       struct request          *rq;            /* blk layer request */
+       struct bio              *bio;           /* cloned bio */
+       struct osdblk_device    *osdev;         /* associated blkdev */
+};
+
+struct osdblk_device {
+       int                     id;             /* blkdev unique id */
+
+       int                     major;          /* blkdev assigned major */
+       struct gendisk          *disk;          /* blkdev's gendisk and rq */
+       struct request_queue    *q;
+
+       struct osd_dev          *osd;           /* associated OSD */
+
+       char                    name[32];       /* blkdev name, e.g. osdblk34 */
+
+       spinlock_t              lock;           /* queue lock */
+
+       struct osd_obj_id       obj;            /* OSD partition, obj id */
+       uint8_t                 obj_cred[OSD_CAP_LEN]; /* OSD cred */
+
+       struct osdblk_request   req[OSDBLK_MAX_REQ]; /* request table */
+
+       struct list_head        node;
+
+       char                    osd_path[0];    /* OSD device path */
+};
+
+static struct class *class_osdblk;             /* /sys/class/osdblk */
+static DEFINE_MUTEX(ctl_mutex);        /* Serialize open/close/setup/teardown */
+static LIST_HEAD(osdblkdev_list);
+
+static struct block_device_operations osdblk_bd_ops = {
+       .owner          = THIS_MODULE,
+};
+
+static const struct osd_attr g_attr_logical_length = ATTR_DEF(
+       OSD_APAGE_OBJECT_INFORMATION, OSD_ATTR_OI_LOGICAL_LENGTH, 8);
+
+static void osdblk_make_credential(u8 cred_a[OSD_CAP_LEN],
+                                  const struct osd_obj_id *obj)
+{
+       osd_sec_init_nosec_doall_caps(cred_a, obj, false, true);
+}
+
+/* copied from exofs; move to libosd? */
+/*
+ * Perform a synchronous OSD operation.  copied from exofs; move to libosd?
+ */
+static int osd_sync_op(struct osd_request *or, int timeout, uint8_t *credential)
+{
+       int ret;
+
+       or->timeout = timeout;
+       ret = osd_finalize_request(or, 0, credential, NULL);
+       if (ret)
+               return ret;
+
+       ret = osd_execute_request(or);
+
+       /* osd_req_decode_sense(or, ret); */
+       return ret;
+}
+
+/*
+ * Perform an asynchronous OSD operation.  copied from exofs; move to libosd?
+ */
+static int osd_async_op(struct osd_request *or, osd_req_done_fn *async_done,
+                  void *caller_context, u8 *cred)
+{
+       int ret;
+
+       ret = osd_finalize_request(or, 0, cred, NULL);
+       if (ret)
+               return ret;
+
+       ret = osd_execute_request_async(or, async_done, caller_context);
+
+       return ret;
+}
+
+/* copied from exofs; move to libosd? */
+static int extract_attr_from_req(struct osd_request *or, struct osd_attr *attr)
+{
+       struct osd_attr cur_attr = {.attr_page = 0}; /* start with zeros */
+       void *iter = NULL;
+       int nelem;
+
+       do {
+               nelem = 1;
+               osd_req_decode_get_attr_list(or, &cur_attr, &nelem, &iter);
+               if ((cur_attr.attr_page == attr->attr_page) &&
+                   (cur_attr.attr_id == attr->attr_id)) {
+                       attr->len = cur_attr.len;
+                       attr->val_ptr = cur_attr.val_ptr;
+                       return 0;
+               }
+       } while (iter);
+
+       return -EIO;
+}
+
+static int osdblk_get_obj_size(struct osdblk_device *osdev, u64 *size_out)
+{
+       struct osd_request *or;
+       struct osd_attr attr;
+       int ret;
+
+       /* start request */
+       or = osd_start_request(osdev->osd, GFP_KERNEL);
+       if (!or)
+               return -ENOMEM;
+
+       /* create a get-attributes(length) request */
+       osd_req_get_attributes(or, &osdev->obj);
+
+       osd_req_add_get_attr_list(or, &g_attr_logical_length, 1);
+
+       /* execute op synchronously */
+       ret = osd_sync_op(or, OSDBLK_OP_TIMEOUT, osdev->obj_cred);
+       if (ret)
+               goto out;
+
+       /* extract length from returned attribute info */
+       attr = g_attr_logical_length;
+       ret = extract_attr_from_req(or, &attr);
+       if (ret)
+               goto out;
+
+       *size_out = get_unaligned_be64(attr.val_ptr);
+
+out:
+       osd_end_request(or);
+       return ret;
+
+}
+
+static void osdblk_osd_complete(struct osd_request *or, void *private)
+{
+       struct osdblk_request *orq = private;
+       struct osd_sense_info osi;
+       int ret = osd_req_decode_sense(or, &osi);
+
+       if (ret) {
+               ret = -EIO;
+               OSDBLK_DEBUG("osdblk_osd_complete with err=%d\n", ret);
+       }
+
+       /* complete OSD request */
+       osd_end_request(or);
+
+       /* complete request passed to osdblk by block layer */
+       __blk_end_request_all(orq->rq, ret);
+}
+
+static void bio_chain_put(struct bio *chain)
+{
+       struct bio *tmp;
+
+       while (chain) {
+               tmp = chain;
+               chain = chain->bi_next;
+
+               bio_put(tmp);
+       }
+}
+
+static struct bio *bio_chain_clone(struct bio *old_chain, gfp_t gfpmask)
+{
+       struct bio *tmp, *new_chain = NULL, *tail = NULL;
+
+       while (old_chain) {
+               tmp = bio_kmalloc(gfpmask, old_chain->bi_max_vecs);
+               if (!tmp)
+                       goto err_out;
+
+               __bio_clone(tmp, old_chain);
+               tmp->bi_bdev = NULL;
+               gfpmask &= ~__GFP_WAIT;
+               tmp->bi_next = NULL;
+
+               if (!new_chain)
+                       new_chain = tail = tmp;
+               else {
+                       tail->bi_next = tmp;
+                       tail = tmp;
+               }
+
+               old_chain = old_chain->bi_next;
+       }
+
+       return new_chain;
+
+err_out:
+       OSDBLK_DEBUG("bio_chain_clone with err\n");
+       bio_chain_put(new_chain);
+       return NULL;
+}
+
+static void osdblk_rq_fn(struct request_queue *q)
+{
+       struct osdblk_device *osdev = q->queuedata;
+
+       while (1) {
+               struct request *rq;
+               struct osdblk_request *orq;
+               struct osd_request *or;
+               struct bio *bio;
+               bool do_write, do_flush;
+
+               /* peek at request from block layer */
+               rq = blk_fetch_request(q);
+               if (!rq)
+                       break;
+
+               /* filter out block requests we don't understand */
+               if (!blk_fs_request(rq) && !blk_barrier_rq(rq)) {
+                       blk_end_request_all(rq, 0);
+                       continue;
+               }
+
+               /* deduce our operation (read, write, flush) */
+               /* I wish the block layer simplified cmd_type/cmd_flags/cmd[]
+                * into a clearly defined set of RPC commands:
+                * read, write, flush, scsi command, power mgmt req,
+                * driver-specific, etc.
+                */
+
+               do_flush = (rq->special == (void *) 0xdeadbeefUL);
+               do_write = (rq_data_dir(rq) == WRITE);
+
+               if (!do_flush) { /* osd_flush does not use a bio */
+                       /* a bio clone to be passed down to OSD request */
+                       bio = bio_chain_clone(rq->bio, GFP_ATOMIC);
+                       if (!bio)
+                               break;
+               } else
+                       bio = NULL;
+
+               /* alloc internal OSD request, for OSD command execution */
+               or = osd_start_request(osdev->osd, GFP_ATOMIC);
+               if (!or) {
+                       bio_chain_put(bio);
+                       OSDBLK_DEBUG("osd_start_request with err\n");
+                       break;
+               }
+
+               orq = &osdev->req[rq->tag];
+               orq->rq = rq;
+               orq->bio = bio;
+               orq->osdev = osdev;
+
+               /* init OSD command: flush, write or read */
+               if (do_flush)
+                       osd_req_flush_object(or, &osdev->obj,
+                                            OSD_CDB_FLUSH_ALL, 0, 0);
+               else if (do_write)
+                       osd_req_write(or, &osdev->obj, blk_rq_pos(rq) * 512ULL,
+                                     bio, blk_rq_bytes(rq));
+               else
+                       osd_req_read(or, &osdev->obj, blk_rq_pos(rq) * 512ULL,
+                                    bio, blk_rq_bytes(rq));
+
+               OSDBLK_DEBUG("%s 0x%x bytes at 0x%llx\n",
+                       do_flush ? "flush" : do_write ?
+                               "write" : "read", blk_rq_bytes(rq),
+                       blk_rq_pos(rq) * 512ULL);
+
+               /* begin OSD command execution */
+               if (osd_async_op(or, osdblk_osd_complete, orq,
+                                osdev->obj_cred)) {
+                       osd_end_request(or);
+                       blk_requeue_request(q, rq);
+                       bio_chain_put(bio);
+                       OSDBLK_DEBUG("osd_execute_request_async with err\n");
+                       break;
+               }
+
+               /* remove the special 'flush' marker, now that the command
+                * is executing
+                */
+               rq->special = NULL;
+       }
+}
+
+static void osdblk_prepare_flush(struct request_queue *q, struct request *rq)
+{
+       /* add driver-specific marker, to indicate that this request
+        * is a flush command
+        */
+       rq->special = (void *) 0xdeadbeefUL;
+}
+
+static void osdblk_free_disk(struct osdblk_device *osdev)
+{
+       struct gendisk *disk = osdev->disk;
+
+       if (!disk)
+               return;
+
+       if (disk->flags & GENHD_FL_UP)
+               del_gendisk(disk);
+       if (disk->queue)
+               blk_cleanup_queue(disk->queue);
+       put_disk(disk);
+}
+
+static int osdblk_init_disk(struct osdblk_device *osdev)
+{
+       struct gendisk *disk;
+       struct request_queue *q;
+       int rc;
+       u64 obj_size = 0;
+
+       /* contact OSD, request size info about the object being mapped */
+       rc = osdblk_get_obj_size(osdev, &obj_size);
+       if (rc)
+               return rc;
+
+       /* create gendisk info */
+       disk = alloc_disk(OSDBLK_MINORS_PER_MAJOR);
+       if (!disk)
+               return -ENOMEM;
+
+       sprintf(disk->disk_name, DRV_NAME "%d", osdev->id);
+       disk->major = osdev->major;
+       disk->first_minor = 0;
+       disk->fops = &osdblk_bd_ops;
+       disk->private_data = osdev;
+
+       /* init rq */
+       q = blk_init_queue(osdblk_rq_fn, &osdev->lock);
+       if (!q) {
+               put_disk(disk);
+               return -ENOMEM;
+       }
+
+       /* switch queue to TCQ mode; allocate tag map */
+       rc = blk_queue_init_tags(q, OSDBLK_MAX_REQ, NULL);
+       if (rc) {
+               blk_cleanup_queue(q);
+               put_disk(disk);
+               return rc;
+       }
+
+       /* Set our limits to the lower device limits, because osdblk cannot
+        * sleep when allocating a lower-request and therefore cannot be
+        * bouncing.
+        */
+       blk_queue_stack_limits(q, osd_request_queue(osdev->osd));
+
+       blk_queue_prep_rq(q, blk_queue_start_tag);
+       blk_queue_ordered(q, QUEUE_ORDERED_DRAIN_FLUSH, osdblk_prepare_flush);
+
+       disk->queue = q;
+
+       q->queuedata = osdev;
+
+       osdev->disk = disk;
+       osdev->q = q;
+
+       /* finally, announce the disk to the world */
+       set_capacity(disk, obj_size / 512ULL);
+       add_disk(disk);
+
+       printk(KERN_INFO "%s: Added of size 0x%llx\n",
+               disk->disk_name, (unsigned long long)obj_size);
+
+       return 0;
+}
+
+/********************************************************************
+ * /sys/class/osdblk/
+ *                   add       map OSD object to blkdev
+ *                   remove    unmap OSD object
+ *                   list      show mappings
+ *******************************************************************/
+
+static void class_osdblk_release(struct class *cls)
+{
+       kfree(cls);
+}
+
+static ssize_t class_osdblk_list(struct class *c, char *data)
+{
+       int n = 0;
+       struct list_head *tmp;
+
+       mutex_lock_nested(&ctl_mutex, SINGLE_DEPTH_NESTING);
+
+       list_for_each(tmp, &osdblkdev_list) {
+               struct osdblk_device *osdev;
+
+               osdev = list_entry(tmp, struct osdblk_device, node);
+
+               n += sprintf(data+n, "%d %d %llu %llu %s\n",
+                       osdev->id,
+                       osdev->major,
+                       osdev->obj.partition,
+                       osdev->obj.id,
+                       osdev->osd_path);
+       }
+
+       mutex_unlock(&ctl_mutex);
+       return n;
+}
+
+static ssize_t class_osdblk_add(struct class *c, const char *buf, size_t count)
+{
+       struct osdblk_device *osdev;
+       ssize_t rc;
+       int irc, new_id = 0;
+       struct list_head *tmp;
+
+       if (!try_module_get(THIS_MODULE))
+               return -ENODEV;
+
+       /* new osdblk_device object */
+       osdev = kzalloc(sizeof(*osdev) + strlen(buf) + 1, GFP_KERNEL);
+       if (!osdev) {
+               rc = -ENOMEM;
+               goto err_out_mod;
+       }
+
+       /* static osdblk_device initialization */
+       spin_lock_init(&osdev->lock);
+       INIT_LIST_HEAD(&osdev->node);
+
+       /* generate unique id: find highest unique id, add one */
+
+       mutex_lock_nested(&ctl_mutex, SINGLE_DEPTH_NESTING);
+
+       list_for_each(tmp, &osdblkdev_list) {
+               struct osdblk_device *osdev;
+
+               osdev = list_entry(tmp, struct osdblk_device, node);
+               if (osdev->id > new_id)
+                       new_id = osdev->id + 1;
+       }
+
+       osdev->id = new_id;
+
+       /* add to global list */
+       list_add_tail(&osdev->node, &osdblkdev_list);
+
+       mutex_unlock(&ctl_mutex);
+
+       /* parse add command */
+       if (sscanf(buf, "%llu %llu %s", &osdev->obj.partition, &osdev->obj.id,
+                  osdev->osd_path) != 3) {
+               rc = -EINVAL;
+               goto err_out_slot;
+       }
+
+       /* initialize rest of new object */
+       sprintf(osdev->name, DRV_NAME "%d", osdev->id);
+
+       /* contact requested OSD */
+       osdev->osd = osduld_path_lookup(osdev->osd_path);
+       if (IS_ERR(osdev->osd)) {
+               rc = PTR_ERR(osdev->osd);
+               goto err_out_slot;
+       }
+
+       /* build OSD credential */
+       osdblk_make_credential(osdev->obj_cred, &osdev->obj);
+
+       /* register our block device */
+       irc = register_blkdev(0, osdev->name);
+       if (irc < 0) {
+               rc = irc;
+               goto err_out_osd;
+       }
+
+       osdev->major = irc;
+
+       /* set up and announce blkdev mapping */
+       rc = osdblk_init_disk(osdev);
+       if (rc)
+               goto err_out_blkdev;
+
+       return count;
+
+err_out_blkdev:
+       unregister_blkdev(osdev->major, osdev->name);
+err_out_osd:
+       osduld_put_device(osdev->osd);
+err_out_slot:
+       mutex_lock_nested(&ctl_mutex, SINGLE_DEPTH_NESTING);
+       list_del_init(&osdev->node);
+       mutex_unlock(&ctl_mutex);
+
+       kfree(osdev);
+err_out_mod:
+       OSDBLK_DEBUG("Error adding device %s\n", buf);
+       module_put(THIS_MODULE);
+       return rc;
+}
+
+static ssize_t class_osdblk_remove(struct class *c, const char *buf,
+                                       size_t count)
+{
+       struct osdblk_device *osdev = NULL;
+       int target_id, rc;
+       unsigned long ul;
+       struct list_head *tmp;
+
+       rc = strict_strtoul(buf, 10, &ul);
+       if (rc)
+               return rc;
+
+       /* convert to int; abort if we lost anything in the conversion */
+       target_id = (int) ul;
+       if (target_id != ul)
+               return -EINVAL;
+
+       /* remove object from list immediately */
+       mutex_lock_nested(&ctl_mutex, SINGLE_DEPTH_NESTING);
+
+       list_for_each(tmp, &osdblkdev_list) {
+               osdev = list_entry(tmp, struct osdblk_device, node);
+               if (osdev->id == target_id) {
+                       list_del_init(&osdev->node);
+                       break;
+               }
+               osdev = NULL;
+       }
+
+       mutex_unlock(&ctl_mutex);
+
+       if (!osdev)
+               return -ENOENT;
+
+       /* clean up and free blkdev and associated OSD connection */
+       osdblk_free_disk(osdev);
+       unregister_blkdev(osdev->major, osdev->name);
+       osduld_put_device(osdev->osd);
+       kfree(osdev);
+
+       /* release module ref */
+       module_put(THIS_MODULE);
+
+       return count;
+}
+
+static struct class_attribute class_osdblk_attrs[] = {
+       __ATTR(add,     0200, NULL, class_osdblk_add),
+       __ATTR(remove,  0200, NULL, class_osdblk_remove),
+       __ATTR(list,    0444, class_osdblk_list, NULL),
+       __ATTR_NULL
+};
+
+static int osdblk_sysfs_init(void)
+{
+       int ret = 0;
+
+       /*
+        * create control files in sysfs
+        * /sys/class/osdblk/...
+        */
+       class_osdblk = kzalloc(sizeof(*class_osdblk), GFP_KERNEL);
+       if (!class_osdblk)
+               return -ENOMEM;
+
+       class_osdblk->name = DRV_NAME;
+       class_osdblk->owner = THIS_MODULE;
+       class_osdblk->class_release = class_osdblk_release;
+       class_osdblk->class_attrs = class_osdblk_attrs;
+
+       ret = class_register(class_osdblk);
+       if (ret) {
+               kfree(class_osdblk);
+               class_osdblk = NULL;
+               printk(PFX "failed to create class osdblk\n");
+               return ret;
+       }
+
+       return 0;
+}
+
+static void osdblk_sysfs_cleanup(void)
+{
+       if (class_osdblk)
+               class_destroy(class_osdblk);
+       class_osdblk = NULL;
+}
+
+static int __init osdblk_init(void)
+{
+       int rc;
+
+       rc = osdblk_sysfs_init();
+       if (rc)
+               return rc;
+
+       return 0;
+}
+
+static void __exit osdblk_exit(void)
+{
+       osdblk_sysfs_cleanup();
+}
+
+module_init(osdblk_init);
+module_exit(osdblk_exit);
+
index 83650e00632d80b6837678355fbac3c50c6d9a94..99a506f619b71bcadac21608b5969931441e05cf 100644 (file)
@@ -1372,8 +1372,10 @@ try_next_bio:
        wakeup = (pd->write_congestion_on > 0
                        && pd->bio_queue_size <= pd->write_congestion_off);
        spin_unlock(&pd->lock);
-       if (wakeup)
-               clear_bdi_congested(&pd->disk->queue->backing_dev_info, WRITE);
+       if (wakeup) {
+               clear_bdi_congested(&pd->disk->queue->backing_dev_info,
+                                       BLK_RW_ASYNC);
+       }
 
        pkt->sleep_time = max(PACKET_WAIT_TIME, 1);
        pkt_set_state(pkt, PACKET_WAITING_STATE);
@@ -2592,10 +2594,10 @@ static int pkt_make_request(struct request_queue *q, struct bio *bio)
        spin_lock(&pd->lock);
        if (pd->write_congestion_on > 0
            && pd->bio_queue_size >= pd->write_congestion_on) {
-               set_bdi_congested(&q->backing_dev_info, WRITE);
+               set_bdi_congested(&q->backing_dev_info, BLK_RW_ASYNC);
                do {
                        spin_unlock(&pd->lock);
-                       congestion_wait(WRITE, HZ);
+                       congestion_wait(BLK_RW_ASYNC, HZ);
                        spin_lock(&pd->lock);
                } while(pd->bio_queue_size > pd->write_congestion_off);
        }
index 43db3ea15b54936da4502526602c117876bd67fc..fbeefb68a31fc6f9d65509a9552b9d7003af3489 100644 (file)
@@ -213,7 +213,7 @@ static int virtblk_ioctl(struct block_device *bdev, fmode_t mode,
         * Only allow the generic SCSI ioctls if the host can support it.
         */
        if (!virtio_has_feature(vblk->vdev, VIRTIO_BLK_F_SCSI))
-               return -ENOIOCTLCMD;
+               return -ENOTTY;
 
        return scsi_cmd_ioctl(disk->queue, disk, mode, cmd, argp);
 }
@@ -360,6 +360,9 @@ static int __devinit virtblk_probe(struct virtio_device *vdev)
        blk_queue_max_phys_segments(vblk->disk->queue, vblk->sg_elems-2);
        blk_queue_max_hw_segments(vblk->disk->queue, vblk->sg_elems-2);
 
+       /* No need to bounce any requests */
+       blk_queue_bounce_limit(vblk->disk->queue, BLK_BOUNCE_ANY);
+
        /* No real sector limit. */
        blk_queue_max_sectors(vblk->disk->queue, -1U);
 
index f08491a3a813b84e83df249196636c8829466cf7..b20abe102a2b774d66cc4505508762bbed86b8d0 100644 (file)
@@ -390,9 +390,10 @@ static inline void ace_dump_mem(void *base, int len)
 
 static void ace_dump_regs(struct ace_device *ace)
 {
-       dev_info(ace->dev, "    ctrl:  %.8x  seccnt/cmd: %.4x      ver:%.4x\n"
-                KERN_INFO "    status:%.8x  mpu_lba:%.8x  busmode:%4x\n"
-                KERN_INFO "    error: %.8x  cfg_lba:%.8x  fatstat:%.4x\n",
+       dev_info(ace->dev,
+                "    ctrl:  %.8x  seccnt/cmd: %.4x      ver:%.4x\n"
+                "    status:%.8x  mpu_lba:%.8x  busmode:%4x\n"
+                "    error: %.8x  cfg_lba:%.8x  fatstat:%.4x\n",
                 ace_in32(ace, ACE_CTRL),
                 ace_in(ace, ACE_SECCNTCMD),
                 ace_in(ace, ACE_VERSION),
index 1df9dda2e377d8415366ae43fb1c44e57e2ed9d2..d5cde6d86f891a2c01a47cdfbdbe43772e6de86d 100644 (file)
@@ -28,7 +28,6 @@
 #include <linux/kernel.h>
 #include <linux/init.h>
 #include <linux/slab.h>
-#include <linux/smp_lock.h>
 #include <linux/types.h>
 #include <linux/errno.h>
 #include <linux/sched.h>
index 0bd01f49cfd8bc76baf500b7d903ffbe8b40de96..6a06913b01d30151065471350ec492e7df79a6a3 100644 (file)
@@ -1029,10 +1029,6 @@ config CS5535_GPIO
 
          If compiled as a module, it will be called cs5535_gpio.
 
-config GPIO_VR41XX
-       tristate "NEC VR4100 series General-purpose I/O Unit support"
-       depends on CPU_VR41XX
-
 config RAW_DRIVER
        tristate "RAW driver (/dev/raw/rawN)"
        depends on BLOCK
index 189efcff08ce246a58900ab15a7cacd487c37724..66f779ad4f4c05297409c5eefadcf92d0a3903f1 100644 (file)
@@ -95,7 +95,6 @@ obj-$(CONFIG_SCx200_GPIO)     += scx200_gpio.o
 obj-$(CONFIG_PC8736x_GPIO)     += pc8736x_gpio.o
 obj-$(CONFIG_NSC_GPIO)         += nsc_gpio.o
 obj-$(CONFIG_CS5535_GPIO)      += cs5535_gpio.o
-obj-$(CONFIG_GPIO_VR41XX)      += vr41xx_giu.o
 obj-$(CONFIG_GPIO_TB0219)      += tb0219.o
 obj-$(CONFIG_TELCLOCK)         += tlclk.o
 
index 72429b6b2fa831e8ce925145398acfbb7aa66170..6c32fbf071648931374bfc6fa699d6ba37a523f1 100644 (file)
@@ -81,6 +81,7 @@ static char *serial_version = "4.30";
 #include <linux/mm.h>
 #include <linux/seq_file.h>
 #include <linux/slab.h>
+#include <linux/smp_lock.h>
 #include <linux/init.h>
 #include <linux/bitops.h>
 
index 140ea10ecb886e276c8a6ba53d112cdf06d96499..c02db01f736ea46bc536190910a2f4a9e336bfbb 100644 (file)
@@ -27,6 +27,7 @@
 #include <linux/cdev.h>
 #include <linux/list.h>
 #include <linux/mm.h>
+#include <asm/pgtable.h>
 #include <asm/io.h>
 
 /*
@@ -75,12 +76,13 @@ static struct class *bsr_class;
 static int bsr_major;
 
 enum {
-       BSR_8   = 0,
-       BSR_16  = 1,
-       BSR_64  = 2,
-       BSR_128 = 3,
-       BSR_UNKNOWN = 4,
-       BSR_MAX = 5,
+       BSR_8    = 0,
+       BSR_16   = 1,
+       BSR_64   = 2,
+       BSR_128  = 3,
+       BSR_4096 = 4,
+       BSR_UNKNOWN = 5,
+       BSR_MAX  = 6,
 };
 
 static unsigned bsr_types[BSR_MAX];
@@ -117,15 +119,22 @@ static int bsr_mmap(struct file *filp, struct vm_area_struct *vma)
 {
        unsigned long size   = vma->vm_end - vma->vm_start;
        struct bsr_dev *dev = filp->private_data;
+       int ret;
 
-       if (size > dev->bsr_len || (size & (PAGE_SIZE-1)))
-               return -EINVAL;
-
-       vma->vm_flags |= (VM_IO | VM_DONTEXPAND);
        vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
 
-       if (io_remap_pfn_range(vma, vma->vm_start, dev->bsr_addr >> PAGE_SHIFT,
-                              size, vma->vm_page_prot))
+       /* check for the case of a small BSR device and map one 4k page for it*/
+       if (dev->bsr_len < PAGE_SIZE && size == PAGE_SIZE)
+               ret = remap_4k_pfn(vma, vma->vm_start, dev->bsr_addr >> 12,
+                                  vma->vm_page_prot);
+       else if (size <= dev->bsr_len)
+               ret = io_remap_pfn_range(vma, vma->vm_start,
+                                        dev->bsr_addr >> PAGE_SHIFT,
+                                        size, vma->vm_page_prot);
+       else
+               return -EINVAL;
+
+       if (ret)
                return -EAGAIN;
 
        return 0;
@@ -205,6 +214,11 @@ static int bsr_add_node(struct device_node *bn)
                cur->bsr_stride = bsr_stride[i];
                cur->bsr_dev    = MKDEV(bsr_major, i + total_bsr_devs);
 
+               /* if we have a bsr_len of > 4k and less then PAGE_SIZE (64k pages) */
+               /* we can only map 4k of it, so only advertise the 4k in sysfs */
+               if (cur->bsr_len > 4096 && cur->bsr_len < PAGE_SIZE)
+                       cur->bsr_len = 4096;
+
                switch(cur->bsr_bytes) {
                case 8:
                        cur->bsr_type = BSR_8;
@@ -218,9 +232,11 @@ static int bsr_add_node(struct device_node *bn)
                case 128:
                        cur->bsr_type = BSR_128;
                        break;
+               case 4096:
+                       cur->bsr_type = BSR_4096;
+                       break;
                default:
                        cur->bsr_type = BSR_UNKNOWN;
-                       printk(KERN_INFO "unknown BSR size %d\n",cur->bsr_bytes);
                }
 
                cur->bsr_num = bsr_types[cur->bsr_type];
index f3366d3f06cfe404cdfe94b6d3393c55b7b05886..2dafc2da06488f631b1b6937b287440d8a1417bd 100644 (file)
 #include <linux/tty.h>
 #include <linux/tty_flip.h>
 #include <linux/serial.h>
+#include <linux/smp_lock.h>
 #include <linux/major.h>
 #include <linux/string.h>
 #include <linux/fcntl.h>
index abef1f7d84fefb03ef23ffc90417d173aea7ceef..ff647ca1c4895d9f08049ea840496b86b40fbf28 100644 (file)
@@ -36,6 +36,7 @@
 #include <linux/tty.h>
 #include <linux/tty_flip.h>
 #include <linux/slab.h>
+#include <linux/smp_lock.h>
 #include <linux/ioport.h>
 #include <linux/interrupt.h>
 #include <linux/uaccess.h>
index 5dcbe603eca2eae981e70077d1cddfc7616ab0a9..91b53eb1c053bff15349b80d6b949abb71ad4fb8 100644 (file)
@@ -305,10 +305,11 @@ static int __init intel_init_hw_struct(struct intel_rng_hw *intel_rng_hw,
             (BIOS_CNTL_LOCK_ENABLE_MASK|BIOS_CNTL_WRITE_ENABLE_MASK))
            == BIOS_CNTL_LOCK_ENABLE_MASK) {
                static __initdata /*const*/ char warning[] =
-                       KERN_WARNING PFX "Firmware space is locked read-only. If you can't or\n"
-                       KERN_WARNING PFX "don't want to disable this in firmware setup, and if\n"
-                       KERN_WARNING PFX "you are certain that your system has a functional\n"
-                       KERN_WARNING PFX "RNG, try using the 'no_fwh_detect' option.\n";
+                       KERN_WARNING
+PFX "Firmware space is locked read-only. If you can't or\n"
+PFX "don't want to disable this in firmware setup, and if\n"
+PFX "you are certain that your system has a functional\n"
+PFX "RNG, try using the 'no_fwh_detect' option.\n";
 
                if (no_fwh_detect)
                        return -ENODEV;
index 4159292e35cf4e570fa6c0322bbe26b339ef9569..4f1f4cd670dac7dcd252d088ee2760d2977df1f3 100644 (file)
 #include <linux/fs.h>
 #include <linux/sched.h>
 #include <linux/serial.h>
+#include <linux/smp_lock.h>
 #include <linux/mm.h>
 #include <linux/interrupt.h>
 #include <linux/timer.h>
@@ -1478,10 +1479,10 @@ static int __devinit load_firmware(struct pci_dev *pdev,
                status = inw(base + 0x4);
                if (status != 0) {
                        dev_warn(&pdev->dev, "Card%d rejected load header:\n"
-                               KERN_WARNING "Address:0x%x\n"
-                               KERN_WARNING "Count:0x%x\n"
-                               KERN_WARNING "Status:0x%x\n",
-                               index + 1, frame->addr, frame->count, status);
+                                "Address:0x%x\n"
+                                "Count:0x%x\n"
+                                "Status:0x%x\n",
+                                index + 1, frame->addr, frame->count, status);
                        goto errrelfw;
                }
                outsw(base, frame->data, word_count);
@@ -1526,10 +1527,10 @@ static int __devinit load_firmware(struct pci_dev *pdev,
                status = inw(base + 0x4);
                if (status != 0) {
                        dev_warn(&pdev->dev, "Card%d rejected verify header:\n"
-                               KERN_WARNING "Address:0x%x\n"
-                               KERN_WARNING "Count:0x%x\n"
-                               KERN_WARNING "Status: 0x%x\n",
-                               index + 1, frame->addr, frame->count, status);
+                                "Address:0x%x\n"
+                                "Count:0x%x\n"
+                                "Status: 0x%x\n",
+                                index + 1, frame->addr, frame->count, status);
                        goto errrelfw;
                }
 
index 0c999f5bb3db6df69e0062609e9f82d1c0ee8955..ab2f3349c5c4cc9dc13e3021307a3ede3ddf9a92 100644 (file)
@@ -20,6 +20,7 @@
 
 #include <linux/module.h>
 #include <linux/slab.h>
+#include <linux/smp_lock.h>
 #include <linux/interrupt.h>
 #include <linux/tty.h>
 #include <linux/tty_flip.h>
index 65b6ff2442c6df4edfd839b37752ded8340df9c9..dd0083bbb64addaea9b286ac8d5a914a474625ea 100644 (file)
@@ -34,6 +34,7 @@
 #include <linux/tty.h>
 #include <linux/tty_flip.h>
 #include <linux/major.h>
+#include <linux/smp_lock.h>
 #include <linux/string.h>
 #include <linux/fcntl.h>
 #include <linux/ptrace.h>
index 9533f43a30bb0e7bad9873acb85d25cf39e44625..dbf8d52f31d02d743b0436abcc871104bdf7e588 100644 (file)
@@ -23,6 +23,7 @@
 #include <linux/errno.h>
 #include <linux/signal.h>
 #include <linux/sched.h>
+#include <linux/smp_lock.h>
 #include <linux/timer.h>
 #include <linux/interrupt.h>
 #include <linux/tty.h>
@@ -1048,8 +1049,6 @@ static int mxser_open(struct tty_struct *tty, struct file *filp)
        if (retval)
                return retval;
 
-       /* unmark here for very high baud rate (ex. 921600 bps) used */
-       tty->low_latency = 1;
        return 0;
 }
 
index 1c43c8cdee259f18d3ffbf0e063be81dc5c2f3f2..c68118efad844940e7977f4e30afa5f3c694977d 100644 (file)
@@ -97,6 +97,7 @@
 #include <linux/slab.h>
 #include <linux/tty.h>
 #include <linux/errno.h>
+#include <linux/smp_lock.h>
 #include <linux/string.h>      /* used in new tty drivers */
 #include <linux/signal.h>      /* used in new tty drivers */
 #include <linux/if.h>
index 2e99158ebb8a6e7922a1ac0c0f97c0a06b49f338..6934025a1ac10d5e094c0b9df10ec88ff0f40468 100644 (file)
@@ -58,6 +58,7 @@
 #include <linux/ioport.h>
 #include <linux/in.h>
 #include <linux/slab.h>
+#include <linux/smp_lock.h>
 #include <linux/tty.h>
 #include <linux/errno.h>
 #include <linux/string.h>      /* used in new tty drivers */
index 94a5d5020abcec935e08d6bc74180a249ea58423..ff47907ff1bf9f9ae8ddc3e073c06ae4f3a615df 100644 (file)
@@ -1331,9 +1331,6 @@ handle_newline:
 
 static void n_tty_write_wakeup(struct tty_struct *tty)
 {
-       /* Write out any echoed characters that are still pending */
-       process_echoes(tty);
-
        if (tty->fasync && test_and_clear_bit(TTY_DO_WRITE_WAKEUP, &tty->flags))
                kill_fasync(&tty->fasync, SIGIO, POLL_OUT);
 }
index d6102b644b550d0f9a306b015dd985f642d7e974..280b41c507a723b12a62560f67d325151cbf979d 100644 (file)
@@ -828,7 +828,7 @@ static int receive_data(enum port_type index, struct nozomi *dc)
        struct port *port = &dc->port[index];
        void __iomem *addr = port->dl_addr[port->toggle_dl];
        struct tty_struct *tty = tty_port_tty_get(&port->port);
-       int i;
+       int i, ret;
 
        if (unlikely(!tty)) {
                DBG1("tty not open for port: %d?", index);
@@ -844,12 +844,14 @@ static int receive_data(enum port_type index, struct nozomi *dc)
 
                /* disable interrupt in downlink... */
                disable_transmit_dl(index, dc);
-               return 0;
+               ret = 0;
+               goto put;
        }
 
        if (unlikely(size == 0)) {
                dev_err(&dc->pdev->dev, "size == 0?\n");
-               return 1;
+               ret = 1;
+               goto put;
        }
 
        tty_buffer_request_room(tty, size);
@@ -871,8 +873,10 @@ static int receive_data(enum port_type index, struct nozomi *dc)
        }
 
        set_bit(index, &dc->flip);
+       ret = 1;
+put:
        tty_kref_put(tty);
-       return 1;
+       return ret;
 }
 
 /* Debug for interrupts */
@@ -1591,8 +1595,6 @@ static int ntty_open(struct tty_struct *tty, struct file *file)
 
        /* Enable interrupt downlink for channel */
        if (port->port.count == 1) {
-               /* FIXME: is this needed now ? */
-               tty->low_latency = 1;
                tty->driver_data = port;
                tty_port_tty_set(&port->port, tty);
                DBG1("open: %d", port->token_dl);
index daebe1ba43d42ad0f3a4053cea80e6c411e8968a..6e6942c45f5b6cb76d6c1aaf91ed96fee9185ae7 100644 (file)
@@ -22,6 +22,7 @@
 #include <linux/major.h>
 #include <linux/mm.h>
 #include <linux/init.h>
+#include <linux/smp_lock.h>
 #include <linux/sysctl.h>
 #include <linux/device.h>
 #include <linux/uaccess.h>
@@ -75,114 +76,88 @@ static void pty_close(struct tty_struct *tty, struct file *filp)
  */
 static void pty_unthrottle(struct tty_struct *tty)
 {
-       struct tty_struct *o_tty = tty->link;
-
-       if (!o_tty)
-               return;
-
-       tty_wakeup(o_tty);
+       tty_wakeup(tty->link);
        set_bit(TTY_THROTTLED, &tty->flags);
 }
 
-/*
- * WSH 05/24/97: modified to
- *   (1) use space in tty->flip instead of a shared temp buffer
- *      The flip buffers aren't being used for a pty, so there's lots
- *      of space available.  The buffer is protected by a per-pty
- *      semaphore that should almost never come under contention.
- *   (2) avoid redundant copying for cases where count >> receive_room
- * N.B. Calls from user space may now return an error code instead of
- * a count.
+/**
+ *     pty_space       -       report space left for writing
+ *     @to: tty we are writing into
  *
- * FIXME: Our pty_write method is called with our ldisc lock held but
- * not our partners. We can't just wait on the other one blindly without
- * risking deadlocks. At some point when everything has settled down we need
- * to look into making pty_write at least able to sleep over an ldisc change.
+ *     The tty buffers allow 64K but we sneak a peak and clip at 8K this
+ *     allows a lot of overspill room for echo and other fun messes to
+ *     be handled properly
+ */
+
+static int pty_space(struct tty_struct *to)
+{
+       int n = 8192 - to->buf.memory_used;
+       if (n < 0)
+               return 0;
+       return n;
+}
+
+/**
+ *     pty_write               -       write to a pty
+ *     @tty: the tty we write from
+ *     @buf: kernel buffer of data
+ *     @count: bytes to write
  *
- * The return on no ldisc is a bit counter intuitive but the logic works
- * like this. During an ldisc change the other end will flush its buffers. We
- * thus return the full length which is identical to the case where we had
- * proper locking and happened to queue the bytes just before the flush during
- * the ldisc change.
+ *     Our "hardware" write method. Data is coming from the ldisc which
+ *     may be in a non sleeping state. We simply throw this at the other
+ *     end of the link as if we were an IRQ handler receiving stuff for
+ *     the other side of the pty/tty pair.
  */
+
 static int pty_write(struct tty_struct *tty, const unsigned char *buf,
                                                                int count)
 {
        struct tty_struct *to = tty->link;
-       struct tty_ldisc *ld;
-       int c = count;
+       int c;
 
-       if (!to || tty->stopped)
+       if (tty->stopped)
                return 0;
-       ld = tty_ldisc_ref(to);
-
-       if (ld) {
-               c = to->receive_room;
-               if (c > count)
-                       c = count;
-               ld->ops->receive_buf(to, buf, NULL, c);
-               tty_ldisc_deref(ld);
+
+       /* This isn't locked but our 8K is quite sloppy so no
+          big deal */
+
+       c = pty_space(to);
+       if (c > count)
+               c = count;
+       if (c > 0) {
+               /* Stuff the data into the input queue of the other end */
+               c = tty_insert_flip_string(to, buf, c);
+               /* And shovel */
+               tty_flip_buffer_push(to);
+               tty_wakeup(tty);
        }
        return c;
 }
 
+/**
+ *     pty_write_room  -       write space
+ *     @tty: tty we are writing from
+ *
+ *     Report how many bytes the ldisc can send into the queue for
+ *     the other device.
+ */
+
 static int pty_write_room(struct tty_struct *tty)
 {
-       struct tty_struct *to = tty->link;
-
-       if (!to || tty->stopped)
-               return 0;
-
-       return to->receive_room;
+       return pty_space(tty->link);
 }
 
-/*
- *     WSH 05/24/97:  Modified for asymmetric MASTER/SLAVE behavior
- *     The chars_in_buffer() value is used by the ldisc select() function
- *     to hold off writing when chars_in_buffer > WAKEUP_CHARS (== 256).
- *     The pty driver chars_in_buffer() Master/Slave must behave differently:
- *
- *      The Master side needs to allow typed-ahead commands to accumulate
- *      while being canonicalized, so we report "our buffer" as empty until
- *     some threshold is reached, and then report the count. (Any count >
- *     WAKEUP_CHARS is regarded by select() as "full".)  To avoid deadlock
- *     the count returned must be 0 if no canonical data is available to be
- *     read. (The N_TTY ldisc.chars_in_buffer now knows this.)
+/**
+ *     pty_chars_in_buffer     -       characters currently in our tx queue
+ *     @tty: our tty
  *
- *     The Slave side passes all characters in raw mode to the Master side's
- *     buffer where they can be read immediately, so in this case we can
- *     return the true count in the buffer.
+ *     Report how much we have in the transmit queue. As everything is
+ *     instantly at the other end this is easy to implement.
  */
+
 static int pty_chars_in_buffer(struct tty_struct *tty)
 {
-       struct tty_struct *to = tty->link;
-       struct tty_ldisc *ld;
-       int count = 0;
-
-       /* We should get the line discipline lock for "tty->link" */
-       if (!to)
-               return 0;
-       /* We cannot take a sleeping reference here without deadlocking with
-          an ldisc change - but it doesn't really matter */
-       ld = tty_ldisc_ref(to);
-       if (ld == NULL)
-               return 0;
-
-       /* The ldisc must report 0 if no characters available to be read */
-       if (ld->ops->chars_in_buffer)
-               count = ld->ops->chars_in_buffer(to);
-
-       tty_ldisc_deref(ld);
-
-       if (tty->driver->subtype == PTY_TYPE_SLAVE)
-               return count;
-
-       /* Master side driver ... if the other side's read buffer is less than
-        * half full, return 0 to allow writers to proceed; otherwise return
-        * the count.  This leaves a comfortable margin to avoid overflow,
-        * and still allows half a buffer's worth of typed-ahead commands.
-        */
-       return (count < N_TTY_BUF_SIZE/2) ? 0 : count;
+       return 0;
 }
 
 /* Set the lock flag on a pty */
@@ -202,20 +177,10 @@ static void pty_flush_buffer(struct tty_struct *tty)
 {
        struct tty_struct *to = tty->link;
        unsigned long flags;
-       struct tty_ldisc *ld;
 
        if (!to)
                return;
-       ld = tty_ldisc_ref(to);
-
-       /* The other end is changing discipline */
-       if (!ld)
-               return;
-
-       if (ld->ops->flush_buffer)
-               to->ldisc->ops->flush_buffer(to);
-       tty_ldisc_deref(ld);
-
+       /* tty_buffer_flush(to); FIXME */
        if (to->packet) {
                spin_lock_irqsave(&tty->ctrl_lock, flags);
                tty->ctrl_status |= TIOCPKT_FLUSHWRITE;
index ce81da5b2da9a20079cf46fe64eddcac546b1474..d58c2eb07f07aaad25a568095ccaab7d3e53f686 100644 (file)
@@ -44,6 +44,7 @@
 #include <linux/delay.h>
 #include <linux/pci.h>
 #include <linux/slab.h>
+#include <linux/smp_lock.h>
 #include <linux/miscdevice.h>
 #include <linux/init.h>
 
index 217660451237a79c7cd186d38697bad07f9dbcf8..171711acf5cd33736ebb74d69a6f02983b15bdb3 100644 (file)
@@ -47,6 +47,7 @@
 #include <linux/init.h>
 #include <linux/delay.h>
 #include <linux/tty_flip.h>
+#include <linux/smp_lock.h>
 #include <linux/spinlock.h>
 #include <linux/device.h>
 
index 63d5b628477a72bbffb6cb8696a0a4b615ef5725..0e29a23ec4c50be1f2d74b492c91785a8feae2b3 100644 (file)
@@ -73,6 +73,7 @@
 #include <linux/tty_driver.h>
 #include <linux/tty_flip.h>
 #include <linux/serial.h>
+#include <linux/smp_lock.h>
 #include <linux/string.h>
 #include <linux/fcntl.h>
 #include <linux/ptrace.h>
index f1f24f0ee26f4281392925b0d86b4ad4a5e897af..51e7a46787bea72aa23e93535e4d9ce636b63448 100644 (file)
@@ -52,6 +52,7 @@
 #include <linux/interrupt.h>
 #include <linux/serial.h>
 #include <linux/serialP.h>
+#include <linux/smp_lock.h>
 #include <linux/string.h>
 #include <linux/fcntl.h>
 #include <linux/ptrace.h>
index e72be4190a442a6378cca9a68a306b3421dcb06c..bfe4cdb2febb17c65ed8900b7dff9a5b40ed7921 100644 (file)
@@ -87,6 +87,7 @@
 #include <linux/tty_flip.h>
 #include <linux/mm.h>
 #include <linux/serial.h>
+#include <linux/smp_lock.h>
 #include <linux/fcntl.h>
 #include <linux/major.h>
 #include <linux/delay.h>
index 518f2a25d91ec6b1a208c6fe233c505a7395aa47..a81ec4fcf6ff4480b9473587d5424b09cb74510e 100644 (file)
 #include <linux/eisa.h>
 #include <linux/pci.h>
 #include <linux/slab.h>
+#include <linux/smp_lock.h>
 #include <linux/init.h>
 #include <linux/miscdevice.h>
 #include <linux/bitops.h>
index afded3a2379c592082e85e373236addce5d9fcd3..813552f14884427ea785b1ac0e2bec080c704a6a 100644 (file)
@@ -81,6 +81,7 @@
 #include <linux/mm.h>
 #include <linux/seq_file.h>
 #include <linux/slab.h>
+#include <linux/smp_lock.h>
 #include <linux/delay.h>
 #include <linux/netdevice.h>
 #include <linux/vmalloc.h>
index 1386625fc4caae4bdf6a39e6835d0026b0e27ca7..91f20a92fddf2f9afb76dc10b7ab1d86a150954f 100644 (file)
@@ -62,6 +62,7 @@
 #include <linux/mm.h>
 #include <linux/seq_file.h>
 #include <linux/slab.h>
+#include <linux/smp_lock.h>
 #include <linux/netdevice.h>
 #include <linux/vmalloc.h>
 #include <linux/init.h>
@@ -467,7 +468,6 @@ static unsigned int free_tbuf_count(struct slgt_info *info);
 static unsigned int tbuf_bytes(struct slgt_info *info);
 static void reset_tbufs(struct slgt_info *info);
 static void tdma_reset(struct slgt_info *info);
-static void tdma_start(struct slgt_info *info);
 static void tx_load(struct slgt_info *info, const char *buf, unsigned int count);
 
 static void get_signals(struct slgt_info *info);
@@ -795,6 +795,18 @@ static void set_termios(struct tty_struct *tty, struct ktermios *old_termios)
        }
 }
 
+static void update_tx_timer(struct slgt_info *info)
+{
+       /*
+        * use worst case speed of 1200bps to calculate transmit timeout
+        * based on data in buffers (tbuf_bytes) and FIFO (128 bytes)
+        */
+       if (info->params.mode == MGSL_MODE_HDLC) {
+               int timeout  = (tbuf_bytes(info) * 7) + 1000;
+               mod_timer(&info->tx_timer, jiffies + msecs_to_jiffies(timeout));
+       }
+}
+
 static int write(struct tty_struct *tty,
                 const unsigned char *buf, int count)
 {
@@ -838,8 +850,18 @@ start:
                spin_lock_irqsave(&info->lock,flags);
                if (!info->tx_active)
                        tx_start(info);
-               else
-                       tdma_start(info);
+               else if (!(rd_reg32(info, TDCSR) & BIT0)) {
+                       /* transmit still active but transmit DMA stopped */
+                       unsigned int i = info->tbuf_current;
+                       if (!i)
+                               i = info->tbuf_count;
+                       i--;
+                       /* if DMA buf unsent must try later after tx idle */
+                       if (desc_count(info->tbufs[i]))
+                               ret = 0;
+               }
+               if (ret > 0)
+                       update_tx_timer(info);
                spin_unlock_irqrestore(&info->lock,flags);
        }
 
@@ -1502,10 +1524,9 @@ static int hdlcdev_xmit(struct sk_buff *skb, struct net_device *dev)
        /* save start time for transmit timeout detection */
        dev->trans_start = jiffies;
 
-       /* start hardware transmitter if necessary */
        spin_lock_irqsave(&info->lock,flags);
-       if (!info->tx_active)
-               tx_start(info);
+       tx_start(info);
+       update_tx_timer(info);
        spin_unlock_irqrestore(&info->lock,flags);
 
        return 0;
@@ -3946,50 +3967,19 @@ static void tx_start(struct slgt_info *info)
                        slgt_irq_on(info, IRQ_TXUNDER + IRQ_TXIDLE);
                        /* clear tx idle and underrun status bits */
                        wr_reg16(info, SSR, (unsigned short)(IRQ_TXIDLE + IRQ_TXUNDER));
-                       if (info->params.mode == MGSL_MODE_HDLC)
-                               mod_timer(&info->tx_timer, jiffies +
-                                               msecs_to_jiffies(5000));
                } else {
                        slgt_irq_off(info, IRQ_TXDATA);
                        slgt_irq_on(info, IRQ_TXIDLE);
                        /* clear tx idle status bit */
                        wr_reg16(info, SSR, IRQ_TXIDLE);
                }
-               tdma_start(info);
+               /* set 1st descriptor address and start DMA */
+               wr_reg32(info, TDDAR, info->tbufs[info->tbuf_start].pdesc);
+               wr_reg32(info, TDCSR, BIT2 + BIT0);
                info->tx_active = true;
        }
 }
 
-/*
- * start transmit DMA if inactive and there are unsent buffers
- */
-static void tdma_start(struct slgt_info *info)
-{
-       unsigned int i;
-
-       if (rd_reg32(info, TDCSR) & BIT0)
-               return;
-
-       /* transmit DMA inactive, check for unsent buffers */
-       i = info->tbuf_start;
-       while (!desc_count(info->tbufs[i])) {
-               if (++i == info->tbuf_count)
-                       i = 0;
-               if (i == info->tbuf_current)
-                       return;
-       }
-       info->tbuf_start = i;
-
-       /* there are unsent buffers, start transmit DMA */
-
-       /* reset needed if previous error condition */
-       tdma_reset(info);
-
-       /* set 1st descriptor address */
-       wr_reg32(info, TDDAR, info->tbufs[info->tbuf_start].pdesc);
-       wr_reg32(info, TDCSR, BIT2 + BIT0); /* IRQ + DMA enable */
-}
-
 static void tx_stop(struct slgt_info *info)
 {
        unsigned short val;
@@ -5004,8 +4994,7 @@ static void tx_timeout(unsigned long context)
                info->icount.txtimeout++;
        }
        spin_lock_irqsave(&info->lock,flags);
-       info->tx_active = false;
-       info->tx_count = 0;
+       tx_stop(info);
        spin_unlock_irqrestore(&info->lock,flags);
 
 #if SYNCLINK_GENERIC_HDLC
index 6f727e3c53ade1028d21cf11f364bdcc2fafbed9..8d4a2a8a0a7001ad314fa282c589229ea53d8804 100644 (file)
@@ -52,6 +52,7 @@
 #include <linux/mm.h>
 #include <linux/seq_file.h>
 #include <linux/slab.h>
+#include <linux/smp_lock.h>
 #include <linux/netdevice.h>
 #include <linux/vmalloc.h>
 #include <linux/init.h>
index 6062b62800fd2d97e01a640fedaf655983b6997d..b3ec9b10e29208e5272f2f00593d6cf9421503c1 100644 (file)
@@ -1,7 +1,7 @@
 /*
  *  Driver for TANBAC TB0219 base board.
  *
- *  Copyright (C) 2005  Yoichi Yuasa <yoichi_yuasa@tripeaks.co.jp>
+ *  Copyright (C) 2005  Yoichi Yuasa <yuasa@linux-mips.org>
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
@@ -28,7 +28,7 @@
 #include <asm/vr41xx/giu.h>
 #include <asm/vr41xx/tb0219.h>
 
-MODULE_AUTHOR("Yoichi Yuasa <yoichi_yuasa@tripeaks.co.jp>");
+MODULE_AUTHOR("Yoichi Yuasa <yuasa@linux-mips.org>");
 MODULE_DESCRIPTION("TANBAC TB0219 base board driver");
 MODULE_LICENSE("GPL");
 
index ccdd828adcef2711e2ed91a7c52f38b1a6dca844..b0603b2e56844e38e1e4082eaf20ed115d78b07e 100644 (file)
@@ -26,7 +26,6 @@
 #include <linux/poll.h>
 #include <linux/mutex.h>
 #include <linux/spinlock.h>
-#include <linux/smp_lock.h>
 
 #include "tpm.h"
 
index b24f6c6a1ea317c1ccf399eaf2842f281175d70d..ad6ba4ed280853bce299b8bf6aab4d3d53b7c68e 100644 (file)
@@ -21,7 +21,6 @@
 #include <linux/module.h>
 #include <linux/bitops.h>
 #include <linux/mutex.h>
-#include <linux/smp_lock.h>
 
 #include <asm/io.h>
 #include <asm/uaccess.h>
index a19e935847b0a14e9740184e32d6e099efc26955..acd76b767d4c10aac5b540e31a1cd2dddf3c8436 100644 (file)
@@ -21,7 +21,6 @@
 #include <linux/proc_fs.h>
 #include <linux/init.h>
 #include <linux/module.h>
-#include <linux/smp_lock.h>
 #include <linux/device.h>
 #include <linux/wait.h>
 #include <linux/bitops.h>
@@ -791,17 +790,20 @@ void tty_ldisc_hangup(struct tty_struct *tty)
         * N_TTY.
         */
        if (tty->driver->flags & TTY_DRIVER_RESET_TERMIOS) {
-               /* Avoid racing set_ldisc */
+               /* Avoid racing set_ldisc or tty_ldisc_release */
                mutex_lock(&tty->ldisc_mutex);
-               /* Switch back to N_TTY */
-               tty_ldisc_halt(tty);
-               tty_ldisc_wait_idle(tty);
-               tty_ldisc_reinit(tty);
-               /* At this point we have a closed ldisc and we want to
-                  reopen it. We could defer this to the next open but
-                  it means auditing a lot of other paths so this is a FIXME */
-               WARN_ON(tty_ldisc_open(tty, tty->ldisc));
-               tty_ldisc_enable(tty);
+               if (tty->ldisc) {       /* Not yet closed */
+                       /* Switch back to N_TTY */
+                       tty_ldisc_halt(tty);
+                       tty_ldisc_wait_idle(tty);
+                       tty_ldisc_reinit(tty);
+                       /* At this point we have a closed ldisc and we want to
+                          reopen it. We could defer this to the next open but
+                          it means auditing a lot of other paths so this is
+                          a FIXME */
+                       WARN_ON(tty_ldisc_open(tty, tty->ldisc));
+                       tty_ldisc_enable(tty);
+               }
                mutex_unlock(&tty->ldisc_mutex);
                tty_reset_termios(tty);
        }
@@ -866,16 +868,25 @@ void tty_ldisc_release(struct tty_struct *tty, struct tty_struct *o_tty)
 
        tty_ldisc_wait_idle(tty);
 
+       mutex_lock(&tty->ldisc_mutex);
        /*
-        * Shutdown the current line discipline, and reset it to N_TTY.
-        *
-        * FIXME: this MUST get fixed for the new reflocking
+        * Now kill off the ldisc
         */
+       tty_ldisc_close(tty, tty->ldisc);
+       tty_ldisc_put(tty->ldisc);
+       /* Force an oops if we mess this up */
+       tty->ldisc = NULL;
+
+       /* Ensure the next open requests the N_TTY ldisc */
+       tty_set_termios_ldisc(tty, N_TTY);
+       mutex_unlock(&tty->ldisc_mutex);
 
-       tty_ldisc_reinit(tty);
        /* This will need doing differently if we need to lock */
        if (o_tty)
                tty_ldisc_release(o_tty, NULL);
+
+       /* And the memory resources remaining (buffers, termios) will be
+          disposed of when the kref hits zero */
 }
 
 /**
index 62dadfc95e341078ef42a284366cef37dbac6432..9769b1149f7602cf9c2c7ea1a3eab70bfad9b0a0 100644 (file)
@@ -193,7 +193,7 @@ int tty_port_block_til_ready(struct tty_port *port,
 {
        int do_clocal = 0, retval;
        unsigned long flags;
-       DECLARE_WAITQUEUE(wait, current);
+       DEFINE_WAIT(wait);
        int cd;
 
        /* block if port is in the process of being closed */
@@ -267,7 +267,7 @@ int tty_port_block_til_ready(struct tty_port *port,
        if (retval == 0)
                port->flags |= ASYNC_NORMAL_ACTIVE;
        spin_unlock_irqrestore(&port->lock, flags);
-       return 0;
+       return retval;
        
 }
 EXPORT_SYMBOL(tty_port_block_til_ready);
index 54c837288d19453ff2baf3756d28b8cbc5b1092e..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 100644 (file)
@@ -1,680 +0,0 @@
-/*
- *  Driver for NEC VR4100 series General-purpose I/O Unit.
- *
- *  Copyright (C) 2002 MontaVista Software Inc.
- *     Author: Yoichi Yuasa <yyuasa@mvista.com or source@mvista.com>
- *  Copyright (C) 2003-2007  Yoichi Yuasa <yoichi_yuasa@tripeaks.co.jp>
- *
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; either version 2 of the License, or
- *  (at your option) any later version.
- *
- *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *  GNU General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
- */
-#include <linux/errno.h>
-#include <linux/fs.h>
-#include <linux/init.h>
-#include <linux/interrupt.h>
-#include <linux/irq.h>
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/platform_device.h>
-#include <linux/smp_lock.h>
-#include <linux/spinlock.h>
-#include <linux/types.h>
-
-#include <asm/io.h>
-#include <asm/vr41xx/giu.h>
-#include <asm/vr41xx/irq.h>
-#include <asm/vr41xx/vr41xx.h>
-
-MODULE_AUTHOR("Yoichi Yuasa <yoichi_yuasa@tripeaks.co.jp>");
-MODULE_DESCRIPTION("NEC VR4100 series General-purpose I/O Unit driver");
-MODULE_LICENSE("GPL");
-
-static int major;      /* default is dynamic major device number */
-module_param(major, int, 0);
-MODULE_PARM_DESC(major, "Major device number");
-
-#define GIUIOSELL      0x00
-#define GIUIOSELH      0x02
-#define GIUPIODL       0x04
-#define GIUPIODH       0x06
-#define GIUINTSTATL    0x08
-#define GIUINTSTATH    0x0a
-#define GIUINTENL      0x0c
-#define GIUINTENH      0x0e
-#define GIUINTTYPL     0x10
-#define GIUINTTYPH     0x12
-#define GIUINTALSELL   0x14
-#define GIUINTALSELH   0x16
-#define GIUINTHTSELL   0x18
-#define GIUINTHTSELH   0x1a
-#define GIUPODATL      0x1c
-#define GIUPODATEN     0x1c
-#define GIUPODATH      0x1e
- #define PIOEN0                0x0100
- #define PIOEN1                0x0200
-#define GIUPODAT       0x1e
-#define GIUFEDGEINHL   0x20
-#define GIUFEDGEINHH   0x22
-#define GIUREDGEINHL   0x24
-#define GIUREDGEINHH   0x26
-
-#define GIUUSEUPDN     0x1e0
-#define GIUTERMUPDN    0x1e2
-
-#define GPIO_HAS_PULLUPDOWN_IO         0x0001
-#define GPIO_HAS_OUTPUT_ENABLE         0x0002
-#define GPIO_HAS_INTERRUPT_EDGE_SELECT 0x0100
-
-static spinlock_t giu_lock;
-static unsigned long giu_flags;
-static unsigned int giu_nr_pins;
-
-static void __iomem *giu_base;
-
-#define giu_read(offset)               readw(giu_base + (offset))
-#define giu_write(offset, value)       writew((value), giu_base + (offset))
-
-#define GPIO_PIN_OF_IRQ(irq)   ((irq) - GIU_IRQ_BASE)
-#define GIUINT_HIGH_OFFSET     16
-#define GIUINT_HIGH_MAX                32
-
-static inline uint16_t giu_set(uint16_t offset, uint16_t set)
-{
-       uint16_t data;
-
-       data = giu_read(offset);
-       data |= set;
-       giu_write(offset, data);
-
-       return data;
-}
-
-static inline uint16_t giu_clear(uint16_t offset, uint16_t clear)
-{
-       uint16_t data;
-
-       data = giu_read(offset);
-       data &= ~clear;
-       giu_write(offset, data);
-
-       return data;
-}
-
-static void ack_giuint_low(unsigned int irq)
-{
-       giu_write(GIUINTSTATL, 1 << GPIO_PIN_OF_IRQ(irq));
-}
-
-static void mask_giuint_low(unsigned int irq)
-{
-       giu_clear(GIUINTENL, 1 << GPIO_PIN_OF_IRQ(irq));
-}
-
-static void mask_ack_giuint_low(unsigned int irq)
-{
-       unsigned int pin;
-
-       pin = GPIO_PIN_OF_IRQ(irq);
-       giu_clear(GIUINTENL, 1 << pin);
-       giu_write(GIUINTSTATL, 1 << pin);
-}
-
-static void unmask_giuint_low(unsigned int irq)
-{
-       giu_set(GIUINTENL, 1 << GPIO_PIN_OF_IRQ(irq));
-}
-
-static struct irq_chip giuint_low_irq_chip = {
-       .name           = "GIUINTL",
-       .ack            = ack_giuint_low,
-       .mask           = mask_giuint_low,
-       .mask_ack       = mask_ack_giuint_low,
-       .unmask         = unmask_giuint_low,
-};
-
-static void ack_giuint_high(unsigned int irq)
-{
-       giu_write(GIUINTSTATH, 1 << (GPIO_PIN_OF_IRQ(irq) - GIUINT_HIGH_OFFSET));
-}
-
-static void mask_giuint_high(unsigned int irq)
-{
-       giu_clear(GIUINTENH, 1 << (GPIO_PIN_OF_IRQ(irq) - GIUINT_HIGH_OFFSET));
-}
-
-static void mask_ack_giuint_high(unsigned int irq)
-{
-       unsigned int pin;
-
-       pin = GPIO_PIN_OF_IRQ(irq) - GIUINT_HIGH_OFFSET;
-       giu_clear(GIUINTENH, 1 << pin);
-       giu_write(GIUINTSTATH, 1 << pin);
-}
-
-static void unmask_giuint_high(unsigned int irq)
-{
-       giu_set(GIUINTENH, 1 << (GPIO_PIN_OF_IRQ(irq) - GIUINT_HIGH_OFFSET));
-}
-
-static struct irq_chip giuint_high_irq_chip = {
-       .name           = "GIUINTH",
-       .ack            = ack_giuint_high,
-       .mask           = mask_giuint_high,
-       .mask_ack       = mask_ack_giuint_high,
-       .unmask         = unmask_giuint_high,
-};
-
-static int giu_get_irq(unsigned int irq)
-{
-       uint16_t pendl, pendh, maskl, maskh;
-       int i;
-
-       pendl = giu_read(GIUINTSTATL);
-       pendh = giu_read(GIUINTSTATH);
-       maskl = giu_read(GIUINTENL);
-       maskh = giu_read(GIUINTENH);
-
-       maskl &= pendl;
-       maskh &= pendh;
-
-       if (maskl) {
-               for (i = 0; i < 16; i++) {
-                       if (maskl & (1 << i))
-                               return GIU_IRQ(i);
-               }
-       } else if (maskh) {
-               for (i = 0; i < 16; i++) {
-                       if (maskh & (1 << i))
-                               return GIU_IRQ(i + GIUINT_HIGH_OFFSET);
-               }
-       }
-
-       printk(KERN_ERR "spurious GIU interrupt: %04x(%04x),%04x(%04x)\n",
-              maskl, pendl, maskh, pendh);
-
-       atomic_inc(&irq_err_count);
-
-       return -EINVAL;
-}
-
-void vr41xx_set_irq_trigger(unsigned int pin, irq_trigger_t trigger, irq_signal_t signal)
-{
-       uint16_t mask;
-
-       if (pin < GIUINT_HIGH_OFFSET) {
-               mask = 1 << pin;
-               if (trigger != IRQ_TRIGGER_LEVEL) {
-                       giu_set(GIUINTTYPL, mask);
-                       if (signal == IRQ_SIGNAL_HOLD)
-                               giu_set(GIUINTHTSELL, mask);
-                       else
-                               giu_clear(GIUINTHTSELL, mask);
-                       if (giu_flags & GPIO_HAS_INTERRUPT_EDGE_SELECT) {
-                               switch (trigger) {
-                               case IRQ_TRIGGER_EDGE_FALLING:
-                                       giu_set(GIUFEDGEINHL, mask);
-                                       giu_clear(GIUREDGEINHL, mask);
-                                       break;
-                               case IRQ_TRIGGER_EDGE_RISING:
-                                       giu_clear(GIUFEDGEINHL, mask);
-                                       giu_set(GIUREDGEINHL, mask);
-                                       break;
-                               default:
-                                       giu_set(GIUFEDGEINHL, mask);
-                                       giu_set(GIUREDGEINHL, mask);
-                                       break;
-                               }
-                       }
-                       set_irq_chip_and_handler(GIU_IRQ(pin),
-                                                &giuint_low_irq_chip,
-                                                handle_edge_irq);
-               } else {
-                       giu_clear(GIUINTTYPL, mask);
-                       giu_clear(GIUINTHTSELL, mask);
-                       set_irq_chip_and_handler(GIU_IRQ(pin),
-                                                &giuint_low_irq_chip,
-                                                handle_level_irq);
-               }
-               giu_write(GIUINTSTATL, mask);
-       } else if (pin < GIUINT_HIGH_MAX) {
-               mask = 1 << (pin - GIUINT_HIGH_OFFSET);
-               if (trigger != IRQ_TRIGGER_LEVEL) {
-                       giu_set(GIUINTTYPH, mask);
-                       if (signal == IRQ_SIGNAL_HOLD)
-                               giu_set(GIUINTHTSELH, mask);
-                       else
-                               giu_clear(GIUINTHTSELH, mask);
-                       if (giu_flags & GPIO_HAS_INTERRUPT_EDGE_SELECT) {
-                               switch (trigger) {
-                               case IRQ_TRIGGER_EDGE_FALLING:
-                                       giu_set(GIUFEDGEINHH, mask);
-                                       giu_clear(GIUREDGEINHH, mask);
-                                       break;
-                               case IRQ_TRIGGER_EDGE_RISING:
-                                       giu_clear(GIUFEDGEINHH, mask);
-                                       giu_set(GIUREDGEINHH, mask);
-                                       break;
-                               default:
-                                       giu_set(GIUFEDGEINHH, mask);
-                                       giu_set(GIUREDGEINHH, mask);
-                                       break;
-                               }
-                       }
-                       set_irq_chip_and_handler(GIU_IRQ(pin),
-                                                &giuint_high_irq_chip,
-                                                handle_edge_irq);
-               } else {
-                       giu_clear(GIUINTTYPH, mask);
-                       giu_clear(GIUINTHTSELH, mask);
-                       set_irq_chip_and_handler(GIU_IRQ(pin),
-                                                &giuint_high_irq_chip,
-                                                handle_level_irq);
-               }
-               giu_write(GIUINTSTATH, mask);
-       }
-}
-EXPORT_SYMBOL_GPL(vr41xx_set_irq_trigger);
-
-void vr41xx_set_irq_level(unsigned int pin, irq_level_t level)
-{
-       uint16_t mask;
-
-       if (pin < GIUINT_HIGH_OFFSET) {
-               mask = 1 << pin;
-               if (level == IRQ_LEVEL_HIGH)
-                       giu_set(GIUINTALSELL, mask);
-               else
-                       giu_clear(GIUINTALSELL, mask);
-               giu_write(GIUINTSTATL, mask);
-       } else if (pin < GIUINT_HIGH_MAX) {
-               mask = 1 << (pin - GIUINT_HIGH_OFFSET);
-               if (level == IRQ_LEVEL_HIGH)
-                       giu_set(GIUINTALSELH, mask);
-               else
-                       giu_clear(GIUINTALSELH, mask);
-               giu_write(GIUINTSTATH, mask);
-       }
-}
-EXPORT_SYMBOL_GPL(vr41xx_set_irq_level);
-
-gpio_data_t vr41xx_gpio_get_pin(unsigned int pin)
-{
-       uint16_t reg, mask;
-
-       if (pin >= giu_nr_pins)
-               return GPIO_DATA_INVAL;
-
-       if (pin < 16) {
-               reg = giu_read(GIUPIODL);
-               mask = (uint16_t)1 << pin;
-       } else if (pin < 32) {
-               reg = giu_read(GIUPIODH);
-               mask = (uint16_t)1 << (pin - 16);
-       } else if (pin < 48) {
-               reg = giu_read(GIUPODATL);
-               mask = (uint16_t)1 << (pin - 32);
-       } else {
-               reg = giu_read(GIUPODATH);
-               mask = (uint16_t)1 << (pin - 48);
-       }
-
-       if (reg & mask)
-               return GPIO_DATA_HIGH;
-
-       return GPIO_DATA_LOW;
-}
-EXPORT_SYMBOL_GPL(vr41xx_gpio_get_pin);
-
-int vr41xx_gpio_set_pin(unsigned int pin, gpio_data_t data)
-{
-       uint16_t offset, mask, reg;
-       unsigned long flags;
-
-       if (pin >= giu_nr_pins)
-               return -EINVAL;
-
-       if (pin < 16) {
-               offset = GIUPIODL;
-               mask = (uint16_t)1 << pin;
-       } else if (pin < 32) {
-               offset = GIUPIODH;
-               mask = (uint16_t)1 << (pin - 16);
-       } else if (pin < 48) {
-               offset = GIUPODATL;
-               mask = (uint16_t)1 << (pin - 32);
-       } else {
-               offset = GIUPODATH;
-               mask = (uint16_t)1 << (pin - 48);
-       }
-
-       spin_lock_irqsave(&giu_lock, flags);
-
-       reg = giu_read(offset);
-       if (data == GPIO_DATA_HIGH)
-               reg |= mask;
-       else
-               reg &= ~mask;
-       giu_write(offset, reg);
-
-       spin_unlock_irqrestore(&giu_lock, flags);
-
-       return 0;
-}
-EXPORT_SYMBOL_GPL(vr41xx_gpio_set_pin);
-
-int vr41xx_gpio_set_direction(unsigned int pin, gpio_direction_t dir)
-{
-       uint16_t offset, mask, reg;
-       unsigned long flags;
-
-       if (pin >= giu_nr_pins)
-               return -EINVAL;
-
-       if (pin < 16) {
-               offset = GIUIOSELL;
-               mask = (uint16_t)1 << pin;
-       } else if (pin < 32) {
-               offset = GIUIOSELH;
-               mask = (uint16_t)1 << (pin - 16);
-       } else {
-               if (giu_flags & GPIO_HAS_OUTPUT_ENABLE) {
-                       offset = GIUPODATEN;
-                       mask = (uint16_t)1 << (pin - 32);
-               } else {
-                       switch (pin) {
-                       case 48:
-                               offset = GIUPODATH;
-                               mask = PIOEN0;
-                               break;
-                       case 49:
-                               offset = GIUPODATH;
-                               mask = PIOEN1;
-                               break;
-                       default:
-                               return -EINVAL;
-                       }
-               }
-       }
-
-       spin_lock_irqsave(&giu_lock, flags);
-
-       reg = giu_read(offset);
-       if (dir == GPIO_OUTPUT)
-               reg |= mask;
-       else
-               reg &= ~mask;
-       giu_write(offset, reg);
-
-       spin_unlock_irqrestore(&giu_lock, flags);
-
-       return 0;
-}
-EXPORT_SYMBOL_GPL(vr41xx_gpio_set_direction);
-
-int vr41xx_gpio_pullupdown(unsigned int pin, gpio_pull_t pull)
-{
-       uint16_t reg, mask;
-       unsigned long flags;
-
-       if ((giu_flags & GPIO_HAS_PULLUPDOWN_IO) != GPIO_HAS_PULLUPDOWN_IO)
-               return -EPERM;
-
-       if (pin >= 15)
-               return -EINVAL;
-
-       mask = (uint16_t)1 << pin;
-
-       spin_lock_irqsave(&giu_lock, flags);
-
-       if (pull == GPIO_PULL_UP || pull == GPIO_PULL_DOWN) {
-               reg = giu_read(GIUTERMUPDN);
-               if (pull == GPIO_PULL_UP)
-                       reg |= mask;
-               else
-                       reg &= ~mask;
-               giu_write(GIUTERMUPDN, reg);
-
-               reg = giu_read(GIUUSEUPDN);
-               reg |= mask;
-               giu_write(GIUUSEUPDN, reg);
-       } else {
-               reg = giu_read(GIUUSEUPDN);
-               reg &= ~mask;
-               giu_write(GIUUSEUPDN, reg);
-       }
-
-       spin_unlock_irqrestore(&giu_lock, flags);
-
-       return 0;
-}
-EXPORT_SYMBOL_GPL(vr41xx_gpio_pullupdown);
-
-static ssize_t gpio_read(struct file *file, char __user *buf, size_t len,
-                         loff_t *ppos)
-{
-       unsigned int pin;
-       char value = '0';
-
-       pin = iminor(file->f_path.dentry->d_inode);
-       if (pin >= giu_nr_pins)
-               return -EBADF;
-
-       if (vr41xx_gpio_get_pin(pin) == GPIO_DATA_HIGH)
-               value = '1';
-
-       if (len <= 0)
-               return -EFAULT;
-
-       if (put_user(value, buf))
-               return -EFAULT;
-
-       return 1;
-}
-
-static ssize_t gpio_write(struct file *file, const char __user *data,
-                          size_t len, loff_t *ppos)
-{
-       unsigned int pin;
-       size_t i;
-       char c;
-       int retval = 0;
-
-       pin = iminor(file->f_path.dentry->d_inode);
-       if (pin >= giu_nr_pins)
-               return -EBADF;
-
-       for (i = 0; i < len; i++) {
-               if (get_user(c, data + i))
-                       return -EFAULT;
-
-               switch (c) {
-               case '0':
-                       retval = vr41xx_gpio_set_pin(pin, GPIO_DATA_LOW);
-                       break;
-               case '1':
-                       retval = vr41xx_gpio_set_pin(pin, GPIO_DATA_HIGH);
-                       break;
-               case 'D':
-                       printk(KERN_INFO "GPIO%d: pull down\n", pin);
-                       retval = vr41xx_gpio_pullupdown(pin, GPIO_PULL_DOWN);
-                       break;
-               case 'd':
-                       printk(KERN_INFO "GPIO%d: pull up/down disable\n", pin);
-                       retval = vr41xx_gpio_pullupdown(pin, GPIO_PULL_DISABLE);
-                       break;
-               case 'I':
-                       printk(KERN_INFO "GPIO%d: input\n", pin);
-                       retval = vr41xx_gpio_set_direction(pin, GPIO_INPUT);
-                       break;
-               case 'O':
-                       printk(KERN_INFO "GPIO%d: output\n", pin);
-                       retval = vr41xx_gpio_set_direction(pin, GPIO_OUTPUT);
-                       break;
-               case 'o':
-                       printk(KERN_INFO "GPIO%d: output disable\n", pin);
-                       retval = vr41xx_gpio_set_direction(pin, GPIO_OUTPUT_DISABLE);
-                       break;
-               case 'P':
-                       printk(KERN_INFO "GPIO%d: pull up\n", pin);
-                       retval = vr41xx_gpio_pullupdown(pin, GPIO_PULL_UP);
-                       break;
-               case 'p':
-                       printk(KERN_INFO "GPIO%d: pull up/down disable\n", pin);
-                       retval = vr41xx_gpio_pullupdown(pin, GPIO_PULL_DISABLE);
-                       break;
-               default:
-                       break;
-               }
-
-               if (retval < 0)
-                       break;
-       }
-
-       return i;
-}
-
-static int gpio_open(struct inode *inode, struct file *file)
-{
-       unsigned int pin;
-
-       cycle_kernel_lock();
-       pin = iminor(inode);
-       if (pin >= giu_nr_pins)
-               return -EBADF;
-
-       return nonseekable_open(inode, file);
-}
-
-static int gpio_release(struct inode *inode, struct file *file)
-{
-       unsigned int pin;
-
-       pin = iminor(inode);
-       if (pin >= giu_nr_pins)
-               return -EBADF;
-
-       return 0;
-}
-
-static const struct file_operations gpio_fops = {
-       .owner          = THIS_MODULE,
-       .read           = gpio_read,
-       .write          = gpio_write,
-       .open           = gpio_open,
-       .release        = gpio_release,
-};
-
-static int __devinit giu_probe(struct platform_device *dev)
-{
-       struct resource *res;
-       unsigned int trigger, i, pin;
-       struct irq_chip *chip;
-       int irq, retval;
-
-       switch (dev->id) {
-       case GPIO_50PINS_PULLUPDOWN:
-               giu_flags = GPIO_HAS_PULLUPDOWN_IO;
-               giu_nr_pins = 50;
-               break;
-       case GPIO_36PINS:
-               giu_nr_pins = 36;
-               break;
-       case GPIO_48PINS_EDGE_SELECT:
-               giu_flags = GPIO_HAS_INTERRUPT_EDGE_SELECT;
-               giu_nr_pins = 48;
-               break;
-       default:
-               printk(KERN_ERR "GIU: unknown ID %d\n", dev->id);
-               return -ENODEV;
-       }
-
-       res = platform_get_resource(dev, IORESOURCE_MEM, 0);
-       if (!res)
-               return -EBUSY;
-
-       giu_base = ioremap(res->start, res->end - res->start + 1);
-       if (!giu_base)
-               return -ENOMEM;
-
-       retval = register_chrdev(major, "GIU", &gpio_fops);
-       if (retval < 0) {
-               iounmap(giu_base);
-               giu_base = NULL;
-               return retval;
-       }
-
-       if (major == 0) {
-               major = retval;
-               printk(KERN_INFO "GIU: major number %d\n", major);
-       }
-
-       spin_lock_init(&giu_lock);
-
-       giu_write(GIUINTENL, 0);
-       giu_write(GIUINTENH, 0);
-
-       trigger = giu_read(GIUINTTYPH) << 16;
-       trigger |= giu_read(GIUINTTYPL);
-       for (i = GIU_IRQ_BASE; i <= GIU_IRQ_LAST; i++) {
-               pin = GPIO_PIN_OF_IRQ(i);
-               if (pin < GIUINT_HIGH_OFFSET)
-                       chip = &giuint_low_irq_chip;
-               else
-                       chip = &giuint_high_irq_chip;
-
-               if (trigger & (1 << pin))
-                       set_irq_chip_and_handler(i, chip, handle_edge_irq);
-               else
-                       set_irq_chip_and_handler(i, chip, handle_level_irq);
-
-       }
-
-       irq = platform_get_irq(dev, 0);
-       if (irq < 0 || irq >= nr_irqs)
-               return -EBUSY;
-
-       return cascade_irq(irq, giu_get_irq);
-}
-
-static int __devexit giu_remove(struct platform_device *dev)
-{
-       if (giu_base) {
-               iounmap(giu_base);
-               giu_base = NULL;
-       }
-
-       return 0;
-}
-
-static struct platform_driver giu_device_driver = {
-       .probe          = giu_probe,
-       .remove         = __devexit_p(giu_remove),
-       .driver         = {
-               .name   = "GIU",
-               .owner  = THIS_MODULE,
-       },
-};
-
-static int __init vr41xx_giu_init(void)
-{
-       return platform_driver_register(&giu_device_driver);
-}
-
-static void __exit vr41xx_giu_exit(void)
-{
-       platform_driver_unregister(&giu_device_driver);
-}
-
-module_init(vr41xx_giu_init);
-module_exit(vr41xx_giu_exit);
index d9113b4c76e370bad289b19558958448846a6064..404f4c1ee43145c5429f6639f0454e5a59818f3f 100644 (file)
@@ -89,6 +89,7 @@
 #include <linux/mutex.h>
 #include <linux/vt_kern.h>
 #include <linux/selection.h>
+#include <linux/smp_lock.h>
 #include <linux/tiocl.h>
 #include <linux/kbd_kern.h>
 #include <linux/consolemap.h>
@@ -769,14 +770,12 @@ int vc_allocate(unsigned int currcons)    /* return 0 on success */
            visual_init(vc, currcons, 1);
            if (!*vc->vc_uni_pagedir_loc)
                con_set_default_unimap(vc);
-           if (!vc->vc_kmalloced)
-               vc->vc_screenbuf = kmalloc(vc->vc_screenbuf_size, GFP_KERNEL);
+           vc->vc_screenbuf = kmalloc(vc->vc_screenbuf_size, GFP_KERNEL);
            if (!vc->vc_screenbuf) {
                kfree(vc);
                vc_cons[currcons].d = NULL;
                return -ENOMEM;
            }
-           vc->vc_kmalloced = 1;
            vc_init(vc, vc->vc_rows, vc->vc_cols, 1);
            vcs_make_sysfs(currcons);
            atomic_notifier_call_chain(&vt_notifier_list, VT_ALLOCATE, &param);
@@ -912,10 +911,8 @@ static int vc_do_resize(struct tty_struct *tty, struct vc_data *vc,
        if (new_scr_end > new_origin)
                scr_memsetw((void *)new_origin, vc->vc_video_erase_char,
                            new_scr_end - new_origin);
-       if (vc->vc_kmalloced)
-               kfree(vc->vc_screenbuf);
+       kfree(vc->vc_screenbuf);
        vc->vc_screenbuf = newscreen;
-       vc->vc_kmalloced = 1;
        vc->vc_screenbuf_size = new_screen_size;
        set_origin(vc);
 
@@ -994,8 +991,7 @@ void vc_deallocate(unsigned int currcons)
                vc->vc_sw->con_deinit(vc);
                put_pid(vc->vt_pid);
                module_put(vc->vc_sw->owner);
-               if (vc->vc_kmalloced)
-                       kfree(vc->vc_screenbuf);
+               kfree(vc->vc_screenbuf);
                if (currcons >= MIN_NR_CONSOLES)
                        kfree(vc);
                vc_cons[currcons].d = NULL;
@@ -2880,7 +2876,6 @@ static int __init con_init(void)
                INIT_WORK(&vc_cons[currcons].SAK_work, vc_SAK);
                visual_init(vc, currcons, 1);
                vc->vc_screenbuf = kzalloc(vc->vc_screenbuf_size, GFP_NOWAIT);
-               vc->vc_kmalloced = 0;
                vc_init(vc, vc->vc_rows, vc->vc_cols,
                        currcons || !vc->vc_sw->con_save_screen);
        }
index 7539bed0f7e07ec315e9dff21a3a0914161afee6..95189f288f8ccffcab9204c9fbeec0cd1357e3a4 100644 (file)
@@ -25,6 +25,7 @@
 #include <linux/console.h>
 #include <linux/consolemap.h>
 #include <linux/signal.h>
+#include <linux/smp_lock.h>
 #include <linux/timex.h>
 
 #include <asm/io.h>
index 9ffb05f4095d7598c6b8fc8e37bc55cae96ae2b6..93c2322feab79e8e119d0b51949ac0b1bc42135d 100644 (file)
@@ -161,7 +161,7 @@ static void sh_tmu_set_next(struct sh_tmu_priv *p, unsigned long delta,
        if (periodic)
                sh_tmu_write(p, TCOR, delta);
        else
-               sh_tmu_write(p, TCOR, 0);
+               sh_tmu_write(p, TCOR, 0xffffffff);
 
        sh_tmu_write(p, TCNT, delta);
 
index 6e2ec0b189489803ebaa55ecb4ae094bd2a1fdf0..b90eda8b34409680863edb45bc7b993ed87a1082 100644 (file)
@@ -761,6 +761,10 @@ static struct kobj_type ktype_cpufreq = {
  * cpufreq_add_dev - add a CPU device
  *
  * Adds the cpufreq interface for a CPU device.
+ *
+ * The Oracle says: try running cpufreq registration/unregistration concurrently
+ * with with cpu hotplugging and all hell will break loose. Tried to clean this
+ * mess up, but more thorough testing is needed. - Mathieu
  */
 static int cpufreq_add_dev(struct sys_device *sys_dev)
 {
@@ -772,9 +776,6 @@ static int cpufreq_add_dev(struct sys_device *sys_dev)
        struct sys_device *cpu_sys_dev;
        unsigned long flags;
        unsigned int j;
-#ifdef CONFIG_SMP
-       struct cpufreq_policy *managed_policy;
-#endif
 
        if (cpu_is_offline(cpu))
                return 0;
@@ -804,15 +805,12 @@ static int cpufreq_add_dev(struct sys_device *sys_dev)
                goto nomem_out;
        }
        if (!alloc_cpumask_var(&policy->cpus, GFP_KERNEL)) {
-               kfree(policy);
                ret = -ENOMEM;
-               goto nomem_out;
+               goto err_free_policy;
        }
        if (!zalloc_cpumask_var(&policy->related_cpus, GFP_KERNEL)) {
-               free_cpumask_var(policy->cpus);
-               kfree(policy);
                ret = -ENOMEM;
-               goto nomem_out;
+               goto err_free_cpumask;
        }
 
        policy->cpu = cpu;
@@ -820,7 +818,8 @@ static int cpufreq_add_dev(struct sys_device *sys_dev)
 
        /* Initially set CPU itself as the policy_cpu */
        per_cpu(policy_cpu, cpu) = cpu;
-       lock_policy_rwsem_write(cpu);
+       ret = (lock_policy_rwsem_write(cpu) < 0);
+       WARN_ON(ret);
 
        init_completion(&policy->kobj_unregister);
        INIT_WORK(&policy->update, handle_update);
@@ -833,7 +832,7 @@ static int cpufreq_add_dev(struct sys_device *sys_dev)
        ret = cpufreq_driver->init(policy);
        if (ret) {
                dprintk("initialization failed\n");
-               goto err_out;
+               goto err_unlock_policy;
        }
        policy->user_policy.min = policy->min;
        policy->user_policy.max = policy->max;
@@ -852,21 +851,29 @@ static int cpufreq_add_dev(struct sys_device *sys_dev)
 #endif
 
        for_each_cpu(j, policy->cpus) {
+               struct cpufreq_policy *managed_policy;
+
                if (cpu == j)
                        continue;
 
                /* Check for existing affected CPUs.
                 * They may not be aware of it due to CPU Hotplug.
                 */
-               managed_policy = cpufreq_cpu_get(j);            /* FIXME: Where is this released?  What about error paths? */
+               managed_policy = cpufreq_cpu_get(j);
                if (unlikely(managed_policy)) {
 
                        /* Set proper policy_cpu */
                        unlock_policy_rwsem_write(cpu);
                        per_cpu(policy_cpu, cpu) = managed_policy->cpu;
 
-                       if (lock_policy_rwsem_write(cpu) < 0)
-                               goto err_out_driver_exit;
+                       if (lock_policy_rwsem_write(cpu) < 0) {
+                               /* Should not go through policy unlock path */
+                               if (cpufreq_driver->exit)
+                                       cpufreq_driver->exit(policy);
+                               ret = -EBUSY;
+                               cpufreq_cpu_put(managed_policy);
+                               goto err_free_cpumask;
+                       }
 
                        spin_lock_irqsave(&cpufreq_driver_lock, flags);
                        cpumask_copy(managed_policy->cpus, policy->cpus);
@@ -877,12 +884,14 @@ static int cpufreq_add_dev(struct sys_device *sys_dev)
                        ret = sysfs_create_link(&sys_dev->kobj,
                                                &managed_policy->kobj,
                                                "cpufreq");
-                       if (ret)
-                               goto err_out_driver_exit;
-
-                       cpufreq_debug_enable_ratelimit();
-                       ret = 0;
-                       goto err_out_driver_exit; /* call driver->exit() */
+                       if (!ret)
+                               cpufreq_cpu_put(managed_policy);
+                       /*
+                        * Success. We only needed to be added to the mask.
+                        * Call driver->exit() because only the cpu parent of
+                        * the kobj needed to call init().
+                        */
+                       goto out_driver_exit; /* call driver->exit() */
                }
        }
 #endif
@@ -892,25 +901,25 @@ static int cpufreq_add_dev(struct sys_device *sys_dev)
        ret = kobject_init_and_add(&policy->kobj, &ktype_cpufreq, &sys_dev->kobj,
                                   "cpufreq");
        if (ret)
-               goto err_out_driver_exit;
+               goto out_driver_exit;
 
        /* set up files for this cpu device */
        drv_attr = cpufreq_driver->attr;
        while ((drv_attr) && (*drv_attr)) {
                ret = sysfs_create_file(&policy->kobj, &((*drv_attr)->attr));
                if (ret)
-                       goto err_out_driver_exit;
+                       goto err_out_kobj_put;
                drv_attr++;
        }
        if (cpufreq_driver->get) {
                ret = sysfs_create_file(&policy->kobj, &cpuinfo_cur_freq.attr);
                if (ret)
-                       goto err_out_driver_exit;
+                       goto err_out_kobj_put;
        }
        if (cpufreq_driver->target) {
                ret = sysfs_create_file(&policy->kobj, &scaling_cur_freq.attr);
                if (ret)
-                       goto err_out_driver_exit;
+                       goto err_out_kobj_put;
        }
 
        spin_lock_irqsave(&cpufreq_driver_lock, flags);
@@ -922,18 +931,22 @@ static int cpufreq_add_dev(struct sys_device *sys_dev)
 
        /* symlink affected CPUs */
        for_each_cpu(j, policy->cpus) {
+               struct cpufreq_policy *managed_policy;
+
                if (j == cpu)
                        continue;
                if (!cpu_online(j))
                        continue;
 
                dprintk("CPU %u already managed, adding link\n", j);
-               cpufreq_cpu_get(cpu);
+               managed_policy = cpufreq_cpu_get(cpu);
                cpu_sys_dev = get_cpu_sysdev(j);
                ret = sysfs_create_link(&cpu_sys_dev->kobj, &policy->kobj,
                                        "cpufreq");
-               if (ret)
+               if (ret) {
+                       cpufreq_cpu_put(managed_policy);
                        goto err_out_unregister;
+               }
        }
 
        policy->governor = NULL; /* to assure that the starting sequence is
@@ -965,17 +978,20 @@ err_out_unregister:
                per_cpu(cpufreq_cpu_data, j) = NULL;
        spin_unlock_irqrestore(&cpufreq_driver_lock, flags);
 
+err_out_kobj_put:
        kobject_put(&policy->kobj);
        wait_for_completion(&policy->kobj_unregister);
 
-err_out_driver_exit:
+out_driver_exit:
        if (cpufreq_driver->exit)
                cpufreq_driver->exit(policy);
 
-err_out:
+err_unlock_policy:
        unlock_policy_rwsem_write(cpu);
+err_free_cpumask:
+       free_cpumask_var(policy->cpus);
+err_free_policy:
        kfree(policy);
-
 nomem_out:
        module_put(cpufreq_driver->owner);
 module_out:
@@ -1070,8 +1086,6 @@ static int __cpufreq_remove_dev(struct sys_device *sys_dev)
        spin_unlock_irqrestore(&cpufreq_driver_lock, flags);
 #endif
 
-       unlock_policy_rwsem_write(cpu);
-
        if (cpufreq_driver->target)
                __cpufreq_governor(data, CPUFREQ_GOV_STOP);
 
@@ -1088,6 +1102,8 @@ static int __cpufreq_remove_dev(struct sys_device *sys_dev)
        if (cpufreq_driver->exit)
                cpufreq_driver->exit(data);
 
+       unlock_policy_rwsem_write(cpu);
+
        free_cpumask_var(data->related_cpus);
        free_cpumask_var(data->cpus);
        kfree(data);
index 7fc58af748b49b8ba4bf18e71dd1302fa6590c7d..57490502b21cbddbd71c2ef38b0134b62e55d21d 100644 (file)
@@ -63,22 +63,20 @@ struct cpu_dbs_info_s {
        unsigned int down_skip;
        unsigned int requested_freq;
        int cpu;
-       unsigned int enable:1;
+       /*
+        * percpu mutex that serializes governor limit change with
+        * do_dbs_timer invocation. We do not want do_dbs_timer to run
+        * when user is changing the governor or limits.
+        */
+       struct mutex timer_mutex;
 };
 static DEFINE_PER_CPU(struct cpu_dbs_info_s, cpu_dbs_info);
 
 static unsigned int dbs_enable;        /* number of CPUs using this policy */
 
 /*
- * DEADLOCK ALERT! There is a ordering requirement between cpu_hotplug
- * lock and dbs_mutex. cpu_hotplug lock should always be held before
- * dbs_mutex. If any function that can potentially take cpu_hotplug lock
- * (like __cpufreq_driver_target()) is being called with dbs_mutex taken, then
- * cpu_hotplug lock should be taken before that. Note that cpu_hotplug lock
- * is recursive for the same process. -Venki
- * DEADLOCK ALERT! (2) : do_dbs_timer() must not take the dbs_mutex, because it
- * would deadlock with cancel_delayed_work_sync(), which is needed for proper
- * raceless workqueue teardown.
+ * dbs_mutex protects data in dbs_tuners_ins from concurrent changes on
+ * different CPUs. It protects dbs_enable in governor start/stop.
  */
 static DEFINE_MUTEX(dbs_mutex);
 
@@ -143,9 +141,6 @@ dbs_cpufreq_notifier(struct notifier_block *nb, unsigned long val,
 
        struct cpufreq_policy *policy;
 
-       if (!this_dbs_info->enable)
-               return 0;
-
        policy = this_dbs_info->cur_policy;
 
        /*
@@ -488,18 +483,12 @@ static void do_dbs_timer(struct work_struct *work)
 
        delay -= jiffies % delay;
 
-       if (lock_policy_rwsem_write(cpu) < 0)
-               return;
-
-       if (!dbs_info->enable) {
-               unlock_policy_rwsem_write(cpu);
-               return;
-       }
+       mutex_lock(&dbs_info->timer_mutex);
 
        dbs_check_cpu(dbs_info);
 
        queue_delayed_work_on(cpu, kconservative_wq, &dbs_info->work, delay);
-       unlock_policy_rwsem_write(cpu);
+       mutex_unlock(&dbs_info->timer_mutex);
 }
 
 static inline void dbs_timer_init(struct cpu_dbs_info_s *dbs_info)
@@ -508,7 +497,6 @@ static inline void dbs_timer_init(struct cpu_dbs_info_s *dbs_info)
        int delay = usecs_to_jiffies(dbs_tuners_ins.sampling_rate);
        delay -= jiffies % delay;
 
-       dbs_info->enable = 1;
        INIT_DELAYED_WORK_DEFERRABLE(&dbs_info->work, do_dbs_timer);
        queue_delayed_work_on(dbs_info->cpu, kconservative_wq, &dbs_info->work,
                                delay);
@@ -516,7 +504,6 @@ static inline void dbs_timer_init(struct cpu_dbs_info_s *dbs_info)
 
 static inline void dbs_timer_exit(struct cpu_dbs_info_s *dbs_info)
 {
-       dbs_info->enable = 0;
        cancel_delayed_work_sync(&dbs_info->work);
 }
 
@@ -535,9 +522,6 @@ static int cpufreq_governor_dbs(struct cpufreq_policy *policy,
                if ((!cpu_online(cpu)) || (!policy->cur))
                        return -EINVAL;
 
-               if (this_dbs_info->enable) /* Already enabled */
-                       break;
-
                mutex_lock(&dbs_mutex);
 
                rc = sysfs_create_group(&policy->kobj, &dbs_attr_group);
@@ -561,6 +545,7 @@ static int cpufreq_governor_dbs(struct cpufreq_policy *policy,
                this_dbs_info->down_skip = 0;
                this_dbs_info->requested_freq = policy->cur;
 
+               mutex_init(&this_dbs_info->timer_mutex);
                dbs_enable++;
                /*
                 * Start the timerschedule work, when this governor
@@ -590,17 +575,19 @@ static int cpufreq_governor_dbs(struct cpufreq_policy *policy,
                                        &dbs_cpufreq_notifier_block,
                                        CPUFREQ_TRANSITION_NOTIFIER);
                }
-               dbs_timer_init(this_dbs_info);
-
                mutex_unlock(&dbs_mutex);
 
+               dbs_timer_init(this_dbs_info);
+
                break;
 
        case CPUFREQ_GOV_STOP:
-               mutex_lock(&dbs_mutex);
                dbs_timer_exit(this_dbs_info);
+
+               mutex_lock(&dbs_mutex);
                sysfs_remove_group(&policy->kobj, &dbs_attr_group);
                dbs_enable--;
+               mutex_destroy(&this_dbs_info->timer_mutex);
 
                /*
                 * Stop the timerschedule work, when this governor
@@ -616,7 +603,7 @@ static int cpufreq_governor_dbs(struct cpufreq_policy *policy,
                break;
 
        case CPUFREQ_GOV_LIMITS:
-               mutex_lock(&dbs_mutex);
+               mutex_lock(&this_dbs_info->timer_mutex);
                if (policy->max < this_dbs_info->cur_policy->cur)
                        __cpufreq_driver_target(
                                        this_dbs_info->cur_policy,
@@ -625,7 +612,7 @@ static int cpufreq_governor_dbs(struct cpufreq_policy *policy,
                        __cpufreq_driver_target(
                                        this_dbs_info->cur_policy,
                                        policy->min, CPUFREQ_RELATION_L);
-               mutex_unlock(&dbs_mutex);
+               mutex_unlock(&this_dbs_info->timer_mutex);
 
                break;
        }
index 1911d1729353fe3bdc621ae76896fbabd0a31c5e..d6ba14276bb1b0fda545cfab00367403d9b17408 100644 (file)
@@ -70,23 +70,21 @@ struct cpu_dbs_info_s {
        unsigned int freq_lo_jiffies;
        unsigned int freq_hi_jiffies;
        int cpu;
-       unsigned int enable:1,
-               sample_type:1;
+       unsigned int sample_type:1;
+       /*
+        * percpu mutex that serializes governor limit change with
+        * do_dbs_timer invocation. We do not want do_dbs_timer to run
+        * when user is changing the governor or limits.
+        */
+       struct mutex timer_mutex;
 };
 static DEFINE_PER_CPU(struct cpu_dbs_info_s, cpu_dbs_info);
 
 static unsigned int dbs_enable;        /* number of CPUs using this policy */
 
 /*
- * DEADLOCK ALERT! There is a ordering requirement between cpu_hotplug
- * lock and dbs_mutex. cpu_hotplug lock should always be held before
- * dbs_mutex. If any function that can potentially take cpu_hotplug lock
- * (like __cpufreq_driver_target()) is being called with dbs_mutex taken, then
- * cpu_hotplug lock should be taken before that. Note that cpu_hotplug lock
- * is recursive for the same process. -Venki
- * DEADLOCK ALERT! (2) : do_dbs_timer() must not take the dbs_mutex, because it
- * would deadlock with cancel_delayed_work_sync(), which is needed for proper
- * raceless workqueue teardown.
+ * dbs_mutex protects data in dbs_tuners_ins from concurrent changes on
+ * different CPUs. It protects dbs_enable in governor start/stop.
  */
 static DEFINE_MUTEX(dbs_mutex);
 
@@ -192,13 +190,18 @@ static unsigned int powersave_bias_target(struct cpufreq_policy *policy,
        return freq_hi;
 }
 
+static void ondemand_powersave_bias_init_cpu(int cpu)
+{
+       struct cpu_dbs_info_s *dbs_info = &per_cpu(cpu_dbs_info, cpu);
+       dbs_info->freq_table = cpufreq_frequency_get_table(cpu);
+       dbs_info->freq_lo = 0;
+}
+
 static void ondemand_powersave_bias_init(void)
 {
        int i;
        for_each_online_cpu(i) {
-               struct cpu_dbs_info_s *dbs_info = &per_cpu(cpu_dbs_info, i);
-               dbs_info->freq_table = cpufreq_frequency_get_table(i);
-               dbs_info->freq_lo = 0;
+               ondemand_powersave_bias_init_cpu(i);
        }
 }
 
@@ -240,12 +243,10 @@ static ssize_t store_sampling_rate(struct cpufreq_policy *unused,
        unsigned int input;
        int ret;
        ret = sscanf(buf, "%u", &input);
+       if (ret != 1)
+               return -EINVAL;
 
        mutex_lock(&dbs_mutex);
-       if (ret != 1) {
-               mutex_unlock(&dbs_mutex);
-               return -EINVAL;
-       }
        dbs_tuners_ins.sampling_rate = max(input, min_sampling_rate);
        mutex_unlock(&dbs_mutex);
 
@@ -259,13 +260,12 @@ static ssize_t store_up_threshold(struct cpufreq_policy *unused,
        int ret;
        ret = sscanf(buf, "%u", &input);
 
-       mutex_lock(&dbs_mutex);
        if (ret != 1 || input > MAX_FREQUENCY_UP_THRESHOLD ||
                        input < MIN_FREQUENCY_UP_THRESHOLD) {
-               mutex_unlock(&dbs_mutex);
                return -EINVAL;
        }
 
+       mutex_lock(&dbs_mutex);
        dbs_tuners_ins.up_threshold = input;
        mutex_unlock(&dbs_mutex);
 
@@ -363,9 +363,6 @@ static void dbs_check_cpu(struct cpu_dbs_info_s *this_dbs_info)
        struct cpufreq_policy *policy;
        unsigned int j;
 
-       if (!this_dbs_info->enable)
-               return;
-
        this_dbs_info->freq_lo = 0;
        policy = this_dbs_info->cur_policy;
 
@@ -493,14 +490,7 @@ static void do_dbs_timer(struct work_struct *work)
        int delay = usecs_to_jiffies(dbs_tuners_ins.sampling_rate);
 
        delay -= jiffies % delay;
-
-       if (lock_policy_rwsem_write(cpu) < 0)
-               return;
-
-       if (!dbs_info->enable) {
-               unlock_policy_rwsem_write(cpu);
-               return;
-       }
+       mutex_lock(&dbs_info->timer_mutex);
 
        /* Common NORMAL_SAMPLE setup */
        dbs_info->sample_type = DBS_NORMAL_SAMPLE;
@@ -517,7 +507,7 @@ static void do_dbs_timer(struct work_struct *work)
                        dbs_info->freq_lo, CPUFREQ_RELATION_H);
        }
        queue_delayed_work_on(cpu, kondemand_wq, &dbs_info->work, delay);
-       unlock_policy_rwsem_write(cpu);
+       mutex_unlock(&dbs_info->timer_mutex);
 }
 
 static inline void dbs_timer_init(struct cpu_dbs_info_s *dbs_info)
@@ -526,8 +516,6 @@ static inline void dbs_timer_init(struct cpu_dbs_info_s *dbs_info)
        int delay = usecs_to_jiffies(dbs_tuners_ins.sampling_rate);
        delay -= jiffies % delay;
 
-       dbs_info->enable = 1;
-       ondemand_powersave_bias_init();
        dbs_info->sample_type = DBS_NORMAL_SAMPLE;
        INIT_DELAYED_WORK_DEFERRABLE(&dbs_info->work, do_dbs_timer);
        queue_delayed_work_on(dbs_info->cpu, kondemand_wq, &dbs_info->work,
@@ -536,7 +524,6 @@ static inline void dbs_timer_init(struct cpu_dbs_info_s *dbs_info)
 
 static inline void dbs_timer_exit(struct cpu_dbs_info_s *dbs_info)
 {
-       dbs_info->enable = 0;
        cancel_delayed_work_sync(&dbs_info->work);
 }
 
@@ -555,19 +542,15 @@ static int cpufreq_governor_dbs(struct cpufreq_policy *policy,
                if ((!cpu_online(cpu)) || (!policy->cur))
                        return -EINVAL;
 
-               if (this_dbs_info->enable) /* Already enabled */
-                       break;
-
                mutex_lock(&dbs_mutex);
-               dbs_enable++;
 
                rc = sysfs_create_group(&policy->kobj, &dbs_attr_group);
                if (rc) {
-                       dbs_enable--;
                        mutex_unlock(&dbs_mutex);
                        return rc;
                }
 
+               dbs_enable++;
                for_each_cpu(j, policy->cpus) {
                        struct cpu_dbs_info_s *j_dbs_info;
                        j_dbs_info = &per_cpu(cpu_dbs_info, j);
@@ -581,6 +564,8 @@ static int cpufreq_governor_dbs(struct cpufreq_policy *policy,
                        }
                }
                this_dbs_info->cpu = cpu;
+               ondemand_powersave_bias_init_cpu(cpu);
+               mutex_init(&this_dbs_info->timer_mutex);
                /*
                 * Start the timerschedule work, when this governor
                 * is used for first time
@@ -598,29 +583,31 @@ static int cpufreq_governor_dbs(struct cpufreq_policy *policy,
                                max(min_sampling_rate,
                                    latency * LATENCY_MULTIPLIER);
                }
-               dbs_timer_init(this_dbs_info);
-
                mutex_unlock(&dbs_mutex);
+
+               dbs_timer_init(this_dbs_info);
                break;
 
        case CPUFREQ_GOV_STOP:
-               mutex_lock(&dbs_mutex);
                dbs_timer_exit(this_dbs_info);
+
+               mutex_lock(&dbs_mutex);
                sysfs_remove_group(&policy->kobj, &dbs_attr_group);
+               mutex_destroy(&this_dbs_info->timer_mutex);
                dbs_enable--;
                mutex_unlock(&dbs_mutex);
 
                break;
 
        case CPUFREQ_GOV_LIMITS:
-               mutex_lock(&dbs_mutex);
+               mutex_lock(&this_dbs_info->timer_mutex);
                if (policy->max < this_dbs_info->cur_policy->cur)
                        __cpufreq_driver_target(this_dbs_info->cur_policy,
                                policy->max, CPUFREQ_RELATION_H);
                else if (policy->min > this_dbs_info->cur_policy->cur)
                        __cpufreq_driver_target(this_dbs_info->cur_policy,
                                policy->min, CPUFREQ_RELATION_L);
-               mutex_unlock(&dbs_mutex);
+               mutex_unlock(&this_dbs_info->timer_mutex);
                break;
        }
        return 0;
index 9aa9ea9822c85c0c714d21dfbeaefbc5a7b5428d..88dab52926f4ae73217d8f2c8ec55d37d74a0597 100644 (file)
@@ -432,23 +432,27 @@ txx9dmac_descriptor_complete(struct txx9dmac_chan *dc,
        list_splice_init(&txd->tx_list, &dc->free_list);
        list_move(&desc->desc_node, &dc->free_list);
 
-       /*
-        * We use dma_unmap_page() regardless of how the buffers were
-        * mapped before they were submitted...
-        */
        if (!ds) {
                dma_addr_t dmaaddr;
                if (!(txd->flags & DMA_COMPL_SKIP_DEST_UNMAP)) {
                        dmaaddr = is_dmac64(dc) ?
                                desc->hwdesc.DAR : desc->hwdesc32.DAR;
-                       dma_unmap_page(chan2parent(&dc->chan), dmaaddr,
-                                      desc->len, DMA_FROM_DEVICE);
+                       if (txd->flags & DMA_COMPL_DEST_UNMAP_SINGLE)
+                               dma_unmap_single(chan2parent(&dc->chan),
+                                       dmaaddr, desc->len, DMA_FROM_DEVICE);
+                       else
+                               dma_unmap_page(chan2parent(&dc->chan),
+                                       dmaaddr, desc->len, DMA_FROM_DEVICE);
                }
                if (!(txd->flags & DMA_COMPL_SKIP_SRC_UNMAP)) {
                        dmaaddr = is_dmac64(dc) ?
                                desc->hwdesc.SAR : desc->hwdesc32.SAR;
-                       dma_unmap_page(chan2parent(&dc->chan), dmaaddr,
-                                      desc->len, DMA_TO_DEVICE);
+                       if (txd->flags & DMA_COMPL_SRC_UNMAP_SINGLE)
+                               dma_unmap_single(chan2parent(&dc->chan),
+                                       dmaaddr, desc->len, DMA_TO_DEVICE);
+                       else
+                               dma_unmap_page(chan2parent(&dc->chan),
+                                       dmaaddr, desc->len, DMA_TO_DEVICE);
                }
        }
 
index c36bf40568cf8e7de0aacaa5ce7219650cec5a26..858fe603722361f4292052952a738f3f9cc4a03e 100644 (file)
@@ -754,13 +754,13 @@ static void amd64_cpu_display_info(struct amd64_pvt *pvt)
 static enum edac_type amd64_determine_edac_cap(struct amd64_pvt *pvt)
 {
        int bit;
-       enum dev_type edac_cap = EDAC_NONE;
+       enum dev_type edac_cap = EDAC_FLAG_NONE;
 
        bit = (boot_cpu_data.x86 > 0xf || pvt->ext_model >= OPTERON_CPU_REV_F)
                ? 19
                : 17;
 
-       if (pvt->dclr0 >> BIT(bit))
+       if (pvt->dclr0 & BIT(bit))
                edac_cap = EDAC_FLAG_SECDED;
 
        return edac_cap;
@@ -1269,7 +1269,7 @@ static int f10_early_channel_count(struct amd64_pvt *pvt)
        if (channels == 0)
                channels = 1;
 
-       debugf0("DIMM count= %d\n", channels);
+       debugf0("MCT channel count: %d\n", channels);
 
        return channels;
 
@@ -2966,7 +2966,12 @@ static int amd64_check_ecc_enabled(struct amd64_pvt *pvt)
                                "    Use of the override can cause "
                                "unknown side effects.\n");
                        ret = -ENODEV;
-               }
+               } else
+                       /*
+                        * enable further driver loading if ECC enable is
+                        * overridden.
+                        */
+                       ret = 0;
        } else {
                amd64_printk(KERN_INFO,
                        "ECC is enabled by BIOS, Proceeding "
@@ -3006,7 +3011,6 @@ static void amd64_setup_mci_misc_attributes(struct mem_ctl_info *mci)
 
        mci->mtype_cap          = MEM_FLAG_DDR2 | MEM_FLAG_RDDR2;
        mci->edac_ctl_cap       = EDAC_FLAG_NONE;
-       mci->edac_cap           = EDAC_FLAG_NONE;
 
        if (pvt->nbcap & K8_NBCAP_SECDED)
                mci->edac_ctl_cap |= EDAC_FLAG_SECDED;
@@ -3052,7 +3056,7 @@ static int amd64_probe_one_instance(struct pci_dev *dram_f2_ctl,
        if (!pvt)
                goto err_exit;
 
-       pvt->mc_node_id = get_mc_node_id_from_pdev(dram_f2_ctl);
+       pvt->mc_node_id = get_node_id(dram_f2_ctl);
 
        pvt->dram_f2_ctl        = dram_f2_ctl;
        pvt->ext_model          = boot_cpu_data.x86_model >> 4;
@@ -3179,8 +3183,7 @@ static int __devinit amd64_init_one_instance(struct pci_dev *pdev,
 {
        int ret = 0;
 
-       debugf0("(MC node=%d,mc_type='%s')\n",
-               get_mc_node_id_from_pdev(pdev),
+       debugf0("(MC node=%d,mc_type='%s')\n", get_node_id(pdev),
                get_amd_family_name(mc_type->driver_data));
 
        ret = pci_enable_device(pdev);
@@ -3319,15 +3322,17 @@ static int __init amd64_edac_init(void)
 
                err = amd64_init_2nd_stage(pvt_lookup[nb]);
                if (err)
-                       goto err_exit;
+                       goto err_2nd_stage;
        }
 
        amd64_setup_pci_device();
 
        return 0;
 
+err_2nd_stage:
+       debugf0("2nd stage failed\n");
+
 err_exit:
-       debugf0("'finish_setup' stage failed\n");
        pci_unregister_driver(&amd64_pci_driver);
 
        return err;
index a159957e167b158e85ca3ebbced142d6690e2d53..ba73015af8e48d22307b3e9e22e47474a48cc3fa 100644 (file)
@@ -444,7 +444,7 @@ enum {
 #define K8_MSR_MC4ADDR                 0x0412
 
 /* AMD sets the first MC device at device ID 0x18. */
-static inline int get_mc_node_id_from_pdev(struct pci_dev *pdev)
+static inline int get_node_id(struct pci_dev *pdev)
 {
        return PCI_SLOT(pdev->devfn) - 0x18;
 }
index 3493c6bdb8206b7f712c00cf07b355974bdd27a2..871c13b4c1489587a91a12a9503aa73ff6dd1670 100644 (file)
@@ -150,6 +150,8 @@ enum mem_type {
        MEM_FB_DDR2,            /* fully buffered DDR2 */
        MEM_RDDR2,              /* Registered DDR2 RAM */
        MEM_XDR,                /* Rambus XDR */
+       MEM_DDR3,               /* DDR3 RAM */
+       MEM_RDDR3,              /* Registered DDR3 RAM */
 };
 
 #define MEM_FLAG_EMPTY         BIT(MEM_EMPTY)
@@ -167,6 +169,8 @@ enum mem_type {
 #define MEM_FLAG_FB_DDR2        BIT(MEM_FB_DDR2)
 #define MEM_FLAG_RDDR2          BIT(MEM_RDDR2)
 #define MEM_FLAG_XDR            BIT(MEM_XDR)
+#define MEM_FLAG_DDR3           BIT(MEM_DDR3)
+#define MEM_FLAG_RDDR3          BIT(MEM_RDDR3)
 
 /* chipset Error Detection and Correction capabilities and mode */
 enum edac_type {
index ad218fe4942dfcf258273ee22f56776f3a0b23c2..e1d4ce0834813b79ba347c8f78baeaa6616f8b4e 100644 (file)
@@ -94,7 +94,9 @@ static const char *mem_types[] = {
        [MEM_DDR2] = "Unbuffered-DDR2",
        [MEM_FB_DDR2] = "FullyBuffered-DDR2",
        [MEM_RDDR2] = "Registered-DDR2",
-       [MEM_XDR] = "XDR"
+       [MEM_XDR] = "XDR",
+       [MEM_DDR3] = "Unbuffered-DDR3",
+       [MEM_RDDR3] = "Registered-DDR3"
 };
 
 static const char *dev_types[] = {
index 7c8c2d72916f60f0ade44a323a7f01cc644e0d21..3f2ccfc6407c298be7be4260e5b09512590e0dfe 100644 (file)
@@ -757,6 +757,9 @@ static void __devinit mpc85xx_init_csrows(struct mem_ctl_info *mci)
                case DSC_SDTYPE_DDR2:
                        mtype = MEM_RDDR2;
                        break;
+               case DSC_SDTYPE_DDR3:
+                       mtype = MEM_RDDR3;
+                       break;
                default:
                        mtype = MEM_UNKNOWN;
                        break;
@@ -769,6 +772,9 @@ static void __devinit mpc85xx_init_csrows(struct mem_ctl_info *mci)
                case DSC_SDTYPE_DDR2:
                        mtype = MEM_DDR2;
                        break;
+               case DSC_SDTYPE_DDR3:
+                       mtype = MEM_DDR3;
+                       break;
                default:
                        mtype = MEM_UNKNOWN;
                        break;
index 135b3539a030d4cee2eca42217564bbf4b050476..52432ee7c4b98bf96a10e605116e04c00131481e 100644 (file)
@@ -53,6 +53,7 @@
 
 #define DSC_SDTYPE_DDR         0x02000000
 #define DSC_SDTYPE_DDR2                0x03000000
+#define DSC_SDTYPE_DDR3                0x07000000
 #define DSC_X32_EN     0x00000020
 
 /* Err_Int_En */
index 543fccac81bb953aa38c60cebb764374602e2d4d..f74edae5cb4cfce68726102cca77711865003bc5 100644 (file)
@@ -196,8 +196,8 @@ static void allocate_broadcast_channel(struct fw_card *card, int generation)
 {
        int channel, bandwidth = 0;
 
-       fw_iso_resource_manage(card, generation, 1ULL << 31,
-                              &channel, &bandwidth, true);
+       fw_iso_resource_manage(card, generation, 1ULL << 31, &channel,
+                              &bandwidth, true, card->bm_transaction_data);
        if (channel == 31) {
                card->broadcast_channel_allocated = true;
                device_for_each_child(card->device, (void *)(long)generation,
@@ -230,7 +230,6 @@ static void fw_card_bm_work(struct work_struct *work)
        bool do_reset = false;
        bool root_device_is_running;
        bool root_device_is_cmc;
-       __be32 lock_data[2];
 
        spin_lock_irqsave(&card->lock, flags);
 
@@ -273,22 +272,23 @@ static void fw_card_bm_work(struct work_struct *work)
                        goto pick_me;
                }
 
-               lock_data[0] = cpu_to_be32(0x3f);
-               lock_data[1] = cpu_to_be32(local_id);
+               card->bm_transaction_data[0] = cpu_to_be32(0x3f);
+               card->bm_transaction_data[1] = cpu_to_be32(local_id);
 
                spin_unlock_irqrestore(&card->lock, flags);
 
                rcode = fw_run_transaction(card, TCODE_LOCK_COMPARE_SWAP,
                                irm_id, generation, SCODE_100,
                                CSR_REGISTER_BASE + CSR_BUS_MANAGER_ID,
-                               lock_data, sizeof(lock_data));
+                               card->bm_transaction_data,
+                               sizeof(card->bm_transaction_data));
 
                if (rcode == RCODE_GENERATION)
                        /* Another bus reset, BM work has been rescheduled. */
                        goto out;
 
                if (rcode == RCODE_COMPLETE &&
-                   lock_data[0] != cpu_to_be32(0x3f)) {
+                   card->bm_transaction_data[0] != cpu_to_be32(0x3f)) {
 
                        /* Somebody else is BM.  Only act as IRM. */
                        if (local_id == irm_id)
index d1d30c615b0f191c7fb33a313e64bfd37b2835d5..ced186d7e9a9d16552fcf3d73a95203303a8251a 100644 (file)
@@ -125,6 +125,7 @@ struct iso_resource {
        int generation;
        u64 channels;
        s32 bandwidth;
+       __be32 transaction_data[2];
        struct iso_resource_event *e_alloc, *e_dealloc;
 };
 
@@ -1049,7 +1050,8 @@ static void iso_resource_work(struct work_struct *work)
                        r->channels, &channel, &bandwidth,
                        todo == ISO_RES_ALLOC ||
                        todo == ISO_RES_REALLOC ||
-                       todo == ISO_RES_ALLOC_ONCE);
+                       todo == ISO_RES_ALLOC_ONCE,
+                       r->transaction_data);
        /*
         * Is this generation outdated already?  As long as this resource sticks
         * in the idr, it will be scheduled again for a newer generation or at
index 166f19c6d38d6dd86930751a9aefbac0ddb819cb..110e731f5574130cb69338a99aab0c8ec8a16916 100644 (file)
@@ -177,9 +177,8 @@ EXPORT_SYMBOL(fw_iso_context_stop);
  */
 
 static int manage_bandwidth(struct fw_card *card, int irm_id, int generation,
-                           int bandwidth, bool allocate)
+                           int bandwidth, bool allocate, __be32 data[2])
 {
-       __be32 data[2];
        int try, new, old = allocate ? BANDWIDTH_AVAILABLE_INITIAL : 0;
 
        /*
@@ -215,9 +214,9 @@ static int manage_bandwidth(struct fw_card *card, int irm_id, int generation,
 }
 
 static int manage_channel(struct fw_card *card, int irm_id, int generation,
-                         u32 channels_mask, u64 offset, bool allocate)
+               u32 channels_mask, u64 offset, bool allocate, __be32 data[2])
 {
-       __be32 data[2], c, all, old;
+       __be32 c, all, old;
        int i, retry = 5;
 
        old = all = allocate ? cpu_to_be32(~0) : 0;
@@ -260,7 +259,7 @@ static int manage_channel(struct fw_card *card, int irm_id, int generation,
 }
 
 static void deallocate_channel(struct fw_card *card, int irm_id,
-                              int generation, int channel)
+                              int generation, int channel, __be32 buffer[2])
 {
        u32 mask;
        u64 offset;
@@ -269,7 +268,7 @@ static void deallocate_channel(struct fw_card *card, int irm_id,
        offset = channel < 32 ? CSR_REGISTER_BASE + CSR_CHANNELS_AVAILABLE_HI :
                                CSR_REGISTER_BASE + CSR_CHANNELS_AVAILABLE_LO;
 
-       manage_channel(card, irm_id, generation, mask, offset, false);
+       manage_channel(card, irm_id, generation, mask, offset, false, buffer);
 }
 
 /**
@@ -298,7 +297,7 @@ static void deallocate_channel(struct fw_card *card, int irm_id,
  */
 void fw_iso_resource_manage(struct fw_card *card, int generation,
                            u64 channels_mask, int *channel, int *bandwidth,
-                           bool allocate)
+                           bool allocate, __be32 buffer[2])
 {
        u32 channels_hi = channels_mask;        /* channels 31...0 */
        u32 channels_lo = channels_mask >> 32;  /* channels 63...32 */
@@ -310,10 +309,12 @@ void fw_iso_resource_manage(struct fw_card *card, int generation,
 
        if (channels_hi)
                c = manage_channel(card, irm_id, generation, channels_hi,
-                   CSR_REGISTER_BASE + CSR_CHANNELS_AVAILABLE_HI, allocate);
+                               CSR_REGISTER_BASE + CSR_CHANNELS_AVAILABLE_HI,
+                               allocate, buffer);
        if (channels_lo && c < 0) {
                c = manage_channel(card, irm_id, generation, channels_lo,
-                   CSR_REGISTER_BASE + CSR_CHANNELS_AVAILABLE_LO, allocate);
+                               CSR_REGISTER_BASE + CSR_CHANNELS_AVAILABLE_LO,
+                               allocate, buffer);
                if (c >= 0)
                        c += 32;
        }
@@ -325,12 +326,13 @@ void fw_iso_resource_manage(struct fw_card *card, int generation,
        if (*bandwidth == 0)
                return;
 
-       ret = manage_bandwidth(card, irm_id, generation, *bandwidth, allocate);
+       ret = manage_bandwidth(card, irm_id, generation, *bandwidth,
+                              allocate, buffer);
        if (ret < 0)
                *bandwidth = 0;
 
        if (allocate && ret < 0 && c >= 0) {
-               deallocate_channel(card, irm_id, generation, c);
+               deallocate_channel(card, irm_id, generation, c, buffer);
                *channel = ret;
        }
 }
index c3cfc647e5e30dae6edfa9e38fae365d416184d3..6052816be353e899b540394afa05747f7dc1d2c0 100644 (file)
@@ -120,7 +120,8 @@ void fw_node_event(struct fw_card *card, struct fw_node *node, int event);
 
 int fw_iso_buffer_map(struct fw_iso_buffer *buffer, struct vm_area_struct *vma);
 void fw_iso_resource_manage(struct fw_card *card, int generation,
-               u64 channels_mask, int *channel, int *bandwidth, bool allocate);
+                           u64 channels_mask, int *channel, int *bandwidth,
+                           bool allocate, __be32 buffer[2]);
 
 
 /* -topology */
index 24c45635376a746ba9ae3e69ef53cfa7da1ab514..8d51568ee14344ee1e9e4ac11f690ae7a2c1d6a2 100644 (file)
@@ -200,6 +200,12 @@ static struct fw_device *target_device(struct sbp2_target *tgt)
 #define SBP2_RETRY_LIMIT               0xf             /* 15 retries */
 #define SBP2_CYCLE_LIMIT               (0xc8 << 12)    /* 200 125us cycles */
 
+/*
+ * There is no transport protocol limit to the CDB length,  but we implement
+ * a fixed length only.  16 bytes is enough for disks larger than 2 TB.
+ */
+#define SBP2_MAX_CDB_SIZE              16
+
 /*
  * The default maximum s/g segment size of a FireWire controller is
  * usually 0x10000, but SBP-2 only allows 0xffff. Since buffers have to
@@ -312,7 +318,7 @@ struct sbp2_command_orb {
                struct sbp2_pointer next;
                struct sbp2_pointer data_descriptor;
                __be32 misc;
-               u8 command_block[12];
+               u8 command_block[SBP2_MAX_CDB_SIZE];
        } request;
        struct scsi_cmnd *cmd;
        scsi_done_fn_t done;
@@ -1146,6 +1152,8 @@ static int sbp2_probe(struct device *dev)
        if (fw_device_enable_phys_dma(device) < 0)
                goto fail_shost_put;
 
+       shost->max_cmd_len = SBP2_MAX_CDB_SIZE;
+
        if (scsi_add_host(shost, &unit->device) < 0)
                goto fail_shost_put;
 
index 3582c39f97258ee7f9a95612816fa0f1c83bc467..96dda81c922855ecb564a232df184a5896f6ec99 100644 (file)
@@ -79,6 +79,12 @@ config GPIO_XILINX
        help
          Say yes here to support the Xilinx FPGA GPIO device
 
+config GPIO_VR41XX
+       tristate "NEC VR4100 series General-purpose I/O Uint support"
+       depends on CPU_VR41XX
+       help
+         Say yes here to support the NEC VR4100 series General-purpose I/O Uint
+
 comment "I2C GPIO expanders:"
 
 config GPIO_MAX732X
index ef90203e8f3c77df4c2f1b9cbe1433f50ce2b92a..9244c6fcd8be3e60a211609160c0f320726df594 100644 (file)
@@ -13,3 +13,4 @@ obj-$(CONFIG_GPIO_PL061)      += pl061.o
 obj-$(CONFIG_GPIO_TWL4030)     += twl4030-gpio.o
 obj-$(CONFIG_GPIO_XILINX)      += xilinx_gpio.o
 obj-$(CONFIG_GPIO_BT8XX)       += bt8xxgpio.o
+obj-$(CONFIG_GPIO_VR41XX)      += vr41xx_giu.o
index aa8e7cb020d93bf2e3d9b24a1a75bb1e0d8850aa..4ee4c8367a3f988144c7a721399a5d14306be50e 100644 (file)
@@ -109,6 +109,16 @@ static void pl061_set_value(struct gpio_chip *gc, unsigned offset, int value)
        writeb(!!value << offset, chip->base + (1 << (offset + 2)));
 }
 
+static int pl061_to_irq(struct gpio_chip *gc, unsigned offset)
+{
+       struct pl061_gpio *chip = container_of(gc, struct pl061_gpio, gc);
+
+       if (chip->irq_base == (unsigned) -1)
+               return -EINVAL;
+
+       return chip->irq_base + offset;
+}
+
 /*
  * PL061 GPIO IRQ
  */
@@ -200,7 +210,7 @@ static void pl061_irq_handler(unsigned irq, struct irq_desc *desc)
        desc->chip->ack(irq);
        list_for_each(ptr, chip_list) {
                unsigned long pending;
-               int gpio;
+               int offset;
 
                chip = list_entry(ptr, struct pl061_gpio, list);
                pending = readb(chip->base + GPIOMIS);
@@ -209,8 +219,8 @@ static void pl061_irq_handler(unsigned irq, struct irq_desc *desc)
                if (pending == 0)
                        continue;
 
-               for_each_bit(gpio, &pending, PL061_GPIO_NR)
-                       generic_handle_irq(gpio_to_irq(gpio));
+               for_each_bit(offset, &pending, PL061_GPIO_NR)
+                       generic_handle_irq(pl061_to_irq(&chip->gc, offset));
        }
        desc->chip->unmask(irq);
 }
@@ -221,7 +231,7 @@ static int __init pl061_probe(struct amba_device *dev, struct amba_id *id)
        struct pl061_gpio *chip;
        struct list_head *chip_list;
        int ret, irq, i;
-       static unsigned long init_irq[BITS_TO_LONGS(NR_IRQS)];
+       static DECLARE_BITMAP(init_irq, NR_IRQS);
 
        pdata = dev->dev.platform_data;
        if (pdata == NULL)
@@ -251,6 +261,7 @@ static int __init pl061_probe(struct amba_device *dev, struct amba_id *id)
        chip->gc.direction_output = pl061_direction_output;
        chip->gc.get = pl061_get_value;
        chip->gc.set = pl061_set_value;
+       chip->gc.to_irq = pl061_to_irq;
        chip->gc.base = pdata->gpio_base;
        chip->gc.ngpio = PL061_GPIO_NR;
        chip->gc.label = dev_name(&dev->dev);
@@ -280,6 +291,7 @@ static int __init pl061_probe(struct amba_device *dev, struct amba_id *id)
        if (!test_and_set_bit(irq, init_irq)) { /* list initialized? */
                chip_list = kmalloc(sizeof(*chip_list), GFP_KERNEL);
                if (chip_list == NULL) {
+                       clear_bit(irq, init_irq);
                        ret = -ENOMEM;
                        goto iounmap;
                }
diff --git a/drivers/gpio/vr41xx_giu.c b/drivers/gpio/vr41xx_giu.c
new file mode 100644 (file)
index 0000000..b16c9a8
--- /dev/null
@@ -0,0 +1,585 @@
+/*
+ *  Driver for NEC VR4100 series General-purpose I/O Unit.
+ *
+ *  Copyright (C) 2002 MontaVista Software Inc.
+ *     Author: Yoichi Yuasa <source@mvista.com>
+ *  Copyright (C) 2003-2009  Yoichi Yuasa <yuasa@linux-mips.org>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+#include <linux/errno.h>
+#include <linux/fs.h>
+#include <linux/gpio.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/irq.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/spinlock.h>
+#include <linux/types.h>
+
+#include <asm/vr41xx/giu.h>
+#include <asm/vr41xx/irq.h>
+#include <asm/vr41xx/vr41xx.h>
+
+MODULE_AUTHOR("Yoichi Yuasa <yuasa@linux-mips.org>");
+MODULE_DESCRIPTION("NEC VR4100 series General-purpose I/O Unit driver");
+MODULE_LICENSE("GPL");
+
+#define GIUIOSELL      0x00
+#define GIUIOSELH      0x02
+#define GIUPIODL       0x04
+#define GIUPIODH       0x06
+#define GIUINTSTATL    0x08
+#define GIUINTSTATH    0x0a
+#define GIUINTENL      0x0c
+#define GIUINTENH      0x0e
+#define GIUINTTYPL     0x10
+#define GIUINTTYPH     0x12
+#define GIUINTALSELL   0x14
+#define GIUINTALSELH   0x16
+#define GIUINTHTSELL   0x18
+#define GIUINTHTSELH   0x1a
+#define GIUPODATL      0x1c
+#define GIUPODATEN     0x1c
+#define GIUPODATH      0x1e
+ #define PIOEN0                0x0100
+ #define PIOEN1                0x0200
+#define GIUPODAT       0x1e
+#define GIUFEDGEINHL   0x20
+#define GIUFEDGEINHH   0x22
+#define GIUREDGEINHL   0x24
+#define GIUREDGEINHH   0x26
+
+#define GIUUSEUPDN     0x1e0
+#define GIUTERMUPDN    0x1e2
+
+#define GPIO_HAS_PULLUPDOWN_IO         0x0001
+#define GPIO_HAS_OUTPUT_ENABLE         0x0002
+#define GPIO_HAS_INTERRUPT_EDGE_SELECT 0x0100
+
+enum {
+       GPIO_INPUT,
+       GPIO_OUTPUT,
+};
+
+static DEFINE_SPINLOCK(giu_lock);
+static unsigned long giu_flags;
+
+static void __iomem *giu_base;
+
+#define giu_read(offset)               readw(giu_base + (offset))
+#define giu_write(offset, value)       writew((value), giu_base + (offset))
+
+#define GPIO_PIN_OF_IRQ(irq)   ((irq) - GIU_IRQ_BASE)
+#define GIUINT_HIGH_OFFSET     16
+#define GIUINT_HIGH_MAX                32
+
+static inline u16 giu_set(u16 offset, u16 set)
+{
+       u16 data;
+
+       data = giu_read(offset);
+       data |= set;
+       giu_write(offset, data);
+
+       return data;
+}
+
+static inline u16 giu_clear(u16 offset, u16 clear)
+{
+       u16 data;
+
+       data = giu_read(offset);
+       data &= ~clear;
+       giu_write(offset, data);
+
+       return data;
+}
+
+static void ack_giuint_low(unsigned int irq)
+{
+       giu_write(GIUINTSTATL, 1 << GPIO_PIN_OF_IRQ(irq));
+}
+
+static void mask_giuint_low(unsigned int irq)
+{
+       giu_clear(GIUINTENL, 1 << GPIO_PIN_OF_IRQ(irq));
+}
+
+static void mask_ack_giuint_low(unsigned int irq)
+{
+       unsigned int pin;
+
+       pin = GPIO_PIN_OF_IRQ(irq);
+       giu_clear(GIUINTENL, 1 << pin);
+       giu_write(GIUINTSTATL, 1 << pin);
+}
+
+static void unmask_giuint_low(unsigned int irq)
+{
+       giu_set(GIUINTENL, 1 << GPIO_PIN_OF_IRQ(irq));
+}
+
+static struct irq_chip giuint_low_irq_chip = {
+       .name           = "GIUINTL",
+       .ack            = ack_giuint_low,
+       .mask           = mask_giuint_low,
+       .mask_ack       = mask_ack_giuint_low,
+       .unmask         = unmask_giuint_low,
+};
+
+static void ack_giuint_high(unsigned int irq)
+{
+       giu_write(GIUINTSTATH,
+                 1 << (GPIO_PIN_OF_IRQ(irq) - GIUINT_HIGH_OFFSET));
+}
+
+static void mask_giuint_high(unsigned int irq)
+{
+       giu_clear(GIUINTENH, 1 << (GPIO_PIN_OF_IRQ(irq) - GIUINT_HIGH_OFFSET));
+}
+
+static void mask_ack_giuint_high(unsigned int irq)
+{
+       unsigned int pin;
+
+       pin = GPIO_PIN_OF_IRQ(irq) - GIUINT_HIGH_OFFSET;
+       giu_clear(GIUINTENH, 1 << pin);
+       giu_write(GIUINTSTATH, 1 << pin);
+}
+
+static void unmask_giuint_high(unsigned int irq)
+{
+       giu_set(GIUINTENH, 1 << (GPIO_PIN_OF_IRQ(irq) - GIUINT_HIGH_OFFSET));
+}
+
+static struct irq_chip giuint_high_irq_chip = {
+       .name           = "GIUINTH",
+       .ack            = ack_giuint_high,
+       .mask           = mask_giuint_high,
+       .mask_ack       = mask_ack_giuint_high,
+       .unmask         = unmask_giuint_high,
+};
+
+static int giu_get_irq(unsigned int irq)
+{
+       u16 pendl, pendh, maskl, maskh;
+       int i;
+
+       pendl = giu_read(GIUINTSTATL);
+       pendh = giu_read(GIUINTSTATH);
+       maskl = giu_read(GIUINTENL);
+       maskh = giu_read(GIUINTENH);
+
+       maskl &= pendl;
+       maskh &= pendh;
+
+       if (maskl) {
+               for (i = 0; i < 16; i++) {
+                       if (maskl & (1 << i))
+                               return GIU_IRQ(i);
+               }
+       } else if (maskh) {
+               for (i = 0; i < 16; i++) {
+                       if (maskh & (1 << i))
+                               return GIU_IRQ(i + GIUINT_HIGH_OFFSET);
+               }
+       }
+
+       printk(KERN_ERR "spurious GIU interrupt: %04x(%04x),%04x(%04x)\n",
+              maskl, pendl, maskh, pendh);
+
+       atomic_inc(&irq_err_count);
+
+       return -EINVAL;
+}
+
+void vr41xx_set_irq_trigger(unsigned int pin, irq_trigger_t trigger,
+                           irq_signal_t signal)
+{
+       u16 mask;
+
+       if (pin < GIUINT_HIGH_OFFSET) {
+               mask = 1 << pin;
+               if (trigger != IRQ_TRIGGER_LEVEL) {
+                       giu_set(GIUINTTYPL, mask);
+                       if (signal == IRQ_SIGNAL_HOLD)
+                               giu_set(GIUINTHTSELL, mask);
+                       else
+                               giu_clear(GIUINTHTSELL, mask);
+                       if (giu_flags & GPIO_HAS_INTERRUPT_EDGE_SELECT) {
+                               switch (trigger) {
+                               case IRQ_TRIGGER_EDGE_FALLING:
+                                       giu_set(GIUFEDGEINHL, mask);
+                                       giu_clear(GIUREDGEINHL, mask);
+                                       break;
+                               case IRQ_TRIGGER_EDGE_RISING:
+                                       giu_clear(GIUFEDGEINHL, mask);
+                                       giu_set(GIUREDGEINHL, mask);
+                                       break;
+                               default:
+                                       giu_set(GIUFEDGEINHL, mask);
+                                       giu_set(GIUREDGEINHL, mask);
+                                       break;
+                               }
+                       }
+                       set_irq_chip_and_handler(GIU_IRQ(pin),
+                                                &giuint_low_irq_chip,
+                                                handle_edge_irq);
+               } else {
+                       giu_clear(GIUINTTYPL, mask);
+                       giu_clear(GIUINTHTSELL, mask);
+                       set_irq_chip_and_handler(GIU_IRQ(pin),
+                                                &giuint_low_irq_chip,
+                                                handle_level_irq);
+               }
+               giu_write(GIUINTSTATL, mask);
+       } else if (pin < GIUINT_HIGH_MAX) {
+               mask = 1 << (pin - GIUINT_HIGH_OFFSET);
+               if (trigger != IRQ_TRIGGER_LEVEL) {
+                       giu_set(GIUINTTYPH, mask);
+                       if (signal == IRQ_SIGNAL_HOLD)
+                               giu_set(GIUINTHTSELH, mask);
+                       else
+                               giu_clear(GIUINTHTSELH, mask);
+                       if (giu_flags & GPIO_HAS_INTERRUPT_EDGE_SELECT) {
+                               switch (trigger) {
+                               case IRQ_TRIGGER_EDGE_FALLING:
+                                       giu_set(GIUFEDGEINHH, mask);
+                                       giu_clear(GIUREDGEINHH, mask);
+                                       break;
+                               case IRQ_TRIGGER_EDGE_RISING:
+                                       giu_clear(GIUFEDGEINHH, mask);
+                                       giu_set(GIUREDGEINHH, mask);
+                                       break;
+                               default:
+                                       giu_set(GIUFEDGEINHH, mask);
+                                       giu_set(GIUREDGEINHH, mask);
+                                       break;
+                               }
+                       }
+                       set_irq_chip_and_handler(GIU_IRQ(pin),
+                                                &giuint_high_irq_chip,
+                                                handle_edge_irq);
+               } else {
+                       giu_clear(GIUINTTYPH, mask);
+                       giu_clear(GIUINTHTSELH, mask);
+                       set_irq_chip_and_handler(GIU_IRQ(pin),
+                                                &giuint_high_irq_chip,
+                                                handle_level_irq);
+               }
+               giu_write(GIUINTSTATH, mask);
+       }
+}
+EXPORT_SYMBOL_GPL(vr41xx_set_irq_trigger);
+
+void vr41xx_set_irq_level(unsigned int pin, irq_level_t level)
+{
+       u16 mask;
+
+       if (pin < GIUINT_HIGH_OFFSET) {
+               mask = 1 << pin;
+               if (level == IRQ_LEVEL_HIGH)
+                       giu_set(GIUINTALSELL, mask);
+               else
+                       giu_clear(GIUINTALSELL, mask);
+               giu_write(GIUINTSTATL, mask);
+       } else if (pin < GIUINT_HIGH_MAX) {
+               mask = 1 << (pin - GIUINT_HIGH_OFFSET);
+               if (level == IRQ_LEVEL_HIGH)
+                       giu_set(GIUINTALSELH, mask);
+               else
+                       giu_clear(GIUINTALSELH, mask);
+               giu_write(GIUINTSTATH, mask);
+       }
+}
+EXPORT_SYMBOL_GPL(vr41xx_set_irq_level);
+
+static int giu_set_direction(struct gpio_chip *chip, unsigned pin, int dir)
+{
+       u16 offset, mask, reg;
+       unsigned long flags;
+
+       if (pin >= chip->ngpio)
+               return -EINVAL;
+
+       if (pin < 16) {
+               offset = GIUIOSELL;
+               mask = 1 << pin;
+       } else if (pin < 32) {
+               offset = GIUIOSELH;
+               mask = 1 << (pin - 16);
+       } else {
+               if (giu_flags & GPIO_HAS_OUTPUT_ENABLE) {
+                       offset = GIUPODATEN;
+                       mask = 1 << (pin - 32);
+               } else {
+                       switch (pin) {
+                       case 48:
+                               offset = GIUPODATH;
+                               mask = PIOEN0;
+                               break;
+                       case 49:
+                               offset = GIUPODATH;
+                               mask = PIOEN1;
+                               break;
+                       default:
+                               return -EINVAL;
+                       }
+               }
+       }
+
+       spin_lock_irqsave(&giu_lock, flags);
+
+       reg = giu_read(offset);
+       if (dir == GPIO_OUTPUT)
+               reg |= mask;
+       else
+               reg &= ~mask;
+       giu_write(offset, reg);
+
+       spin_unlock_irqrestore(&giu_lock, flags);
+
+       return 0;
+}
+
+int vr41xx_gpio_pullupdown(unsigned int pin, gpio_pull_t pull)
+{
+       u16 reg, mask;
+       unsigned long flags;
+
+       if ((giu_flags & GPIO_HAS_PULLUPDOWN_IO) != GPIO_HAS_PULLUPDOWN_IO)
+               return -EPERM;
+
+       if (pin >= 15)
+               return -EINVAL;
+
+       mask = 1 << pin;
+
+       spin_lock_irqsave(&giu_lock, flags);
+
+       if (pull == GPIO_PULL_UP || pull == GPIO_PULL_DOWN) {
+               reg = giu_read(GIUTERMUPDN);
+               if (pull == GPIO_PULL_UP)
+                       reg |= mask;
+               else
+                       reg &= ~mask;
+               giu_write(GIUTERMUPDN, reg);
+
+               reg = giu_read(GIUUSEUPDN);
+               reg |= mask;
+               giu_write(GIUUSEUPDN, reg);
+       } else {
+               reg = giu_read(GIUUSEUPDN);
+               reg &= ~mask;
+               giu_write(GIUUSEUPDN, reg);
+       }
+
+       spin_unlock_irqrestore(&giu_lock, flags);
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(vr41xx_gpio_pullupdown);
+
+static int vr41xx_gpio_get(struct gpio_chip *chip, unsigned pin)
+{
+       u16 reg, mask;
+
+       if (pin >= chip->ngpio)
+               return -EINVAL;
+
+       if (pin < 16) {
+               reg = giu_read(GIUPIODL);
+               mask = 1 << pin;
+       } else if (pin < 32) {
+               reg = giu_read(GIUPIODH);
+               mask = 1 << (pin - 16);
+       } else if (pin < 48) {
+               reg = giu_read(GIUPODATL);
+               mask = 1 << (pin - 32);
+       } else {
+               reg = giu_read(GIUPODATH);
+               mask = 1 << (pin - 48);
+       }
+
+       if (reg & mask)
+               return 1;
+
+       return 0;
+}
+
+static void vr41xx_gpio_set(struct gpio_chip *chip, unsigned pin,
+                           int value)
+{
+       u16 offset, mask, reg;
+       unsigned long flags;
+
+       if (pin >= chip->ngpio)
+               return;
+
+       if (pin < 16) {
+               offset = GIUPIODL;
+               mask = 1 << pin;
+       } else if (pin < 32) {
+               offset = GIUPIODH;
+               mask = 1 << (pin - 16);
+       } else if (pin < 48) {
+               offset = GIUPODATL;
+               mask = 1 << (pin - 32);
+       } else {
+               offset = GIUPODATH;
+               mask = 1 << (pin - 48);
+       }
+
+       spin_lock_irqsave(&giu_lock, flags);
+
+       reg = giu_read(offset);
+       if (value)
+               reg |= mask;
+       else
+               reg &= ~mask;
+       giu_write(offset, reg);
+
+       spin_unlock_irqrestore(&giu_lock, flags);
+}
+
+
+static int vr41xx_gpio_direction_input(struct gpio_chip *chip, unsigned offset)
+{
+       return giu_set_direction(chip, offset, GPIO_INPUT);
+}
+
+static int vr41xx_gpio_direction_output(struct gpio_chip *chip, unsigned offset,
+                               int value)
+{
+       vr41xx_gpio_set(chip, offset, value);
+
+       return giu_set_direction(chip, offset, GPIO_OUTPUT);
+}
+
+static int vr41xx_gpio_to_irq(struct gpio_chip *chip, unsigned offset)
+{
+       if (offset >= chip->ngpio)
+               return -EINVAL;
+
+       return GIU_IRQ_BASE + offset;
+}
+
+static struct gpio_chip vr41xx_gpio_chip = {
+       .label                  = "vr41xx",
+       .owner                  = THIS_MODULE,
+       .direction_input        = vr41xx_gpio_direction_input,
+       .get                    = vr41xx_gpio_get,
+       .direction_output       = vr41xx_gpio_direction_output,
+       .set                    = vr41xx_gpio_set,
+       .to_irq                 = vr41xx_gpio_to_irq,
+};
+
+static int __devinit giu_probe(struct platform_device *pdev)
+{
+       struct resource *res;
+       unsigned int trigger, i, pin;
+       struct irq_chip *chip;
+       int irq, retval;
+
+       switch (pdev->id) {
+       case GPIO_50PINS_PULLUPDOWN:
+               giu_flags = GPIO_HAS_PULLUPDOWN_IO;
+               vr41xx_gpio_chip.ngpio = 50;
+               break;
+       case GPIO_36PINS:
+               vr41xx_gpio_chip.ngpio = 36;
+               break;
+       case GPIO_48PINS_EDGE_SELECT:
+               giu_flags = GPIO_HAS_INTERRUPT_EDGE_SELECT;
+               vr41xx_gpio_chip.ngpio = 48;
+               break;
+       default:
+               dev_err(&pdev->dev, "GIU: unknown ID %d\n", pdev->id);
+               return -ENODEV;
+       }
+
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (!res)
+               return -EBUSY;
+
+       giu_base = ioremap(res->start, res->end - res->start + 1);
+       if (!giu_base)
+               return -ENOMEM;
+
+       vr41xx_gpio_chip.dev = &pdev->dev;
+
+       retval = gpiochip_add(&vr41xx_gpio_chip);
+
+       giu_write(GIUINTENL, 0);
+       giu_write(GIUINTENH, 0);
+
+       trigger = giu_read(GIUINTTYPH) << 16;
+       trigger |= giu_read(GIUINTTYPL);
+       for (i = GIU_IRQ_BASE; i <= GIU_IRQ_LAST; i++) {
+               pin = GPIO_PIN_OF_IRQ(i);
+               if (pin < GIUINT_HIGH_OFFSET)
+                       chip = &giuint_low_irq_chip;
+               else
+                       chip = &giuint_high_irq_chip;
+
+               if (trigger & (1 << pin))
+                       set_irq_chip_and_handler(i, chip, handle_edge_irq);
+               else
+                       set_irq_chip_and_handler(i, chip, handle_level_irq);
+
+       }
+
+       irq = platform_get_irq(pdev, 0);
+       if (irq < 0 || irq >= nr_irqs)
+               return -EBUSY;
+
+       return cascade_irq(irq, giu_get_irq);
+}
+
+static int __devexit giu_remove(struct platform_device *pdev)
+{
+       if (giu_base) {
+               iounmap(giu_base);
+               giu_base = NULL;
+       }
+
+       return 0;
+}
+
+static struct platform_driver giu_device_driver = {
+       .probe          = giu_probe,
+       .remove         = __devexit_p(giu_remove),
+       .driver         = {
+               .name   = "GIU",
+               .owner  = THIS_MODULE,
+       },
+};
+
+static int __init vr41xx_giu_init(void)
+{
+       return platform_driver_register(&giu_device_driver);
+}
+
+static void __exit vr41xx_giu_exit(void)
+{
+       platform_driver_unregister(&giu_device_driver);
+}
+
+module_init(vr41xx_giu_init);
+module_exit(vr41xx_giu_exit);
index c961fe415aef83bfecda56873b59431601674bce..39b393d38bb3e6f9a7ba3c016265f213858ed612 100644 (file)
@@ -81,6 +81,7 @@ config DRM_I830
 
 config DRM_I915
        tristate "i915 driver"
+       depends on AGP_INTEL
        select FB_CFB_FILLRECT
        select FB_CFB_COPYAREA
        select FB_CFB_IMAGEBLIT
index 4e89ab08b7b8d9eecf6fccc6e16901f5e41f4ed9..fe23f29f7cba8bc7fb3e88450b07c2b8537a7913 100644 (file)
@@ -16,6 +16,7 @@ drm-y       :=        drm_auth.o drm_bufs.o drm_cache.o \
 drm-$(CONFIG_COMPAT) += drm_ioc32.o
 
 obj-$(CONFIG_DRM)      += drm.o
+obj-$(CONFIG_DRM_TTM)  += ttm/
 obj-$(CONFIG_DRM_TDFX) += tdfx/
 obj-$(CONFIG_DRM_R128) += r128/
 obj-$(CONFIG_DRM_RADEON)+= radeon/
@@ -26,4 +27,3 @@ obj-$(CONFIG_DRM_I915)  += i915/
 obj-$(CONFIG_DRM_SIS)   += sis/
 obj-$(CONFIG_DRM_SAVAGE)+= savage/
 obj-$(CONFIG_DRM_VIA)  +=via/
-obj-$(CONFIG_DRM_TTM)  += ttm/
index a6f73f1e99d9b839e369861c5b24e4f17279b8aa..3da9cfa31848c0eb37b36f66c7b3ed8607962e2d 100644 (file)
@@ -1090,6 +1090,8 @@ int drm_helper_resume_force_mode(struct drm_device *dev)
                if (ret == false)
                        DRM_ERROR("failed to set mode on crtc %p\n", crtc);
        }
+       /* disable the unused connectors while restoring the modesetting */
+       drm_helper_disable_unused_functions(dev);
        return 0;
 }
 EXPORT_SYMBOL(drm_helper_resume_force_mode);
index 2960b6d73456d65b672ad4a7b715976113002859..9903f270e4409c8239add50adc2a3db80ca56623 100644 (file)
@@ -101,6 +101,10 @@ int drm_debugfs_create_files(struct drm_info_list *files, int count,
                        continue;
 
                tmp = kmalloc(sizeof(struct drm_info_node), GFP_KERNEL);
+               if (tmp == NULL) {
+                       ret = -1;
+                       goto fail;
+               }
                ent = debugfs_create_file(files[i].name, S_IFREG | S_IRUGO,
                                          root, tmp, &drm_debugfs_fops);
                if (!ent) {
index 7d0835226f6edece18d91ebd1c5cfa95de5b1546..80cc6d06d61b6ba53ae316a8de5112c8cf434a09 100644 (file)
@@ -294,10 +294,10 @@ static struct drm_display_mode *drm_mode_detailed(struct drm_device *dev,
        unsigned vactive = (pt->vactive_vblank_hi & 0xf0) << 4 | pt->vactive_lo;
        unsigned hblank = (pt->hactive_hblank_hi & 0xf) << 8 | pt->hblank_lo;
        unsigned vblank = (pt->vactive_vblank_hi & 0xf) << 8 | pt->vblank_lo;
-       unsigned hsync_offset = (pt->hsync_vsync_offset_pulse_width_hi & 0x3) << 8 | pt->hsync_offset_lo;
-       unsigned hsync_pulse_width = (pt->hsync_vsync_offset_pulse_width_hi & 0xc) << 6 | pt->hsync_pulse_width_lo;
-       unsigned vsync_offset = (pt->hsync_vsync_offset_pulse_width_hi & 0x30) | (pt->vsync_offset_pulse_width_lo & 0xf);
-       unsigned vsync_pulse_width = (pt->hsync_vsync_offset_pulse_width_hi & 0xc0) >> 2 | pt->vsync_offset_pulse_width_lo >> 4;
+       unsigned hsync_offset = (pt->hsync_vsync_offset_pulse_width_hi & 0xc0) << 2 | pt->hsync_offset_lo;
+       unsigned hsync_pulse_width = (pt->hsync_vsync_offset_pulse_width_hi & 0x30) << 4 | pt->hsync_pulse_width_lo;
+       unsigned vsync_offset = (pt->hsync_vsync_offset_pulse_width_hi & 0xc) >> 2 | pt->vsync_offset_pulse_width_lo >> 4;
+       unsigned vsync_pulse_width = (pt->hsync_vsync_offset_pulse_width_hi & 0x3) << 4 | (pt->vsync_offset_pulse_width_lo & 0xf);
 
        /* ignore tiny modes */
        if (hactive < 64 || vactive < 64)
@@ -347,8 +347,8 @@ static struct drm_display_mode *drm_mode_detailed(struct drm_device *dev,
        mode->flags |= (pt->misc & DRM_EDID_PT_VSYNC_POSITIVE) ?
                DRM_MODE_FLAG_PVSYNC : DRM_MODE_FLAG_NVSYNC;
 
-       mode->width_mm = pt->width_mm_lo | (pt->width_height_mm_hi & 0xf) << 8;
-       mode->height_mm = pt->height_mm_lo | (pt->width_height_mm_hi & 0xf0) << 4;
+       mode->width_mm = pt->width_mm_lo | (pt->width_height_mm_hi & 0xf0) << 4;
+       mode->height_mm = pt->height_mm_lo | (pt->width_height_mm_hi & 0xf) << 8;
 
        if (quirks & EDID_QUIRK_DETAILED_IN_CM) {
                mode->width_mm *= 10;
index 8104ecaea26fbe7170d4c85b41ee0a96e6a0bec4..ffe8f4394d50d71f96411200d9d4d90907bd5f2c 100644 (file)
@@ -134,26 +134,29 @@ drm_gem_object_alloc(struct drm_device *dev, size_t size)
        BUG_ON((size & (PAGE_SIZE - 1)) != 0);
 
        obj = kzalloc(sizeof(*obj), GFP_KERNEL);
+       if (!obj)
+               goto free;
 
        obj->dev = dev;
        obj->filp = shmem_file_setup("drm mm object", size, VM_NORESERVE);
-       if (IS_ERR(obj->filp)) {
-               kfree(obj);
-               return NULL;
-       }
+       if (IS_ERR(obj->filp))
+               goto free;
 
        kref_init(&obj->refcount);
        kref_init(&obj->handlecount);
        obj->size = size;
        if (dev->driver->gem_init_object != NULL &&
            dev->driver->gem_init_object(obj) != 0) {
-               fput(obj->filp);
-               kfree(obj);
-               return NULL;
+               goto fput;
        }
        atomic_inc(&dev->object_count);
        atomic_add(obj->size, &dev->object_memory);
        return obj;
+fput:
+       fput(obj->filp);
+free:
+       kfree(obj);
+       return NULL;
 }
 EXPORT_SYMBOL(drm_gem_object_alloc);
 
index 155a5bbce680ac4187f297699644a29317a188e6..55bb8a82d6127cb5d1ec3bea675e0001de593122 100644 (file)
@@ -489,7 +489,7 @@ int drm_put_minor(struct drm_minor **minor_p)
  */
 void drm_put_dev(struct drm_device *dev)
 {
-       struct drm_driver *driver = dev->driver;
+       struct drm_driver *driver;
        struct drm_map_list *r_list, *list_temp;
 
        DRM_DEBUG("\n");
@@ -498,6 +498,7 @@ void drm_put_dev(struct drm_device *dev)
                DRM_ERROR("cleanup called no dev\n");
                return;
        }
+       driver = dev->driver;
 
        drm_vblank_cleanup(dev);
 
index 51c5a050aa730ee2b1f841d2a413c6e77c31833d..30d6b99fb302908d4aaadd03edef03ba1266f733 100644 (file)
@@ -13,6 +13,8 @@ i915-y := i915_drv.o i915_dma.o i915_irq.o i915_mem.o \
          intel_crt.o \
          intel_lvds.o \
          intel_bios.o \
+         intel_dp.o \
+         intel_dp_i2c.o \
          intel_hdmi.o \
          intel_sdvo.o \
          intel_modes.o \
index e747ac42fe3a9b117ca8e99235fccad7d925a40d..288fc50627e2de2f795854b2ec965a3ebc19a8c5 100644 (file)
@@ -37,7 +37,7 @@ struct intel_dvo_device {
        /* GPIO register used for i2c bus to control this device */
        u32 gpio;
        int slave_addr;
-       struct intel_i2c_chan *i2c_bus;
+       struct i2c_adapter *i2c_bus;
 
        const struct intel_dvo_dev_ops *dev_ops;
        void *dev_priv;
@@ -52,7 +52,7 @@ struct intel_dvo_dev_ops {
         * Returns NULL if the device does not exist.
         */
        bool (*init)(struct intel_dvo_device *dvo,
-                    struct intel_i2c_chan *i2cbus);
+                    struct i2c_adapter *i2cbus);
 
        /*
         * Called to allow the output a chance to create properties after the
index 03d4b4973b02e1c30262efd0a0061ca84198f05f..621815b531dbba427b87e1290589a7de6a94fd6b 100644 (file)
@@ -176,19 +176,20 @@ static void ch7017_dpms(struct intel_dvo_device *dvo, int mode);
 
 static bool ch7017_read(struct intel_dvo_device *dvo, int addr, uint8_t *val)
 {
-       struct intel_i2c_chan *i2cbus = dvo->i2c_bus;
+       struct i2c_adapter *adapter = dvo->i2c_bus;
+       struct intel_i2c_chan *i2cbus = container_of(adapter, struct intel_i2c_chan, adapter);
        u8 out_buf[2];
        u8 in_buf[2];
 
        struct i2c_msg msgs[] = {
                {
-                       .addr = i2cbus->slave_addr,
+                       .addr = dvo->slave_addr,
                        .flags = 0,
                        .len = 1,
                        .buf = out_buf,
                },
                {
-                       .addr = i2cbus->slave_addr,
+                       .addr = dvo->slave_addr,
                        .flags = I2C_M_RD,
                        .len = 1,
                        .buf = in_buf,
@@ -208,10 +209,11 @@ static bool ch7017_read(struct intel_dvo_device *dvo, int addr, uint8_t *val)
 
 static bool ch7017_write(struct intel_dvo_device *dvo, int addr, uint8_t val)
 {
-       struct intel_i2c_chan *i2cbus = dvo->i2c_bus;
+       struct i2c_adapter *adapter = dvo->i2c_bus;
+       struct intel_i2c_chan *i2cbus = container_of(adapter, struct intel_i2c_chan, adapter);
        uint8_t out_buf[2];
        struct i2c_msg msg = {
-               .addr = i2cbus->slave_addr,
+               .addr = dvo->slave_addr,
                .flags = 0,
                .len = 2,
                .buf = out_buf,
@@ -228,8 +230,9 @@ static bool ch7017_write(struct intel_dvo_device *dvo, int addr, uint8_t val)
 
 /** Probes for a CH7017 on the given bus and slave address. */
 static bool ch7017_init(struct intel_dvo_device *dvo,
-                       struct intel_i2c_chan *i2cbus)
+                       struct i2c_adapter *adapter)
 {
+       struct intel_i2c_chan *i2cbus = container_of(adapter, struct intel_i2c_chan, adapter);
        struct ch7017_priv *priv;
        uint8_t val;
 
@@ -237,8 +240,7 @@ static bool ch7017_init(struct intel_dvo_device *dvo,
        if (priv == NULL)
                return false;
 
-       dvo->i2c_bus = i2cbus;
-       dvo->i2c_bus->slave_addr = dvo->slave_addr;
+       dvo->i2c_bus = adapter;
        dvo->dev_priv = priv;
 
        if (!ch7017_read(dvo, CH7017_DEVICE_ID, &val))
@@ -248,7 +250,7 @@ static bool ch7017_init(struct intel_dvo_device *dvo,
            val != CH7018_DEVICE_ID_VALUE &&
            val != CH7019_DEVICE_ID_VALUE) {
                DRM_DEBUG("ch701x not detected, got %d: from %s Slave %d.\n",
-                         val, i2cbus->adapter.name,i2cbus->slave_addr);
+                         val, i2cbus->adapter.name,dvo->slave_addr);
                goto fail;
        }
 
index d2fd95dbd034b948d180a95129b09817da8314da..a9b8962896801ffe674bafe06685e9e40f846036 100644 (file)
@@ -123,19 +123,20 @@ static char *ch7xxx_get_id(uint8_t vid)
 static bool ch7xxx_readb(struct intel_dvo_device *dvo, int addr, uint8_t *ch)
 {
        struct ch7xxx_priv *ch7xxx= dvo->dev_priv;
-       struct intel_i2c_chan *i2cbus = dvo->i2c_bus;
+       struct i2c_adapter *adapter = dvo->i2c_bus;
+       struct intel_i2c_chan *i2cbus = container_of(adapter, struct intel_i2c_chan, adapter);
        u8 out_buf[2];
        u8 in_buf[2];
 
        struct i2c_msg msgs[] = {
                {
-                       .addr = i2cbus->slave_addr,
+                       .addr = dvo->slave_addr,
                        .flags = 0,
                        .len = 1,
                        .buf = out_buf,
                },
                {
-                       .addr = i2cbus->slave_addr,
+                       .addr = dvo->slave_addr,
                        .flags = I2C_M_RD,
                        .len = 1,
                        .buf = in_buf,
@@ -152,7 +153,7 @@ static bool ch7xxx_readb(struct intel_dvo_device *dvo, int addr, uint8_t *ch)
 
        if (!ch7xxx->quiet) {
                DRM_DEBUG("Unable to read register 0x%02x from %s:%02x.\n",
-                         addr, i2cbus->adapter.name, i2cbus->slave_addr);
+                         addr, i2cbus->adapter.name, dvo->slave_addr);
        }
        return false;
 }
@@ -161,10 +162,11 @@ static bool ch7xxx_readb(struct intel_dvo_device *dvo, int addr, uint8_t *ch)
 static bool ch7xxx_writeb(struct intel_dvo_device *dvo, int addr, uint8_t ch)
 {
        struct ch7xxx_priv *ch7xxx = dvo->dev_priv;
-       struct intel_i2c_chan *i2cbus = dvo->i2c_bus;
+       struct i2c_adapter *adapter = dvo->i2c_bus;
+       struct intel_i2c_chan *i2cbus = container_of(adapter, struct intel_i2c_chan, adapter);
        uint8_t out_buf[2];
        struct i2c_msg msg = {
-               .addr = i2cbus->slave_addr,
+               .addr = dvo->slave_addr,
                .flags = 0,
                .len = 2,
                .buf = out_buf,
@@ -178,14 +180,14 @@ static bool ch7xxx_writeb(struct intel_dvo_device *dvo, int addr, uint8_t ch)
 
        if (!ch7xxx->quiet) {
                DRM_DEBUG("Unable to write register 0x%02x to %s:%d.\n",
-                         addr, i2cbus->adapter.name, i2cbus->slave_addr);
+                         addr, i2cbus->adapter.name, dvo->slave_addr);
        }
 
        return false;
 }
 
 static bool ch7xxx_init(struct intel_dvo_device *dvo,
-                       struct intel_i2c_chan *i2cbus)
+                       struct i2c_adapter *adapter)
 {
        /* this will detect the CH7xxx chip on the specified i2c bus */
        struct ch7xxx_priv *ch7xxx;
@@ -196,8 +198,7 @@ static bool ch7xxx_init(struct intel_dvo_device *dvo,
        if (ch7xxx == NULL)
                return false;
 
-       dvo->i2c_bus = i2cbus;
-       dvo->i2c_bus->slave_addr = dvo->slave_addr;
+       dvo->i2c_bus = adapter;
        dvo->dev_priv = ch7xxx;
        ch7xxx->quiet = true;
 
@@ -207,7 +208,7 @@ static bool ch7xxx_init(struct intel_dvo_device *dvo,
        name = ch7xxx_get_id(vendor);
        if (!name) {
                DRM_DEBUG("ch7xxx not detected; got 0x%02x from %s slave %d.\n",
-                         vendor, i2cbus->adapter.name, i2cbus->slave_addr);
+                         vendor, adapter->name, dvo->slave_addr);
                goto out;
        }
 
@@ -217,7 +218,7 @@ static bool ch7xxx_init(struct intel_dvo_device *dvo,
 
        if (device != CH7xxx_DID) {
                DRM_DEBUG("ch7xxx not detected; got 0x%02x from %s slave %d.\n",
-                         vendor, i2cbus->adapter.name, i2cbus->slave_addr);
+                         vendor, adapter->name, dvo->slave_addr);
                goto out;
        }
 
index 0c8d375e8e378e523c46ca62bf5ab6564a803b16..aa176f9921fe2c772ade093f67d970647b175f34 100644 (file)
@@ -169,13 +169,14 @@ static void ivch_dump_regs(struct intel_dvo_device *dvo);
 static bool ivch_read(struct intel_dvo_device *dvo, int addr, uint16_t *data)
 {
        struct ivch_priv *priv = dvo->dev_priv;
-       struct intel_i2c_chan *i2cbus = dvo->i2c_bus;
+       struct i2c_adapter *adapter = dvo->i2c_bus;
+       struct intel_i2c_chan *i2cbus = container_of(adapter, struct intel_i2c_chan, adapter);
        u8 out_buf[1];
        u8 in_buf[2];
 
        struct i2c_msg msgs[] = {
                {
-                       .addr = i2cbus->slave_addr,
+                       .addr = dvo->slave_addr,
                        .flags = I2C_M_RD,
                        .len = 0,
                },
@@ -186,7 +187,7 @@ static bool ivch_read(struct intel_dvo_device *dvo, int addr, uint16_t *data)
                        .buf = out_buf,
                },
                {
-                       .addr = i2cbus->slave_addr,
+                       .addr = dvo->slave_addr,
                        .flags = I2C_M_RD | I2C_M_NOSTART,
                        .len = 2,
                        .buf = in_buf,
@@ -202,7 +203,7 @@ static bool ivch_read(struct intel_dvo_device *dvo, int addr, uint16_t *data)
 
        if (!priv->quiet) {
                DRM_DEBUG("Unable to read register 0x%02x from %s:%02x.\n",
-                         addr, i2cbus->adapter.name, i2cbus->slave_addr);
+                         addr, i2cbus->adapter.name, dvo->slave_addr);
        }
        return false;
 }
@@ -211,10 +212,11 @@ static bool ivch_read(struct intel_dvo_device *dvo, int addr, uint16_t *data)
 static bool ivch_write(struct intel_dvo_device *dvo, int addr, uint16_t data)
 {
        struct ivch_priv *priv = dvo->dev_priv;
-       struct intel_i2c_chan *i2cbus = dvo->i2c_bus;
+       struct i2c_adapter *adapter = dvo->i2c_bus;
+       struct intel_i2c_chan *i2cbus = container_of(adapter, struct intel_i2c_chan, adapter);
        u8 out_buf[3];
        struct i2c_msg msg = {
-               .addr = i2cbus->slave_addr,
+               .addr = dvo->slave_addr,
                .flags = 0,
                .len = 3,
                .buf = out_buf,
@@ -229,7 +231,7 @@ static bool ivch_write(struct intel_dvo_device *dvo, int addr, uint16_t data)
 
        if (!priv->quiet) {
                DRM_DEBUG("Unable to write register 0x%02x to %s:%d.\n",
-                         addr, i2cbus->adapter.name, i2cbus->slave_addr);
+                         addr, i2cbus->adapter.name, dvo->slave_addr);
        }
 
        return false;
@@ -237,7 +239,7 @@ static bool ivch_write(struct intel_dvo_device *dvo, int addr, uint16_t data)
 
 /** Probes the given bus and slave address for an ivch */
 static bool ivch_init(struct intel_dvo_device *dvo,
-                     struct intel_i2c_chan *i2cbus)
+                     struct i2c_adapter *adapter)
 {
        struct ivch_priv *priv;
        uint16_t temp;
@@ -246,8 +248,7 @@ static bool ivch_init(struct intel_dvo_device *dvo,
        if (priv == NULL)
                return false;
 
-       dvo->i2c_bus = i2cbus;
-       dvo->i2c_bus->slave_addr = dvo->slave_addr;
+       dvo->i2c_bus = adapter;
        dvo->dev_priv = priv;
        priv->quiet = true;
 
index 033a4bb070b2ac7b89660183ae4ade657531d613..e1c1f7341e5cff60a15fb568e7a0dd322782ef91 100644 (file)
@@ -76,19 +76,20 @@ struct sil164_priv {
 static bool sil164_readb(struct intel_dvo_device *dvo, int addr, uint8_t *ch)
 {
        struct sil164_priv *sil = dvo->dev_priv;
-       struct intel_i2c_chan *i2cbus = dvo->i2c_bus;
+       struct i2c_adapter *adapter = dvo->i2c_bus;
+       struct intel_i2c_chan *i2cbus = container_of(adapter, struct intel_i2c_chan, adapter);
        u8 out_buf[2];
        u8 in_buf[2];
 
        struct i2c_msg msgs[] = {
                {
-                       .addr = i2cbus->slave_addr,
+                       .addr = dvo->slave_addr,
                        .flags = 0,
                        .len = 1,
                        .buf = out_buf,
                },
                {
-                       .addr = i2cbus->slave_addr,
+                       .addr = dvo->slave_addr,
                        .flags = I2C_M_RD,
                        .len = 1,
                        .buf = in_buf,
@@ -105,7 +106,7 @@ static bool sil164_readb(struct intel_dvo_device *dvo, int addr, uint8_t *ch)
 
        if (!sil->quiet) {
                DRM_DEBUG("Unable to read register 0x%02x from %s:%02x.\n",
-                         addr, i2cbus->adapter.name, i2cbus->slave_addr);
+                         addr, i2cbus->adapter.name, dvo->slave_addr);
        }
        return false;
 }
@@ -113,10 +114,11 @@ static bool sil164_readb(struct intel_dvo_device *dvo, int addr, uint8_t *ch)
 static bool sil164_writeb(struct intel_dvo_device *dvo, int addr, uint8_t ch)
 {
        struct sil164_priv *sil= dvo->dev_priv;
-       struct intel_i2c_chan *i2cbus = dvo->i2c_bus;
+       struct i2c_adapter *adapter = dvo->i2c_bus;
+       struct intel_i2c_chan *i2cbus = container_of(adapter, struct intel_i2c_chan, adapter);
        uint8_t out_buf[2];
        struct i2c_msg msg = {
-               .addr = i2cbus->slave_addr,
+               .addr = dvo->slave_addr,
                .flags = 0,
                .len = 2,
                .buf = out_buf,
@@ -130,7 +132,7 @@ static bool sil164_writeb(struct intel_dvo_device *dvo, int addr, uint8_t ch)
 
        if (!sil->quiet) {
                DRM_DEBUG("Unable to write register 0x%02x to %s:%d.\n",
-                         addr, i2cbus->adapter.name, i2cbus->slave_addr);
+                         addr, i2cbus->adapter.name, dvo->slave_addr);
        }
 
        return false;
@@ -138,7 +140,7 @@ static bool sil164_writeb(struct intel_dvo_device *dvo, int addr, uint8_t ch)
 
 /* Silicon Image 164 driver for chip on i2c bus */
 static bool sil164_init(struct intel_dvo_device *dvo,
-                       struct intel_i2c_chan *i2cbus)
+                       struct i2c_adapter *adapter)
 {
        /* this will detect the SIL164 chip on the specified i2c bus */
        struct sil164_priv *sil;
@@ -148,8 +150,7 @@ static bool sil164_init(struct intel_dvo_device *dvo,
        if (sil == NULL)
                return false;
 
-       dvo->i2c_bus = i2cbus;
-       dvo->i2c_bus->slave_addr = dvo->slave_addr;
+       dvo->i2c_bus = adapter;
        dvo->dev_priv = sil;
        sil->quiet = true;
 
@@ -158,7 +159,7 @@ static bool sil164_init(struct intel_dvo_device *dvo,
 
        if (ch != (SIL164_VID & 0xff)) {
                DRM_DEBUG("sil164 not detected got %d: from %s Slave %d.\n",
-                         ch, i2cbus->adapter.name, i2cbus->slave_addr);
+                         ch, adapter->name, dvo->slave_addr);
                goto out;
        }
 
@@ -167,7 +168,7 @@ static bool sil164_init(struct intel_dvo_device *dvo,
 
        if (ch != (SIL164_DID & 0xff)) {
                DRM_DEBUG("sil164 not detected got %d: from %s Slave %d.\n",
-                         ch, i2cbus->adapter.name, i2cbus->slave_addr);
+                         ch, adapter->name, dvo->slave_addr);
                goto out;
        }
        sil->quiet = false;
index 207fda806ebf87a212141353e44c88b3caa456b3..9ecc907384ec339d312ca31c5ea26a2a0636aedf 100644 (file)
@@ -101,19 +101,20 @@ struct tfp410_priv {
 static bool tfp410_readb(struct intel_dvo_device *dvo, int addr, uint8_t *ch)
 {
        struct tfp410_priv *tfp = dvo->dev_priv;
-       struct intel_i2c_chan *i2cbus = dvo->i2c_bus;
+       struct i2c_adapter *adapter = dvo->i2c_bus;
+       struct intel_i2c_chan *i2cbus = container_of(adapter, struct intel_i2c_chan, adapter);
        u8 out_buf[2];
        u8 in_buf[2];
 
        struct i2c_msg msgs[] = {
                {
-                       .addr = i2cbus->slave_addr,
+                       .addr = dvo->slave_addr,
                        .flags = 0,
                        .len = 1,
                        .buf = out_buf,
                },
                {
-                       .addr = i2cbus->slave_addr,
+                       .addr = dvo->slave_addr,
                        .flags = I2C_M_RD,
                        .len = 1,
                        .buf = in_buf,
@@ -130,7 +131,7 @@ static bool tfp410_readb(struct intel_dvo_device *dvo, int addr, uint8_t *ch)
 
        if (!tfp->quiet) {
                DRM_DEBUG("Unable to read register 0x%02x from %s:%02x.\n",
-                         addr, i2cbus->adapter.name, i2cbus->slave_addr);
+                         addr, i2cbus->adapter.name, dvo->slave_addr);
        }
        return false;
 }
@@ -138,10 +139,11 @@ static bool tfp410_readb(struct intel_dvo_device *dvo, int addr, uint8_t *ch)
 static bool tfp410_writeb(struct intel_dvo_device *dvo, int addr, uint8_t ch)
 {
        struct tfp410_priv *tfp = dvo->dev_priv;
-       struct intel_i2c_chan *i2cbus = dvo->i2c_bus;
+       struct i2c_adapter *adapter = dvo->i2c_bus;
+       struct intel_i2c_chan *i2cbus = container_of(adapter, struct intel_i2c_chan, adapter);
        uint8_t out_buf[2];
        struct i2c_msg msg = {
-               .addr = i2cbus->slave_addr,
+               .addr = dvo->slave_addr,
                .flags = 0,
                .len = 2,
                .buf = out_buf,
@@ -155,7 +157,7 @@ static bool tfp410_writeb(struct intel_dvo_device *dvo, int addr, uint8_t ch)
 
        if (!tfp->quiet) {
                DRM_DEBUG("Unable to write register 0x%02x to %s:%d.\n",
-                         addr, i2cbus->adapter.name, i2cbus->slave_addr);
+                         addr, i2cbus->adapter.name, dvo->slave_addr);
        }
 
        return false;
@@ -174,7 +176,7 @@ static int tfp410_getid(struct intel_dvo_device *dvo, int addr)
 
 /* Ti TFP410 driver for chip on i2c bus */
 static bool tfp410_init(struct intel_dvo_device *dvo,
-                       struct intel_i2c_chan *i2cbus)
+                       struct i2c_adapter *adapter)
 {
        /* this will detect the tfp410 chip on the specified i2c bus */
        struct tfp410_priv *tfp;
@@ -184,20 +186,19 @@ static bool tfp410_init(struct intel_dvo_device *dvo,
        if (tfp == NULL)
                return false;
 
-       dvo->i2c_bus = i2cbus;
-       dvo->i2c_bus->slave_addr = dvo->slave_addr;
+       dvo->i2c_bus = adapter;
        dvo->dev_priv = tfp;
        tfp->quiet = true;
 
        if ((id = tfp410_getid(dvo, TFP410_VID_LO)) != TFP410_VID) {
                DRM_DEBUG("tfp410 not detected got VID %X: from %s Slave %d.\n",
-                         id, i2cbus->adapter.name, i2cbus->slave_addr);
+                         id, adapter->name, dvo->slave_addr);
                goto out;
        }
 
        if ((id = tfp410_getid(dvo, TFP410_DID_LO)) != TFP410_DID) {
                DRM_DEBUG("tfp410 not detected got DID %X: from %s Slave %d.\n",
-                         id, i2cbus->adapter.name, i2cbus->slave_addr);
+                         id, adapter->name, dvo->slave_addr);
                goto out;
        }
        tfp->quiet = false;
index f112c769d5334148683040deef54a3dde80382f8..8c4783180bf653e9a1885b40896c711c074f78d9 100644 (file)
@@ -846,7 +846,7 @@ static int i915_set_status_page(struct drm_device *dev, void *data,
                return 0;
        }
 
-       printk(KERN_DEBUG "set status page addr 0x%08x\n", (u32)hws->addr);
+       DRM_DEBUG("set status page addr 0x%08x\n", (u32)hws->addr);
 
        dev_priv->status_gfx_addr = hws->addr & (0x1ffff<<12);
 
@@ -885,8 +885,8 @@ static int i915_set_status_page(struct drm_device *dev, void *data,
  * some RAM for the framebuffer at early boot.  This code figures out
  * how much was set aside so we can use it for our own purposes.
  */
-static int i915_probe_agp(struct drm_device *dev, unsigned long *aperture_size,
-                         unsigned long *preallocated_size)
+static int i915_probe_agp(struct drm_device *dev, uint32_t *aperture_size,
+                         uint32_t *preallocated_size)
 {
        struct pci_dev *bridge_dev;
        u16 tmp = 0;
@@ -984,10 +984,11 @@ static int i915_probe_agp(struct drm_device *dev, unsigned long *aperture_size,
        return 0;
 }
 
-static int i915_load_modeset_init(struct drm_device *dev)
+static int i915_load_modeset_init(struct drm_device *dev,
+                                 unsigned long prealloc_size,
+                                 unsigned long agp_size)
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
-       unsigned long agp_size, prealloc_size;
        int fb_bar = IS_I9XX(dev) ? 2 : 0;
        int ret = 0;
 
@@ -1002,10 +1003,6 @@ static int i915_load_modeset_init(struct drm_device *dev)
        if (IS_I965G(dev) || IS_G33(dev))
                dev_priv->cursor_needs_physical = false;
 
-       ret = i915_probe_agp(dev, &agp_size, &prealloc_size);
-       if (ret)
-               goto out;
-
        /* Basic memrange allocator for stolen space (aka vram) */
        drm_mm_init(&dev_priv->vram, 0, prealloc_size);
 
@@ -1082,6 +1079,44 @@ void i915_master_destroy(struct drm_device *dev, struct drm_master *master)
        master->driver_priv = NULL;
 }
 
+static void i915_get_mem_freq(struct drm_device *dev)
+{
+       drm_i915_private_t *dev_priv = dev->dev_private;
+       u32 tmp;
+
+       if (!IS_IGD(dev))
+               return;
+
+       tmp = I915_READ(CLKCFG);
+
+       switch (tmp & CLKCFG_FSB_MASK) {
+       case CLKCFG_FSB_533:
+               dev_priv->fsb_freq = 533; /* 133*4 */
+               break;
+       case CLKCFG_FSB_800:
+               dev_priv->fsb_freq = 800; /* 200*4 */
+               break;
+       case CLKCFG_FSB_667:
+               dev_priv->fsb_freq =  667; /* 167*4 */
+               break;
+       case CLKCFG_FSB_400:
+               dev_priv->fsb_freq = 400; /* 100*4 */
+               break;
+       }
+
+       switch (tmp & CLKCFG_MEM_MASK) {
+       case CLKCFG_MEM_533:
+               dev_priv->mem_freq = 533;
+               break;
+       case CLKCFG_MEM_667:
+               dev_priv->mem_freq = 667;
+               break;
+       case CLKCFG_MEM_800:
+               dev_priv->mem_freq = 800;
+               break;
+       }
+}
+
 /**
  * i915_driver_load - setup chip and create an initial config
  * @dev: DRM device
@@ -1098,6 +1133,7 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags)
        struct drm_i915_private *dev_priv = dev->dev_private;
        resource_size_t base, size;
        int ret = 0, mmio_bar = IS_I9XX(dev) ? 0 : 1;
+       uint32_t agp_size, prealloc_size;
 
        /* i915 has 4 more counters */
        dev->counters += 4;
@@ -1146,9 +1182,22 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags)
                         "performance may suffer.\n");
        }
 
+       ret = i915_probe_agp(dev, &agp_size, &prealloc_size);
+       if (ret)
+               goto out_iomapfree;
+
        /* enable GEM by default */
        dev_priv->has_gem = 1;
 
+       if (prealloc_size > agp_size * 3 / 4) {
+               DRM_ERROR("Detected broken video BIOS with %d/%dkB of video "
+                         "memory stolen.\n",
+                         prealloc_size / 1024, agp_size / 1024);
+               DRM_ERROR("Disabling GEM. (try reducing stolen memory or "
+                         "updating the BIOS to fix).\n");
+               dev_priv->has_gem = 0;
+       }
+
        dev->driver->get_vblank_counter = i915_get_vblank_counter;
        dev->max_vblank_count = 0xffffff; /* only 24 bits of frame count */
        if (IS_G4X(dev) || IS_IGDNG(dev)) {
@@ -1165,6 +1214,8 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags)
                        goto out_iomapfree;
        }
 
+       i915_get_mem_freq(dev);
+
        /* On the 945G/GM, the chipset reports the MSI capability on the
         * integrated graphics even though the support isn't actually there
         * according to the published specs.  It doesn't appear to function
@@ -1180,6 +1231,7 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags)
                pci_enable_msi(dev->pdev);
 
        spin_lock_init(&dev_priv->user_irq_lock);
+       spin_lock_init(&dev_priv->error_lock);
        dev_priv->user_irq_refcount = 0;
 
        ret = drm_vblank_init(dev, I915_NUM_PIPE);
@@ -1190,7 +1242,7 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags)
        }
 
        if (drm_core_check_feature(dev, DRIVER_MODESET)) {
-               ret = i915_load_modeset_init(dev);
+               ret = i915_load_modeset_init(dev, prealloc_size, agp_size);
                if (ret < 0) {
                        DRM_ERROR("failed to init modeset\n");
                        goto out_rmmap;
index 98560e1e899a83171ddd2ef041e1d76df191e37d..fc4b68aa2d056e9c8b9256860c38b4ac2175f529 100644 (file)
@@ -35,6 +35,7 @@
 
 #include "drm_pciids.h"
 #include <linux/console.h>
+#include "drm_crtc_helper.h"
 
 static unsigned int i915_modeset = -1;
 module_param_named(modeset, i915_modeset, int, 0400);
@@ -57,8 +58,8 @@ static int i915_suspend(struct drm_device *dev, pm_message_t state)
        struct drm_i915_private *dev_priv = dev->dev_private;
 
        if (!dev || !dev_priv) {
-               printk(KERN_ERR "dev: %p, dev_priv: %p\n", dev, dev_priv);
-               printk(KERN_ERR "DRM not initialized, aborting suspend.\n");
+               DRM_ERROR("dev: %p, dev_priv: %p\n", dev, dev_priv);
+               DRM_ERROR("DRM not initialized, aborting suspend.\n");
                return -ENODEV;
        }
 
@@ -67,8 +68,6 @@ static int i915_suspend(struct drm_device *dev, pm_message_t state)
 
        pci_save_state(dev->pdev);
 
-       i915_save_state(dev);
-
        /* If KMS is active, we do the leavevt stuff here */
        if (drm_core_check_feature(dev, DRIVER_MODESET)) {
                if (i915_gem_idle(dev))
@@ -77,6 +76,8 @@ static int i915_suspend(struct drm_device *dev, pm_message_t state)
                drm_irq_uninstall(dev);
        }
 
+       i915_save_state(dev);
+
        intel_opregion_free(dev, 1);
 
        if (state.event == PM_EVENT_SUSPEND) {
@@ -115,6 +116,10 @@ static int i915_resume(struct drm_device *dev)
 
                drm_irq_install(dev);
        }
+       if (drm_core_check_feature(dev, DRIVER_MODESET)) {
+               /* Resume the modeset for every activated CRTC */
+               drm_helper_resume_force_mode(dev);
+       }
 
        return ret;
 }
index 7a84f04e8439c1ea2f68acce4520f0d4665490f7..d087528758856c78b5b8e6d6f4a1857dc5be20e4 100644 (file)
@@ -133,6 +133,22 @@ struct sdvo_device_mapping {
        u8 initialized;
 };
 
+struct drm_i915_error_state {
+       u32 eir;
+       u32 pgtbl_er;
+       u32 pipeastat;
+       u32 pipebstat;
+       u32 ipeir;
+       u32 ipehr;
+       u32 instdone;
+       u32 acthd;
+       u32 instpm;
+       u32 instps;
+       u32 instdone1;
+       u32 seqno;
+       struct timeval time;
+};
+
 typedef struct drm_i915_private {
        struct drm_device *dev;
 
@@ -209,6 +225,11 @@ typedef struct drm_i915_private {
        int fence_reg_start; /* 4 if userland hasn't ioctl'd us yet */
        int num_fence_regs; /* 8 on pre-965, 16 otherwise */
 
+       unsigned int fsb_freq, mem_freq;
+
+       spinlock_t error_lock;
+       struct drm_i915_error_state *first_error;
+
        /* Register state */
        u8 saveLBB;
        u32 saveDSPACNTR;
@@ -306,6 +327,17 @@ typedef struct drm_i915_private {
        u32 saveCURBPOS;
        u32 saveCURBBASE;
        u32 saveCURSIZE;
+       u32 saveDP_B;
+       u32 saveDP_C;
+       u32 saveDP_D;
+       u32 savePIPEA_GMCH_DATA_M;
+       u32 savePIPEB_GMCH_DATA_M;
+       u32 savePIPEA_GMCH_DATA_N;
+       u32 savePIPEB_GMCH_DATA_N;
+       u32 savePIPEA_DP_LINK_M;
+       u32 savePIPEB_DP_LINK_M;
+       u32 savePIPEA_DP_LINK_N;
+       u32 savePIPEB_DP_LINK_N;
 
        struct {
                struct drm_mm gtt_space;
@@ -457,9 +489,6 @@ struct drm_i915_gem_object {
         */
        int fence_reg;
 
-       /** Boolean whether this object has a valid gtt offset. */
-       int gtt_bound;
-
        /** How many users have pinned this object in GTT space */
        int pin_count;
 
@@ -644,6 +673,7 @@ void i915_gem_free_object(struct drm_gem_object *obj);
 int i915_gem_object_pin(struct drm_gem_object *obj, uint32_t alignment);
 void i915_gem_object_unpin(struct drm_gem_object *obj);
 int i915_gem_object_unbind(struct drm_gem_object *obj);
+void i915_gem_release_mmap(struct drm_gem_object *obj);
 void i915_gem_lastclose(struct drm_device *dev);
 uint32_t i915_get_gem_seqno(struct drm_device *dev);
 int i915_gem_object_get_fence_reg(struct drm_gem_object *obj);
@@ -857,7 +887,10 @@ extern int i915_wait_ring(struct drm_device * dev, int n, const char *caller);
 #define HAS_128_BYTE_Y_TILING(dev) (IS_I9XX(dev) && !(IS_I915G(dev) || \
                                                      IS_I915GM(dev)))
 #define SUPPORTS_INTEGRATED_HDMI(dev)  (IS_G4X(dev) || IS_IGDNG(dev))
+#define SUPPORTS_INTEGRATED_DP(dev)    (IS_G4X(dev) || IS_IGDNG(dev))
 #define I915_HAS_HOTPLUG(dev) (IS_I945G(dev) || IS_I945GM(dev) || IS_I965G(dev))
+/* dsparb controlled by hw only */
+#define DSPARB_HWCONTROL(dev) (IS_G4X(dev) || IS_IGDNG(dev))
 
 #define PRIMARY_RINGBUFFER_SIZE         (128*1024)
 
index fd2b8bdffe3f416b7a7869051ff44b954e03ada7..5bf420378b6d547a8146535c36830d84dd7bc087 100644 (file)
@@ -1006,7 +1006,7 @@ i915_gem_set_domain_ioctl(struct drm_device *dev, void *data,
 
        mutex_lock(&dev->struct_mutex);
 #if WATCH_BUF
-       DRM_INFO("set_domain_ioctl %p(%d), %08x %08x\n",
+       DRM_INFO("set_domain_ioctl %p(%zd), %08x %08x\n",
                 obj, obj->size, read_domains, write_domain);
 #endif
        if (read_domains & I915_GEM_DOMAIN_GTT) {
@@ -1050,7 +1050,7 @@ i915_gem_sw_finish_ioctl(struct drm_device *dev, void *data,
        }
 
 #if WATCH_BUF
-       DRM_INFO("%s: sw_finish %d (%p %d)\n",
+       DRM_INFO("%s: sw_finish %d (%p %zd)\n",
                 __func__, args->handle, obj, obj->size);
 #endif
        obj_priv = obj->driver_private;
@@ -1252,6 +1252,31 @@ out_free_list:
        return ret;
 }
 
+/**
+ * i915_gem_release_mmap - remove physical page mappings
+ * @obj: obj in question
+ *
+ * Preserve the reservation of the mmaping with the DRM core code, but
+ * relinquish ownership of the pages back to the system.
+ *
+ * It is vital that we remove the page mapping if we have mapped a tiled
+ * object through the GTT and then lose the fence register due to
+ * resource pressure. Similarly if the object has been moved out of the
+ * aperture, than pages mapped into userspace must be revoked. Removing the
+ * mapping will then trigger a page fault on the next user access, allowing
+ * fixup by i915_gem_fault().
+ */
+void
+i915_gem_release_mmap(struct drm_gem_object *obj)
+{
+       struct drm_device *dev = obj->dev;
+       struct drm_i915_gem_object *obj_priv = obj->driver_private;
+
+       if (dev->dev_mapping)
+               unmap_mapping_range(dev->dev_mapping,
+                                   obj_priv->mmap_offset, obj->size, 1);
+}
+
 static void
 i915_gem_free_mmap_offset(struct drm_gem_object *obj)
 {
@@ -1861,7 +1886,6 @@ i915_gem_object_unbind(struct drm_gem_object *obj)
 {
        struct drm_device *dev = obj->dev;
        struct drm_i915_gem_object *obj_priv = obj->driver_private;
-       loff_t offset;
        int ret = 0;
 
 #if WATCH_BUF
@@ -1898,9 +1922,7 @@ i915_gem_object_unbind(struct drm_gem_object *obj)
        BUG_ON(obj_priv->active);
 
        /* blow away mappings if mapped through GTT */
-       offset = ((loff_t) obj->map_list.hash.key) << PAGE_SHIFT;
-       if (dev->dev_mapping)
-               unmap_mapping_range(dev->dev_mapping, offset, obj->size, 1);
+       i915_gem_release_mmap(obj);
 
        if (obj_priv->fence_reg != I915_FENCE_REG_NONE)
                i915_gem_clear_fence_reg(obj);
@@ -2222,7 +2244,6 @@ try_again:
        /* None available, try to steal one or wait for a user to finish */
        if (i == dev_priv->num_fence_regs) {
                uint32_t seqno = dev_priv->mm.next_gem_seqno;
-               loff_t offset;
 
                if (avail == 0)
                        return -ENOSPC;
@@ -2274,10 +2295,7 @@ try_again:
                 * Zap this virtual mapping so we can set up a fence again
                 * for this object next time we need it.
                 */
-               offset = ((loff_t) reg->obj->map_list.hash.key) << PAGE_SHIFT;
-               if (dev->dev_mapping)
-                       unmap_mapping_range(dev->dev_mapping, offset,
-                                           reg->obj->size, 1);
+               i915_gem_release_mmap(reg->obj);
                old_obj_priv->fence_reg = I915_FENCE_REG_NONE;
        }
 
@@ -2423,7 +2441,7 @@ i915_gem_object_bind_to_gtt(struct drm_gem_object *obj, unsigned alignment)
        }
 
 #if WATCH_BUF
-       DRM_INFO("Binding object of size %d at 0x%08x\n",
+       DRM_INFO("Binding object of size %zd at 0x%08x\n",
                 obj->size, obj_priv->gtt_offset);
 #endif
        ret = i915_gem_object_get_pages(obj);
@@ -4227,6 +4245,7 @@ i915_gem_lastclose(struct drm_device *dev)
 void
 i915_gem_load(struct drm_device *dev)
 {
+       int i;
        drm_i915_private_t *dev_priv = dev->dev_private;
 
        spin_lock_init(&dev_priv->mm.active_list_lock);
@@ -4246,6 +4265,18 @@ i915_gem_load(struct drm_device *dev)
        else
                dev_priv->num_fence_regs = 8;
 
+       /* Initialize fence registers to zero */
+       if (IS_I965G(dev)) {
+               for (i = 0; i < 16; i++)
+                       I915_WRITE64(FENCE_REG_965_0 + (i * 8), 0);
+       } else {
+               for (i = 0; i < 8; i++)
+                       I915_WRITE(FENCE_REG_830_0 + (i * 4), 0);
+               if (IS_I945G(dev) || IS_I945GM(dev) || IS_G33(dev))
+                       for (i = 0; i < 8; i++)
+                               I915_WRITE(FENCE_REG_945_8 + (i * 4), 0);
+       }
+
        i915_gem_detect_bit_6_swizzle(dev);
 }
 
index 8d0b943e2c5aced503603a5848e291ea0a0c9694..e602614bd3f89a9cbbb7f53c6503e93814272a18 100644 (file)
@@ -87,7 +87,7 @@ i915_gem_dump_object(struct drm_gem_object *obj, int len,
                        chunk_len = page_len - chunk;
                        if (chunk_len > 128)
                                chunk_len = 128;
-                       i915_gem_dump_page(obj_priv->page_list[page],
+                       i915_gem_dump_page(obj_priv->pages[page],
                                           chunk, chunk + chunk_len,
                                           obj_priv->gtt_offset +
                                           page * PAGE_SIZE,
@@ -143,7 +143,7 @@ i915_gem_object_check_coherency(struct drm_gem_object *obj, int handle)
        uint32_t *backing_map = NULL;
        int bad_count = 0;
 
-       DRM_INFO("%s: checking coherency of object %p@0x%08x (%d, %dkb):\n",
+       DRM_INFO("%s: checking coherency of object %p@0x%08x (%d, %zdkb):\n",
                 __func__, obj, obj_priv->gtt_offset, handle,
                 obj->size / 1024);
 
@@ -157,7 +157,7 @@ i915_gem_object_check_coherency(struct drm_gem_object *obj, int handle)
        for (page = 0; page < obj->size / PAGE_SIZE; page++) {
                int i;
 
-               backing_map = kmap_atomic(obj_priv->page_list[page], KM_USER0);
+               backing_map = kmap_atomic(obj_priv->pages[page], KM_USER0);
 
                if (backing_map == NULL) {
                        DRM_ERROR("failed to map backing page\n");
index 28146e405e87404cf5177100ee2c467d8e5238e1..9a44bfcb81394c96a986b71e9b4da8ecb0ef7bee 100644 (file)
@@ -75,11 +75,10 @@ static int i915_gem_object_list_info(struct seq_file *m, void *data)
        case ACTIVE_LIST:
                seq_printf(m, "Active:\n");
                lock = &dev_priv->mm.active_list_lock;
-               spin_lock(lock);
                head = &dev_priv->mm.active_list;
                break;
        case INACTIVE_LIST:
-               seq_printf(m, "Inctive:\n");
+               seq_printf(m, "Inactive:\n");
                head = &dev_priv->mm.inactive_list;
                break;
        case FLUSHING_LIST:
@@ -91,6 +90,8 @@ static int i915_gem_object_list_info(struct seq_file *m, void *data)
                return 0;
        }
 
+       if (lock)
+               spin_lock(lock);
        list_for_each_entry(obj_priv, head, list)
        {
                struct drm_gem_object *obj = obj_priv->obj;
@@ -104,7 +105,10 @@ static int i915_gem_object_list_info(struct seq_file *m, void *data)
                if (obj->name)
                        seq_printf(m, " (name: %d)", obj->name);
                if (obj_priv->fence_reg != I915_FENCE_REG_NONE)
-                       seq_printf(m, " (fence: %d)\n", obj_priv->fence_reg);
+                       seq_printf(m, " (fence: %d)", obj_priv->fence_reg);
+               if (obj_priv->gtt_space != NULL)
+                       seq_printf(m, " (gtt_offset: %08x)", obj_priv->gtt_offset);
+
                seq_printf(m, "\n");
        }
 
@@ -323,6 +327,39 @@ static int i915_ringbuffer_info(struct seq_file *m, void *data)
        return 0;
 }
 
+static int i915_error_state(struct seq_file *m, void *unused)
+{
+       struct drm_info_node *node = (struct drm_info_node *) m->private;
+       struct drm_device *dev = node->minor->dev;
+       drm_i915_private_t *dev_priv = dev->dev_private;
+       struct drm_i915_error_state *error;
+       unsigned long flags;
+
+       spin_lock_irqsave(&dev_priv->error_lock, flags);
+       if (!dev_priv->first_error) {
+               seq_printf(m, "no error state collected\n");
+               goto out;
+       }
+
+       error = dev_priv->first_error;
+
+       seq_printf(m, "EIR: 0x%08x\n", error->eir);
+       seq_printf(m, "  PGTBL_ER: 0x%08x\n", error->pgtbl_er);
+       seq_printf(m, "  INSTPM: 0x%08x\n", error->instpm);
+       seq_printf(m, "  IPEIR: 0x%08x\n", error->ipeir);
+       seq_printf(m, "  IPEHR: 0x%08x\n", error->ipehr);
+       seq_printf(m, "  INSTDONE: 0x%08x\n", error->instdone);
+       seq_printf(m, "  ACTHD: 0x%08x\n", error->acthd);
+       if (IS_I965G(dev)) {
+               seq_printf(m, "  INSTPS: 0x%08x\n", error->instps);
+               seq_printf(m, "  INSTDONE1: 0x%08x\n", error->instdone1);
+       }
+
+out:
+       spin_unlock_irqrestore(&dev_priv->error_lock, flags);
+
+       return 0;
+}
 
 static struct drm_info_list i915_gem_debugfs_list[] = {
        {"i915_gem_active", i915_gem_object_list_info, 0, (void *) ACTIVE_LIST},
@@ -336,6 +373,7 @@ static struct drm_info_list i915_gem_debugfs_list[] = {
        {"i915_ringbuffer_data", i915_ringbuffer_data, 0},
        {"i915_ringbuffer_info", i915_ringbuffer_info, 0},
        {"i915_batchbuffers", i915_batchbuffer_info, 0},
+       {"i915_error_state", i915_error_state, 0},
 };
 #define I915_GEM_DEBUGFS_ENTRIES ARRAY_SIZE(i915_gem_debugfs_list)
 
index 5c1ceec49f5b6daf499cb9a984cc3aabaea1bb2c..a2d527b22ec4f7ba837d9787f11585cf141cf844 100644 (file)
@@ -114,11 +114,13 @@ intel_alloc_mchbar_resource(struct drm_device *dev)
        mchbar_addr = ((u64)temp_hi << 32) | temp_lo;
 
        /* If ACPI doesn't have it, assume we need to allocate it ourselves */
+#ifdef CONFIG_PNP
        if (mchbar_addr &&
            pnp_range_reserved(mchbar_addr, mchbar_addr + MCHBAR_SIZE)) {
                ret = 0;
                goto out_put;
        }
+#endif
 
        /* Get some space for it */
        ret = pci_bus_alloc_resource(bridge_dev->bus, &dev_priv->mch_res,
@@ -519,6 +521,12 @@ i915_gem_set_tiling(struct drm_device *dev, void *data,
                        goto err;
                }
 
+               /* If we've changed tiling, GTT-mappings of the object
+                * need to re-fault to ensure that the correct fence register
+                * setup is in place.
+                */
+               i915_gem_release_mmap(obj);
+
                obj_priv->tiling_mode = args->tiling_mode;
                obj_priv->stride = args->stride;
        }
index b86b7b7130c603beca04456ccca0abc4c5bbfbcc..7ba23a69a0c0e39a983937a76d1178c6bea052ad 100644 (file)
@@ -26,6 +26,7 @@
  *
  */
 
+#include <linux/sysrq.h>
 #include "drmP.h"
 #include "drm.h"
 #include "i915_drm.h"
  * we leave them always unmasked in IMR and then control enabling them through
  * PIPESTAT alone.
  */
-#define I915_INTERRUPT_ENABLE_FIX (I915_ASLE_INTERRUPT | \
-                                  I915_DISPLAY_PIPE_A_EVENT_INTERRUPT |  \
-                                  I915_DISPLAY_PIPE_B_EVENT_INTERRUPT)
+#define I915_INTERRUPT_ENABLE_FIX (I915_ASLE_INTERRUPT |                \
+                                  I915_DISPLAY_PIPE_A_EVENT_INTERRUPT | \
+                                  I915_DISPLAY_PIPE_B_EVENT_INTERRUPT | \
+                                  I915_RENDER_COMMAND_PARSER_ERROR_INTERRUPT)
 
 /** Interrupts that we mask and unmask at runtime. */
 #define I915_INTERRUPT_ENABLE_VAR (I915_USER_INTERRUPT)
@@ -232,7 +234,17 @@ static void i915_hotplug_work_func(struct work_struct *work)
        drm_i915_private_t *dev_priv = container_of(work, drm_i915_private_t,
                                                    hotplug_work);
        struct drm_device *dev = dev_priv->dev;
-
+       struct drm_mode_config *mode_config = &dev->mode_config;
+       struct drm_connector *connector;
+
+       if (mode_config->num_connector) {
+               list_for_each_entry(connector, &mode_config->connector_list, head) {
+                       struct intel_output *intel_output = to_intel_output(connector);
+       
+                       if (intel_output->hot_plug)
+                               (*intel_output->hot_plug) (intel_output);
+               }
+       }
        /* Just fire off a uevent and let userspace tell us what to do */
        drm_sysfs_hotplug_event(dev);
 }
@@ -278,6 +290,47 @@ irqreturn_t igdng_irq_handler(struct drm_device *dev)
        return ret;
 }
 
+static void i915_capture_error_state(struct drm_device *dev)
+{
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       struct drm_i915_error_state *error;
+       unsigned long flags;
+
+       spin_lock_irqsave(&dev_priv->error_lock, flags);
+       if (dev_priv->first_error)
+               goto out;
+
+       error = kmalloc(sizeof(*error), GFP_ATOMIC);
+       if (!error) {
+               DRM_DEBUG("out ot memory, not capturing error state\n");
+               goto out;
+       }
+
+       error->eir = I915_READ(EIR);
+       error->pgtbl_er = I915_READ(PGTBL_ER);
+       error->pipeastat = I915_READ(PIPEASTAT);
+       error->pipebstat = I915_READ(PIPEBSTAT);
+       error->instpm = I915_READ(INSTPM);
+       if (!IS_I965G(dev)) {
+               error->ipeir = I915_READ(IPEIR);
+               error->ipehr = I915_READ(IPEHR);
+               error->instdone = I915_READ(INSTDONE);
+               error->acthd = I915_READ(ACTHD);
+       } else {
+               error->ipeir = I915_READ(IPEIR_I965);
+               error->ipehr = I915_READ(IPEHR_I965);
+               error->instdone = I915_READ(INSTDONE_I965);
+               error->instps = I915_READ(INSTPS);
+               error->instdone1 = I915_READ(INSTDONE1);
+               error->acthd = I915_READ(ACTHD_I965);
+       }
+
+       dev_priv->first_error = error;
+
+out:
+       spin_unlock_irqrestore(&dev_priv->error_lock, flags);
+}
+
 irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS)
 {
        struct drm_device *dev = (struct drm_device *) arg;
@@ -323,11 +376,15 @@ irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS)
                 * Clear the PIPE(A|B)STAT regs before the IIR
                 */
                if (pipea_stats & 0x8000ffff) {
+                       if (pipea_stats &  PIPE_FIFO_UNDERRUN_STATUS)
+                               DRM_DEBUG("pipe a underrun\n");
                        I915_WRITE(PIPEASTAT, pipea_stats);
                        irq_received = 1;
                }
 
                if (pipeb_stats & 0x8000ffff) {
+                       if (pipeb_stats &  PIPE_FIFO_UNDERRUN_STATUS)
+                               DRM_DEBUG("pipe b underrun\n");
                        I915_WRITE(PIPEBSTAT, pipeb_stats);
                        irq_received = 1;
                }
@@ -352,6 +409,80 @@ irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS)
                        I915_READ(PORT_HOTPLUG_STAT);
                }
 
+               if (iir & I915_RENDER_COMMAND_PARSER_ERROR_INTERRUPT) {
+                       u32 eir = I915_READ(EIR);
+
+                       i915_capture_error_state(dev);
+
+                       printk(KERN_ERR "render error detected, EIR: 0x%08x\n",
+                              eir);
+                       if (eir & I915_ERROR_PAGE_TABLE) {
+                               u32 pgtbl_err = I915_READ(PGTBL_ER);
+                               printk(KERN_ERR "page table error\n");
+                               printk(KERN_ERR "  PGTBL_ER: 0x%08x\n",
+                                      pgtbl_err);
+                               I915_WRITE(PGTBL_ER, pgtbl_err);
+                               (void)I915_READ(PGTBL_ER);
+                       }
+                       if (eir & I915_ERROR_MEMORY_REFRESH) {
+                               printk(KERN_ERR "memory refresh error\n");
+                               printk(KERN_ERR "PIPEASTAT: 0x%08x\n",
+                                      pipea_stats);
+                               printk(KERN_ERR "PIPEBSTAT: 0x%08x\n",
+                                      pipeb_stats);
+                               /* pipestat has already been acked */
+                       }
+                       if (eir & I915_ERROR_INSTRUCTION) {
+                               printk(KERN_ERR "instruction error\n");
+                               printk(KERN_ERR "  INSTPM: 0x%08x\n",
+                                      I915_READ(INSTPM));
+                               if (!IS_I965G(dev)) {
+                                       u32 ipeir = I915_READ(IPEIR);
+
+                                       printk(KERN_ERR "  IPEIR: 0x%08x\n",
+                                              I915_READ(IPEIR));
+                                       printk(KERN_ERR "  IPEHR: 0x%08x\n",
+                                                  I915_READ(IPEHR));
+                                       printk(KERN_ERR "  INSTDONE: 0x%08x\n",
+                                                  I915_READ(INSTDONE));
+                                       printk(KERN_ERR "  ACTHD: 0x%08x\n",
+                                                  I915_READ(ACTHD));
+                                       I915_WRITE(IPEIR, ipeir);
+                                       (void)I915_READ(IPEIR);
+                               } else {
+                                       u32 ipeir = I915_READ(IPEIR_I965);
+
+                                       printk(KERN_ERR "  IPEIR: 0x%08x\n",
+                                              I915_READ(IPEIR_I965));
+                                       printk(KERN_ERR "  IPEHR: 0x%08x\n",
+                                              I915_READ(IPEHR_I965));
+                                       printk(KERN_ERR "  INSTDONE: 0x%08x\n",
+                                              I915_READ(INSTDONE_I965));
+                                       printk(KERN_ERR "  INSTPS: 0x%08x\n",
+                                              I915_READ(INSTPS));
+                                       printk(KERN_ERR "  INSTDONE1: 0x%08x\n",
+                                              I915_READ(INSTDONE1));
+                                       printk(KERN_ERR "  ACTHD: 0x%08x\n",
+                                              I915_READ(ACTHD_I965));
+                                       I915_WRITE(IPEIR_I965, ipeir);
+                                       (void)I915_READ(IPEIR_I965);
+                               }
+                       }
+
+                       I915_WRITE(EIR, eir);
+                       (void)I915_READ(EIR);
+                       eir = I915_READ(EIR);
+                       if (eir) {
+                               /*
+                                * some errors might have become stuck,
+                                * mask them.
+                                */
+                               DRM_ERROR("EIR stuck: 0x%08x, masking\n", eir);
+                               I915_WRITE(EMR, I915_READ(EMR) | eir);
+                               I915_WRITE(IIR, I915_RENDER_COMMAND_PARSER_ERROR_INTERRUPT);
+                       }
+               }
+
                I915_WRITE(IIR, iir);
                new_iir = I915_READ(IIR); /* Flush posted writes */
 
@@ -722,6 +853,7 @@ int i915_driver_irq_postinstall(struct drm_device *dev)
 {
        drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
        u32 enable_mask = I915_INTERRUPT_ENABLE_FIX | I915_INTERRUPT_ENABLE_VAR;
+       u32 error_mask;
 
        DRM_INIT_WAITQUEUE(&dev_priv->irq_queue);
 
@@ -758,6 +890,21 @@ int i915_driver_irq_postinstall(struct drm_device *dev)
                i915_enable_irq(dev_priv, I915_DISPLAY_PORT_INTERRUPT);
        }
 
+       /*
+        * Enable some error detection, note the instruction error mask
+        * bit is reserved, so we leave it masked.
+        */
+       if (IS_G4X(dev)) {
+               error_mask = ~(GM45_ERROR_PAGE_TABLE |
+                              GM45_ERROR_MEM_PRIV |
+                              GM45_ERROR_CP_PRIV |
+                              I915_ERROR_MEMORY_REFRESH);
+       } else {
+               error_mask = ~(I915_ERROR_PAGE_TABLE |
+                              I915_ERROR_MEMORY_REFRESH);
+       }
+       I915_WRITE(EMR, error_mask);
+
        /* Disable pipe interrupt enables, clear pending pipe status */
        I915_WRITE(PIPEASTAT, I915_READ(PIPEASTAT) & 0x8000ffff);
        I915_WRITE(PIPEBSTAT, I915_READ(PIPEBSTAT) & 0x8000ffff);
index dc425e74a268e0c59d9f008cb3d791e1b83c8751..e4b4e8898e39a20a451cd97a5b57b13d9e63561b 100644 (file)
@@ -419,7 +419,7 @@ void intel_opregion_free(struct drm_device *dev, int suspend)
                return;
 
        if (!suspend)
-               acpi_video_exit();
+               acpi_video_unregister();
 
        opregion->acpi->drdy = 0;
 
index f6237a0b1133c0429cc27a2a0c26282bd6051b8c..6c08584840944d6e711386ba8b4352b8c9dcdce3 100644 (file)
 /*
  * Instruction and interrupt control regs
  */
+#define PGTBL_ER       0x02024
 #define PRB0_TAIL      0x02030
 #define PRB0_HEAD      0x02034
 #define PRB0_START     0x02038
 #define PRB1_HEAD      0x02044 /* 915+ only */
 #define PRB1_START     0x02048 /* 915+ only */
 #define PRB1_CTL       0x0204c /* 915+ only */
+#define IPEIR_I965     0x02064
+#define IPEHR_I965     0x02068
+#define INSTDONE_I965  0x0206c
+#define INSTPS         0x02070 /* 965+ only */
+#define INSTDONE1      0x0207c /* 965+ only */
 #define ACTHD_I965     0x02074
 #define HWS_PGA                0x02080
 #define HWS_ADDRESS_MASK       0xfffff000
 #define HWS_START_ADDRESS_SHIFT        4
 #define IPEIR          0x02088
+#define IPEHR          0x0208c
+#define INSTDONE       0x02090
 #define NOPID          0x02094
 #define HWSTAM         0x02098
 #define SCPD0          0x0209c /* 915+ only */
 #define EIR            0x020b0
 #define EMR            0x020b4
 #define ESR            0x020b8
+#define   GM45_ERROR_PAGE_TABLE                                (1<<5)
+#define   GM45_ERROR_MEM_PRIV                          (1<<4)
+#define   I915_ERROR_PAGE_TABLE                                (1<<4)
+#define   GM45_ERROR_CP_PRIV                           (1<<3)
+#define   I915_ERROR_MEMORY_REFRESH                    (1<<1)
+#define   I915_ERROR_INSTRUCTION                       (1<<0)
 #define INSTPM         0x020c0
 #define ACTHD          0x020c8
 #define FW_BLC         0x020d8
+#define FW_BLC2                0x020dc
 #define FW_BLC_SELF    0x020e0 /* 915+ only */
+#define   FW_BLC_SELF_EN (1<<15)
+#define MM_BURST_LENGTH     0x00700000
+#define MM_FIFO_WATERMARK   0x0001F000
+#define LM_BURST_LENGTH     0x00000700
+#define LM_FIFO_WATERMARK   0x0000001F
 #define MI_ARB_STATE   0x020e4 /* 915+ only */
 #define CACHE_MODE_0   0x02120 /* 915+ only */
 #define   CM0_MASK_SHIFT          16
 #define C0DRB3                 0x10206
 #define C1DRB3                 0x10606
 
+/* Clocking configuration register */
+#define CLKCFG                 0x10c00
+#define CLKCFG_FSB_400                                 (5 << 0)        /* hrawclk 100 */
+#define CLKCFG_FSB_533                                 (1 << 0)        /* hrawclk 133 */
+#define CLKCFG_FSB_667                                 (3 << 0)        /* hrawclk 166 */
+#define CLKCFG_FSB_800                                 (2 << 0)        /* hrawclk 200 */
+#define CLKCFG_FSB_1067                                        (6 << 0)        /* hrawclk 266 */
+#define CLKCFG_FSB_1333                                        (7 << 0)        /* hrawclk 333 */
+/* Note, below two are guess */
+#define CLKCFG_FSB_1600                                        (4 << 0)        /* hrawclk 400 */
+#define CLKCFG_FSB_1600_ALT                            (0 << 0)        /* hrawclk 400 */
+#define CLKCFG_FSB_MASK                                        (7 << 0)
+#define CLKCFG_MEM_533                                 (1 << 4)
+#define CLKCFG_MEM_667                                 (2 << 4)
+#define CLKCFG_MEM_800                                 (3 << 4)
+#define CLKCFG_MEM_MASK                                        (7 << 4)
+
 /** GM965 GM45 render standby register */
 #define MCHBAR_RENDER_STANDBY  0x111B8
 
 #define   HORIZ_INTERP_MASK    (3 << 6)
 #define   HORIZ_AUTO_SCALE     (1 << 5)
 #define   PANEL_8TO6_DITHER_ENABLE (1 << 3)
+#define   PFIT_FILTER_FUZZY    (0 << 24)
+#define   PFIT_SCALING_AUTO    (0 << 26)
+#define   PFIT_SCALING_PROGRAMMED (1 << 26)
+#define   PFIT_SCALING_PILLAR  (2 << 26)
+#define   PFIT_SCALING_LETTER  (3 << 26)
 #define PFIT_PGM_RATIOS        0x61234
 #define   PFIT_VERT_SCALE_MASK                 0xfff00000
 #define   PFIT_HORIZ_SCALE_MASK                        0x0000fff0
+/* Pre-965 */
+#define                PFIT_VERT_SCALE_SHIFT           20
+#define                PFIT_VERT_SCALE_MASK            0xfff00000
+#define                PFIT_HORIZ_SCALE_SHIFT          4
+#define                PFIT_HORIZ_SCALE_MASK           0x0000fff0
+/* 965+ */
+#define                PFIT_VERT_SCALE_SHIFT_965       16
+#define                PFIT_VERT_SCALE_MASK_965        0x1fff0000
+#define                PFIT_HORIZ_SCALE_SHIFT_965      0
+#define                PFIT_HORIZ_SCALE_MASK_965       0x00001fff
+
 #define PFIT_AUTO_RATIOS 0x61238
 
 /* Backlight control */
 #define   DSPARB_CSTART_SHIFT  7
 #define   DSPARB_BSTART_MASK   (0x7f)
 #define   DSPARB_BSTART_SHIFT  0
+#define   DSPARB_BEND_SHIFT    9 /* on 855 */
+#define   DSPARB_AEND_SHIFT    0
+
+#define DSPFW1                 0x70034
+#define DSPFW2                 0x70038
+#define DSPFW3                 0x7003c
+#define   IGD_SELF_REFRESH_EN  (1<<30)
+
+/* FIFO watermark sizes etc */
+#define I915_FIFO_LINE_SIZE    64
+#define I830_FIFO_LINE_SIZE    32
+#define I945_FIFO_SIZE         127 /* 945 & 965 */
+#define I915_FIFO_SIZE         95
+#define I855GM_FIFO_SIZE       255
+#define I830_FIFO_SIZE         95
+#define I915_MAX_WM            0x3f
+
+#define IGD_DISPLAY_FIFO       512 /* in 64byte unit */
+#define IGD_FIFO_LINE_SIZE     64
+#define IGD_MAX_WM             0x1ff
+#define IGD_DFT_WM             0x3f
+#define IGD_DFT_HPLLOFF_WM     0
+#define IGD_GUARD_WM           10
+#define IGD_CURSOR_FIFO                64
+#define IGD_CURSOR_MAX_WM      0x3f
+#define IGD_CURSOR_DFT_WM      0
+#define IGD_CURSOR_GUARD_WM    5
+
 /*
  * The two pipe frame counter registers are not synchronized, so
  * reading a stable value is somewhat tricky. The following code
index a98e2831ed31787ee6985fb058bdc3d32725367c..9e1d16e5c3ead86f0e805f9d72a95eb7be8e293e 100644 (file)
@@ -222,23 +222,12 @@ static void i915_restore_vga(struct drm_device *dev)
        I915_WRITE8(VGA_DACMASK, dev_priv->saveDACMASK);
 }
 
-int i915_save_state(struct drm_device *dev)
+static void i915_save_modeset_reg(struct drm_device *dev)
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
-       int i;
-
-       pci_read_config_byte(dev->pdev, LBB, &dev_priv->saveLBB);
-
-       /* Render Standby */
-       if (IS_I965G(dev) && IS_MOBILE(dev))
-               dev_priv->saveRENDERSTANDBY = I915_READ(MCHBAR_RENDER_STANDBY);
-
-       /* Hardware status page */
-       dev_priv->saveHWS = I915_READ(HWS_PGA);
-
-       /* Display arbitration control */
-       dev_priv->saveDSPARB = I915_READ(DSPARB);
 
+       if (drm_core_check_feature(dev, DRIVER_MODESET))
+               return;
        /* Pipe & plane A info */
        dev_priv->savePIPEACONF = I915_READ(PIPEACONF);
        dev_priv->savePIPEASRC = I915_READ(PIPEASRC);
@@ -294,7 +283,122 @@ int i915_save_state(struct drm_device *dev)
        }
        i915_save_palette(dev, PIPE_B);
        dev_priv->savePIPEBSTAT = I915_READ(PIPEBSTAT);
+       return;
+}
+static void i915_restore_modeset_reg(struct drm_device *dev)
+{
+       struct drm_i915_private *dev_priv = dev->dev_private;
+
+       if (drm_core_check_feature(dev, DRIVER_MODESET))
+               return;
+
+       /* Pipe & plane A info */
+       /* Prime the clock */
+       if (dev_priv->saveDPLL_A & DPLL_VCO_ENABLE) {
+               I915_WRITE(DPLL_A, dev_priv->saveDPLL_A &
+                          ~DPLL_VCO_ENABLE);
+               DRM_UDELAY(150);
+       }
+       I915_WRITE(FPA0, dev_priv->saveFPA0);
+       I915_WRITE(FPA1, dev_priv->saveFPA1);
+       /* Actually enable it */
+       I915_WRITE(DPLL_A, dev_priv->saveDPLL_A);
+       DRM_UDELAY(150);
+       if (IS_I965G(dev))
+               I915_WRITE(DPLL_A_MD, dev_priv->saveDPLL_A_MD);
+       DRM_UDELAY(150);
+
+       /* Restore mode */
+       I915_WRITE(HTOTAL_A, dev_priv->saveHTOTAL_A);
+       I915_WRITE(HBLANK_A, dev_priv->saveHBLANK_A);
+       I915_WRITE(HSYNC_A, dev_priv->saveHSYNC_A);
+       I915_WRITE(VTOTAL_A, dev_priv->saveVTOTAL_A);
+       I915_WRITE(VBLANK_A, dev_priv->saveVBLANK_A);
+       I915_WRITE(VSYNC_A, dev_priv->saveVSYNC_A);
+       I915_WRITE(BCLRPAT_A, dev_priv->saveBCLRPAT_A);
+
+       /* Restore plane info */
+       I915_WRITE(DSPASIZE, dev_priv->saveDSPASIZE);
+       I915_WRITE(DSPAPOS, dev_priv->saveDSPAPOS);
+       I915_WRITE(PIPEASRC, dev_priv->savePIPEASRC);
+       I915_WRITE(DSPAADDR, dev_priv->saveDSPAADDR);
+       I915_WRITE(DSPASTRIDE, dev_priv->saveDSPASTRIDE);
+       if (IS_I965G(dev)) {
+               I915_WRITE(DSPASURF, dev_priv->saveDSPASURF);
+               I915_WRITE(DSPATILEOFF, dev_priv->saveDSPATILEOFF);
+       }
+
+       I915_WRITE(PIPEACONF, dev_priv->savePIPEACONF);
+
+       i915_restore_palette(dev, PIPE_A);
+       /* Enable the plane */
+       I915_WRITE(DSPACNTR, dev_priv->saveDSPACNTR);
+       I915_WRITE(DSPAADDR, I915_READ(DSPAADDR));
+
+       /* Pipe & plane B info */
+       if (dev_priv->saveDPLL_B & DPLL_VCO_ENABLE) {
+               I915_WRITE(DPLL_B, dev_priv->saveDPLL_B &
+                          ~DPLL_VCO_ENABLE);
+               DRM_UDELAY(150);
+       }
+       I915_WRITE(FPB0, dev_priv->saveFPB0);
+       I915_WRITE(FPB1, dev_priv->saveFPB1);
+       /* Actually enable it */
+       I915_WRITE(DPLL_B, dev_priv->saveDPLL_B);
+       DRM_UDELAY(150);
+       if (IS_I965G(dev))
+               I915_WRITE(DPLL_B_MD, dev_priv->saveDPLL_B_MD);
+       DRM_UDELAY(150);
+
+       /* Restore mode */
+       I915_WRITE(HTOTAL_B, dev_priv->saveHTOTAL_B);
+       I915_WRITE(HBLANK_B, dev_priv->saveHBLANK_B);
+       I915_WRITE(HSYNC_B, dev_priv->saveHSYNC_B);
+       I915_WRITE(VTOTAL_B, dev_priv->saveVTOTAL_B);
+       I915_WRITE(VBLANK_B, dev_priv->saveVBLANK_B);
+       I915_WRITE(VSYNC_B, dev_priv->saveVSYNC_B);
+       I915_WRITE(BCLRPAT_B, dev_priv->saveBCLRPAT_B);
+
+       /* Restore plane info */
+       I915_WRITE(DSPBSIZE, dev_priv->saveDSPBSIZE);
+       I915_WRITE(DSPBPOS, dev_priv->saveDSPBPOS);
+       I915_WRITE(PIPEBSRC, dev_priv->savePIPEBSRC);
+       I915_WRITE(DSPBADDR, dev_priv->saveDSPBADDR);
+       I915_WRITE(DSPBSTRIDE, dev_priv->saveDSPBSTRIDE);
+       if (IS_I965G(dev)) {
+               I915_WRITE(DSPBSURF, dev_priv->saveDSPBSURF);
+               I915_WRITE(DSPBTILEOFF, dev_priv->saveDSPBTILEOFF);
+       }
+
+       I915_WRITE(PIPEBCONF, dev_priv->savePIPEBCONF);
+
+       i915_restore_palette(dev, PIPE_B);
+       /* Enable the plane */
+       I915_WRITE(DSPBCNTR, dev_priv->saveDSPBCNTR);
+       I915_WRITE(DSPBADDR, I915_READ(DSPBADDR));
 
+       return;
+}
+int i915_save_state(struct drm_device *dev)
+{
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       int i;
+
+       pci_read_config_byte(dev->pdev, LBB, &dev_priv->saveLBB);
+
+       /* Render Standby */
+       if (IS_I965G(dev) && IS_MOBILE(dev))
+               dev_priv->saveRENDERSTANDBY = I915_READ(MCHBAR_RENDER_STANDBY);
+
+       /* Hardware status page */
+       dev_priv->saveHWS = I915_READ(HWS_PGA);
+
+       /* Display arbitration control */
+       dev_priv->saveDSPARB = I915_READ(DSPARB);
+
+       /* This is only meaningful in non-KMS mode */
+       /* Don't save them in KMS mode */
+       i915_save_modeset_reg(dev);
        /* Cursor state */
        dev_priv->saveCURACNTR = I915_READ(CURACNTR);
        dev_priv->saveCURAPOS = I915_READ(CURAPOS);
@@ -322,6 +426,20 @@ int i915_save_state(struct drm_device *dev)
        dev_priv->savePP_OFF_DELAYS = I915_READ(PP_OFF_DELAYS);
        dev_priv->savePP_DIVISOR = I915_READ(PP_DIVISOR);
 
+       /* Display Port state */
+       if (SUPPORTS_INTEGRATED_DP(dev)) {
+               dev_priv->saveDP_B = I915_READ(DP_B);
+               dev_priv->saveDP_C = I915_READ(DP_C);
+               dev_priv->saveDP_D = I915_READ(DP_D);
+               dev_priv->savePIPEA_GMCH_DATA_M = I915_READ(PIPEA_GMCH_DATA_M);
+               dev_priv->savePIPEB_GMCH_DATA_M = I915_READ(PIPEB_GMCH_DATA_M);
+               dev_priv->savePIPEA_GMCH_DATA_N = I915_READ(PIPEA_GMCH_DATA_N);
+               dev_priv->savePIPEB_GMCH_DATA_N = I915_READ(PIPEB_GMCH_DATA_N);
+               dev_priv->savePIPEA_DP_LINK_M = I915_READ(PIPEA_DP_LINK_M);
+               dev_priv->savePIPEB_DP_LINK_M = I915_READ(PIPEB_DP_LINK_M);
+               dev_priv->savePIPEA_DP_LINK_N = I915_READ(PIPEA_DP_LINK_N);
+               dev_priv->savePIPEB_DP_LINK_N = I915_READ(PIPEB_DP_LINK_N);
+       }
        /* FIXME: save TV & SDVO state */
 
        /* FBC state */
@@ -404,92 +522,21 @@ int i915_restore_state(struct drm_device *dev)
                        for (i = 0; i < 8; i++)
                                I915_WRITE(FENCE_REG_945_8 + (i * 4), dev_priv->saveFENCE[i+8]);
        }
-
-       /* Pipe & plane A info */
-       /* Prime the clock */
-       if (dev_priv->saveDPLL_A & DPLL_VCO_ENABLE) {
-               I915_WRITE(DPLL_A, dev_priv->saveDPLL_A &
-                          ~DPLL_VCO_ENABLE);
-               DRM_UDELAY(150);
+       
+       /* Display port ratios (must be done before clock is set) */
+       if (SUPPORTS_INTEGRATED_DP(dev)) {
+               I915_WRITE(PIPEA_GMCH_DATA_M, dev_priv->savePIPEA_GMCH_DATA_M);
+               I915_WRITE(PIPEB_GMCH_DATA_M, dev_priv->savePIPEB_GMCH_DATA_M);
+               I915_WRITE(PIPEA_GMCH_DATA_N, dev_priv->savePIPEA_GMCH_DATA_N);
+               I915_WRITE(PIPEB_GMCH_DATA_N, dev_priv->savePIPEB_GMCH_DATA_N);
+               I915_WRITE(PIPEA_DP_LINK_M, dev_priv->savePIPEA_DP_LINK_M);
+               I915_WRITE(PIPEB_DP_LINK_M, dev_priv->savePIPEB_DP_LINK_M);
+               I915_WRITE(PIPEA_DP_LINK_N, dev_priv->savePIPEA_DP_LINK_N);
+               I915_WRITE(PIPEB_DP_LINK_N, dev_priv->savePIPEB_DP_LINK_N);
        }
-       I915_WRITE(FPA0, dev_priv->saveFPA0);
-       I915_WRITE(FPA1, dev_priv->saveFPA1);
-       /* Actually enable it */
-       I915_WRITE(DPLL_A, dev_priv->saveDPLL_A);
-       DRM_UDELAY(150);
-       if (IS_I965G(dev))
-               I915_WRITE(DPLL_A_MD, dev_priv->saveDPLL_A_MD);
-       DRM_UDELAY(150);
-
-       /* Restore mode */
-       I915_WRITE(HTOTAL_A, dev_priv->saveHTOTAL_A);
-       I915_WRITE(HBLANK_A, dev_priv->saveHBLANK_A);
-       I915_WRITE(HSYNC_A, dev_priv->saveHSYNC_A);
-       I915_WRITE(VTOTAL_A, dev_priv->saveVTOTAL_A);
-       I915_WRITE(VBLANK_A, dev_priv->saveVBLANK_A);
-       I915_WRITE(VSYNC_A, dev_priv->saveVSYNC_A);
-       I915_WRITE(BCLRPAT_A, dev_priv->saveBCLRPAT_A);
-
-       /* Restore plane info */
-       I915_WRITE(DSPASIZE, dev_priv->saveDSPASIZE);
-       I915_WRITE(DSPAPOS, dev_priv->saveDSPAPOS);
-       I915_WRITE(PIPEASRC, dev_priv->savePIPEASRC);
-       I915_WRITE(DSPAADDR, dev_priv->saveDSPAADDR);
-       I915_WRITE(DSPASTRIDE, dev_priv->saveDSPASTRIDE);
-       if (IS_I965G(dev)) {
-               I915_WRITE(DSPASURF, dev_priv->saveDSPASURF);
-               I915_WRITE(DSPATILEOFF, dev_priv->saveDSPATILEOFF);
-       }
-
-       I915_WRITE(PIPEACONF, dev_priv->savePIPEACONF);
-
-       i915_restore_palette(dev, PIPE_A);
-       /* Enable the plane */
-       I915_WRITE(DSPACNTR, dev_priv->saveDSPACNTR);
-       I915_WRITE(DSPAADDR, I915_READ(DSPAADDR));
-
-       /* Pipe & plane B info */
-       if (dev_priv->saveDPLL_B & DPLL_VCO_ENABLE) {
-               I915_WRITE(DPLL_B, dev_priv->saveDPLL_B &
-                          ~DPLL_VCO_ENABLE);
-               DRM_UDELAY(150);
-       }
-       I915_WRITE(FPB0, dev_priv->saveFPB0);
-       I915_WRITE(FPB1, dev_priv->saveFPB1);
-       /* Actually enable it */
-       I915_WRITE(DPLL_B, dev_priv->saveDPLL_B);
-       DRM_UDELAY(150);
-       if (IS_I965G(dev))
-               I915_WRITE(DPLL_B_MD, dev_priv->saveDPLL_B_MD);
-       DRM_UDELAY(150);
-
-       /* Restore mode */
-       I915_WRITE(HTOTAL_B, dev_priv->saveHTOTAL_B);
-       I915_WRITE(HBLANK_B, dev_priv->saveHBLANK_B);
-       I915_WRITE(HSYNC_B, dev_priv->saveHSYNC_B);
-       I915_WRITE(VTOTAL_B, dev_priv->saveVTOTAL_B);
-       I915_WRITE(VBLANK_B, dev_priv->saveVBLANK_B);
-       I915_WRITE(VSYNC_B, dev_priv->saveVSYNC_B);
-       I915_WRITE(BCLRPAT_B, dev_priv->saveBCLRPAT_B);
-
-       /* Restore plane info */
-       I915_WRITE(DSPBSIZE, dev_priv->saveDSPBSIZE);
-       I915_WRITE(DSPBPOS, dev_priv->saveDSPBPOS);
-       I915_WRITE(PIPEBSRC, dev_priv->savePIPEBSRC);
-       I915_WRITE(DSPBADDR, dev_priv->saveDSPBADDR);
-       I915_WRITE(DSPBSTRIDE, dev_priv->saveDSPBSTRIDE);
-       if (IS_I965G(dev)) {
-               I915_WRITE(DSPBSURF, dev_priv->saveDSPBSURF);
-               I915_WRITE(DSPBTILEOFF, dev_priv->saveDSPBTILEOFF);
-       }
-
-       I915_WRITE(PIPEBCONF, dev_priv->savePIPEBCONF);
-
-       i915_restore_palette(dev, PIPE_B);
-       /* Enable the plane */
-       I915_WRITE(DSPBCNTR, dev_priv->saveDSPBCNTR);
-       I915_WRITE(DSPBADDR, I915_READ(DSPBADDR));
-
+       /* This is only meaningful in non-KMS mode */
+       /* Don't restore them in KMS mode */
+       i915_restore_modeset_reg(dev);
        /* Cursor state */
        I915_WRITE(CURAPOS, dev_priv->saveCURAPOS);
        I915_WRITE(CURACNTR, dev_priv->saveCURACNTR);
@@ -518,6 +565,12 @@ int i915_restore_state(struct drm_device *dev)
        I915_WRITE(PP_DIVISOR, dev_priv->savePP_DIVISOR);
        I915_WRITE(PP_CONTROL, dev_priv->savePP_CONTROL);
 
+       /* Display Port state */
+       if (SUPPORTS_INTEGRATED_DP(dev)) {
+               I915_WRITE(DP_B, dev_priv->saveDP_B);
+               I915_WRITE(DP_C, dev_priv->saveDP_C);
+               I915_WRITE(DP_D, dev_priv->saveDP_D);
+       }
        /* FIXME: restore TV & SDVO state */
 
        /* FBC info */
index cdd126d068a7283577caf5338ffc5d6d8fe786f0..7cc447191028d70f11b6ea5c0082492d5d0247df 100644 (file)
@@ -97,11 +97,14 @@ static void
 parse_lfp_panel_data(struct drm_i915_private *dev_priv,
                            struct bdb_header *bdb)
 {
+       struct drm_device *dev = dev_priv->dev;
        struct bdb_lvds_options *lvds_options;
        struct bdb_lvds_lfp_data *lvds_lfp_data;
+       struct bdb_lvds_lfp_data_ptrs *lvds_lfp_data_ptrs;
        struct bdb_lvds_lfp_data_entry *entry;
        struct lvds_dvo_timing *dvo_timing;
        struct drm_display_mode *panel_fixed_mode;
+       int lfp_data_size;
 
        /* Defaults if we can't find VBT info */
        dev_priv->lvds_dither = 0;
@@ -119,10 +122,25 @@ parse_lfp_panel_data(struct drm_i915_private *dev_priv,
        if (!lvds_lfp_data)
                return;
 
+       lvds_lfp_data_ptrs = find_section(bdb, BDB_LVDS_LFP_DATA_PTRS);
+       if (!lvds_lfp_data_ptrs)
+               return;
+
        dev_priv->lvds_vbt = 1;
 
-       entry = &lvds_lfp_data->data[lvds_options->panel_type];
-       dvo_timing = &entry->dvo_timing;
+       lfp_data_size = lvds_lfp_data_ptrs->ptr[1].dvo_timing_offset -
+               lvds_lfp_data_ptrs->ptr[0].dvo_timing_offset;
+       entry = (struct bdb_lvds_lfp_data_entry *)
+               ((uint8_t *)lvds_lfp_data->data + (lfp_data_size *
+                                                  lvds_options->panel_type));
+
+       /* On IGDNG mobile, LVDS data block removes panel fitting registers.
+          So dec 2 dword from dvo_timing offset */
+       if (IS_IGDNG(dev))
+               dvo_timing = (struct lvds_dvo_timing *)
+                                       ((u8 *)&entry->dvo_timing - 8);
+       else
+               dvo_timing = &entry->dvo_timing;
 
        panel_fixed_mode = kzalloc(sizeof(*panel_fixed_mode), GFP_KERNEL);
 
@@ -185,10 +203,12 @@ parse_general_features(struct drm_i915_private *dev_priv,
                dev_priv->lvds_use_ssc = general->enable_ssc;
 
                if (dev_priv->lvds_use_ssc) {
-                 if (IS_I855(dev_priv->dev))
-                   dev_priv->lvds_ssc_freq = general->ssc_freq ? 66 : 48;
-                 else
-                   dev_priv->lvds_ssc_freq = general->ssc_freq ? 100 : 96;
+                       if (IS_I85X(dev_priv->dev))
+                               dev_priv->lvds_ssc_freq =
+                                       general->ssc_freq ? 66 : 48;
+                       else
+                               dev_priv->lvds_ssc_freq =
+                                       general->ssc_freq ? 100 : 96;
                }
        }
 }
index 6de97fc66029ed2f28707649f65dfd19ea87d042..d6a1a6e5539a58da94b57ad67e3db54486963a5a 100644 (file)
@@ -46,7 +46,7 @@ static void intel_crt_dpms(struct drm_encoder *encoder, int mode)
 
        temp = I915_READ(reg);
        temp &= ~(ADPA_HSYNC_CNTL_DISABLE | ADPA_VSYNC_CNTL_DISABLE);
-       temp |= ADPA_DAC_ENABLE;
+       temp &= ~ADPA_DAC_ENABLE;
 
        switch(mode) {
        case DRM_MODE_DPMS_ON:
@@ -428,8 +428,34 @@ static void intel_crt_destroy(struct drm_connector *connector)
 
 static int intel_crt_get_modes(struct drm_connector *connector)
 {
+       int ret;
        struct intel_output *intel_output = to_intel_output(connector);
-       return intel_ddc_get_modes(intel_output);
+       struct i2c_adapter *ddcbus;
+       struct drm_device *dev = connector->dev;
+
+
+       ret = intel_ddc_get_modes(intel_output);
+       if (ret || !IS_G4X(dev))
+               goto end;
+
+       ddcbus = intel_output->ddc_bus;
+       /* Try to probe digital port for output in DVI-I -> VGA mode. */
+       intel_output->ddc_bus =
+               intel_i2c_create(connector->dev, GPIOD, "CRTDDC_D");
+
+       if (!intel_output->ddc_bus) {
+               intel_output->ddc_bus = ddcbus;
+               dev_printk(KERN_ERR, &connector->dev->pdev->dev,
+                          "DDC bus registration failed for CRTDDC_D.\n");
+               goto end;
+       }
+       /* Try to get modes by GPIOD port */
+       ret = intel_ddc_get_modes(intel_output);
+       intel_i2c_destroy(ddcbus);
+
+end:
+       return ret;
+
 }
 
 static int intel_crt_set_property(struct drm_connector *connector,
index 3e1c7816211904391c1b65a43a7aace7726db5fc..508838ee31e023f2ac1038236299b7ea7eb4e38b 100644 (file)
  */
 
 #include <linux/i2c.h>
+#include <linux/kernel.h>
 #include "drmP.h"
 #include "intel_drv.h"
 #include "i915_drm.h"
 #include "i915_drv.h"
+#include "intel_dp.h"
 
 #include "drm_crtc_helper.h"
 
 bool intel_pipe_has_type (struct drm_crtc *crtc, int type);
+static void intel_update_watermarks(struct drm_device *dev);
 
 typedef struct {
     /* given values */
@@ -127,19 +130,6 @@ struct intel_limit {
 #define I9XX_P2_LVDS_FAST                    7
 #define I9XX_P2_LVDS_SLOW_LIMIT                 112000
 
-#define INTEL_LIMIT_I8XX_DVO_DAC    0
-#define INTEL_LIMIT_I8XX_LVDS      1
-#define INTEL_LIMIT_I9XX_SDVO_DAC   2
-#define INTEL_LIMIT_I9XX_LVDS      3
-#define INTEL_LIMIT_G4X_SDVO       4
-#define INTEL_LIMIT_G4X_HDMI_DAC   5
-#define INTEL_LIMIT_G4X_SINGLE_CHANNEL_LVDS   6
-#define INTEL_LIMIT_G4X_DUAL_CHANNEL_LVDS   7
-#define INTEL_LIMIT_IGD_SDVO_DAC    8
-#define INTEL_LIMIT_IGD_LVDS       9
-#define INTEL_LIMIT_IGDNG_SDVO_DAC  10
-#define INTEL_LIMIT_IGDNG_LVDS     11
-
 /*The parameter is for SDVO on G4x platform*/
 #define G4X_DOT_SDVO_MIN           25000
 #define G4X_DOT_SDVO_MAX           270000
@@ -218,6 +208,25 @@ struct intel_limit {
 #define G4X_P2_DUAL_CHANNEL_LVDS_FAST           7
 #define G4X_P2_DUAL_CHANNEL_LVDS_LIMIT          0
 
+/*The parameter is for DISPLAY PORT on G4x platform*/
+#define G4X_DOT_DISPLAY_PORT_MIN           161670
+#define G4X_DOT_DISPLAY_PORT_MAX           227000
+#define G4X_N_DISPLAY_PORT_MIN             1
+#define G4X_N_DISPLAY_PORT_MAX             2
+#define G4X_M_DISPLAY_PORT_MIN             97
+#define G4X_M_DISPLAY_PORT_MAX             108
+#define G4X_M1_DISPLAY_PORT_MIN            0x10
+#define G4X_M1_DISPLAY_PORT_MAX            0x12
+#define G4X_M2_DISPLAY_PORT_MIN            0x05
+#define G4X_M2_DISPLAY_PORT_MAX            0x06
+#define G4X_P_DISPLAY_PORT_MIN             10
+#define G4X_P_DISPLAY_PORT_MAX             20
+#define G4X_P1_DISPLAY_PORT_MIN            1
+#define G4X_P1_DISPLAY_PORT_MAX            2
+#define G4X_P2_DISPLAY_PORT_SLOW           10
+#define G4X_P2_DISPLAY_PORT_FAST           10
+#define G4X_P2_DISPLAY_PORT_LIMIT          0
+
 /* IGDNG */
 /* as we calculate clock using (register_value + 2) for
    N/M1/M2, so here the range value for them is (actual_value-2).
@@ -256,8 +265,11 @@ static bool
 intel_igdng_find_best_PLL(const intel_limit_t *limit, struct drm_crtc *crtc,
                        int target, int refclk, intel_clock_t *best_clock);
 
-static const intel_limit_t intel_limits[] = {
-    { /* INTEL_LIMIT_I8XX_DVO_DAC */
+static bool
+intel_find_pll_g4x_dp(const intel_limit_t *, struct drm_crtc *crtc,
+                     int target, int refclk, intel_clock_t *best_clock);
+
+static const intel_limit_t intel_limits_i8xx_dvo = {
         .dot = { .min = I8XX_DOT_MIN,          .max = I8XX_DOT_MAX },
         .vco = { .min = I8XX_VCO_MIN,          .max = I8XX_VCO_MAX },
         .n   = { .min = I8XX_N_MIN,            .max = I8XX_N_MAX },
@@ -269,8 +281,9 @@ static const intel_limit_t intel_limits[] = {
        .p2  = { .dot_limit = I8XX_P2_SLOW_LIMIT,
                 .p2_slow = I8XX_P2_SLOW,       .p2_fast = I8XX_P2_FAST },
        .find_pll = intel_find_best_PLL,
-    },
-    { /* INTEL_LIMIT_I8XX_LVDS */
+};
+
+static const intel_limit_t intel_limits_i8xx_lvds = {
         .dot = { .min = I8XX_DOT_MIN,          .max = I8XX_DOT_MAX },
         .vco = { .min = I8XX_VCO_MIN,          .max = I8XX_VCO_MAX },
         .n   = { .min = I8XX_N_MIN,            .max = I8XX_N_MAX },
@@ -282,8 +295,9 @@ static const intel_limit_t intel_limits[] = {
        .p2  = { .dot_limit = I8XX_P2_SLOW_LIMIT,
                 .p2_slow = I8XX_P2_LVDS_SLOW,  .p2_fast = I8XX_P2_LVDS_FAST },
        .find_pll = intel_find_best_PLL,
-    },
-    { /* INTEL_LIMIT_I9XX_SDVO_DAC */
+};
+       
+static const intel_limit_t intel_limits_i9xx_sdvo = {
         .dot = { .min = I9XX_DOT_MIN,          .max = I9XX_DOT_MAX },
         .vco = { .min = I9XX_VCO_MIN,          .max = I9XX_VCO_MAX },
         .n   = { .min = I9XX_N_MIN,            .max = I9XX_N_MAX },
@@ -295,8 +309,9 @@ static const intel_limit_t intel_limits[] = {
        .p2  = { .dot_limit = I9XX_P2_SDVO_DAC_SLOW_LIMIT,
                 .p2_slow = I9XX_P2_SDVO_DAC_SLOW,      .p2_fast = I9XX_P2_SDVO_DAC_FAST },
        .find_pll = intel_find_best_PLL,
-    },
-    { /* INTEL_LIMIT_I9XX_LVDS */
+};
+
+static const intel_limit_t intel_limits_i9xx_lvds = {
         .dot = { .min = I9XX_DOT_MIN,          .max = I9XX_DOT_MAX },
         .vco = { .min = I9XX_VCO_MIN,          .max = I9XX_VCO_MAX },
         .n   = { .min = I9XX_N_MIN,            .max = I9XX_N_MAX },
@@ -311,9 +326,10 @@ static const intel_limit_t intel_limits[] = {
        .p2  = { .dot_limit = I9XX_P2_LVDS_SLOW_LIMIT,
                 .p2_slow = I9XX_P2_LVDS_SLOW,  .p2_fast = I9XX_P2_LVDS_FAST },
        .find_pll = intel_find_best_PLL,
-    },
+};
+
     /* below parameter and function is for G4X Chipset Family*/
-    { /* INTEL_LIMIT_G4X_SDVO */
+static const intel_limit_t intel_limits_g4x_sdvo = {
        .dot = { .min = G4X_DOT_SDVO_MIN,       .max = G4X_DOT_SDVO_MAX },
        .vco = { .min = G4X_VCO_MIN,            .max = G4X_VCO_MAX},
        .n   = { .min = G4X_N_SDVO_MIN,         .max = G4X_N_SDVO_MAX },
@@ -327,8 +343,9 @@ static const intel_limit_t intel_limits[] = {
                 .p2_fast = G4X_P2_SDVO_FAST
        },
        .find_pll = intel_g4x_find_best_PLL,
-    },
-    { /* INTEL_LIMIT_G4X_HDMI_DAC */
+};
+
+static const intel_limit_t intel_limits_g4x_hdmi = {
        .dot = { .min = G4X_DOT_HDMI_DAC_MIN,   .max = G4X_DOT_HDMI_DAC_MAX },
        .vco = { .min = G4X_VCO_MIN,            .max = G4X_VCO_MAX},
        .n   = { .min = G4X_N_HDMI_DAC_MIN,     .max = G4X_N_HDMI_DAC_MAX },
@@ -342,8 +359,9 @@ static const intel_limit_t intel_limits[] = {
                 .p2_fast = G4X_P2_HDMI_DAC_FAST
        },
        .find_pll = intel_g4x_find_best_PLL,
-    },
-    { /* INTEL_LIMIT_G4X_SINGLE_CHANNEL_LVDS */
+};
+
+static const intel_limit_t intel_limits_g4x_single_channel_lvds = {
        .dot = { .min = G4X_DOT_SINGLE_CHANNEL_LVDS_MIN,
                 .max = G4X_DOT_SINGLE_CHANNEL_LVDS_MAX },
        .vco = { .min = G4X_VCO_MIN,
@@ -365,8 +383,9 @@ static const intel_limit_t intel_limits[] = {
                 .p2_fast = G4X_P2_SINGLE_CHANNEL_LVDS_FAST
        },
        .find_pll = intel_g4x_find_best_PLL,
-    },
-    { /* INTEL_LIMIT_G4X_DUAL_CHANNEL_LVDS */
+};
+
+static const intel_limit_t intel_limits_g4x_dual_channel_lvds = {
        .dot = { .min = G4X_DOT_DUAL_CHANNEL_LVDS_MIN,
                 .max = G4X_DOT_DUAL_CHANNEL_LVDS_MAX },
        .vco = { .min = G4X_VCO_MIN,
@@ -388,8 +407,32 @@ static const intel_limit_t intel_limits[] = {
                 .p2_fast = G4X_P2_DUAL_CHANNEL_LVDS_FAST
        },
        .find_pll = intel_g4x_find_best_PLL,
-    },
-    { /* INTEL_LIMIT_IGD_SDVO */
+};
+
+static const intel_limit_t intel_limits_g4x_display_port = {
+        .dot = { .min = G4X_DOT_DISPLAY_PORT_MIN,
+                 .max = G4X_DOT_DISPLAY_PORT_MAX },
+        .vco = { .min = G4X_VCO_MIN,
+                 .max = G4X_VCO_MAX},
+        .n   = { .min = G4X_N_DISPLAY_PORT_MIN,
+                 .max = G4X_N_DISPLAY_PORT_MAX },
+        .m   = { .min = G4X_M_DISPLAY_PORT_MIN,
+                 .max = G4X_M_DISPLAY_PORT_MAX },
+        .m1  = { .min = G4X_M1_DISPLAY_PORT_MIN,
+                 .max = G4X_M1_DISPLAY_PORT_MAX },
+        .m2  = { .min = G4X_M2_DISPLAY_PORT_MIN,
+                 .max = G4X_M2_DISPLAY_PORT_MAX },
+        .p   = { .min = G4X_P_DISPLAY_PORT_MIN,
+                 .max = G4X_P_DISPLAY_PORT_MAX },
+        .p1  = { .min = G4X_P1_DISPLAY_PORT_MIN,
+                 .max = G4X_P1_DISPLAY_PORT_MAX},
+        .p2  = { .dot_limit = G4X_P2_DISPLAY_PORT_LIMIT,
+                 .p2_slow = G4X_P2_DISPLAY_PORT_SLOW,
+                 .p2_fast = G4X_P2_DISPLAY_PORT_FAST },
+        .find_pll = intel_find_pll_g4x_dp,
+};
+
+static const intel_limit_t intel_limits_igd_sdvo = {
         .dot = { .min = I9XX_DOT_MIN,          .max = I9XX_DOT_MAX},
         .vco = { .min = IGD_VCO_MIN,           .max = IGD_VCO_MAX },
         .n   = { .min = IGD_N_MIN,             .max = IGD_N_MAX },
@@ -401,8 +444,9 @@ static const intel_limit_t intel_limits[] = {
        .p2  = { .dot_limit = I9XX_P2_SDVO_DAC_SLOW_LIMIT,
                 .p2_slow = I9XX_P2_SDVO_DAC_SLOW,      .p2_fast = I9XX_P2_SDVO_DAC_FAST },
        .find_pll = intel_find_best_PLL,
-    },
-    { /* INTEL_LIMIT_IGD_LVDS */
+};
+
+static const intel_limit_t intel_limits_igd_lvds = {
         .dot = { .min = I9XX_DOT_MIN,          .max = I9XX_DOT_MAX },
         .vco = { .min = IGD_VCO_MIN,           .max = IGD_VCO_MAX },
         .n   = { .min = IGD_N_MIN,             .max = IGD_N_MAX },
@@ -415,8 +459,9 @@ static const intel_limit_t intel_limits[] = {
        .p2  = { .dot_limit = I9XX_P2_LVDS_SLOW_LIMIT,
                 .p2_slow = I9XX_P2_LVDS_SLOW,  .p2_fast = I9XX_P2_LVDS_SLOW },
        .find_pll = intel_find_best_PLL,
-    },
-    { /* INTEL_LIMIT_IGDNG_SDVO_DAC */
+};
+
+static const intel_limit_t intel_limits_igdng_sdvo = {
        .dot = { .min = IGDNG_DOT_MIN,          .max = IGDNG_DOT_MAX },
        .vco = { .min = IGDNG_VCO_MIN,          .max = IGDNG_VCO_MAX },
        .n   = { .min = IGDNG_N_MIN,            .max = IGDNG_N_MAX },
@@ -429,8 +474,9 @@ static const intel_limit_t intel_limits[] = {
                 .p2_slow = IGDNG_P2_SDVO_DAC_SLOW,
                 .p2_fast = IGDNG_P2_SDVO_DAC_FAST },
        .find_pll = intel_igdng_find_best_PLL,
-    },
-    { /* INTEL_LIMIT_IGDNG_LVDS */
+};
+
+static const intel_limit_t intel_limits_igdng_lvds = {
        .dot = { .min = IGDNG_DOT_MIN,          .max = IGDNG_DOT_MAX },
        .vco = { .min = IGDNG_VCO_MIN,          .max = IGDNG_VCO_MAX },
        .n   = { .min = IGDNG_N_MIN,            .max = IGDNG_N_MAX },
@@ -443,16 +489,15 @@ static const intel_limit_t intel_limits[] = {
                 .p2_slow = IGDNG_P2_LVDS_SLOW,
                 .p2_fast = IGDNG_P2_LVDS_FAST },
        .find_pll = intel_igdng_find_best_PLL,
-    },
 };
 
 static const intel_limit_t *intel_igdng_limit(struct drm_crtc *crtc)
 {
        const intel_limit_t *limit;
        if (intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS))
-               limit = &intel_limits[INTEL_LIMIT_IGDNG_LVDS];
+               limit = &intel_limits_igdng_lvds;
        else
-               limit = &intel_limits[INTEL_LIMIT_IGDNG_SDVO_DAC];
+               limit = &intel_limits_igdng_sdvo;
 
        return limit;
 }
@@ -467,19 +512,19 @@ static const intel_limit_t *intel_g4x_limit(struct drm_crtc *crtc)
                if ((I915_READ(LVDS) & LVDS_CLKB_POWER_MASK) ==
                    LVDS_CLKB_POWER_UP)
                        /* LVDS with dual channel */
-                       limit = &intel_limits
-                                       [INTEL_LIMIT_G4X_DUAL_CHANNEL_LVDS];
+                       limit = &intel_limits_g4x_dual_channel_lvds;
                else
                        /* LVDS with dual channel */
-                       limit = &intel_limits
-                                       [INTEL_LIMIT_G4X_SINGLE_CHANNEL_LVDS];
+                       limit = &intel_limits_g4x_single_channel_lvds;
        } else if (intel_pipe_has_type(crtc, INTEL_OUTPUT_HDMI) ||
                   intel_pipe_has_type(crtc, INTEL_OUTPUT_ANALOG)) {
-               limit = &intel_limits[INTEL_LIMIT_G4X_HDMI_DAC];
+               limit = &intel_limits_g4x_hdmi;
        } else if (intel_pipe_has_type(crtc, INTEL_OUTPUT_SDVO)) {
-               limit = &intel_limits[INTEL_LIMIT_G4X_SDVO];
+               limit = &intel_limits_g4x_sdvo;
+       } else if (intel_pipe_has_type (crtc, INTEL_OUTPUT_DISPLAYPORT)) {
+               limit = &intel_limits_g4x_display_port;
        } else /* The option is for other outputs */
-               limit = &intel_limits[INTEL_LIMIT_I9XX_SDVO_DAC];
+               limit = &intel_limits_i9xx_sdvo;
 
        return limit;
 }
@@ -495,19 +540,19 @@ static const intel_limit_t *intel_limit(struct drm_crtc *crtc)
                limit = intel_g4x_limit(crtc);
        } else if (IS_I9XX(dev) && !IS_IGD(dev)) {
                if (intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS))
-                       limit = &intel_limits[INTEL_LIMIT_I9XX_LVDS];
+                       limit = &intel_limits_i9xx_lvds;
                else
-                       limit = &intel_limits[INTEL_LIMIT_I9XX_SDVO_DAC];
+                       limit = &intel_limits_i9xx_sdvo;
        } else if (IS_IGD(dev)) {
                if (intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS))
-                       limit = &intel_limits[INTEL_LIMIT_IGD_LVDS];
+                       limit = &intel_limits_igd_lvds;
                else
-                       limit = &intel_limits[INTEL_LIMIT_IGD_SDVO_DAC];
+                       limit = &intel_limits_igd_sdvo;
        } else {
                if (intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS))
-                       limit = &intel_limits[INTEL_LIMIT_I8XX_LVDS];
+                       limit = &intel_limits_i8xx_lvds;
                else
-                       limit = &intel_limits[INTEL_LIMIT_I8XX_DVO_DAC];
+                       limit = &intel_limits_i8xx_dvo;
        }
        return limit;
 }
@@ -764,6 +809,32 @@ out:
        return found;
 }
 
+/* DisplayPort has only two frequencies, 162MHz and 270MHz */
+static bool
+intel_find_pll_g4x_dp(const intel_limit_t *limit, struct drm_crtc *crtc,
+                     int target, int refclk, intel_clock_t *best_clock)
+{
+    intel_clock_t clock;
+    if (target < 200000) {
+       clock.p1 = 2;
+       clock.p2 = 10;
+       clock.n = 2;
+       clock.m1 = 23;
+       clock.m2 = 8;
+    } else {
+       clock.p1 = 1;
+       clock.p2 = 10;
+       clock.n = 1;
+       clock.m1 = 14;
+       clock.m2 = 2;
+    }
+    clock.m = 5 * (clock.m1 + 2) + (clock.m2 + 2);
+    clock.p = (clock.p1 * clock.p2);
+    clock.dot = 96000 * clock.m / (clock.n + 2) / clock.p;
+    memcpy(best_clock, &clock, sizeof(intel_clock_t));
+    return true;
+}
+
 void
 intel_wait_for_vblank(struct drm_device *dev)
 {
@@ -933,7 +1004,7 @@ static void igdng_crtc_dpms(struct drm_crtc *crtc, int mode)
        struct drm_i915_private *dev_priv = dev->dev_private;
        struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
        int pipe = intel_crtc->pipe;
-       int plane = intel_crtc->pipe;
+       int plane = intel_crtc->plane;
        int pch_dpll_reg = (pipe == 0) ? PCH_DPLL_A : PCH_DPLL_B;
        int pipeconf_reg = (pipe == 0) ? PIPEACONF : PIPEBCONF;
        int dspcntr_reg = (plane == 0) ? DSPACNTR : DSPBCNTR;
@@ -1263,8 +1334,10 @@ static void i9xx_crtc_dpms(struct drm_crtc *crtc, int mode)
 
                /* Give the overlay scaler a chance to enable if it's on this pipe */
                //intel_crtc_dpms_video(crtc, true); TODO
+               intel_update_watermarks(dev);
        break;
        case DRM_MODE_DPMS_OFF:
+               intel_update_watermarks(dev);
                /* Give the overlay scaler a chance to disable if it's on this pipe */
                //intel_crtc_dpms_video(crtc, FALSE); TODO
 
@@ -1443,7 +1516,6 @@ static int intel_get_core_clock_speed(struct drm_device *dev)
        return 0; /* Silence gcc warning */
 }
 
-
 /**
  * Return the pipe currently connected to the panel fitter,
  * or -1 if the panel fitter is not present or not in use
@@ -1502,7 +1574,7 @@ igdng_compute_m_n(int bytes_per_pixel, int nlanes,
 
        temp = (u64) DATA_N * pixel_clock;
        temp = div_u64(temp, link_clock);
-       m_n->gmch_m = (temp * bytes_per_pixel) / nlanes;
+       m_n->gmch_m = div_u64(temp * bytes_per_pixel, nlanes);
        m_n->gmch_n = DATA_N;
        fdi_reduce_ratio(&m_n->gmch_m, &m_n->gmch_n);
 
@@ -1513,6 +1585,420 @@ igdng_compute_m_n(int bytes_per_pixel, int nlanes,
 }
 
 
+struct intel_watermark_params {
+       unsigned long fifo_size;
+       unsigned long max_wm;
+       unsigned long default_wm;
+       unsigned long guard_size;
+       unsigned long cacheline_size;
+};
+
+/* IGD has different values for various configs */
+static struct intel_watermark_params igd_display_wm = {
+       IGD_DISPLAY_FIFO,
+       IGD_MAX_WM,
+       IGD_DFT_WM,
+       IGD_GUARD_WM,
+       IGD_FIFO_LINE_SIZE
+};
+static struct intel_watermark_params igd_display_hplloff_wm = {
+       IGD_DISPLAY_FIFO,
+       IGD_MAX_WM,
+       IGD_DFT_HPLLOFF_WM,
+       IGD_GUARD_WM,
+       IGD_FIFO_LINE_SIZE
+};
+static struct intel_watermark_params igd_cursor_wm = {
+       IGD_CURSOR_FIFO,
+       IGD_CURSOR_MAX_WM,
+       IGD_CURSOR_DFT_WM,
+       IGD_CURSOR_GUARD_WM,
+       IGD_FIFO_LINE_SIZE,
+};
+static struct intel_watermark_params igd_cursor_hplloff_wm = {
+       IGD_CURSOR_FIFO,
+       IGD_CURSOR_MAX_WM,
+       IGD_CURSOR_DFT_WM,
+       IGD_CURSOR_GUARD_WM,
+       IGD_FIFO_LINE_SIZE
+};
+static struct intel_watermark_params i945_wm_info = {
+       I915_FIFO_LINE_SIZE,
+       I915_MAX_WM,
+       1,
+       0,
+       IGD_FIFO_LINE_SIZE
+};
+static struct intel_watermark_params i915_wm_info = {
+       I945_FIFO_SIZE,
+       I915_MAX_WM,
+       1,
+       0,
+       I915_FIFO_LINE_SIZE
+};
+static struct intel_watermark_params i855_wm_info = {
+       I855GM_FIFO_SIZE,
+       I915_MAX_WM,
+       1,
+       0,
+       I830_FIFO_LINE_SIZE
+};
+static struct intel_watermark_params i830_wm_info = {
+       I830_FIFO_SIZE,
+       I915_MAX_WM,
+       1,
+       0,
+       I830_FIFO_LINE_SIZE
+};
+
+static unsigned long intel_calculate_wm(unsigned long clock_in_khz,
+                                       struct intel_watermark_params *wm,
+                                       int pixel_size,
+                                       unsigned long latency_ns)
+{
+       unsigned long bytes_required, wm_size;
+
+       bytes_required = (clock_in_khz * pixel_size * latency_ns) / 1000000;
+       bytes_required /= wm->cacheline_size;
+       wm_size = wm->fifo_size - bytes_required - wm->guard_size;
+
+       if (wm_size > wm->max_wm)
+               wm_size = wm->max_wm;
+       if (wm_size == 0)
+               wm_size = wm->default_wm;
+       return wm_size;
+}
+
+struct cxsr_latency {
+       int is_desktop;
+       unsigned long fsb_freq;
+       unsigned long mem_freq;
+       unsigned long display_sr;
+       unsigned long display_hpll_disable;
+       unsigned long cursor_sr;
+       unsigned long cursor_hpll_disable;
+};
+
+static struct cxsr_latency cxsr_latency_table[] = {
+       {1, 800, 400, 3382, 33382, 3983, 33983},    /* DDR2-400 SC */
+       {1, 800, 667, 3354, 33354, 3807, 33807},    /* DDR2-667 SC */
+       {1, 800, 800, 3347, 33347, 3763, 33763},    /* DDR2-800 SC */
+
+       {1, 667, 400, 3400, 33400, 4021, 34021},    /* DDR2-400 SC */
+       {1, 667, 667, 3372, 33372, 3845, 33845},    /* DDR2-667 SC */
+       {1, 667, 800, 3386, 33386, 3822, 33822},    /* DDR2-800 SC */
+
+       {1, 400, 400, 3472, 33472, 4173, 34173},    /* DDR2-400 SC */
+       {1, 400, 667, 3443, 33443, 3996, 33996},    /* DDR2-667 SC */
+       {1, 400, 800, 3430, 33430, 3946, 33946},    /* DDR2-800 SC */
+
+       {0, 800, 400, 3438, 33438, 4065, 34065},    /* DDR2-400 SC */
+       {0, 800, 667, 3410, 33410, 3889, 33889},    /* DDR2-667 SC */
+       {0, 800, 800, 3403, 33403, 3845, 33845},    /* DDR2-800 SC */
+
+       {0, 667, 400, 3456, 33456, 4103, 34106},    /* DDR2-400 SC */
+       {0, 667, 667, 3428, 33428, 3927, 33927},    /* DDR2-667 SC */
+       {0, 667, 800, 3443, 33443, 3905, 33905},    /* DDR2-800 SC */
+
+       {0, 400, 400, 3528, 33528, 4255, 34255},    /* DDR2-400 SC */
+       {0, 400, 667, 3500, 33500, 4079, 34079},    /* DDR2-667 SC */
+       {0, 400, 800, 3487, 33487, 4029, 34029},    /* DDR2-800 SC */
+};
+
+static struct cxsr_latency *intel_get_cxsr_latency(int is_desktop, int fsb,
+                                                  int mem)
+{
+       int i;
+       struct cxsr_latency *latency;
+
+       if (fsb == 0 || mem == 0)
+               return NULL;
+
+       for (i = 0; i < ARRAY_SIZE(cxsr_latency_table); i++) {
+               latency = &cxsr_latency_table[i];
+               if (is_desktop == latency->is_desktop &&
+                       fsb == latency->fsb_freq && mem == latency->mem_freq)
+                       break;
+       }
+       if (i >= ARRAY_SIZE(cxsr_latency_table)) {
+               DRM_DEBUG("Unknown FSB/MEM found, disable CxSR\n");
+               return NULL;
+       }
+       return latency;
+}
+
+static void igd_disable_cxsr(struct drm_device *dev)
+{
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       u32 reg;
+
+       /* deactivate cxsr */
+       reg = I915_READ(DSPFW3);
+       reg &= ~(IGD_SELF_REFRESH_EN);
+       I915_WRITE(DSPFW3, reg);
+       DRM_INFO("Big FIFO is disabled\n");
+}
+
+static void igd_enable_cxsr(struct drm_device *dev, unsigned long clock,
+                           int pixel_size)
+{
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       u32 reg;
+       unsigned long wm;
+       struct cxsr_latency *latency;
+
+       latency = intel_get_cxsr_latency(IS_IGDG(dev), dev_priv->fsb_freq,
+               dev_priv->mem_freq);
+       if (!latency) {
+               DRM_DEBUG("Unknown FSB/MEM found, disable CxSR\n");
+               igd_disable_cxsr(dev);
+               return;
+       }
+
+       /* Display SR */
+       wm = intel_calculate_wm(clock, &igd_display_wm, pixel_size,
+                               latency->display_sr);
+       reg = I915_READ(DSPFW1);
+       reg &= 0x7fffff;
+       reg |= wm << 23;
+       I915_WRITE(DSPFW1, reg);
+       DRM_DEBUG("DSPFW1 register is %x\n", reg);
+
+       /* cursor SR */
+       wm = intel_calculate_wm(clock, &igd_cursor_wm, pixel_size,
+                               latency->cursor_sr);
+       reg = I915_READ(DSPFW3);
+       reg &= ~(0x3f << 24);
+       reg |= (wm & 0x3f) << 24;
+       I915_WRITE(DSPFW3, reg);
+
+       /* Display HPLL off SR */
+       wm = intel_calculate_wm(clock, &igd_display_hplloff_wm,
+               latency->display_hpll_disable, I915_FIFO_LINE_SIZE);
+       reg = I915_READ(DSPFW3);
+       reg &= 0xfffffe00;
+       reg |= wm & 0x1ff;
+       I915_WRITE(DSPFW3, reg);
+
+       /* cursor HPLL off SR */
+       wm = intel_calculate_wm(clock, &igd_cursor_hplloff_wm, pixel_size,
+                               latency->cursor_hpll_disable);
+       reg = I915_READ(DSPFW3);
+       reg &= ~(0x3f << 16);
+       reg |= (wm & 0x3f) << 16;
+       I915_WRITE(DSPFW3, reg);
+       DRM_DEBUG("DSPFW3 register is %x\n", reg);
+
+       /* activate cxsr */
+       reg = I915_READ(DSPFW3);
+       reg |= IGD_SELF_REFRESH_EN;
+       I915_WRITE(DSPFW3, reg);
+
+       DRM_INFO("Big FIFO is enabled\n");
+
+       return;
+}
+
+const static int latency_ns = 5000; /* default for non-igd platforms */
+
+
+static void i965_update_wm(struct drm_device *dev)
+{
+       struct drm_i915_private *dev_priv = dev->dev_private;
+
+       DRM_DEBUG("Setting FIFO watermarks - A: 8, B: 8, C: 8, SR 8\n");
+
+       /* 965 has limitations... */
+       I915_WRITE(DSPFW1, (8 << 16) | (8 << 8) | (8 << 0));
+       I915_WRITE(DSPFW2, (8 << 8) | (8 << 0));
+}
+
+static void i9xx_update_wm(struct drm_device *dev, int planea_clock,
+                          int planeb_clock, int sr_hdisplay, int pixel_size)
+{
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       uint32_t fwater_lo = I915_READ(FW_BLC) & MM_FIFO_WATERMARK;
+       uint32_t fwater_hi = I915_READ(FW_BLC2) & LM_FIFO_WATERMARK;
+       int bsize, asize, cwm, bwm = 1, awm = 1, srwm = 1;
+       uint32_t dsparb = I915_READ(DSPARB);
+       int planea_entries, planeb_entries;
+       struct intel_watermark_params *wm_params;
+       unsigned long line_time_us;
+       int sr_clock, sr_entries = 0;
+
+       if (IS_I965GM(dev) || IS_I945GM(dev))
+               wm_params = &i945_wm_info;
+       else if (IS_I9XX(dev))
+               wm_params = &i915_wm_info;
+       else
+               wm_params = &i855_wm_info;
+
+       planea_entries = intel_calculate_wm(planea_clock, wm_params,
+                                           pixel_size, latency_ns);
+       planeb_entries = intel_calculate_wm(planeb_clock, wm_params,
+                                           pixel_size, latency_ns);
+
+       DRM_DEBUG("FIFO entries - A: %d, B: %d\n", planea_entries,
+                 planeb_entries);
+
+       if (IS_I9XX(dev)) {
+               asize = dsparb & 0x7f;
+               bsize = (dsparb >> DSPARB_CSTART_SHIFT) & 0x7f;
+       } else {
+               asize = dsparb & 0x1ff;
+               bsize = (dsparb >> DSPARB_BEND_SHIFT) & 0x1ff;
+       }
+       DRM_DEBUG("FIFO size - A: %d, B: %d\n", asize, bsize);
+
+       /* Two extra entries for padding */
+       awm = asize - (planea_entries + 2);
+       bwm = bsize - (planeb_entries + 2);
+
+       /* Sanity check against potentially bad FIFO allocations */
+       if (awm <= 0) {
+               /* pipe is on but has too few FIFO entries */
+               if (planea_entries != 0)
+                       DRM_DEBUG("plane A needs more FIFO entries\n");
+               awm = 1;
+       }
+       if (bwm <= 0) {
+               if (planeb_entries != 0)
+                       DRM_DEBUG("plane B needs more FIFO entries\n");
+               bwm = 1;
+       }
+
+       /*
+        * Overlay gets an aggressive default since video jitter is bad.
+        */
+       cwm = 2;
+
+       /* Calc sr entries for one pipe configs */
+       if (!planea_clock || !planeb_clock) {
+               sr_clock = planea_clock ? planea_clock : planeb_clock;
+               line_time_us = (sr_hdisplay * 1000) / sr_clock;
+               sr_entries = (((latency_ns / line_time_us) + 1) * pixel_size *
+                             sr_hdisplay) / 1000;
+               sr_entries = roundup(sr_entries / wm_params->cacheline_size, 1);
+               if (sr_entries < wm_params->fifo_size)
+                       srwm = wm_params->fifo_size - sr_entries;
+       }
+
+       DRM_DEBUG("Setting FIFO watermarks - A: %d, B: %d, C: %d, SR %d\n",
+                 awm, bwm, cwm, srwm);
+
+       fwater_lo = fwater_lo | ((bwm & 0x3f) << 16) | (awm & 0x3f);
+       fwater_hi = fwater_hi | (cwm & 0x1f);
+
+       I915_WRITE(FW_BLC, fwater_lo);
+       I915_WRITE(FW_BLC2, fwater_hi);
+       if (IS_I9XX(dev))
+               I915_WRITE(FW_BLC_SELF, FW_BLC_SELF_EN | (srwm & 0x3f));
+}
+
+static void i830_update_wm(struct drm_device *dev, int planea_clock,
+                          int pixel_size)
+{
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       uint32_t dsparb = I915_READ(DSPARB);
+       uint32_t fwater_lo = I915_READ(FW_BLC) & MM_FIFO_WATERMARK;
+       unsigned int asize, awm;
+       int planea_entries;
+
+       planea_entries = intel_calculate_wm(planea_clock, &i830_wm_info,
+                                           pixel_size, latency_ns);
+
+       asize = dsparb & 0x7f;
+
+       awm = asize - planea_entries;
+
+       fwater_lo = fwater_lo | awm;
+
+       I915_WRITE(FW_BLC, fwater_lo);
+}
+
+/**
+ * intel_update_watermarks - update FIFO watermark values based on current modes
+ *
+ * Calculate watermark values for the various WM regs based on current mode
+ * and plane configuration.
+ *
+ * There are several cases to deal with here:
+ *   - normal (i.e. non-self-refresh)
+ *   - self-refresh (SR) mode
+ *   - lines are large relative to FIFO size (buffer can hold up to 2)
+ *   - lines are small relative to FIFO size (buffer can hold more than 2
+ *     lines), so need to account for TLB latency
+ *
+ *   The normal calculation is:
+ *     watermark = dotclock * bytes per pixel * latency
+ *   where latency is platform & configuration dependent (we assume pessimal
+ *   values here).
+ *
+ *   The SR calculation is:
+ *     watermark = (trunc(latency/line time)+1) * surface width *
+ *       bytes per pixel
+ *   where
+ *     line time = htotal / dotclock
+ *   and latency is assumed to be high, as above.
+ *
+ * The final value programmed to the register should always be rounded up,
+ * and include an extra 2 entries to account for clock crossings.
+ *
+ * We don't use the sprite, so we can ignore that.  And on Crestline we have
+ * to set the non-SR watermarks to 8.
+  */
+static void intel_update_watermarks(struct drm_device *dev)
+{
+       struct drm_crtc *crtc;
+       struct intel_crtc *intel_crtc;
+       int sr_hdisplay = 0;
+       unsigned long planea_clock = 0, planeb_clock = 0, sr_clock = 0;
+       int enabled = 0, pixel_size = 0;
+
+       if (DSPARB_HWCONTROL(dev))
+               return;
+
+       /* Get the clock config from both planes */
+       list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
+               intel_crtc = to_intel_crtc(crtc);
+               if (crtc->enabled) {
+                       enabled++;
+                       if (intel_crtc->plane == 0) {
+                               DRM_DEBUG("plane A (pipe %d) clock: %d\n",
+                                         intel_crtc->pipe, crtc->mode.clock);
+                               planea_clock = crtc->mode.clock;
+                       } else {
+                               DRM_DEBUG("plane B (pipe %d) clock: %d\n",
+                                         intel_crtc->pipe, crtc->mode.clock);
+                               planeb_clock = crtc->mode.clock;
+                       }
+                       sr_hdisplay = crtc->mode.hdisplay;
+                       sr_clock = crtc->mode.clock;
+                       if (crtc->fb)
+                               pixel_size = crtc->fb->bits_per_pixel / 8;
+                       else
+                               pixel_size = 4; /* by default */
+               }
+       }
+
+       if (enabled <= 0)
+               return;
+
+       /* Single pipe configs can enable self refresh */
+       if (enabled == 1 && IS_IGD(dev))
+               igd_enable_cxsr(dev, sr_clock, pixel_size);
+       else if (IS_IGD(dev))
+               igd_disable_cxsr(dev);
+
+       if (IS_I965G(dev))
+               i965_update_wm(dev);
+       else if (IS_I9XX(dev) || IS_MOBILE(dev))
+               i9xx_update_wm(dev, planea_clock, planeb_clock, sr_hdisplay,
+                              pixel_size);
+       else
+               i830_update_wm(dev, planea_clock, pixel_size);
+}
+
 static int intel_crtc_mode_set(struct drm_crtc *crtc,
                               struct drm_display_mode *mode,
                               struct drm_display_mode *adjusted_mode,
@@ -1541,7 +2027,7 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc,
        intel_clock_t clock;
        u32 dpll = 0, fp = 0, dspcntr, pipeconf;
        bool ok, is_sdvo = false, is_dvo = false;
-       bool is_crt = false, is_lvds = false, is_tv = false;
+       bool is_crt = false, is_lvds = false, is_tv = false, is_dp = false;
        struct drm_mode_config *mode_config = &dev->mode_config;
        struct drm_connector *connector;
        const intel_limit_t *limit;
@@ -1585,6 +2071,9 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc,
                case INTEL_OUTPUT_ANALOG:
                        is_crt = true;
                        break;
+               case INTEL_OUTPUT_DISPLAYPORT:
+                       is_dp = true;
+                       break;
                }
 
                num_outputs++;
@@ -1600,6 +2089,7 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc,
        } else {
                refclk = 48000;
        }
+       
 
        /*
         * Returns a set of divisors for the desired target clock with the given
@@ -1662,6 +2152,8 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc,
                        else if (IS_IGDNG(dev))
                                dpll |= (sdvo_pixel_multiply - 1) << PLL_REF_SDVO_HDMI_MULTIPLIER_SHIFT;
                }
+               if (is_dp)
+                       dpll |= DPLL_DVO_HIGH_SPEED;
 
                /* compute bitmask from p1 value */
                if (IS_IGD(dev))
@@ -1809,6 +2301,8 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc,
                I915_WRITE(lvds_reg, lvds);
                I915_READ(lvds_reg);
        }
+       if (is_dp)
+               intel_dp_set_m_n(crtc, mode, adjusted_mode);
 
        I915_WRITE(fp_reg, fp);
        I915_WRITE(dpll_reg, dpll);
@@ -1871,6 +2365,9 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc,
 
        /* Flush the plane changes */
        ret = intel_pipe_set_base(crtc, x, y, old_fb);
+
+       intel_update_watermarks(dev);
+
        drm_vblank_post_modeset(dev, pipe);
 
        return ret;
@@ -2359,6 +2856,7 @@ static void intel_crtc_init(struct drm_device *dev, int pipe)
 
        drm_mode_crtc_set_gamma_size(&intel_crtc->base, 256);
        intel_crtc->pipe = pipe;
+       intel_crtc->plane = pipe;
        for (i = 0; i < 256; i++) {
                intel_crtc->lut_r[i] = i;
                intel_crtc->lut_g[i] = i;
@@ -2475,6 +2973,8 @@ static void intel_setup_outputs(struct drm_device *dev)
                        found = intel_sdvo_init(dev, SDVOB);
                        if (!found && SUPPORTS_INTEGRATED_HDMI(dev))
                                intel_hdmi_init(dev, SDVOB);
+                       if (!found && SUPPORTS_INTEGRATED_DP(dev))
+                               intel_dp_init(dev, DP_B);
                }
 
                /* Before G4X SDVOC doesn't have its own detect register */
@@ -2487,7 +2987,11 @@ static void intel_setup_outputs(struct drm_device *dev)
                        found = intel_sdvo_init(dev, SDVOC);
                        if (!found && SUPPORTS_INTEGRATED_HDMI(dev))
                                intel_hdmi_init(dev, SDVOC);
+                       if (!found && SUPPORTS_INTEGRATED_DP(dev))
+                               intel_dp_init(dev, DP_C);
                }
+               if (SUPPORTS_INTEGRATED_DP(dev) && (I915_READ(DP_D) & DP_DETECTED))
+                       intel_dp_init(dev, DP_D);
        } else
                intel_dvo_init(dev);
 
@@ -2530,6 +3034,11 @@ static void intel_setup_outputs(struct drm_device *dev)
                                     (1 << 1));
                        clone_mask = (1 << INTEL_OUTPUT_TVOUT);
                        break;
+               case INTEL_OUTPUT_DISPLAYPORT:
+                       crtc_mask = ((1 << 0) |
+                                    (1 << 1));
+                       clone_mask = (1 << INTEL_OUTPUT_DISPLAYPORT);
+                       break;
                }
                encoder->possible_crtcs = crtc_mask;
                encoder->possible_clones = intel_connector_clones(dev, clone_mask);
diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c
new file mode 100644 (file)
index 0000000..6770ae8
--- /dev/null
@@ -0,0 +1,1156 @@
+/*
+ * Copyright Â© 2008 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ *
+ * Authors:
+ *    Keith Packard <keithp@keithp.com>
+ *
+ */
+
+#include <linux/i2c.h>
+#include "drmP.h"
+#include "drm.h"
+#include "drm_crtc.h"
+#include "drm_crtc_helper.h"
+#include "intel_drv.h"
+#include "i915_drm.h"
+#include "i915_drv.h"
+#include "intel_dp.h"
+
+#define DP_LINK_STATUS_SIZE    6
+#define DP_LINK_CHECK_TIMEOUT  (10 * 1000)
+
+#define DP_LINK_CONFIGURATION_SIZE     9
+
+struct intel_dp_priv {
+       uint32_t output_reg;
+       uint32_t DP;
+       uint8_t  link_configuration[DP_LINK_CONFIGURATION_SIZE];
+       uint32_t save_DP;
+       uint8_t  save_link_configuration[DP_LINK_CONFIGURATION_SIZE];
+       bool has_audio;
+       int dpms_mode;
+       uint8_t link_bw;
+       uint8_t lane_count;
+       uint8_t dpcd[4];
+       struct intel_output *intel_output;
+       struct i2c_adapter adapter;
+       struct i2c_algo_dp_aux_data algo;
+};
+
+static void
+intel_dp_link_train(struct intel_output *intel_output, uint32_t DP,
+                   uint8_t link_configuration[DP_LINK_CONFIGURATION_SIZE]);
+
+static void
+intel_dp_link_down(struct intel_output *intel_output, uint32_t DP);
+
+static int
+intel_dp_max_lane_count(struct intel_output *intel_output)
+{
+       struct intel_dp_priv   *dp_priv = intel_output->dev_priv;
+       int max_lane_count = 4;
+
+       if (dp_priv->dpcd[0] >= 0x11) {
+               max_lane_count = dp_priv->dpcd[2] & 0x1f;
+               switch (max_lane_count) {
+               case 1: case 2: case 4:
+                       break;
+               default:
+                       max_lane_count = 4;
+               }
+       }
+       return max_lane_count;
+}
+
+static int
+intel_dp_max_link_bw(struct intel_output *intel_output)
+{
+       struct intel_dp_priv   *dp_priv = intel_output->dev_priv;
+       int max_link_bw = dp_priv->dpcd[1];
+
+       switch (max_link_bw) {
+       case DP_LINK_BW_1_62:
+       case DP_LINK_BW_2_7:
+               break;
+       default:
+               max_link_bw = DP_LINK_BW_1_62;
+               break;
+       }
+       return max_link_bw;
+}
+
+static int
+intel_dp_link_clock(uint8_t link_bw)
+{
+       if (link_bw == DP_LINK_BW_2_7)
+               return 270000;
+       else
+               return 162000;
+}
+
+/* I think this is a fiction */
+static int
+intel_dp_link_required(int pixel_clock)
+{
+       return pixel_clock * 3;
+}
+
+static int
+intel_dp_mode_valid(struct drm_connector *connector,
+                   struct drm_display_mode *mode)
+{
+       struct intel_output *intel_output = to_intel_output(connector);
+       int max_link_clock = intel_dp_link_clock(intel_dp_max_link_bw(intel_output));
+       int max_lanes = intel_dp_max_lane_count(intel_output);
+
+       if (intel_dp_link_required(mode->clock) > max_link_clock * max_lanes)
+               return MODE_CLOCK_HIGH;
+
+       if (mode->clock < 10000)
+               return MODE_CLOCK_LOW;
+
+       return MODE_OK;
+}
+
+static uint32_t
+pack_aux(uint8_t *src, int src_bytes)
+{
+       int     i;
+       uint32_t v = 0;
+
+       if (src_bytes > 4)
+               src_bytes = 4;
+       for (i = 0; i < src_bytes; i++)
+               v |= ((uint32_t) src[i]) << ((3-i) * 8);
+       return v;
+}
+
+static void
+unpack_aux(uint32_t src, uint8_t *dst, int dst_bytes)
+{
+       int i;
+       if (dst_bytes > 4)
+               dst_bytes = 4;
+       for (i = 0; i < dst_bytes; i++)
+               dst[i] = src >> ((3-i) * 8);
+}
+
+/* hrawclock is 1/4 the FSB frequency */
+static int
+intel_hrawclk(struct drm_device *dev)
+{
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       uint32_t clkcfg;
+
+       clkcfg = I915_READ(CLKCFG);
+       switch (clkcfg & CLKCFG_FSB_MASK) {
+       case CLKCFG_FSB_400:
+               return 100;
+       case CLKCFG_FSB_533:
+               return 133;
+       case CLKCFG_FSB_667:
+               return 166;
+       case CLKCFG_FSB_800:
+               return 200;
+       case CLKCFG_FSB_1067:
+               return 266;
+       case CLKCFG_FSB_1333:
+               return 333;
+       /* these two are just a guess; one of them might be right */
+       case CLKCFG_FSB_1600:
+       case CLKCFG_FSB_1600_ALT:
+               return 400;
+       default:
+               return 133;
+       }
+}
+
+static int
+intel_dp_aux_ch(struct intel_output *intel_output,
+               uint8_t *send, int send_bytes,
+               uint8_t *recv, int recv_size)
+{
+       struct intel_dp_priv *dp_priv = intel_output->dev_priv;
+       uint32_t output_reg = dp_priv->output_reg;
+       struct drm_device *dev = intel_output->base.dev;
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       uint32_t ch_ctl = output_reg + 0x10;
+       uint32_t ch_data = ch_ctl + 4;
+       int i;
+       int recv_bytes;
+       uint32_t ctl;
+       uint32_t status;
+       uint32_t aux_clock_divider;
+       int try;
+
+       /* The clock divider is based off the hrawclk,
+        * and would like to run at 2MHz. So, take the
+        * hrawclk value and divide by 2 and use that
+        */
+       aux_clock_divider = intel_hrawclk(dev) / 2;
+       /* Must try at least 3 times according to DP spec */
+       for (try = 0; try < 5; try++) {
+               /* Load the send data into the aux channel data registers */
+               for (i = 0; i < send_bytes; i += 4) {
+                       uint32_t    d = pack_aux(send + i, send_bytes - i);;
+       
+                       I915_WRITE(ch_data + i, d);
+               }
+       
+               ctl = (DP_AUX_CH_CTL_SEND_BUSY |
+                      DP_AUX_CH_CTL_TIME_OUT_400us |
+                      (send_bytes << DP_AUX_CH_CTL_MESSAGE_SIZE_SHIFT) |
+                      (5 << DP_AUX_CH_CTL_PRECHARGE_2US_SHIFT) |
+                      (aux_clock_divider << DP_AUX_CH_CTL_BIT_CLOCK_2X_SHIFT) |
+                      DP_AUX_CH_CTL_DONE |
+                      DP_AUX_CH_CTL_TIME_OUT_ERROR |
+                      DP_AUX_CH_CTL_RECEIVE_ERROR);
+       
+               /* Send the command and wait for it to complete */
+               I915_WRITE(ch_ctl, ctl);
+               (void) I915_READ(ch_ctl);
+               for (;;) {
+                       udelay(100);
+                       status = I915_READ(ch_ctl);
+                       if ((status & DP_AUX_CH_CTL_SEND_BUSY) == 0)
+                               break;
+               }
+       
+               /* Clear done status and any errors */
+               I915_WRITE(ch_ctl, (ctl |
+                               DP_AUX_CH_CTL_DONE |
+                               DP_AUX_CH_CTL_TIME_OUT_ERROR |
+                               DP_AUX_CH_CTL_RECEIVE_ERROR));
+               (void) I915_READ(ch_ctl);
+               if ((status & DP_AUX_CH_CTL_TIME_OUT_ERROR) == 0)
+                       break;
+       }
+
+       if ((status & DP_AUX_CH_CTL_DONE) == 0) {
+               DRM_ERROR("dp_aux_ch not done status 0x%08x\n", status);
+               return -EBUSY;
+       }
+
+       /* Check for timeout or receive error.
+        * Timeouts occur when the sink is not connected
+        */
+       if (status & DP_AUX_CH_CTL_RECEIVE_ERROR) {
+               DRM_ERROR("dp_aux_ch receive error status 0x%08x\n", status);
+               return -EIO;
+       }
+
+       /* Timeouts occur when the device isn't connected, so they're
+        * "normal" -- don't fill the kernel log with these */
+       if (status & DP_AUX_CH_CTL_TIME_OUT_ERROR) {
+               DRM_DEBUG("dp_aux_ch timeout status 0x%08x\n", status);
+               return -ETIMEDOUT;
+       }
+
+       /* Unload any bytes sent back from the other side */
+       recv_bytes = ((status & DP_AUX_CH_CTL_MESSAGE_SIZE_MASK) >>
+                     DP_AUX_CH_CTL_MESSAGE_SIZE_SHIFT);
+
+       if (recv_bytes > recv_size)
+               recv_bytes = recv_size;
+       
+       for (i = 0; i < recv_bytes; i += 4) {
+               uint32_t    d = I915_READ(ch_data + i);
+
+               unpack_aux(d, recv + i, recv_bytes - i);
+       }
+
+       return recv_bytes;
+}
+
+/* Write data to the aux channel in native mode */
+static int
+intel_dp_aux_native_write(struct intel_output *intel_output,
+                         uint16_t address, uint8_t *send, int send_bytes)
+{
+       int ret;
+       uint8_t msg[20];
+       int msg_bytes;
+       uint8_t ack;
+
+       if (send_bytes > 16)
+               return -1;
+       msg[0] = AUX_NATIVE_WRITE << 4;
+       msg[1] = address >> 8;
+       msg[2] = address;
+       msg[3] = send_bytes - 1;
+       memcpy(&msg[4], send, send_bytes);
+       msg_bytes = send_bytes + 4;
+       for (;;) {
+               ret = intel_dp_aux_ch(intel_output, msg, msg_bytes, &ack, 1);
+               if (ret < 0)
+                       return ret;
+               if ((ack & AUX_NATIVE_REPLY_MASK) == AUX_NATIVE_REPLY_ACK)
+                       break;
+               else if ((ack & AUX_NATIVE_REPLY_MASK) == AUX_NATIVE_REPLY_DEFER)
+                       udelay(100);
+               else
+                       return -EIO;
+       }
+       return send_bytes;
+}
+
+/* Write a single byte to the aux channel in native mode */
+static int
+intel_dp_aux_native_write_1(struct intel_output *intel_output,
+                           uint16_t address, uint8_t byte)
+{
+       return intel_dp_aux_native_write(intel_output, address, &byte, 1);
+}
+
+/* read bytes from a native aux channel */
+static int
+intel_dp_aux_native_read(struct intel_output *intel_output,
+                        uint16_t address, uint8_t *recv, int recv_bytes)
+{
+       uint8_t msg[4];
+       int msg_bytes;
+       uint8_t reply[20];
+       int reply_bytes;
+       uint8_t ack;
+       int ret;
+
+       msg[0] = AUX_NATIVE_READ << 4;
+       msg[1] = address >> 8;
+       msg[2] = address & 0xff;
+       msg[3] = recv_bytes - 1;
+
+       msg_bytes = 4;
+       reply_bytes = recv_bytes + 1;
+
+       for (;;) {
+               ret = intel_dp_aux_ch(intel_output, msg, msg_bytes,
+                                     reply, reply_bytes);
+               if (ret == 0)
+                       return -EPROTO;
+               if (ret < 0)
+                       return ret;
+               ack = reply[0];
+               if ((ack & AUX_NATIVE_REPLY_MASK) == AUX_NATIVE_REPLY_ACK) {
+                       memcpy(recv, reply + 1, ret - 1);
+                       return ret - 1;
+               }
+               else if ((ack & AUX_NATIVE_REPLY_MASK) == AUX_NATIVE_REPLY_DEFER)
+                       udelay(100);
+               else
+                       return -EIO;
+       }
+}
+
+static int
+intel_dp_i2c_aux_ch(struct i2c_adapter *adapter,
+                   uint8_t *send, int send_bytes,
+                   uint8_t *recv, int recv_bytes)
+{
+       struct intel_dp_priv *dp_priv = container_of(adapter,
+                                                    struct intel_dp_priv,
+                                                    adapter);
+       struct intel_output *intel_output = dp_priv->intel_output;
+
+       return intel_dp_aux_ch(intel_output,
+                              send, send_bytes, recv, recv_bytes);
+}
+
+static int
+intel_dp_i2c_init(struct intel_output *intel_output, const char *name)
+{
+       struct intel_dp_priv   *dp_priv = intel_output->dev_priv;
+
+       DRM_ERROR("i2c_init %s\n", name);
+       dp_priv->algo.running = false;
+       dp_priv->algo.address = 0;
+       dp_priv->algo.aux_ch = intel_dp_i2c_aux_ch;
+
+       memset(&dp_priv->adapter, '\0', sizeof (dp_priv->adapter));
+       dp_priv->adapter.owner = THIS_MODULE;
+       dp_priv->adapter.class = I2C_CLASS_DDC;
+       strncpy (dp_priv->adapter.name, name, sizeof dp_priv->adapter.name - 1);
+       dp_priv->adapter.name[sizeof dp_priv->adapter.name - 1] = '\0';
+       dp_priv->adapter.algo_data = &dp_priv->algo;
+       dp_priv->adapter.dev.parent = &intel_output->base.kdev;
+       
+       return i2c_dp_aux_add_bus(&dp_priv->adapter);
+}
+
+static bool
+intel_dp_mode_fixup(struct drm_encoder *encoder, struct drm_display_mode *mode,
+                   struct drm_display_mode *adjusted_mode)
+{
+       struct intel_output *intel_output = enc_to_intel_output(encoder);
+       struct intel_dp_priv   *dp_priv = intel_output->dev_priv;
+       int lane_count, clock;
+       int max_lane_count = intel_dp_max_lane_count(intel_output);
+       int max_clock = intel_dp_max_link_bw(intel_output) == DP_LINK_BW_2_7 ? 1 : 0;
+       static int bws[2] = { DP_LINK_BW_1_62, DP_LINK_BW_2_7 };
+
+       for (lane_count = 1; lane_count <= max_lane_count; lane_count <<= 1) {
+               for (clock = 0; clock <= max_clock; clock++) {
+                       int link_avail = intel_dp_link_clock(bws[clock]) * lane_count;
+
+                       if (intel_dp_link_required(mode->clock) <= link_avail) {
+                               dp_priv->link_bw = bws[clock];
+                               dp_priv->lane_count = lane_count;
+                               adjusted_mode->clock = intel_dp_link_clock(dp_priv->link_bw);
+                               DRM_DEBUG("Display port link bw %02x lane count %d clock %d\n",
+                                      dp_priv->link_bw, dp_priv->lane_count,
+                                      adjusted_mode->clock);
+                               return true;
+                       }
+               }
+       }
+       return false;
+}
+
+struct intel_dp_m_n {
+       uint32_t        tu;
+       uint32_t        gmch_m;
+       uint32_t        gmch_n;
+       uint32_t        link_m;
+       uint32_t        link_n;
+};
+
+static void
+intel_reduce_ratio(uint32_t *num, uint32_t *den)
+{
+       while (*num > 0xffffff || *den > 0xffffff) {
+               *num >>= 1;
+               *den >>= 1;
+       }
+}
+
+static void
+intel_dp_compute_m_n(int bytes_per_pixel,
+                    int nlanes,
+                    int pixel_clock,
+                    int link_clock,
+                    struct intel_dp_m_n *m_n)
+{
+       m_n->tu = 64;
+       m_n->gmch_m = pixel_clock * bytes_per_pixel;
+       m_n->gmch_n = link_clock * nlanes;
+       intel_reduce_ratio(&m_n->gmch_m, &m_n->gmch_n);
+       m_n->link_m = pixel_clock;
+       m_n->link_n = link_clock;
+       intel_reduce_ratio(&m_n->link_m, &m_n->link_n);
+}
+
+void
+intel_dp_set_m_n(struct drm_crtc *crtc, struct drm_display_mode *mode,
+                struct drm_display_mode *adjusted_mode)
+{
+       struct drm_device *dev = crtc->dev;
+       struct drm_mode_config *mode_config = &dev->mode_config;
+       struct drm_connector *connector;
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
+       int lane_count = 4;
+       struct intel_dp_m_n m_n;
+
+       /*
+        * Find the lane count in the intel_output private
+        */
+       list_for_each_entry(connector, &mode_config->connector_list, head) {
+               struct intel_output *intel_output = to_intel_output(connector);
+               struct intel_dp_priv *dp_priv = intel_output->dev_priv;
+
+               if (!connector->encoder || connector->encoder->crtc != crtc)
+                       continue;
+
+               if (intel_output->type == INTEL_OUTPUT_DISPLAYPORT) {
+                       lane_count = dp_priv->lane_count;
+                       break;
+               }
+       }
+
+       /*
+        * Compute the GMCH and Link ratios. The '3' here is
+        * the number of bytes_per_pixel post-LUT, which we always
+        * set up for 8-bits of R/G/B, or 3 bytes total.
+        */
+       intel_dp_compute_m_n(3, lane_count,
+                            mode->clock, adjusted_mode->clock, &m_n);
+
+       if (intel_crtc->pipe == 0) {
+               I915_WRITE(PIPEA_GMCH_DATA_M,
+                      ((m_n.tu - 1) << PIPE_GMCH_DATA_M_TU_SIZE_SHIFT) |
+                      m_n.gmch_m);
+               I915_WRITE(PIPEA_GMCH_DATA_N,
+                      m_n.gmch_n);
+               I915_WRITE(PIPEA_DP_LINK_M, m_n.link_m);
+               I915_WRITE(PIPEA_DP_LINK_N, m_n.link_n);
+       } else {
+               I915_WRITE(PIPEB_GMCH_DATA_M,
+                      ((m_n.tu - 1) << PIPE_GMCH_DATA_M_TU_SIZE_SHIFT) |
+                      m_n.gmch_m);
+               I915_WRITE(PIPEB_GMCH_DATA_N,
+                      m_n.gmch_n);
+               I915_WRITE(PIPEB_DP_LINK_M, m_n.link_m);
+               I915_WRITE(PIPEB_DP_LINK_N, m_n.link_n);
+       }
+}
+
+static void
+intel_dp_mode_set(struct drm_encoder *encoder, struct drm_display_mode *mode,
+                 struct drm_display_mode *adjusted_mode)
+{
+       struct intel_output *intel_output = enc_to_intel_output(encoder);
+       struct intel_dp_priv *dp_priv = intel_output->dev_priv;
+       struct drm_crtc *crtc = intel_output->enc.crtc;
+       struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
+
+       dp_priv->DP = (DP_LINK_TRAIN_OFF |
+                       DP_VOLTAGE_0_4 |
+                       DP_PRE_EMPHASIS_0 |
+                       DP_SYNC_VS_HIGH |
+                       DP_SYNC_HS_HIGH);
+
+       switch (dp_priv->lane_count) {
+       case 1:
+               dp_priv->DP |= DP_PORT_WIDTH_1;
+               break;
+       case 2:
+               dp_priv->DP |= DP_PORT_WIDTH_2;
+               break;
+       case 4:
+               dp_priv->DP |= DP_PORT_WIDTH_4;
+               break;
+       }
+       if (dp_priv->has_audio)
+               dp_priv->DP |= DP_AUDIO_OUTPUT_ENABLE;
+
+       memset(dp_priv->link_configuration, 0, DP_LINK_CONFIGURATION_SIZE);
+       dp_priv->link_configuration[0] = dp_priv->link_bw;
+       dp_priv->link_configuration[1] = dp_priv->lane_count;
+
+       /*
+        * Check for DPCD version > 1.1,
+        * enable enahanced frame stuff in that case
+        */
+       if (dp_priv->dpcd[0] >= 0x11) {
+               dp_priv->link_configuration[1] |= DP_LANE_COUNT_ENHANCED_FRAME_EN;
+               dp_priv->DP |= DP_ENHANCED_FRAMING;
+       }
+
+       if (intel_crtc->pipe == 1)
+               dp_priv->DP |= DP_PIPEB_SELECT;
+}
+
+
+static void
+intel_dp_dpms(struct drm_encoder *encoder, int mode)
+{
+       struct intel_output *intel_output = enc_to_intel_output(encoder);
+       struct intel_dp_priv *dp_priv = intel_output->dev_priv;
+       struct drm_device *dev = intel_output->base.dev;
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       uint32_t dp_reg = I915_READ(dp_priv->output_reg);
+
+       if (mode != DRM_MODE_DPMS_ON) {
+               if (dp_reg & DP_PORT_EN)
+                       intel_dp_link_down(intel_output, dp_priv->DP);
+       } else {
+               if (!(dp_reg & DP_PORT_EN))
+                       intel_dp_link_train(intel_output, dp_priv->DP, dp_priv->link_configuration);
+       }
+       dp_priv->dpms_mode = mode;
+}
+
+/*
+ * Fetch AUX CH registers 0x202 - 0x207 which contain
+ * link status information
+ */
+static bool
+intel_dp_get_link_status(struct intel_output *intel_output,
+                        uint8_t link_status[DP_LINK_STATUS_SIZE])
+{
+       int ret;
+
+       ret = intel_dp_aux_native_read(intel_output,
+                                      DP_LANE0_1_STATUS,
+                                      link_status, DP_LINK_STATUS_SIZE);
+       if (ret != DP_LINK_STATUS_SIZE)
+               return false;
+       return true;
+}
+
+static uint8_t
+intel_dp_link_status(uint8_t link_status[DP_LINK_STATUS_SIZE],
+                    int r)
+{
+       return link_status[r - DP_LANE0_1_STATUS];
+}
+
+static void
+intel_dp_save(struct drm_connector *connector)
+{
+       struct intel_output *intel_output = to_intel_output(connector);
+       struct drm_device *dev = intel_output->base.dev;
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       struct intel_dp_priv *dp_priv = intel_output->dev_priv;
+
+       dp_priv->save_DP = I915_READ(dp_priv->output_reg);
+       intel_dp_aux_native_read(intel_output, DP_LINK_BW_SET,
+                                dp_priv->save_link_configuration,
+                                sizeof (dp_priv->save_link_configuration));
+}
+
+static uint8_t
+intel_get_adjust_request_voltage(uint8_t link_status[DP_LINK_STATUS_SIZE],
+                                int lane)
+{
+       int         i = DP_ADJUST_REQUEST_LANE0_1 + (lane >> 1);
+       int         s = ((lane & 1) ?
+                        DP_ADJUST_VOLTAGE_SWING_LANE1_SHIFT :
+                        DP_ADJUST_VOLTAGE_SWING_LANE0_SHIFT);
+       uint8_t l = intel_dp_link_status(link_status, i);
+
+       return ((l >> s) & 3) << DP_TRAIN_VOLTAGE_SWING_SHIFT;
+}
+
+static uint8_t
+intel_get_adjust_request_pre_emphasis(uint8_t link_status[DP_LINK_STATUS_SIZE],
+                                     int lane)
+{
+       int         i = DP_ADJUST_REQUEST_LANE0_1 + (lane >> 1);
+       int         s = ((lane & 1) ?
+                        DP_ADJUST_PRE_EMPHASIS_LANE1_SHIFT :
+                        DP_ADJUST_PRE_EMPHASIS_LANE0_SHIFT);
+       uint8_t l = intel_dp_link_status(link_status, i);
+
+       return ((l >> s) & 3) << DP_TRAIN_PRE_EMPHASIS_SHIFT;
+}
+
+
+#if 0
+static char    *voltage_names[] = {
+       "0.4V", "0.6V", "0.8V", "1.2V"
+};
+static char    *pre_emph_names[] = {
+       "0dB", "3.5dB", "6dB", "9.5dB"
+};
+static char    *link_train_names[] = {
+       "pattern 1", "pattern 2", "idle", "off"
+};
+#endif
+
+/*
+ * These are source-specific values; current Intel hardware supports
+ * a maximum voltage of 800mV and a maximum pre-emphasis of 6dB
+ */
+#define I830_DP_VOLTAGE_MAX        DP_TRAIN_VOLTAGE_SWING_800
+
+static uint8_t
+intel_dp_pre_emphasis_max(uint8_t voltage_swing)
+{
+       switch (voltage_swing & DP_TRAIN_VOLTAGE_SWING_MASK) {
+       case DP_TRAIN_VOLTAGE_SWING_400:
+               return DP_TRAIN_PRE_EMPHASIS_6;
+       case DP_TRAIN_VOLTAGE_SWING_600:
+               return DP_TRAIN_PRE_EMPHASIS_6;
+       case DP_TRAIN_VOLTAGE_SWING_800:
+               return DP_TRAIN_PRE_EMPHASIS_3_5;
+       case DP_TRAIN_VOLTAGE_SWING_1200:
+       default:
+               return DP_TRAIN_PRE_EMPHASIS_0;
+       }
+}
+
+static void
+intel_get_adjust_train(struct intel_output *intel_output,
+                      uint8_t link_status[DP_LINK_STATUS_SIZE],
+                      int lane_count,
+                      uint8_t train_set[4])
+{
+       uint8_t v = 0;
+       uint8_t p = 0;
+       int lane;
+
+       for (lane = 0; lane < lane_count; lane++) {
+               uint8_t this_v = intel_get_adjust_request_voltage(link_status, lane);
+               uint8_t this_p = intel_get_adjust_request_pre_emphasis(link_status, lane);
+
+               if (this_v > v)
+                       v = this_v;
+               if (this_p > p)
+                       p = this_p;
+       }
+
+       if (v >= I830_DP_VOLTAGE_MAX)
+               v = I830_DP_VOLTAGE_MAX | DP_TRAIN_MAX_SWING_REACHED;
+
+       if (p >= intel_dp_pre_emphasis_max(v))
+               p = intel_dp_pre_emphasis_max(v) | DP_TRAIN_MAX_PRE_EMPHASIS_REACHED;
+
+       for (lane = 0; lane < 4; lane++)
+               train_set[lane] = v | p;
+}
+
+static uint32_t
+intel_dp_signal_levels(uint8_t train_set, int lane_count)
+{
+       uint32_t        signal_levels = 0;
+
+       switch (train_set & DP_TRAIN_VOLTAGE_SWING_MASK) {
+       case DP_TRAIN_VOLTAGE_SWING_400:
+       default:
+               signal_levels |= DP_VOLTAGE_0_4;
+               break;
+       case DP_TRAIN_VOLTAGE_SWING_600:
+               signal_levels |= DP_VOLTAGE_0_6;
+               break;
+       case DP_TRAIN_VOLTAGE_SWING_800:
+               signal_levels |= DP_VOLTAGE_0_8;
+               break;
+       case DP_TRAIN_VOLTAGE_SWING_1200:
+               signal_levels |= DP_VOLTAGE_1_2;
+               break;
+       }
+       switch (train_set & DP_TRAIN_PRE_EMPHASIS_MASK) {
+       case DP_TRAIN_PRE_EMPHASIS_0:
+       default:
+               signal_levels |= DP_PRE_EMPHASIS_0;
+               break;
+       case DP_TRAIN_PRE_EMPHASIS_3_5:
+               signal_levels |= DP_PRE_EMPHASIS_3_5;
+               break;
+       case DP_TRAIN_PRE_EMPHASIS_6:
+               signal_levels |= DP_PRE_EMPHASIS_6;
+               break;
+       case DP_TRAIN_PRE_EMPHASIS_9_5:
+               signal_levels |= DP_PRE_EMPHASIS_9_5;
+               break;
+       }
+       return signal_levels;
+}
+
+static uint8_t
+intel_get_lane_status(uint8_t link_status[DP_LINK_STATUS_SIZE],
+                     int lane)
+{
+       int i = DP_LANE0_1_STATUS + (lane >> 1);
+       int s = (lane & 1) * 4;
+       uint8_t l = intel_dp_link_status(link_status, i);
+
+       return (l >> s) & 0xf;
+}
+
+/* Check for clock recovery is done on all channels */
+static bool
+intel_clock_recovery_ok(uint8_t link_status[DP_LINK_STATUS_SIZE], int lane_count)
+{
+       int lane;
+       uint8_t lane_status;
+
+       for (lane = 0; lane < lane_count; lane++) {
+               lane_status = intel_get_lane_status(link_status, lane);
+               if ((lane_status & DP_LANE_CR_DONE) == 0)
+                       return false;
+       }
+       return true;
+}
+
+/* Check to see if channel eq is done on all channels */
+#define CHANNEL_EQ_BITS (DP_LANE_CR_DONE|\
+                        DP_LANE_CHANNEL_EQ_DONE|\
+                        DP_LANE_SYMBOL_LOCKED)
+static bool
+intel_channel_eq_ok(uint8_t link_status[DP_LINK_STATUS_SIZE], int lane_count)
+{
+       uint8_t lane_align;
+       uint8_t lane_status;
+       int lane;
+
+       lane_align = intel_dp_link_status(link_status,
+                                         DP_LANE_ALIGN_STATUS_UPDATED);
+       if ((lane_align & DP_INTERLANE_ALIGN_DONE) == 0)
+               return false;
+       for (lane = 0; lane < lane_count; lane++) {
+               lane_status = intel_get_lane_status(link_status, lane);
+               if ((lane_status & CHANNEL_EQ_BITS) != CHANNEL_EQ_BITS)
+                       return false;
+       }
+       return true;
+}
+
+static bool
+intel_dp_set_link_train(struct intel_output *intel_output,
+                       uint32_t dp_reg_value,
+                       uint8_t dp_train_pat,
+                       uint8_t train_set[4],
+                       bool first)
+{
+       struct drm_device *dev = intel_output->base.dev;
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       struct intel_dp_priv *dp_priv = intel_output->dev_priv;
+       int ret;
+
+       I915_WRITE(dp_priv->output_reg, dp_reg_value);
+       POSTING_READ(dp_priv->output_reg);
+       if (first)
+               intel_wait_for_vblank(dev);
+
+       intel_dp_aux_native_write_1(intel_output,
+                                   DP_TRAINING_PATTERN_SET,
+                                   dp_train_pat);
+
+       ret = intel_dp_aux_native_write(intel_output,
+                                       DP_TRAINING_LANE0_SET, train_set, 4);
+       if (ret != 4)
+               return false;
+
+       return true;
+}
+
+static void
+intel_dp_link_train(struct intel_output *intel_output, uint32_t DP,
+                   uint8_t link_configuration[DP_LINK_CONFIGURATION_SIZE])
+{
+       struct drm_device *dev = intel_output->base.dev;
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       struct intel_dp_priv *dp_priv = intel_output->dev_priv;
+       uint8_t train_set[4];
+       uint8_t link_status[DP_LINK_STATUS_SIZE];
+       int i;
+       uint8_t voltage;
+       bool clock_recovery = false;
+       bool channel_eq = false;
+       bool first = true;
+       int tries;
+
+       /* Write the link configuration data */
+       intel_dp_aux_native_write(intel_output, 0x100,
+                                 link_configuration, DP_LINK_CONFIGURATION_SIZE);
+
+       DP |= DP_PORT_EN;
+       DP &= ~DP_LINK_TRAIN_MASK;
+       memset(train_set, 0, 4);
+       voltage = 0xff;
+       tries = 0;
+       clock_recovery = false;
+       for (;;) {
+               /* Use train_set[0] to set the voltage and pre emphasis values */
+               uint32_t    signal_levels = intel_dp_signal_levels(train_set[0], dp_priv->lane_count);
+               DP = (DP & ~(DP_VOLTAGE_MASK|DP_PRE_EMPHASIS_MASK)) | signal_levels;
+
+               if (!intel_dp_set_link_train(intel_output, DP | DP_LINK_TRAIN_PAT_1,
+                                            DP_TRAINING_PATTERN_1, train_set, first))
+                       break;
+               first = false;
+               /* Set training pattern 1 */
+
+               udelay(100);
+               if (!intel_dp_get_link_status(intel_output, link_status))
+                       break;
+
+               if (intel_clock_recovery_ok(link_status, dp_priv->lane_count)) {
+                       clock_recovery = true;
+                       break;
+               }
+
+               /* Check to see if we've tried the max voltage */
+               for (i = 0; i < dp_priv->lane_count; i++)
+                       if ((train_set[i] & DP_TRAIN_MAX_SWING_REACHED) == 0)
+                               break;
+               if (i == dp_priv->lane_count)
+                       break;
+
+               /* Check to see if we've tried the same voltage 5 times */
+               if ((train_set[0] & DP_TRAIN_VOLTAGE_SWING_MASK) == voltage) {
+                       ++tries;
+                       if (tries == 5)
+                               break;
+               } else
+                       tries = 0;
+               voltage = train_set[0] & DP_TRAIN_VOLTAGE_SWING_MASK;
+
+               /* Compute new train_set as requested by target */
+               intel_get_adjust_train(intel_output, link_status, dp_priv->lane_count, train_set);
+       }
+
+       /* channel equalization */
+       tries = 0;
+       channel_eq = false;
+       for (;;) {
+               /* Use train_set[0] to set the voltage and pre emphasis values */
+               uint32_t    signal_levels = intel_dp_signal_levels(train_set[0], dp_priv->lane_count);
+               DP = (DP & ~(DP_VOLTAGE_MASK|DP_PRE_EMPHASIS_MASK)) | signal_levels;
+
+               /* channel eq pattern */
+               if (!intel_dp_set_link_train(intel_output, DP | DP_LINK_TRAIN_PAT_2,
+                                            DP_TRAINING_PATTERN_2, train_set,
+                                            false))
+                       break;
+
+               udelay(400);
+               if (!intel_dp_get_link_status(intel_output, link_status))
+                       break;
+
+               if (intel_channel_eq_ok(link_status, dp_priv->lane_count)) {
+                       channel_eq = true;
+                       break;
+               }
+
+               /* Try 5 times */
+               if (tries > 5)
+                       break;
+
+               /* Compute new train_set as requested by target */
+               intel_get_adjust_train(intel_output, link_status, dp_priv->lane_count, train_set);
+               ++tries;
+       }
+
+       I915_WRITE(dp_priv->output_reg, DP | DP_LINK_TRAIN_OFF);
+       POSTING_READ(dp_priv->output_reg);
+       intel_dp_aux_native_write_1(intel_output,
+                                   DP_TRAINING_PATTERN_SET, DP_TRAINING_PATTERN_DISABLE);
+}
+
+static void
+intel_dp_link_down(struct intel_output *intel_output, uint32_t DP)
+{
+       struct drm_device *dev = intel_output->base.dev;
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       struct intel_dp_priv *dp_priv = intel_output->dev_priv;
+
+       I915_WRITE(dp_priv->output_reg, DP & ~DP_PORT_EN);
+       POSTING_READ(dp_priv->output_reg);
+}
+
+static void
+intel_dp_restore(struct drm_connector *connector)
+{
+       struct intel_output *intel_output = to_intel_output(connector);
+       struct intel_dp_priv *dp_priv = intel_output->dev_priv;
+
+       if (dp_priv->save_DP & DP_PORT_EN)
+               intel_dp_link_train(intel_output, dp_priv->save_DP, dp_priv->save_link_configuration);
+       else
+               intel_dp_link_down(intel_output,  dp_priv->save_DP);
+}
+
+/*
+ * According to DP spec
+ * 5.1.2:
+ *  1. Read DPCD
+ *  2. Configure link according to Receiver Capabilities
+ *  3. Use Link Training from 2.5.3.3 and 3.5.1.3
+ *  4. Check link status on receipt of hot-plug interrupt
+ */
+
+static void
+intel_dp_check_link_status(struct intel_output *intel_output)
+{
+       struct intel_dp_priv *dp_priv = intel_output->dev_priv;
+       uint8_t link_status[DP_LINK_STATUS_SIZE];
+
+       if (!intel_output->enc.crtc)
+               return;
+
+       if (!intel_dp_get_link_status(intel_output, link_status)) {
+               intel_dp_link_down(intel_output, dp_priv->DP);
+               return;
+       }
+
+       if (!intel_channel_eq_ok(link_status, dp_priv->lane_count))
+               intel_dp_link_train(intel_output, dp_priv->DP, dp_priv->link_configuration);
+}
+
+/**
+ * Uses CRT_HOTPLUG_EN and CRT_HOTPLUG_STAT to detect DP connection.
+ *
+ * \return true if DP port is connected.
+ * \return false if DP port is disconnected.
+ */
+static enum drm_connector_status
+intel_dp_detect(struct drm_connector *connector)
+{
+       struct intel_output *intel_output = to_intel_output(connector);
+       struct drm_device *dev = intel_output->base.dev;
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       struct intel_dp_priv *dp_priv = intel_output->dev_priv;
+       uint32_t temp, bit;
+       enum drm_connector_status status;
+
+       dp_priv->has_audio = false;
+
+       temp = I915_READ(PORT_HOTPLUG_EN);
+
+       I915_WRITE(PORT_HOTPLUG_EN,
+              temp |
+              DPB_HOTPLUG_INT_EN |
+              DPC_HOTPLUG_INT_EN |
+              DPD_HOTPLUG_INT_EN);
+
+       POSTING_READ(PORT_HOTPLUG_EN);
+
+       switch (dp_priv->output_reg) {
+       case DP_B:
+               bit = DPB_HOTPLUG_INT_STATUS;
+               break;
+       case DP_C:
+               bit = DPC_HOTPLUG_INT_STATUS;
+               break;
+       case DP_D:
+               bit = DPD_HOTPLUG_INT_STATUS;
+               break;
+       default:
+               return connector_status_unknown;
+       }
+
+       temp = I915_READ(PORT_HOTPLUG_STAT);
+
+       if ((temp & bit) == 0)
+               return connector_status_disconnected;
+
+       status = connector_status_disconnected;
+       if (intel_dp_aux_native_read(intel_output,
+                                    0x000, dp_priv->dpcd,
+                                    sizeof (dp_priv->dpcd)) == sizeof (dp_priv->dpcd))
+       {
+               if (dp_priv->dpcd[0] != 0)
+                       status = connector_status_connected;
+       }
+       return status;
+}
+
+static int intel_dp_get_modes(struct drm_connector *connector)
+{
+       struct intel_output *intel_output = to_intel_output(connector);
+
+       /* We should parse the EDID data and find out if it has an audio sink
+        */
+
+       return intel_ddc_get_modes(intel_output);
+}
+
+static void
+intel_dp_destroy (struct drm_connector *connector)
+{
+       struct intel_output *intel_output = to_intel_output(connector);
+
+       if (intel_output->i2c_bus)
+               intel_i2c_destroy(intel_output->i2c_bus);
+       drm_sysfs_connector_remove(connector);
+       drm_connector_cleanup(connector);
+       kfree(intel_output);
+}
+
+static const struct drm_encoder_helper_funcs intel_dp_helper_funcs = {
+       .dpms = intel_dp_dpms,
+       .mode_fixup = intel_dp_mode_fixup,
+       .prepare = intel_encoder_prepare,
+       .mode_set = intel_dp_mode_set,
+       .commit = intel_encoder_commit,
+};
+
+static const struct drm_connector_funcs intel_dp_connector_funcs = {
+       .dpms = drm_helper_connector_dpms,
+       .save = intel_dp_save,
+       .restore = intel_dp_restore,
+       .detect = intel_dp_detect,
+       .fill_modes = drm_helper_probe_single_connector_modes,
+       .destroy = intel_dp_destroy,
+};
+
+static const struct drm_connector_helper_funcs intel_dp_connector_helper_funcs = {
+       .get_modes = intel_dp_get_modes,
+       .mode_valid = intel_dp_mode_valid,
+       .best_encoder = intel_best_encoder,
+};
+
+static void intel_dp_enc_destroy(struct drm_encoder *encoder)
+{
+       drm_encoder_cleanup(encoder);
+}
+
+static const struct drm_encoder_funcs intel_dp_enc_funcs = {
+       .destroy = intel_dp_enc_destroy,
+};
+
+void
+intel_dp_hot_plug(struct intel_output *intel_output)
+{
+       struct intel_dp_priv *dp_priv = intel_output->dev_priv;
+
+       if (dp_priv->dpms_mode == DRM_MODE_DPMS_ON)
+               intel_dp_check_link_status(intel_output);
+}
+
+void
+intel_dp_init(struct drm_device *dev, int output_reg)
+{
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       struct drm_connector *connector;
+       struct intel_output *intel_output;
+       struct intel_dp_priv *dp_priv;
+
+       intel_output = kcalloc(sizeof(struct intel_output) + 
+                              sizeof(struct intel_dp_priv), 1, GFP_KERNEL);
+       if (!intel_output)
+               return;
+
+       dp_priv = (struct intel_dp_priv *)(intel_output + 1);
+
+       connector = &intel_output->base;
+       drm_connector_init(dev, connector, &intel_dp_connector_funcs,
+                          DRM_MODE_CONNECTOR_DisplayPort);
+       drm_connector_helper_add(connector, &intel_dp_connector_helper_funcs);
+
+       intel_output->type = INTEL_OUTPUT_DISPLAYPORT;
+
+       connector->interlace_allowed = true;
+       connector->doublescan_allowed = 0;
+
+       dp_priv->intel_output = intel_output;
+       dp_priv->output_reg = output_reg;
+       dp_priv->has_audio = false;
+       dp_priv->dpms_mode = DRM_MODE_DPMS_ON;
+       intel_output->dev_priv = dp_priv;
+
+       drm_encoder_init(dev, &intel_output->enc, &intel_dp_enc_funcs,
+                        DRM_MODE_ENCODER_TMDS);
+       drm_encoder_helper_add(&intel_output->enc, &intel_dp_helper_funcs);
+
+       drm_mode_connector_attach_encoder(&intel_output->base,
+                                         &intel_output->enc);
+       drm_sysfs_connector_add(connector);
+
+       /* Set up the DDC bus. */
+       intel_dp_i2c_init(intel_output,
+                         (output_reg == DP_B) ? "DPDDC-B" :
+                         (output_reg == DP_C) ? "DPDDC-C" : "DPDDC-D");
+       intel_output->ddc_bus = &dp_priv->adapter;
+       intel_output->hot_plug = intel_dp_hot_plug;
+
+       /* For G4X desktop chip, PEG_BAND_GAP_DATA 3:0 must first be written
+        * 0xd.  Failure to do so will result in spurious interrupts being
+        * generated on the port when a cable is not attached.
+        */
+       if (IS_G4X(dev) && !IS_GM45(dev)) {
+               u32 temp = I915_READ(PEG_BAND_GAP_DATA);
+               I915_WRITE(PEG_BAND_GAP_DATA, (temp & ~0xf) | 0xd);
+       }
+}
diff --git a/drivers/gpu/drm/i915/intel_dp.h b/drivers/gpu/drm/i915/intel_dp.h
new file mode 100644 (file)
index 0000000..2b38054
--- /dev/null
@@ -0,0 +1,144 @@
+/*
+ * Copyright Â© 2008 Keith Packard
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and its
+ * documentation for any purpose is hereby granted without fee, provided that
+ * the above copyright notice appear in all copies and that both that copyright
+ * notice and this permission notice appear in supporting documentation, and
+ * that the name of the copyright holders not be used in advertising or
+ * publicity pertaining to distribution of the software without specific,
+ * written prior permission.  The copyright holders make no representations
+ * about the suitability of this software for any purpose.  It is provided "as
+ * is" without express or implied warranty.
+ *
+ * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
+ * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+ * OF THIS SOFTWARE.
+ */
+
+#ifndef _INTEL_DP_H_
+#define _INTEL_DP_H_
+
+/* From the VESA DisplayPort spec */
+
+#define AUX_NATIVE_WRITE       0x8
+#define AUX_NATIVE_READ                0x9
+#define AUX_I2C_WRITE          0x0
+#define AUX_I2C_READ           0x1
+#define AUX_I2C_STATUS         0x2
+#define AUX_I2C_MOT            0x4
+
+#define AUX_NATIVE_REPLY_ACK   (0x0 << 4)
+#define AUX_NATIVE_REPLY_NACK  (0x1 << 4)
+#define AUX_NATIVE_REPLY_DEFER (0x2 << 4)
+#define AUX_NATIVE_REPLY_MASK  (0x3 << 4)
+
+#define AUX_I2C_REPLY_ACK      (0x0 << 6)
+#define AUX_I2C_REPLY_NACK     (0x1 << 6)
+#define AUX_I2C_REPLY_DEFER    (0x2 << 6)
+#define AUX_I2C_REPLY_MASK     (0x3 << 6)
+
+/* AUX CH addresses */
+#define        DP_LINK_BW_SET          0x100
+# define DP_LINK_BW_1_62                   0x06
+# define DP_LINK_BW_2_7                            0x0a
+
+#define DP_LANE_COUNT_SET      0x101
+# define DP_LANE_COUNT_MASK                0x0f
+# define DP_LANE_COUNT_ENHANCED_FRAME_EN    (1 << 7)
+
+#define DP_TRAINING_PATTERN_SET        0x102
+
+# define DP_TRAINING_PATTERN_DISABLE       0
+# define DP_TRAINING_PATTERN_1             1
+# define DP_TRAINING_PATTERN_2             2
+# define DP_TRAINING_PATTERN_MASK          0x3
+
+# define DP_LINK_QUAL_PATTERN_DISABLE      (0 << 2)
+# define DP_LINK_QUAL_PATTERN_D10_2        (1 << 2)
+# define DP_LINK_QUAL_PATTERN_ERROR_RATE    (2 << 2)
+# define DP_LINK_QUAL_PATTERN_PRBS7        (3 << 2)
+# define DP_LINK_QUAL_PATTERN_MASK         (3 << 2)
+
+# define DP_RECOVERED_CLOCK_OUT_EN         (1 << 4)
+# define DP_LINK_SCRAMBLING_DISABLE        (1 << 5)
+
+# define DP_SYMBOL_ERROR_COUNT_BOTH        (0 << 6)
+# define DP_SYMBOL_ERROR_COUNT_DISPARITY    (1 << 6)
+# define DP_SYMBOL_ERROR_COUNT_SYMBOL      (2 << 6)
+# define DP_SYMBOL_ERROR_COUNT_MASK        (3 << 6)
+
+#define DP_TRAINING_LANE0_SET              0x103
+#define DP_TRAINING_LANE1_SET              0x104
+#define DP_TRAINING_LANE2_SET              0x105
+#define DP_TRAINING_LANE3_SET              0x106
+
+# define DP_TRAIN_VOLTAGE_SWING_MASK       0x3
+# define DP_TRAIN_VOLTAGE_SWING_SHIFT      0
+# define DP_TRAIN_MAX_SWING_REACHED        (1 << 2)
+# define DP_TRAIN_VOLTAGE_SWING_400        (0 << 0)
+# define DP_TRAIN_VOLTAGE_SWING_600        (1 << 0)
+# define DP_TRAIN_VOLTAGE_SWING_800        (2 << 0)
+# define DP_TRAIN_VOLTAGE_SWING_1200       (3 << 0)
+
+# define DP_TRAIN_PRE_EMPHASIS_MASK        (3 << 3)
+# define DP_TRAIN_PRE_EMPHASIS_0           (0 << 3)
+# define DP_TRAIN_PRE_EMPHASIS_3_5         (1 << 3)
+# define DP_TRAIN_PRE_EMPHASIS_6           (2 << 3)
+# define DP_TRAIN_PRE_EMPHASIS_9_5         (3 << 3)
+
+# define DP_TRAIN_PRE_EMPHASIS_SHIFT       3
+# define DP_TRAIN_MAX_PRE_EMPHASIS_REACHED  (1 << 5)
+
+#define DP_DOWNSPREAD_CTRL                 0x107
+# define DP_SPREAD_AMP_0_5                 (1 << 4)
+
+#define DP_MAIN_LINK_CHANNEL_CODING_SET            0x108
+# define DP_SET_ANSI_8B10B                 (1 << 0)
+
+#define DP_LANE0_1_STATUS                  0x202
+#define DP_LANE2_3_STATUS                  0x203
+
+# define DP_LANE_CR_DONE                   (1 << 0)
+# define DP_LANE_CHANNEL_EQ_DONE           (1 << 1)
+# define DP_LANE_SYMBOL_LOCKED             (1 << 2)
+
+#define DP_LANE_ALIGN_STATUS_UPDATED       0x204
+
+#define DP_INTERLANE_ALIGN_DONE                    (1 << 0)
+#define DP_DOWNSTREAM_PORT_STATUS_CHANGED   (1 << 6)
+#define DP_LINK_STATUS_UPDATED             (1 << 7)
+
+#define DP_SINK_STATUS                     0x205
+
+#define DP_RECEIVE_PORT_0_STATUS           (1 << 0)
+#define DP_RECEIVE_PORT_1_STATUS           (1 << 1)
+
+#define DP_ADJUST_REQUEST_LANE0_1          0x206
+#define DP_ADJUST_REQUEST_LANE2_3          0x207
+
+#define DP_ADJUST_VOLTAGE_SWING_LANE0_MASK  0x03
+#define DP_ADJUST_VOLTAGE_SWING_LANE0_SHIFT 0
+#define DP_ADJUST_PRE_EMPHASIS_LANE0_MASK   0x0c
+#define DP_ADJUST_PRE_EMPHASIS_LANE0_SHIFT  2
+#define DP_ADJUST_VOLTAGE_SWING_LANE1_MASK  0x30
+#define DP_ADJUST_VOLTAGE_SWING_LANE1_SHIFT 4
+#define DP_ADJUST_PRE_EMPHASIS_LANE1_MASK   0xc0
+#define DP_ADJUST_PRE_EMPHASIS_LANE1_SHIFT  6
+
+struct i2c_algo_dp_aux_data {
+       bool running;
+       u16 address;
+       int (*aux_ch) (struct i2c_adapter *adapter,
+                      uint8_t *send, int send_bytes,
+                      uint8_t *recv, int recv_bytes);
+};
+
+int
+i2c_dp_aux_add_bus(struct i2c_adapter *adapter);
+
+#endif /* _INTEL_DP_H_ */
diff --git a/drivers/gpu/drm/i915/intel_dp_i2c.c b/drivers/gpu/drm/i915/intel_dp_i2c.c
new file mode 100644 (file)
index 0000000..a63b6f5
--- /dev/null
@@ -0,0 +1,273 @@
+/*
+ * Copyright Â© 2009 Keith Packard
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and its
+ * documentation for any purpose is hereby granted without fee, provided that
+ * the above copyright notice appear in all copies and that both that copyright
+ * notice and this permission notice appear in supporting documentation, and
+ * that the name of the copyright holders not be used in advertising or
+ * publicity pertaining to distribution of the software without specific,
+ * written prior permission.  The copyright holders make no representations
+ * about the suitability of this software for any purpose.  It is provided "as
+ * is" without express or implied warranty.
+ *
+ * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
+ * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+ * OF THIS SOFTWARE.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/slab.h>
+#include <linux/init.h>
+#include <linux/errno.h>
+#include <linux/sched.h>
+#include <linux/i2c.h>
+#include "intel_dp.h"
+#include "drmP.h"
+
+/* Run a single AUX_CH I2C transaction, writing/reading data as necessary */
+
+#define MODE_I2C_START 1
+#define MODE_I2C_WRITE 2
+#define MODE_I2C_READ  4
+#define MODE_I2C_STOP  8
+
+static int
+i2c_algo_dp_aux_transaction(struct i2c_adapter *adapter, int mode,
+                           uint8_t write_byte, uint8_t *read_byte)
+{
+       struct i2c_algo_dp_aux_data *algo_data = adapter->algo_data;
+       uint16_t address = algo_data->address;
+       uint8_t msg[5];
+       uint8_t reply[2];
+       int msg_bytes;
+       int reply_bytes;
+       int ret;
+
+       /* Set up the command byte */
+       if (mode & MODE_I2C_READ)
+               msg[0] = AUX_I2C_READ << 4;
+       else
+               msg[0] = AUX_I2C_WRITE << 4;
+
+       if (!(mode & MODE_I2C_STOP))
+               msg[0] |= AUX_I2C_MOT << 4;
+
+       msg[1] = address >> 8;
+       msg[2] = address;
+
+       switch (mode) {
+       case MODE_I2C_WRITE:
+               msg[3] = 0;
+               msg[4] = write_byte;
+               msg_bytes = 5;
+               reply_bytes = 1;
+               break;
+       case MODE_I2C_READ:
+               msg[3] = 0;
+               msg_bytes = 4;
+               reply_bytes = 2;
+               break;
+       default:
+               msg_bytes = 3;
+               reply_bytes = 1;
+               break;
+       }
+
+       for (;;) {
+               ret = (*algo_data->aux_ch)(adapter,
+                                          msg, msg_bytes,
+                                          reply, reply_bytes);
+               if (ret < 0) {
+                       DRM_DEBUG("aux_ch failed %d\n", ret);
+                       return ret;
+               }
+               switch (reply[0] & AUX_I2C_REPLY_MASK) {
+               case AUX_I2C_REPLY_ACK:
+                       if (mode == MODE_I2C_READ) {
+                               *read_byte = reply[1];
+                       }
+                       return reply_bytes - 1;
+               case AUX_I2C_REPLY_NACK:
+                       DRM_DEBUG("aux_ch nack\n");
+                       return -EREMOTEIO;
+               case AUX_I2C_REPLY_DEFER:
+                       DRM_DEBUG("aux_ch defer\n");
+                       udelay(100);
+                       break;
+               default:
+                       DRM_ERROR("aux_ch invalid reply 0x%02x\n", reply[0]);
+                       return -EREMOTEIO;
+               }
+       }
+}
+
+/*
+ * I2C over AUX CH
+ */
+
+/*
+ * Send the address. If the I2C link is running, this 'restarts'
+ * the connection with the new address, this is used for doing
+ * a write followed by a read (as needed for DDC)
+ */
+static int
+i2c_algo_dp_aux_address(struct i2c_adapter *adapter, u16 address, bool reading)
+{
+       struct i2c_algo_dp_aux_data *algo_data = adapter->algo_data;
+       int mode = MODE_I2C_START;
+       int ret;
+
+       if (reading)
+               mode |= MODE_I2C_READ;
+       else
+               mode |= MODE_I2C_WRITE;
+       algo_data->address = address;
+       algo_data->running = true;
+       ret = i2c_algo_dp_aux_transaction(adapter, mode, 0, NULL);
+       return ret;
+}
+
+/*
+ * Stop the I2C transaction. This closes out the link, sending
+ * a bare address packet with the MOT bit turned off
+ */
+static void
+i2c_algo_dp_aux_stop(struct i2c_adapter *adapter, bool reading)
+{
+       struct i2c_algo_dp_aux_data *algo_data = adapter->algo_data;
+       int mode = MODE_I2C_STOP;
+
+       if (reading)
+               mode |= MODE_I2C_READ;
+       else
+               mode |= MODE_I2C_WRITE;
+       if (algo_data->running) {
+               (void) i2c_algo_dp_aux_transaction(adapter, mode, 0, NULL);
+               algo_data->running = false;
+       }
+}
+
+/*
+ * Write a single byte to the current I2C address, the
+ * the I2C link must be running or this returns -EIO
+ */
+static int
+i2c_algo_dp_aux_put_byte(struct i2c_adapter *adapter, u8 byte)
+{
+       struct i2c_algo_dp_aux_data *algo_data = adapter->algo_data;
+       int ret;
+
+       if (!algo_data->running)
+               return -EIO;
+
+       ret = i2c_algo_dp_aux_transaction(adapter, MODE_I2C_WRITE, byte, NULL);
+       return ret;
+}
+
+/*
+ * Read a single byte from the current I2C address, the
+ * I2C link must be running or this returns -EIO
+ */
+static int
+i2c_algo_dp_aux_get_byte(struct i2c_adapter *adapter, u8 *byte_ret)
+{
+       struct i2c_algo_dp_aux_data *algo_data = adapter->algo_data;
+       int ret;
+
+       if (!algo_data->running)
+               return -EIO;
+
+       ret = i2c_algo_dp_aux_transaction(adapter, MODE_I2C_READ, 0, byte_ret);
+       return ret;
+}
+
+static int
+i2c_algo_dp_aux_xfer(struct i2c_adapter *adapter,
+                    struct i2c_msg *msgs,
+                    int num)
+{
+       int ret = 0;
+       bool reading = false;
+       int m;
+       int b;
+
+       for (m = 0; m < num; m++) {
+               u16 len = msgs[m].len;
+               u8 *buf = msgs[m].buf;
+               reading = (msgs[m].flags & I2C_M_RD) != 0;
+               ret = i2c_algo_dp_aux_address(adapter, msgs[m].addr, reading);
+               if (ret < 0)
+                       break;
+               if (reading) {
+                       for (b = 0; b < len; b++) {
+                               ret = i2c_algo_dp_aux_get_byte(adapter, &buf[b]);
+                               if (ret < 0)
+                                       break;
+                       }
+               } else {
+                       for (b = 0; b < len; b++) {
+                               ret = i2c_algo_dp_aux_put_byte(adapter, buf[b]);
+                               if (ret < 0)
+                                       break;
+                       }
+               }
+               if (ret < 0)
+                       break;
+       }
+       if (ret >= 0)
+               ret = num;
+       i2c_algo_dp_aux_stop(adapter, reading);
+       DRM_DEBUG("dp_aux_xfer return %d\n", ret);
+       return ret;
+}
+
+static u32
+i2c_algo_dp_aux_functionality(struct i2c_adapter *adapter)
+{
+       return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL |
+              I2C_FUNC_SMBUS_READ_BLOCK_DATA |
+              I2C_FUNC_SMBUS_BLOCK_PROC_CALL |
+              I2C_FUNC_10BIT_ADDR;
+}
+
+static const struct i2c_algorithm i2c_dp_aux_algo = {
+       .master_xfer    = i2c_algo_dp_aux_xfer,
+       .functionality  = i2c_algo_dp_aux_functionality,
+};
+
+static void
+i2c_dp_aux_reset_bus(struct i2c_adapter *adapter)
+{
+       (void) i2c_algo_dp_aux_address(adapter, 0, false);
+       (void) i2c_algo_dp_aux_stop(adapter, false);
+                                          
+}
+
+static int
+i2c_dp_aux_prepare_bus(struct i2c_adapter *adapter)
+{
+       adapter->algo = &i2c_dp_aux_algo;
+       adapter->retries = 3;
+       i2c_dp_aux_reset_bus(adapter);
+       return 0;
+}
+
+int
+i2c_dp_aux_add_bus(struct i2c_adapter *adapter)
+{
+       int error;
+       
+       error = i2c_dp_aux_prepare_bus(adapter);
+       if (error)
+               return error;
+       error = i2c_add_adapter(adapter);
+       return error;
+}
+EXPORT_SYMBOL(i2c_dp_aux_add_bus);
index cd4b9c5f715e82e9abb4981945009aee09b2e9da..004541c935a80bd61bf591c820131d3c3bd02843 100644 (file)
@@ -54,6 +54,7 @@
 #define INTEL_OUTPUT_LVDS 4
 #define INTEL_OUTPUT_TVOUT 5
 #define INTEL_OUTPUT_HDMI 6
+#define INTEL_OUTPUT_DISPLAYPORT 7
 
 #define INTEL_DVO_CHIP_NONE 0
 #define INTEL_DVO_CHIP_LVDS 1
@@ -65,7 +66,6 @@ struct intel_i2c_chan {
        u32 reg; /* GPIO reg */
        struct i2c_adapter adapter;
        struct i2c_algo_bit_data algo;
-        u8 slave_addr;
 };
 
 struct intel_framebuffer {
@@ -79,11 +79,12 @@ struct intel_output {
 
        struct drm_encoder enc;
        int type;
-       struct intel_i2c_chan *i2c_bus; /* for control functions */
-       struct intel_i2c_chan *ddc_bus; /* for DDC only stuff */
+       struct i2c_adapter *i2c_bus;
+       struct i2c_adapter *ddc_bus;
        bool load_detect_temp;
        bool needs_tv_clock;
        void *dev_priv;
+       void (*hot_plug)(struct intel_output *);
 };
 
 struct intel_crtc {
@@ -104,9 +105,9 @@ struct intel_crtc {
 #define enc_to_intel_output(x) container_of(x, struct intel_output, enc)
 #define to_intel_framebuffer(x) container_of(x, struct intel_framebuffer, base)
 
-struct intel_i2c_chan *intel_i2c_create(struct drm_device *dev, const u32 reg,
-                                       const char *name);
-void intel_i2c_destroy(struct intel_i2c_chan *chan);
+struct i2c_adapter *intel_i2c_create(struct drm_device *dev, const u32 reg,
+                                    const char *name);
+void intel_i2c_destroy(struct i2c_adapter *adapter);
 int intel_ddc_get_modes(struct intel_output *intel_output);
 extern bool intel_ddc_probe(struct intel_output *intel_output);
 void intel_i2c_quirk_set(struct drm_device *dev, bool enable);
@@ -116,6 +117,10 @@ extern bool intel_sdvo_init(struct drm_device *dev, int output_device);
 extern void intel_dvo_init(struct drm_device *dev);
 extern void intel_tv_init(struct drm_device *dev);
 extern void intel_lvds_init(struct drm_device *dev);
+extern void intel_dp_init(struct drm_device *dev, int dp_reg);
+void
+intel_dp_set_m_n(struct drm_crtc *crtc, struct drm_display_mode *mode,
+                struct drm_display_mode *adjusted_mode);
 
 extern void intel_crtc_load_lut(struct drm_crtc *crtc);
 extern void intel_encoder_prepare (struct drm_encoder *encoder);
index 1ee3007d6ec04e062e8d18fd482047687b1ea026..13bff20930e89f9a5bd2d83b3a4dace630252cf5 100644 (file)
@@ -384,10 +384,9 @@ void intel_dvo_init(struct drm_device *dev)
 {
        struct intel_output *intel_output;
        struct intel_dvo_device *dvo;
-       struct intel_i2c_chan *i2cbus = NULL;
+       struct i2c_adapter *i2cbus = NULL;
        int ret = 0;
        int i;
-       int gpio_inited = 0;
        int encoder_type = DRM_MODE_ENCODER_NONE;
        intel_output = kzalloc (sizeof(struct intel_output), GFP_KERNEL);
        if (!intel_output)
@@ -420,14 +419,11 @@ void intel_dvo_init(struct drm_device *dev)
                 * It appears that everything is on GPIOE except for panels
                 * on i830 laptops, which are on GPIOB (DVOA).
                 */
-               if (gpio_inited != gpio) {
-                       if (i2cbus != NULL)
-                               intel_i2c_destroy(i2cbus);
-                       if (!(i2cbus = intel_i2c_create(dev, gpio,
-                               gpio == GPIOB ? "DVOI2C_B" : "DVOI2C_E"))) {
-                               continue;
-                       }
-                       gpio_inited = gpio;
+               if (i2cbus != NULL)
+                       intel_i2c_destroy(i2cbus);
+               if (!(i2cbus = intel_i2c_create(dev, gpio,
+                       gpio == GPIOB ? "DVOI2C_B" : "DVOI2C_E"))) {
+                       continue;
                }
 
                if (dvo->dev_ops!= NULL)
index 1af7d68e380756f3f785551cb9c8a4c38da8604a..1d30802e773e383492c03aeabb99e6a3ddd623f2 100644 (file)
@@ -453,7 +453,7 @@ static int intelfb_create(struct drm_device *dev, uint32_t fb_width,
        size = ALIGN(size, PAGE_SIZE);
        fbo = drm_gem_object_alloc(dev, size);
        if (!fbo) {
-               printk(KERN_ERR "failed to allocate framebuffer\n");
+               DRM_ERROR("failed to allocate framebuffer\n");
                ret = -ENOMEM;
                goto out;
        }
@@ -610,8 +610,8 @@ static int intelfb_create(struct drm_device *dev, uint32_t fb_width,
        par->dev = dev;
 
        /* To allow resizeing without swapping buffers */
-       printk("allocated %dx%d fb: 0x%08x, bo %p\n", intel_fb->base.width,
-              intel_fb->base.height, obj_priv->gtt_offset, fbo);
+       DRM_DEBUG("allocated %dx%d fb: 0x%08x, bo %p\n", intel_fb->base.width,
+                 intel_fb->base.height, obj_priv->gtt_offset, fbo);
 
        mutex_unlock(&dev->struct_mutex);
        return 0;
@@ -698,13 +698,13 @@ static int intelfb_multi_fb_probe_crtc(struct drm_device *dev, struct drm_crtc *
        } else
                intelfb_set_par(info);
 
-       printk(KERN_INFO "fb%d: %s frame buffer device\n", info->node,
+       DRM_INFO("fb%d: %s frame buffer device\n", info->node,
               info->fix.id);
 
        /* Switch back to kernel console on panic */
        kernelfb_mode = *modeset;
        atomic_notifier_chain_register(&panic_notifier_list, &paniced);
-       printk(KERN_INFO "registered panic notifier\n");
+       DRM_DEBUG("registered panic notifier\n");
 
        return 0;
 }
@@ -852,13 +852,13 @@ static int intelfb_single_fb_probe(struct drm_device *dev)
        } else
                intelfb_set_par(info);
 
-       printk(KERN_INFO "fb%d: %s frame buffer device\n", info->node,
+       DRM_INFO("fb%d: %s frame buffer device\n", info->node,
               info->fix.id);
 
        /* Switch back to kernel console on panic */
        kernelfb_mode = *modeset;
        atomic_notifier_chain_register(&panic_notifier_list, &paniced);
-       printk(KERN_INFO "registered panic notifier\n");
+       DRM_DEBUG("registered panic notifier\n");
 
        return 0;
 }
@@ -872,8 +872,8 @@ void intelfb_restore(void)
 {
        int ret;
        if ((ret = drm_crtc_helper_set_config(&kernelfb_mode)) != 0) {
-               printk(KERN_ERR "Failed to restore crtc configuration: %d\n",
-                      ret);
+               DRM_ERROR("Failed to restore crtc configuration: %d\n",
+                         ret);
        }
 }
 
index 4ea2a651b92c43079a4c3185a829e241822ca488..9e30daae37dca8c45ba0635f3e22a9d1e98da967 100644 (file)
@@ -31,6 +31,7 @@
 #include "drmP.h"
 #include "drm.h"
 #include "drm_crtc.h"
+#include "drm_edid.h"
 #include "intel_drv.h"
 #include "i915_drm.h"
 #include "i915_drv.h"
@@ -56,8 +57,7 @@ static void intel_hdmi_mode_set(struct drm_encoder *encoder,
        sdvox = SDVO_ENCODING_HDMI |
                SDVO_BORDER_ENABLE |
                SDVO_VSYNC_ACTIVE_HIGH |
-               SDVO_HSYNC_ACTIVE_HIGH |
-               SDVO_NULL_PACKETS_DURING_VSYNC;
+               SDVO_HSYNC_ACTIVE_HIGH;
 
        if (hdmi_priv->has_hdmi_sink)
                sdvox |= SDVO_AUDIO_ENABLE;
@@ -129,20 +129,26 @@ static bool intel_hdmi_mode_fixup(struct drm_encoder *encoder,
        return true;
 }
 
-static void
-intel_hdmi_sink_detect(struct drm_connector *connector)
+static enum drm_connector_status
+intel_hdmi_edid_detect(struct drm_connector *connector)
 {
        struct intel_output *intel_output = to_intel_output(connector);
        struct intel_hdmi_priv *hdmi_priv = intel_output->dev_priv;
        struct edid *edid = NULL;
+       enum drm_connector_status status = connector_status_disconnected;
 
        edid = drm_get_edid(&intel_output->base,
-                           &intel_output->ddc_bus->adapter);
-       if (edid != NULL) {
-               hdmi_priv->has_hdmi_sink = drm_detect_hdmi_monitor(edid);
-               kfree(edid);
+                           intel_output->ddc_bus);
+       hdmi_priv->has_hdmi_sink = false;
+       if (edid) {
+               if (edid->input & DRM_EDID_INPUT_DIGITAL) {
+                       status = connector_status_connected;
+                       hdmi_priv->has_hdmi_sink = drm_detect_hdmi_monitor(edid);
+               }
                intel_output->base.display_info.raw_edid = NULL;
+               kfree(edid);
        }
+       return status;
 }
 
 static enum drm_connector_status
@@ -154,11 +160,7 @@ igdng_hdmi_detect(struct drm_connector *connector)
        /* FIXME hotplug detect */
 
        hdmi_priv->has_hdmi_sink = false;
-       intel_hdmi_sink_detect(connector);
-       if (hdmi_priv->has_hdmi_sink)
-               return connector_status_connected;
-       else
-               return connector_status_disconnected;
+       return intel_hdmi_edid_detect(connector);
 }
 
 static enum drm_connector_status
@@ -201,10 +203,9 @@ intel_hdmi_detect(struct drm_connector *connector)
                return connector_status_unknown;
        }
 
-       if ((I915_READ(PORT_HOTPLUG_STAT) & bit) != 0) {
-               intel_hdmi_sink_detect(connector);
-               return connector_status_connected;
-       } else
+       if ((I915_READ(PORT_HOTPLUG_STAT) & bit) != 0)
+               return intel_hdmi_edid_detect(connector);
+       else
                return connector_status_disconnected;
 }
 
index f7061f68d050c817c86ef1adf4d4bab336d01b59..62b8bead7652cdeed3f12d6680a64d5659da6889 100644 (file)
@@ -124,6 +124,7 @@ static void set_data(void *data, int state_high)
  * @output: driver specific output device
  * @reg: GPIO reg to use
  * @name: name for this bus
+ * @slave_addr: slave address (if fixed)
  *
  * Creates and registers a new i2c bus with the Linux i2c layer, for use
  * in output probing and control (e.g. DDC or SDVO control functions).
@@ -139,8 +140,8 @@ static void set_data(void *data, int state_high)
  *   %GPIOH
  * see PRM for details on how these different busses are used.
  */
-struct intel_i2c_chan *intel_i2c_create(struct drm_device *dev, const u32 reg,
-                                       const char *name)
+struct i2c_adapter *intel_i2c_create(struct drm_device *dev, const u32 reg,
+                                    const char *name)
 {
        struct intel_i2c_chan *chan;
 
@@ -174,7 +175,7 @@ struct intel_i2c_chan *intel_i2c_create(struct drm_device *dev, const u32 reg,
        intel_i2c_quirk_set(dev, false);
        udelay(20);
 
-       return chan;
+       return &chan->adapter;
 
 out_free:
        kfree(chan);
@@ -187,11 +188,16 @@ out_free:
  *
  * Unregister the adapter from the i2c layer, then free the structure.
  */
-void intel_i2c_destroy(struct intel_i2c_chan *chan)
+void intel_i2c_destroy(struct i2c_adapter *adapter)
 {
-       if (!chan)
+       struct intel_i2c_chan *chan;
+
+       if (!adapter)
                return;
 
+       chan = container_of(adapter,
+                           struct intel_i2c_chan,
+                           adapter);
        i2c_del_adapter(&chan->adapter);
        kfree(chan);
 }
index f073ed8432e8fb9547d272653b51315a3bc90de3..9ab38efffecfeab426e48c45bbc3a7ee77bf96f4 100644 (file)
 #include "intel_drv.h"
 #include "i915_drm.h"
 #include "i915_drv.h"
+#include <linux/acpi.h>
 
 #define I915_LVDS "i915_lvds"
 
+/*
+ * the following four scaling options are defined.
+ * #define DRM_MODE_SCALE_NON_GPU      0
+ * #define DRM_MODE_SCALE_FULLSCREEN   1
+ * #define DRM_MODE_SCALE_NO_SCALE     2
+ * #define DRM_MODE_SCALE_ASPECT       3
+ */
+
+/* Private structure for the integrated LVDS support */
+struct intel_lvds_priv {
+       int fitting_mode;
+       u32 pfit_control;
+       u32 pfit_pgm_ratios;
+};
+
 /**
  * Sets the backlight level.
  *
@@ -213,26 +229,45 @@ static bool intel_lvds_mode_fixup(struct drm_encoder *encoder,
                                  struct drm_display_mode *mode,
                                  struct drm_display_mode *adjusted_mode)
 {
+       /*
+        * float point operation is not supported . So the PANEL_RATIO_FACTOR
+        * is defined, which can avoid the float point computation when
+        * calculating the panel ratio.
+        */
+#define PANEL_RATIO_FACTOR 8192
        struct drm_device *dev = encoder->dev;
        struct drm_i915_private *dev_priv = dev->dev_private;
        struct intel_crtc *intel_crtc = to_intel_crtc(encoder->crtc);
        struct drm_encoder *tmp_encoder;
+       struct intel_output *intel_output = enc_to_intel_output(encoder);
+       struct intel_lvds_priv *lvds_priv = intel_output->dev_priv;
+       u32 pfit_control = 0, pfit_pgm_ratios = 0;
+       int left_border = 0, right_border = 0, top_border = 0;
+       int bottom_border = 0;
+       bool border = 0;
+       int panel_ratio, desired_ratio, vert_scale, horiz_scale;
+       int horiz_ratio, vert_ratio;
+       u32 hsync_width, vsync_width;
+       u32 hblank_width, vblank_width;
+       u32 hsync_pos, vsync_pos;
 
        /* Should never happen!! */
        if (!IS_I965G(dev) && intel_crtc->pipe == 0) {
-               printk(KERN_ERR "Can't support LVDS on pipe A\n");
+               DRM_ERROR("Can't support LVDS on pipe A\n");
                return false;
        }
 
        /* Should never happen!! */
        list_for_each_entry(tmp_encoder, &dev->mode_config.encoder_list, head) {
                if (tmp_encoder != encoder && tmp_encoder->crtc == encoder->crtc) {
-                       printk(KERN_ERR "Can't enable LVDS and another "
+                       DRM_ERROR("Can't enable LVDS and another "
                               "encoder on the same pipe\n");
                        return false;
                }
        }
-
+       /* If we don't have a panel mode, there is nothing we can do */
+       if (dev_priv->panel_fixed_mode == NULL)
+               return true;
        /*
         * If we have timings from the BIOS for the panel, put them in
         * to the adjusted mode.  The CRTC will be set up for this mode,
@@ -256,6 +291,243 @@ static bool intel_lvds_mode_fixup(struct drm_encoder *encoder,
                drm_mode_set_crtcinfo(adjusted_mode, CRTC_INTERLACE_HALVE_V);
        }
 
+       /* Make sure pre-965s set dither correctly */
+       if (!IS_I965G(dev)) {
+               if (dev_priv->panel_wants_dither || dev_priv->lvds_dither)
+                       pfit_control |= PANEL_8TO6_DITHER_ENABLE;
+       }
+
+       /* Native modes don't need fitting */
+       if (adjusted_mode->hdisplay == mode->hdisplay &&
+                       adjusted_mode->vdisplay == mode->vdisplay) {
+               pfit_pgm_ratios = 0;
+               border = 0;
+               goto out;
+       }
+
+       /* 965+ wants fuzzy fitting */
+       if (IS_I965G(dev))
+               pfit_control |= (intel_crtc->pipe << PFIT_PIPE_SHIFT) |
+                                       PFIT_FILTER_FUZZY;
+
+       hsync_width = adjusted_mode->crtc_hsync_end -
+                                       adjusted_mode->crtc_hsync_start;
+       vsync_width = adjusted_mode->crtc_vsync_end -
+                                       adjusted_mode->crtc_vsync_start;
+       hblank_width = adjusted_mode->crtc_hblank_end -
+                                       adjusted_mode->crtc_hblank_start;
+       vblank_width = adjusted_mode->crtc_vblank_end -
+                                       adjusted_mode->crtc_vblank_start;
+       /*
+        * Deal with panel fitting options. Figure out how to stretch the
+        * image based on its aspect ratio & the current panel fitting mode.
+        */
+       panel_ratio = adjusted_mode->hdisplay * PANEL_RATIO_FACTOR /
+                               adjusted_mode->vdisplay;
+       desired_ratio = mode->hdisplay * PANEL_RATIO_FACTOR /
+                               mode->vdisplay;
+       /*
+        * Enable automatic panel scaling for non-native modes so that they fill
+        * the screen.  Should be enabled before the pipe is enabled, according
+        * to register description and PRM.
+        * Change the value here to see the borders for debugging
+        */
+       I915_WRITE(BCLRPAT_A, 0);
+       I915_WRITE(BCLRPAT_B, 0);
+
+       switch (lvds_priv->fitting_mode) {
+       case DRM_MODE_SCALE_NO_SCALE:
+               /*
+                * For centered modes, we have to calculate border widths &
+                * heights and modify the values programmed into the CRTC.
+                */
+               left_border = (adjusted_mode->hdisplay - mode->hdisplay) / 2;
+               right_border = left_border;
+               if (mode->hdisplay & 1)
+                       right_border++;
+               top_border = (adjusted_mode->vdisplay - mode->vdisplay) / 2;
+               bottom_border = top_border;
+               if (mode->vdisplay & 1)
+                       bottom_border++;
+               /* Set active & border values */
+               adjusted_mode->crtc_hdisplay = mode->hdisplay;
+               /* Keep the boder be even */
+               if (right_border & 1)
+                       right_border++;
+               /* use the border directly instead of border minuse one */
+               adjusted_mode->crtc_hblank_start = mode->hdisplay +
+                                               right_border;
+               /* keep the blank width constant */
+               adjusted_mode->crtc_hblank_end =
+                       adjusted_mode->crtc_hblank_start + hblank_width;
+               /* get the hsync pos relative to hblank start */
+               hsync_pos = (hblank_width - hsync_width) / 2;
+               /* keep the hsync pos be even */
+               if (hsync_pos & 1)
+                       hsync_pos++;
+               adjusted_mode->crtc_hsync_start =
+                               adjusted_mode->crtc_hblank_start + hsync_pos;
+               /* keep the hsync width constant */
+               adjusted_mode->crtc_hsync_end =
+                               adjusted_mode->crtc_hsync_start + hsync_width;
+               adjusted_mode->crtc_vdisplay = mode->vdisplay;
+               /* use the border instead of border minus one */
+               adjusted_mode->crtc_vblank_start = mode->vdisplay +
+                                               bottom_border;
+               /* keep the vblank width constant */
+               adjusted_mode->crtc_vblank_end =
+                               adjusted_mode->crtc_vblank_start + vblank_width;
+               /* get the vsync start postion relative to vblank start */
+               vsync_pos = (vblank_width - vsync_width) / 2;
+               adjusted_mode->crtc_vsync_start =
+                               adjusted_mode->crtc_vblank_start + vsync_pos;
+               /* keep the vsync width constant */
+               adjusted_mode->crtc_vsync_end =
+                               adjusted_mode->crtc_vblank_start + vsync_width;
+               border = 1;
+               break;
+       case DRM_MODE_SCALE_ASPECT:
+               /* Scale but preserve the spect ratio */
+               pfit_control |= PFIT_ENABLE;
+               if (IS_I965G(dev)) {
+                       /* 965+ is easy, it does everything in hw */
+                       if (panel_ratio > desired_ratio)
+                               pfit_control |= PFIT_SCALING_PILLAR;
+                       else if (panel_ratio < desired_ratio)
+                               pfit_control |= PFIT_SCALING_LETTER;
+                       else
+                               pfit_control |= PFIT_SCALING_AUTO;
+               } else {
+                       /*
+                        * For earlier chips we have to calculate the scaling
+                        * ratio by hand and program it into the
+                        * PFIT_PGM_RATIO register
+                        */
+                       u32 horiz_bits, vert_bits, bits = 12;
+                       horiz_ratio = mode->hdisplay * PANEL_RATIO_FACTOR/
+                                               adjusted_mode->hdisplay;
+                       vert_ratio = mode->vdisplay * PANEL_RATIO_FACTOR/
+                                               adjusted_mode->vdisplay;
+                       horiz_scale = adjusted_mode->hdisplay *
+                                       PANEL_RATIO_FACTOR / mode->hdisplay;
+                       vert_scale = adjusted_mode->vdisplay *
+                                       PANEL_RATIO_FACTOR / mode->vdisplay;
+
+                       /* retain aspect ratio */
+                       if (panel_ratio > desired_ratio) { /* Pillar */
+                               u32 scaled_width;
+                               scaled_width = mode->hdisplay * vert_scale /
+                                               PANEL_RATIO_FACTOR;
+                               horiz_ratio = vert_ratio;
+                               pfit_control |= (VERT_AUTO_SCALE |
+                                                VERT_INTERP_BILINEAR |
+                                                HORIZ_INTERP_BILINEAR);
+                               /* Pillar will have left/right borders */
+                               left_border = (adjusted_mode->hdisplay -
+                                               scaled_width) / 2;
+                               right_border = left_border;
+                               if (mode->hdisplay & 1) /* odd resolutions */
+                                       right_border++;
+                               /* keep the border be even */
+                               if (right_border & 1)
+                                       right_border++;
+                               adjusted_mode->crtc_hdisplay = scaled_width;
+                               /* use border instead of border minus one */
+                               adjusted_mode->crtc_hblank_start =
+                                       scaled_width + right_border;
+                               /* keep the hblank width constant */
+                               adjusted_mode->crtc_hblank_end =
+                                       adjusted_mode->crtc_hblank_start +
+                                                       hblank_width;
+                               /*
+                                * get the hsync start pos relative to
+                                * hblank start
+                                */
+                               hsync_pos = (hblank_width - hsync_width) / 2;
+                               /* keep the hsync_pos be even */
+                               if (hsync_pos & 1)
+                                       hsync_pos++;
+                               adjusted_mode->crtc_hsync_start =
+                                       adjusted_mode->crtc_hblank_start +
+                                                       hsync_pos;
+                               /* keept hsync width constant */
+                               adjusted_mode->crtc_hsync_end =
+                                       adjusted_mode->crtc_hsync_start +
+                                                       hsync_width;
+                               border = 1;
+                       } else if (panel_ratio < desired_ratio) { /* letter */
+                               u32 scaled_height = mode->vdisplay *
+                                       horiz_scale / PANEL_RATIO_FACTOR;
+                               vert_ratio = horiz_ratio;
+                               pfit_control |= (HORIZ_AUTO_SCALE |
+                                                VERT_INTERP_BILINEAR |
+                                                HORIZ_INTERP_BILINEAR);
+                               /* Letterbox will have top/bottom border */
+                               top_border = (adjusted_mode->vdisplay -
+                                       scaled_height) / 2;
+                               bottom_border = top_border;
+                               if (mode->vdisplay & 1)
+                                       bottom_border++;
+                               adjusted_mode->crtc_vdisplay = scaled_height;
+                               /* use border instead of border minus one */
+                               adjusted_mode->crtc_vblank_start =
+                                       scaled_height + bottom_border;
+                               /* keep the vblank width constant */
+                               adjusted_mode->crtc_vblank_end =
+                                       adjusted_mode->crtc_vblank_start +
+                                                       vblank_width;
+                               /*
+                                * get the vsync start pos relative to
+                                * vblank start
+                                */
+                               vsync_pos = (vblank_width - vsync_width) / 2;
+                               adjusted_mode->crtc_vsync_start =
+                                       adjusted_mode->crtc_vblank_start +
+                                                       vsync_pos;
+                               /* keep the vsync width constant */
+                               adjusted_mode->crtc_vsync_end =
+                                       adjusted_mode->crtc_vsync_start +
+                                                       vsync_width;
+                               border = 1;
+                       } else {
+                       /* Aspects match, Let hw scale both directions */
+                               pfit_control |= (VERT_AUTO_SCALE |
+                                                HORIZ_AUTO_SCALE |
+                                                VERT_INTERP_BILINEAR |
+                                                HORIZ_INTERP_BILINEAR);
+                       }
+                       horiz_bits = (1 << bits) * horiz_ratio /
+                                       PANEL_RATIO_FACTOR;
+                       vert_bits = (1 << bits) * vert_ratio /
+                                       PANEL_RATIO_FACTOR;
+                       pfit_pgm_ratios =
+                               ((vert_bits << PFIT_VERT_SCALE_SHIFT) &
+                                               PFIT_VERT_SCALE_MASK) |
+                               ((horiz_bits << PFIT_HORIZ_SCALE_SHIFT) &
+                                               PFIT_HORIZ_SCALE_MASK);
+               }
+               break;
+
+       case DRM_MODE_SCALE_FULLSCREEN:
+               /*
+                * Full scaling, even if it changes the aspect ratio.
+                * Fortunately this is all done for us in hw.
+                */
+               pfit_control |= PFIT_ENABLE;
+               if (IS_I965G(dev))
+                       pfit_control |= PFIT_SCALING_AUTO;
+               else
+                       pfit_control |= (VERT_AUTO_SCALE | HORIZ_AUTO_SCALE |
+                                        VERT_INTERP_BILINEAR |
+                                        HORIZ_INTERP_BILINEAR);
+               break;
+       default:
+               break;
+       }
+
+out:
+       lvds_priv->pfit_control = pfit_control;
+       lvds_priv->pfit_pgm_ratios = pfit_pgm_ratios;
        /*
         * XXX: It would be nice to support lower refresh rates on the
         * panels to reduce power consumption, and perhaps match the
@@ -301,8 +573,8 @@ static void intel_lvds_mode_set(struct drm_encoder *encoder,
 {
        struct drm_device *dev = encoder->dev;
        struct drm_i915_private *dev_priv = dev->dev_private;
-       struct intel_crtc *intel_crtc = to_intel_crtc(encoder->crtc);
-       u32 pfit_control;
+       struct intel_output *intel_output = enc_to_intel_output(encoder);
+       struct intel_lvds_priv *lvds_priv = intel_output->dev_priv;
 
        /*
         * The LVDS pin pair will already have been turned on in the
@@ -319,22 +591,8 @@ static void intel_lvds_mode_set(struct drm_encoder *encoder,
         * screen.  Should be enabled before the pipe is enabled, according to
         * register description and PRM.
         */
-       if (mode->hdisplay != adjusted_mode->hdisplay ||
-           mode->vdisplay != adjusted_mode->vdisplay)
-               pfit_control = (PFIT_ENABLE | VERT_AUTO_SCALE |
-                               HORIZ_AUTO_SCALE | VERT_INTERP_BILINEAR |
-                               HORIZ_INTERP_BILINEAR);
-       else
-               pfit_control = 0;
-
-       if (!IS_I965G(dev)) {
-               if (dev_priv->panel_wants_dither || dev_priv->lvds_dither)
-                       pfit_control |= PANEL_8TO6_DITHER_ENABLE;
-       }
-       else
-               pfit_control |= intel_crtc->pipe << PFIT_PIPE_SHIFT;
-
-       I915_WRITE(PFIT_CONTROL, pfit_control);
+       I915_WRITE(PFIT_PGM_RATIOS, lvds_priv->pfit_pgm_ratios);
+       I915_WRITE(PFIT_CONTROL, lvds_priv->pfit_control);
 }
 
 /**
@@ -406,6 +664,34 @@ static int intel_lvds_set_property(struct drm_connector *connector,
                                   struct drm_property *property,
                                   uint64_t value)
 {
+       struct drm_device *dev = connector->dev;
+       struct intel_output *intel_output =
+                       to_intel_output(connector);
+
+       if (property == dev->mode_config.scaling_mode_property &&
+                               connector->encoder) {
+               struct drm_crtc *crtc = connector->encoder->crtc;
+               struct intel_lvds_priv *lvds_priv = intel_output->dev_priv;
+               if (value == DRM_MODE_SCALE_NON_GPU) {
+                       DRM_DEBUG_KMS(I915_LVDS,
+                                       "non_GPU property is unsupported\n");
+                       return 0;
+               }
+               if (lvds_priv->fitting_mode == value) {
+                       /* the LVDS scaling property is not changed */
+                       return 0;
+               }
+               lvds_priv->fitting_mode = value;
+               if (crtc && crtc->enabled) {
+                       /*
+                        * If the CRTC is enabled, the display will be changed
+                        * according to the new panel fitting mode.
+                        */
+                       drm_crtc_helper_set_mode(crtc, &crtc->mode,
+                               crtc->x, crtc->y, crtc->fb);
+               }
+       }
+
        return 0;
 }
 
@@ -456,7 +742,7 @@ static const struct dmi_system_id intel_no_lvds[] = {
                .callback = intel_no_lvds_dmi_callback,
                .ident = "Apple Mac Mini (Core series)",
                .matches = {
-                       DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."),
+                       DMI_MATCH(DMI_SYS_VENDOR, "Apple"),
                        DMI_MATCH(DMI_PRODUCT_NAME, "Macmini1,1"),
                },
        },
@@ -464,7 +750,7 @@ static const struct dmi_system_id intel_no_lvds[] = {
                .callback = intel_no_lvds_dmi_callback,
                .ident = "Apple Mac Mini (Core 2 series)",
                .matches = {
-                       DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."),
+                       DMI_MATCH(DMI_SYS_VENDOR, "Apple"),
                        DMI_MATCH(DMI_PRODUCT_NAME, "Macmini2,1"),
                },
        },
@@ -503,6 +789,65 @@ static const struct dmi_system_id intel_no_lvds[] = {
        { }     /* terminating entry */
 };
 
+#ifdef CONFIG_ACPI
+/*
+ * check_lid_device -- check whether @handle is an ACPI LID device.
+ * @handle: ACPI device handle
+ * @level : depth in the ACPI namespace tree
+ * @context: the number of LID device when we find the device
+ * @rv: a return value to fill if desired (Not use)
+ */
+static acpi_status
+check_lid_device(acpi_handle handle, u32 level, void *context,
+                       void **return_value)
+{
+       struct acpi_device *acpi_dev;
+       int *lid_present = context;
+
+       acpi_dev = NULL;
+       /* Get the acpi device for device handle */
+       if (acpi_bus_get_device(handle, &acpi_dev) || !acpi_dev) {
+               /* If there is no ACPI device for handle, return */
+               return AE_OK;
+       }
+
+       if (!strncmp(acpi_device_hid(acpi_dev), "PNP0C0D", 7))
+               *lid_present = 1;
+
+       return AE_OK;
+}
+
+/**
+ * check whether there exists the ACPI LID device by enumerating the ACPI
+ * device tree.
+ */
+static int intel_lid_present(void)
+{
+       int lid_present = 0;
+
+       if (acpi_disabled) {
+               /* If ACPI is disabled, there is no ACPI device tree to
+                * check, so assume the LID device would have been present.
+                */
+               return 1;
+       }
+
+       acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT,
+                               ACPI_UINT32_MAX,
+                               check_lid_device, &lid_present, NULL);
+
+       return lid_present;
+}
+#else
+static int intel_lid_present(void)
+{
+       /* In the absence of ACPI built in, assume that the LID device would
+        * have been present.
+        */
+       return 1;
+}
+#endif
+
 /**
  * intel_lvds_init - setup LVDS connectors on this device
  * @dev: drm device
@@ -518,6 +863,7 @@ void intel_lvds_init(struct drm_device *dev)
        struct drm_encoder *encoder;
        struct drm_display_mode *scan; /* *modes, *bios_mode; */
        struct drm_crtc *crtc;
+       struct intel_lvds_priv *lvds_priv;
        u32 lvds;
        int pipe, gpio = GPIOC;
 
@@ -525,13 +871,24 @@ void intel_lvds_init(struct drm_device *dev)
        if (dmi_check_system(intel_no_lvds))
                return;
 
+       /* Assume that any device without an ACPI LID device also doesn't
+        * have an integrated LVDS.  We would be better off parsing the BIOS
+        * to get a reliable indicator, but that code isn't written yet.
+        *
+        * In the case of all-in-one desktops using LVDS that we've seen,
+        * they're using SDVO LVDS.
+        */
+       if (!intel_lid_present())
+               return;
+
        if (IS_IGDNG(dev)) {
                if ((I915_READ(PCH_LVDS) & LVDS_DETECTED) == 0)
                        return;
                gpio = PCH_GPIOC;
        }
 
-       intel_output = kzalloc(sizeof(struct intel_output), GFP_KERNEL);
+       intel_output = kzalloc(sizeof(struct intel_output) +
+                               sizeof(struct intel_lvds_priv), GFP_KERNEL);
        if (!intel_output) {
                return;
        }
@@ -553,7 +910,18 @@ void intel_lvds_init(struct drm_device *dev)
        connector->interlace_allowed = false;
        connector->doublescan_allowed = false;
 
+       lvds_priv = (struct intel_lvds_priv *)(intel_output + 1);
+       intel_output->dev_priv = lvds_priv;
+       /* create the scaling mode property */
+       drm_mode_create_scaling_mode_property(dev);
+       /*
+        * the initial panel fitting mode will be FULL_SCREEN.
+        */
 
+       drm_connector_attach_property(&intel_output->base,
+                                     dev->mode_config.scaling_mode_property,
+                                     DRM_MODE_SCALE_FULLSCREEN);
+       lvds_priv->fitting_mode = DRM_MODE_SCALE_FULLSCREEN;
        /*
         * LVDS discovery:
         * 1) check for EDID on DDC
@@ -649,5 +1017,5 @@ failed:
        if (intel_output->ddc_bus)
                intel_i2c_destroy(intel_output->ddc_bus);
        drm_connector_cleanup(connector);
-       kfree(connector);
+       kfree(intel_output);
 }
index e0910fefce8713d232ec131d39edad62e91c2058..67e2f4632a2451fd77200e0f9810a18c83afca1d 100644 (file)
@@ -53,10 +53,9 @@ bool intel_ddc_probe(struct intel_output *intel_output)
                }
        };
 
-       intel_i2c_quirk_set(intel_output->ddc_bus->drm_dev, true);
-       ret = i2c_transfer(&intel_output->ddc_bus->adapter, msgs, 2);
-       intel_i2c_quirk_set(intel_output->ddc_bus->drm_dev, false);
-
+       intel_i2c_quirk_set(intel_output->base.dev, true);
+       ret = i2c_transfer(intel_output->ddc_bus, msgs, 2);
+       intel_i2c_quirk_set(intel_output->base.dev, false);
        if (ret == 2)
                return true;
 
@@ -74,10 +73,9 @@ int intel_ddc_get_modes(struct intel_output *intel_output)
        struct edid *edid;
        int ret = 0;
 
-       intel_i2c_quirk_set(intel_output->ddc_bus->drm_dev, true);
-       edid = drm_get_edid(&intel_output->base,
-                           &intel_output->ddc_bus->adapter);
-       intel_i2c_quirk_set(intel_output->ddc_bus->drm_dev, false);
+       intel_i2c_quirk_set(intel_output->base.dev, true);
+       edid = drm_get_edid(&intel_output->base, intel_output->ddc_bus);
+       intel_i2c_quirk_set(intel_output->base.dev, false);
        if (edid) {
                drm_mode_connector_update_edid_property(&intel_output->base,
                                                        edid);
index 9a00adb3a50896033302bb70b6d715de72408dce..4f0c30948bc43ae5626f1fa76b4368db7f2149ba 100644 (file)
@@ -38,8 +38,7 @@
 #undef SDVO_DEBUG
 #define I915_SDVO      "i915_sdvo"
 struct intel_sdvo_priv {
-       struct intel_i2c_chan *i2c_bus;
-       int slaveaddr;
+       u8 slave_addr;
 
        /* Register for the SDVO device: SDVOB or SDVOC */
        int output_device;
@@ -69,11 +68,22 @@ struct intel_sdvo_priv {
         * This is set if we treat the device as HDMI, instead of DVI.
         */
        bool is_hdmi;
+
        /**
         * This is set if we detect output of sdvo device as LVDS.
         */
        bool is_lvds;
 
+       /**
+        * This is sdvo flags for input timing.
+        */
+       uint8_t sdvo_flags;
+
+       /**
+        * This is sdvo fixed pannel mode pointer
+        */
+       struct drm_display_mode *sdvo_lvds_fixed_mode;
+
        /**
         * Returned SDTV resolutions allowed for the current format, if the
         * device reported it.
@@ -146,13 +156,13 @@ static bool intel_sdvo_read_byte(struct intel_output *intel_output, u8 addr,
 
        struct i2c_msg msgs[] = {
                {
-                       .addr = sdvo_priv->i2c_bus->slave_addr,
+                       .addr = sdvo_priv->slave_addr >> 1,
                        .flags = 0,
                        .len = 1,
                        .buf = out_buf,
                },
                {
-                       .addr = sdvo_priv->i2c_bus->slave_addr,
+                       .addr = sdvo_priv->slave_addr >> 1,
                        .flags = I2C_M_RD,
                        .len = 1,
                        .buf = buf,
@@ -162,7 +172,7 @@ static bool intel_sdvo_read_byte(struct intel_output *intel_output, u8 addr,
        out_buf[0] = addr;
        out_buf[1] = 0;
 
-       if ((ret = i2c_transfer(&sdvo_priv->i2c_bus->adapter, msgs, 2)) == 2)
+       if ((ret = i2c_transfer(intel_output->i2c_bus, msgs, 2)) == 2)
        {
                *ch = buf[0];
                return true;
@@ -175,10 +185,11 @@ static bool intel_sdvo_read_byte(struct intel_output *intel_output, u8 addr,
 static bool intel_sdvo_write_byte(struct intel_output *intel_output, int addr,
                                  u8 ch)
 {
+       struct intel_sdvo_priv *sdvo_priv = intel_output->dev_priv;
        u8 out_buf[2];
        struct i2c_msg msgs[] = {
                {
-                       .addr = intel_output->i2c_bus->slave_addr,
+                       .addr = sdvo_priv->slave_addr >> 1,
                        .flags = 0,
                        .len = 2,
                        .buf = out_buf,
@@ -188,7 +199,7 @@ static bool intel_sdvo_write_byte(struct intel_output *intel_output, int addr,
        out_buf[0] = addr;
        out_buf[1] = ch;
 
-       if (i2c_transfer(&intel_output->i2c_bus->adapter, msgs, 1) == 1)
+       if (i2c_transfer(intel_output->i2c_bus, msgs, 1) == 1)
        {
                return true;
        }
@@ -592,6 +603,7 @@ intel_sdvo_create_preferred_input_timing(struct intel_output *output,
                                         uint16_t height)
 {
        struct intel_sdvo_preferred_input_timing_args args;
+       struct intel_sdvo_priv *sdvo_priv = output->dev_priv;
        uint8_t status;
 
        memset(&args, 0, sizeof(args));
@@ -599,7 +611,12 @@ intel_sdvo_create_preferred_input_timing(struct intel_output *output,
        args.width = width;
        args.height = height;
        args.interlace = 0;
-       args.scaled = 0;
+
+       if (sdvo_priv->is_lvds &&
+          (sdvo_priv->sdvo_lvds_fixed_mode->hdisplay != width ||
+           sdvo_priv->sdvo_lvds_fixed_mode->vdisplay != height))
+               args.scaled = 1;
+
        intel_sdvo_write_cmd(output, SDVO_CMD_CREATE_PREFERRED_INPUT_TIMING,
                             &args, sizeof(args));
        status = intel_sdvo_read_response(output, NULL, 0);
@@ -944,12 +961,7 @@ static bool intel_sdvo_mode_fixup(struct drm_encoder *encoder,
        struct intel_output *output = enc_to_intel_output(encoder);
        struct intel_sdvo_priv *dev_priv = output->dev_priv;
 
-       if (!dev_priv->is_tv) {
-               /* Make the CRTC code factor in the SDVO pixel multiplier.  The
-                * SDVO device will be told of the multiplier during mode_set.
-                */
-               adjusted_mode->clock *= intel_sdvo_get_pixel_multiplier(mode);
-       } else {
+       if (dev_priv->is_tv) {
                struct intel_sdvo_dtd output_dtd;
                bool success;
 
@@ -980,6 +992,7 @@ static bool intel_sdvo_mode_fixup(struct drm_encoder *encoder,
                        intel_sdvo_get_preferred_input_timing(output,
                                                             &input_dtd);
                        intel_sdvo_get_mode_from_dtd(adjusted_mode, &input_dtd);
+                       dev_priv->sdvo_flags = input_dtd.part2.sdvo_flags;
 
                        drm_mode_set_crtcinfo(adjusted_mode, 0);
 
@@ -990,6 +1003,52 @@ static bool intel_sdvo_mode_fixup(struct drm_encoder *encoder,
                } else {
                        return false;
                }
+       } else if (dev_priv->is_lvds) {
+               struct intel_sdvo_dtd output_dtd;
+               bool success;
+
+               drm_mode_set_crtcinfo(dev_priv->sdvo_lvds_fixed_mode, 0);
+               /* Set output timings */
+               intel_sdvo_get_dtd_from_mode(&output_dtd,
+                               dev_priv->sdvo_lvds_fixed_mode);
+
+               intel_sdvo_set_target_output(output,
+                                            dev_priv->controlled_output);
+               intel_sdvo_set_output_timing(output, &output_dtd);
+
+               /* Set the input timing to the screen. Assume always input 0. */
+               intel_sdvo_set_target_input(output, true, false);
+
+
+               success = intel_sdvo_create_preferred_input_timing(
+                               output,
+                               mode->clock / 10,
+                               mode->hdisplay,
+                               mode->vdisplay);
+
+               if (success) {
+                       struct intel_sdvo_dtd input_dtd;
+
+                       intel_sdvo_get_preferred_input_timing(output,
+                                                            &input_dtd);
+                       intel_sdvo_get_mode_from_dtd(adjusted_mode, &input_dtd);
+                       dev_priv->sdvo_flags = input_dtd.part2.sdvo_flags;
+
+                       drm_mode_set_crtcinfo(adjusted_mode, 0);
+
+                       mode->clock = adjusted_mode->clock;
+
+                       adjusted_mode->clock *=
+                               intel_sdvo_get_pixel_multiplier(mode);
+               } else {
+                       return false;
+               }
+
+       } else {
+               /* Make the CRTC code factor in the SDVO pixel multiplier.  The
+                * SDVO device will be told of the multiplier during mode_set.
+                */
+               adjusted_mode->clock *= intel_sdvo_get_pixel_multiplier(mode);
        }
        return true;
 }
@@ -1033,15 +1092,16 @@ static void intel_sdvo_mode_set(struct drm_encoder *encoder,
 
        /* We have tried to get input timing in mode_fixup, and filled into
           adjusted_mode */
-       if (sdvo_priv->is_tv)
+       if (sdvo_priv->is_tv || sdvo_priv->is_lvds) {
                intel_sdvo_get_dtd_from_mode(&input_dtd, adjusted_mode);
-       else
+               input_dtd.part2.sdvo_flags = sdvo_priv->sdvo_flags;
+       } else
                intel_sdvo_get_dtd_from_mode(&input_dtd, mode);
 
        /* If it's a TV, we already set the output timing in mode_fixup.
         * Otherwise, the output timing is equal to the input timing.
         */
-       if (!sdvo_priv->is_tv) {
+       if (!sdvo_priv->is_tv && !sdvo_priv->is_lvds) {
                /* Set the output timing to the screen */
                intel_sdvo_set_target_output(output,
                                             sdvo_priv->controlled_output);
@@ -1116,6 +1176,8 @@ static void intel_sdvo_mode_set(struct drm_encoder *encoder,
                sdvox |= (sdvo_pixel_multiply - 1) << SDVO_PORT_MULTIPLY_SHIFT;
        }
 
+       if (sdvo_priv->sdvo_flags & SDVO_NEED_TO_STALL)
+               sdvox |= SDVO_STALL_SELECT;
        intel_sdvo_write_sdvox(output, sdvox);
 }
 
@@ -1276,6 +1338,17 @@ static int intel_sdvo_mode_valid(struct drm_connector *connector,
        if (sdvo_priv->pixel_clock_max < mode->clock)
                return MODE_CLOCK_HIGH;
 
+       if (sdvo_priv->is_lvds == true) {
+               if (sdvo_priv->sdvo_lvds_fixed_mode == NULL)
+                       return MODE_PANEL;
+
+               if (mode->hdisplay > sdvo_priv->sdvo_lvds_fixed_mode->hdisplay)
+                       return MODE_PANEL;
+
+               if (mode->vdisplay > sdvo_priv->sdvo_lvds_fixed_mode->vdisplay)
+                       return MODE_PANEL;
+       }
+
        return MODE_OK;
 }
 
@@ -1369,9 +1442,8 @@ intel_sdvo_hdmi_sink_detect(struct drm_connector *connector)
        struct intel_sdvo_priv *sdvo_priv = intel_output->dev_priv;
        struct edid *edid = NULL;
 
-       intel_sdvo_set_control_bus_switch(intel_output, sdvo_priv->ddc_bus);
        edid = drm_get_edid(&intel_output->base,
-                           &intel_output->ddc_bus->adapter);
+                           intel_output->ddc_bus);
        if (edid != NULL) {
                sdvo_priv->is_hdmi = drm_detect_hdmi_monitor(edid);
                kfree(edid);
@@ -1549,23 +1621,21 @@ static void intel_sdvo_get_tv_modes(struct drm_connector *connector)
 static void intel_sdvo_get_lvds_modes(struct drm_connector *connector)
 {
        struct intel_output *intel_output = to_intel_output(connector);
-       struct intel_sdvo_priv *sdvo_priv = intel_output->dev_priv;
        struct drm_i915_private *dev_priv = connector->dev->dev_private;
+       struct intel_sdvo_priv *sdvo_priv = intel_output->dev_priv;
+       struct drm_display_mode *newmode;
 
        /*
         * Attempt to get the mode list from DDC.
         * Assume that the preferred modes are
         * arranged in priority order.
         */
-       /* set the bus switch and get the modes */
-       intel_sdvo_set_control_bus_switch(intel_output, sdvo_priv->ddc_bus);
        intel_ddc_get_modes(intel_output);
        if (list_empty(&connector->probed_modes) == false)
-               return;
+               goto end;
 
        /* Fetch modes from VBT */
        if (dev_priv->sdvo_lvds_vbt_mode != NULL) {
-               struct drm_display_mode *newmode;
                newmode = drm_mode_duplicate(connector->dev,
                                             dev_priv->sdvo_lvds_vbt_mode);
                if (newmode != NULL) {
@@ -1575,6 +1645,16 @@ static void intel_sdvo_get_lvds_modes(struct drm_connector *connector)
                        drm_mode_probed_add(connector, newmode);
                }
        }
+
+end:
+       list_for_each_entry(newmode, &connector->probed_modes, head) {
+               if (newmode->type & DRM_MODE_TYPE_PREFERRED) {
+                       sdvo_priv->sdvo_lvds_fixed_mode =
+                               drm_mode_duplicate(connector->dev, newmode);
+                       break;
+               }
+       }
+
 }
 
 static int intel_sdvo_get_modes(struct drm_connector *connector)
@@ -1597,14 +1677,20 @@ static int intel_sdvo_get_modes(struct drm_connector *connector)
 static void intel_sdvo_destroy(struct drm_connector *connector)
 {
        struct intel_output *intel_output = to_intel_output(connector);
+       struct intel_sdvo_priv *sdvo_priv = intel_output->dev_priv;
 
        if (intel_output->i2c_bus)
                intel_i2c_destroy(intel_output->i2c_bus);
        if (intel_output->ddc_bus)
                intel_i2c_destroy(intel_output->ddc_bus);
 
+       if (sdvo_priv->sdvo_lvds_fixed_mode != NULL)
+               drm_mode_destroy(connector->dev,
+                                sdvo_priv->sdvo_lvds_fixed_mode);
+
        drm_sysfs_connector_remove(connector);
        drm_connector_cleanup(connector);
+
        kfree(intel_output);
 }
 
@@ -1709,7 +1795,7 @@ intel_sdvo_chan_to_intel_output(struct intel_i2c_chan *chan)
 
        list_for_each_entry(connector,
                        &dev->mode_config.connector_list, head) {
-               if (to_intel_output(connector)->ddc_bus == chan) {
+               if (to_intel_output(connector)->ddc_bus == &chan->adapter) {
                        intel_output = to_intel_output(connector);
                        break;
                }
@@ -1723,7 +1809,7 @@ static int intel_sdvo_master_xfer(struct i2c_adapter *i2c_adap,
        struct intel_output *intel_output;
        struct intel_sdvo_priv *sdvo_priv;
        struct i2c_algo_bit_data *algo_data;
-       struct i2c_algorithm *algo;
+       const struct i2c_algorithm *algo;
 
        algo_data = (struct i2c_algo_bit_data *)i2c_adap->algo_data;
        intel_output =
@@ -1733,7 +1819,7 @@ static int intel_sdvo_master_xfer(struct i2c_adapter *i2c_adap,
                return -EINVAL;
 
        sdvo_priv = intel_output->dev_priv;
-       algo = (struct i2c_algorithm *)intel_output->i2c_bus->adapter.algo;
+       algo = intel_output->i2c_bus->algo;
 
        intel_sdvo_set_control_bus_switch(intel_output, sdvo_priv->ddc_bus);
        return algo->master_xfer(i2c_adap, msgs, num);
@@ -1785,13 +1871,11 @@ bool intel_sdvo_init(struct drm_device *dev, int output_device)
        struct drm_connector *connector;
        struct intel_output *intel_output;
        struct intel_sdvo_priv *sdvo_priv;
-       struct intel_i2c_chan *i2cbus = NULL;
-       struct intel_i2c_chan *ddcbus = NULL;
+
        int connector_type;
        u8 ch[0x40];
        int i;
-       int encoder_type, output_id;
-       u8 slave_addr;
+       int encoder_type;
 
        intel_output = kcalloc(sizeof(struct intel_output)+sizeof(struct intel_sdvo_priv), 1, GFP_KERNEL);
        if (!intel_output) {
@@ -1799,29 +1883,24 @@ bool intel_sdvo_init(struct drm_device *dev, int output_device)
        }
 
        sdvo_priv = (struct intel_sdvo_priv *)(intel_output + 1);
+       sdvo_priv->output_device = output_device;
+
+       intel_output->dev_priv = sdvo_priv;
        intel_output->type = INTEL_OUTPUT_SDVO;
 
        /* setup the DDC bus. */
        if (output_device == SDVOB)
-               i2cbus = intel_i2c_create(dev, GPIOE, "SDVOCTRL_E for SDVOB");
+               intel_output->i2c_bus = intel_i2c_create(dev, GPIOE, "SDVOCTRL_E for SDVOB");
        else
-               i2cbus = intel_i2c_create(dev, GPIOE, "SDVOCTRL_E for SDVOC");
+               intel_output->i2c_bus = intel_i2c_create(dev, GPIOE, "SDVOCTRL_E for SDVOC");
 
-       if (!i2cbus)
+       if (!intel_output->i2c_bus)
                goto err_inteloutput;
 
-       slave_addr = intel_sdvo_get_slave_addr(dev, output_device);
-       sdvo_priv->i2c_bus = i2cbus;
+       sdvo_priv->slave_addr = intel_sdvo_get_slave_addr(dev, output_device);
 
-       if (output_device == SDVOB) {
-               output_id = 1;
-       } else {
-               output_id = 2;
-       }
-       sdvo_priv->i2c_bus->slave_addr = slave_addr >> 1;
-       sdvo_priv->output_device = output_device;
-       intel_output->i2c_bus = i2cbus;
-       intel_output->dev_priv = sdvo_priv;
+       /* Save the bit-banging i2c functionality for use by the DDC wrapper */
+       intel_sdvo_i2c_bit_algo.functionality = intel_output->i2c_bus->algo->functionality;
 
        /* Read the regs to test if we can talk to the device */
        for (i = 0; i < 0x40; i++) {
@@ -1835,17 +1914,15 @@ bool intel_sdvo_init(struct drm_device *dev, int output_device)
 
        /* setup the DDC bus. */
        if (output_device == SDVOB)
-               ddcbus = intel_i2c_create(dev, GPIOE, "SDVOB DDC BUS");
+               intel_output->ddc_bus = intel_i2c_create(dev, GPIOE, "SDVOB DDC BUS");
        else
-               ddcbus = intel_i2c_create(dev, GPIOE, "SDVOC DDC BUS");
+               intel_output->ddc_bus = intel_i2c_create(dev, GPIOE, "SDVOC DDC BUS");
 
-       if (ddcbus == NULL)
+       if (intel_output->ddc_bus == NULL)
                goto err_i2c;
 
-       intel_sdvo_i2c_bit_algo.functionality =
-               intel_output->i2c_bus->adapter.algo->functionality;
-       ddcbus->adapter.algo = &intel_sdvo_i2c_bit_algo;
-       intel_output->ddc_bus = ddcbus;
+       /* Wrap with our custom algo which switches to DDC mode */
+       intel_output->ddc_bus->algo = &intel_sdvo_i2c_bit_algo;
 
        /* In defaut case sdvo lvds is false */
        sdvo_priv->is_lvds = false;
@@ -1965,9 +2042,10 @@ bool intel_sdvo_init(struct drm_device *dev, int output_device)
        return true;
 
 err_i2c:
-       if (ddcbus != NULL)
+       if (intel_output->ddc_bus != NULL)
                intel_i2c_destroy(intel_output->ddc_bus);
-       intel_i2c_destroy(intel_output->i2c_bus);
+       if (intel_output->i2c_bus != NULL)
+               intel_i2c_destroy(intel_output->i2c_bus);
 err_inteloutput:
        kfree(intel_output);
 
index 193938b7d7f9ea3cce94188fb733a15990282040..ba5cdf8ae40bea4ab9d5b416fd5c3e10ac43facb 100644 (file)
@@ -715,6 +715,7 @@ struct intel_sdvo_enhancements_arg {
   #define SDVO_HBUF_TX_ONCE    (2 << 6)
   #define SDVO_HBUF_TX_VSYNC   (3 << 6)
 #define SDVO_CMD_GET_AUDIO_TX_INFO     0x9c
+#define SDVO_NEED_TO_STALL  (1 << 7)
 
 struct intel_sdvo_encode{
     u8 dvi_rev;
index ea68992e441607b9356e7d93c4463782bfeae200..a43c98e3f0777dc6de4416a8f00f5c9c8dedcd82 100644 (file)
@@ -1383,34 +1383,31 @@ intel_tv_detect_type (struct drm_crtc *crtc, struct intel_output *intel_output)
        /*
         * Detect TV by polling)
         */
-       if (intel_output->load_detect_temp) {
-               /* TV not currently running, prod it with destructive detect */
-               save_tv_dac = tv_dac;
-               tv_ctl = I915_READ(TV_CTL);
-               save_tv_ctl = tv_ctl;
-               tv_ctl &= ~TV_ENC_ENABLE;
-               tv_ctl &= ~TV_TEST_MODE_MASK;
-               tv_ctl |= TV_TEST_MODE_MONITOR_DETECT;
-               tv_dac &= ~TVDAC_SENSE_MASK;
-               tv_dac &= ~DAC_A_MASK;
-               tv_dac &= ~DAC_B_MASK;
-               tv_dac &= ~DAC_C_MASK;
-               tv_dac |= (TVDAC_STATE_CHG_EN |
-                          TVDAC_A_SENSE_CTL |
-                          TVDAC_B_SENSE_CTL |
-                          TVDAC_C_SENSE_CTL |
-                          DAC_CTL_OVERRIDE |
-                          DAC_A_0_7_V |
-                          DAC_B_0_7_V |
-                          DAC_C_0_7_V);
-               I915_WRITE(TV_CTL, tv_ctl);
-               I915_WRITE(TV_DAC, tv_dac);
-               intel_wait_for_vblank(dev);
-               tv_dac = I915_READ(TV_DAC);
-               I915_WRITE(TV_DAC, save_tv_dac);
-               I915_WRITE(TV_CTL, save_tv_ctl);
-               intel_wait_for_vblank(dev);
-       }
+       save_tv_dac = tv_dac;
+       tv_ctl = I915_READ(TV_CTL);
+       save_tv_ctl = tv_ctl;
+       tv_ctl &= ~TV_ENC_ENABLE;
+       tv_ctl &= ~TV_TEST_MODE_MASK;
+       tv_ctl |= TV_TEST_MODE_MONITOR_DETECT;
+       tv_dac &= ~TVDAC_SENSE_MASK;
+       tv_dac &= ~DAC_A_MASK;
+       tv_dac &= ~DAC_B_MASK;
+       tv_dac &= ~DAC_C_MASK;
+       tv_dac |= (TVDAC_STATE_CHG_EN |
+                  TVDAC_A_SENSE_CTL |
+                  TVDAC_B_SENSE_CTL |
+                  TVDAC_C_SENSE_CTL |
+                  DAC_CTL_OVERRIDE |
+                  DAC_A_0_7_V |
+                  DAC_B_0_7_V |
+                  DAC_C_0_7_V);
+       I915_WRITE(TV_CTL, tv_ctl);
+       I915_WRITE(TV_DAC, tv_dac);
+       intel_wait_for_vblank(dev);
+       tv_dac = I915_READ(TV_DAC);
+       I915_WRITE(TV_DAC, save_tv_dac);
+       I915_WRITE(TV_CTL, save_tv_ctl);
+       intel_wait_for_vblank(dev);
        /*
         *  A B C
         *  0 1 1 Composite
index f30aa7274a54099913d85b7eeede05b1e9daafec..f97563db4e59550d68d8b54c5cfcebf56375a57f 100644 (file)
 #include "radeon_asic.h"
 #include "atom.h"
 
+/*
+ * Clear GPU surface registers.
+ */
+static void radeon_surface_init(struct radeon_device *rdev)
+{
+       /* FIXME: check this out */
+       if (rdev->family < CHIP_R600) {
+               int i;
+
+               for (i = 0; i < 8; i++) {
+                       WREG32(RADEON_SURFACE0_INFO +
+                              i * (RADEON_SURFACE1_INFO - RADEON_SURFACE0_INFO),
+                              0);
+               }
+       }
+}
+
 /*
  * GPU scratch registers helpers function.
  */
@@ -496,6 +513,8 @@ int radeon_device_init(struct radeon_device *rdev,
        radeon_errata(rdev);
        /* Initialize scratch registers */
        radeon_scratch_init(rdev);
+       /* Initialize surface registers */
+       radeon_surface_init(rdev);
 
        /* TODO: disable VGA need to use VGA request */
        /* BIOS*/
@@ -604,9 +623,6 @@ int radeon_device_init(struct radeon_device *rdev,
        if (r) {
                return r;
        }
-       if (rdev->fbdev_rfb && rdev->fbdev_rfb->obj) {
-               rdev->fbdev_robj = rdev->fbdev_rfb->obj->driver_private;
-       }
        if (!ret) {
                DRM_INFO("radeon: kernel modesetting successfully initialized.\n");
        }
index 09c9fb9f621071c864997bdd286b04e0e8a26d99..84ba69f487849f2c936471761228191752e0ce99 100644 (file)
@@ -345,7 +345,7 @@ static void __exit radeon_exit(void)
        drm_exit(driver);
 }
 
-late_initcall(radeon_init);
+module_init(radeon_init);
 module_exit(radeon_exit);
 
 MODULE_AUTHOR(DRIVER_AUTHOR);
index fa86d398945e237c30e71250627626d9b20bbf74..9e8f191eb64a22672e5a7e7f2f747ca5049fa85e 100644 (file)
@@ -478,14 +478,16 @@ int radeonfb_create(struct radeon_device *rdev,
 {
        struct fb_info *info;
        struct radeon_fb_device *rfbdev;
-       struct drm_framebuffer *fb;
+       struct drm_framebuffer *fb = NULL;
        struct radeon_framebuffer *rfb;
        struct drm_mode_fb_cmd mode_cmd;
        struct drm_gem_object *gobj = NULL;
        struct radeon_object *robj = NULL;
        struct device *device = &rdev->pdev->dev;
        int size, aligned_size, ret;
+       u64 fb_gpuaddr;
        void *fbptr = NULL;
+       unsigned long tmp;
 
        mode_cmd.width = surface_width;
        mode_cmd.height = surface_height;
@@ -498,11 +500,12 @@ int radeonfb_create(struct radeon_device *rdev,
        aligned_size = ALIGN(size, PAGE_SIZE);
 
        ret = radeon_gem_object_create(rdev, aligned_size, 0,
-                                      RADEON_GEM_DOMAIN_VRAM,
-                                      false, ttm_bo_type_kernel,
-                                      false, &gobj);
+                       RADEON_GEM_DOMAIN_VRAM,
+                       false, ttm_bo_type_kernel,
+                       false, &gobj);
        if (ret) {
-               printk(KERN_ERR "failed to allocate framebuffer\n");
+               printk(KERN_ERR "failed to allocate framebuffer (%d %d)\n",
+                      surface_width, surface_height);
                ret = -ENOMEM;
                goto out;
        }
@@ -515,12 +518,19 @@ int radeonfb_create(struct radeon_device *rdev,
                ret = -ENOMEM;
                goto out_unref;
        }
+       ret = radeon_object_pin(robj, RADEON_GEM_DOMAIN_VRAM, &fb_gpuaddr);
+       if (ret) {
+               printk(KERN_ERR "failed to pin framebuffer\n");
+               ret = -ENOMEM;
+               goto out_unref;
+       }
 
        list_add(&fb->filp_head, &rdev->ddev->mode_config.fb_kernel_list);
 
        rfb = to_radeon_framebuffer(fb);
        *rfb_p = rfb;
        rdev->fbdev_rfb = rfb;
+       rdev->fbdev_robj = robj;
 
        info = framebuffer_alloc(sizeof(struct radeon_fb_device), device);
        if (info == NULL) {
@@ -541,13 +551,13 @@ int radeonfb_create(struct radeon_device *rdev,
        info->fix.xpanstep = 1; /* doing it in hw */
        info->fix.ypanstep = 1; /* doing it in hw */
        info->fix.ywrapstep = 0;
-       info->fix.accel = FB_ACCEL_I830;
+       info->fix.accel = FB_ACCEL_NONE;
        info->fix.type_aux = 0;
        info->flags = FBINFO_DEFAULT;
        info->fbops = &radeonfb_ops;
        info->fix.line_length = fb->pitch;
-       info->screen_base = fbptr;
-       info->fix.smem_start = (unsigned long)fbptr;
+       tmp = fb_gpuaddr - rdev->mc.vram_location;
+       info->fix.smem_start = rdev->mc.aper_base + tmp;
        info->fix.smem_len = size;
        info->screen_base = fbptr;
        info->screen_size = size;
@@ -562,8 +572,8 @@ int radeonfb_create(struct radeon_device *rdev,
        info->var.width = -1;
        info->var.xres = fb_width;
        info->var.yres = fb_height;
-       info->fix.mmio_start = pci_resource_start(rdev->pdev, 2);
-       info->fix.mmio_len = pci_resource_len(rdev->pdev, 2);
+       info->fix.mmio_start = 0;
+       info->fix.mmio_len = 0;
        info->pixmap.size = 64*1024;
        info->pixmap.buf_align = 8;
        info->pixmap.access_align = 32;
@@ -644,7 +654,7 @@ out_unref:
        if (robj) {
                radeon_object_kunmap(robj);
        }
-       if (ret) {
+       if (fb && ret) {
                list_del(&fb->filp_head);
                drm_gem_object_unreference(gobj);
                drm_framebuffer_cleanup(fb);
@@ -813,6 +823,7 @@ int radeonfb_remove(struct drm_device *dev, struct drm_framebuffer *fb)
                robj = rfb->obj->driver_private;
                unregister_framebuffer(info);
                radeon_object_kunmap(robj);
+               radeon_object_unpin(robj);
                framebuffer_release(info);
        }
 
index 983e8df5e000d392c26b0b711044055137acd761..bac0d06c52ace7a48841d351d6978e3452d634a3 100644 (file)
@@ -223,7 +223,6 @@ int radeon_object_pin(struct radeon_object *robj, uint32_t domain,
 {
        uint32_t flags;
        uint32_t tmp;
-       void *fbptr;
        int r;
 
        flags = radeon_object_flags_from_domain(domain);
@@ -242,10 +241,6 @@ int radeon_object_pin(struct radeon_object *robj, uint32_t domain,
                DRM_ERROR("radeon: failed to reserve object for pinning it.\n");
                return r;
        }
-       if (robj->rdev->fbdev_robj == robj) {
-               mutex_lock(&robj->rdev->fbdev_info->lock);
-               radeon_object_kunmap(robj);
-       }
        tmp = robj->tobj.mem.placement;
        ttm_flag_masked(&tmp, flags, TTM_PL_MASK_MEM);
        robj->tobj.proposed_placement = tmp | TTM_PL_FLAG_NO_EVICT | TTM_PL_MASK_CACHING;
@@ -261,23 +256,12 @@ int radeon_object_pin(struct radeon_object *robj, uint32_t domain,
                DRM_ERROR("radeon: failed to pin object.\n");
        }
        radeon_object_unreserve(robj);
-       if (robj->rdev->fbdev_robj == robj) {
-               if (!r) {
-                       r = radeon_object_kmap(robj, &fbptr);
-               }
-               if (!r) {
-                       robj->rdev->fbdev_info->screen_base = fbptr;
-                       robj->rdev->fbdev_info->fix.smem_start = (unsigned long)fbptr;
-               }
-               mutex_unlock(&robj->rdev->fbdev_info->lock);
-       }
        return r;
 }
 
 void radeon_object_unpin(struct radeon_object *robj)
 {
        uint32_t flags;
-       void *fbptr;
        int r;
 
        spin_lock(&robj->tobj.lock);
@@ -297,10 +281,6 @@ void radeon_object_unpin(struct radeon_object *robj)
                DRM_ERROR("radeon: failed to reserve object for unpinning it.\n");
                return;
        }
-       if (robj->rdev->fbdev_robj == robj) {
-               mutex_lock(&robj->rdev->fbdev_info->lock);
-               radeon_object_kunmap(robj);
-       }
        flags = robj->tobj.mem.placement;
        robj->tobj.proposed_placement = flags & ~TTM_PL_FLAG_NO_EVICT;
        r = ttm_buffer_object_validate(&robj->tobj,
@@ -310,16 +290,6 @@ void radeon_object_unpin(struct radeon_object *robj)
                DRM_ERROR("radeon: failed to unpin buffer.\n");
        }
        radeon_object_unreserve(robj);
-       if (robj->rdev->fbdev_robj == robj) {
-               if (!r) {
-                       r = radeon_object_kmap(robj, &fbptr);
-               }
-               if (!r) {
-                       robj->rdev->fbdev_info->screen_base = fbptr;
-                       robj->rdev->fbdev_info->fix.smem_start = (unsigned long)fbptr;
-               }
-               mutex_unlock(&robj->rdev->fbdev_info->lock);
-       }
 }
 
 int radeon_object_wait(struct radeon_object *robj)
index 517c8455963312e16c6a515dfc8fed21de16fec3..bdec583901ebcc7b5289aeaa63dfd076270a08d9 100644 (file)
@@ -34,7 +34,6 @@
 #include <linux/highmem.h>
 #include <linux/wait.h>
 #include <linux/vmalloc.h>
-#include <linux/version.h>
 #include <linux/module.h>
 
 void ttm_bo_free_old_node(struct ttm_buffer_object *bo)
index 27b146c54fbcb4d41c137ea9fb15a4a873ee068f..fe949a12fe40b4804ebcdd047d7286629d0de51d 100644 (file)
@@ -32,7 +32,6 @@
 #include <ttm/ttm_bo_driver.h>
 #include <ttm/ttm_placement.h>
 #include <linux/mm.h>
-#include <linux/version.h>
 #include <linux/rbtree.h>
 #include <linux/module.h>
 #include <linux/uaccess.h>
@@ -328,7 +327,7 @@ ssize_t ttm_bo_io(struct ttm_bo_device *bdev, struct file *filp,
                goto out_unref;
 
        kmap_offset = dev_offset - bo->vm_node->start;
-       if (unlikely(kmap_offset) >= bo->num_pages) {
+       if (unlikely(kmap_offset >= bo->num_pages)) {
                ret = -EFBIG;
                goto out_unref;
        }
@@ -402,7 +401,7 @@ ssize_t ttm_bo_fbdev_io(struct ttm_buffer_object *bo, const char __user *wbuf,
        bool dummy;
 
        kmap_offset = (*f_pos >> PAGE_SHIFT);
-       if (unlikely(kmap_offset) >= bo->num_pages)
+       if (unlikely(kmap_offset >= bo->num_pages))
                return -EFBIG;
 
        page_offset = *f_pos & ~PAGE_MASK;
index 0331fa74cd3f137396bfa79f9683a709e3ddad45..75dc8bd245920695d77e5f6fd92d5f9d3b150e5c 100644 (file)
@@ -28,7 +28,6 @@
  * Authors: Thomas Hellstrom <thellstrom-at-vmware-dot-com>
  */
 
-#include <linux/version.h>
 #include <linux/vmalloc.h>
 #include <linux/sched.h>
 #include <linux/highmem.h>
index c248c1d37268ac64cfed64e8b6bfba43b3d80332..5935b8842e8687c144ec6503b85ae7e9bee81b68 100644 (file)
@@ -183,7 +183,7 @@ int via_enable_vblank(struct drm_device *dev, int crtc)
        }
 
        status = VIA_READ(VIA_REG_INTERRUPT);
-       VIA_WRITE(VIA_REG_INTERRUPT, status & VIA_IRQ_VBLANK_ENABLE);
+       VIA_WRITE(VIA_REG_INTERRUPT, status | VIA_IRQ_VBLANK_ENABLE);
 
        VIA_WRITE8(0x83d4, 0x11);
        VIA_WRITE8(0x83d5, VIA_READ8(0x83d5) | 0x30);
@@ -194,6 +194,10 @@ int via_enable_vblank(struct drm_device *dev, int crtc)
 void via_disable_vblank(struct drm_device *dev, int crtc)
 {
        drm_via_private_t *dev_priv = dev->dev_private;
+       u32 status;
+
+       status = VIA_READ(VIA_REG_INTERRUPT);
+       VIA_WRITE(VIA_REG_INTERRUPT, status & ~VIA_IRQ_VBLANK_ENABLE);
 
        VIA_WRITE8(0x83d4, 0x11);
        VIA_WRITE8(0x83d5, VIA_READ8(0x83d5) & ~0x30);
index 76c4bbe9dccb334ef64359f701321f8fc13df5b3..3c1fcb7640abe1458d52146f8456c16295ec531f 100644 (file)
@@ -22,7 +22,6 @@
 #include <linux/list.h>
 #include <linux/mm.h>
 #include <linux/mutex.h>
-#include <linux/smp_lock.h>
 #include <linux/spinlock.h>
 #include <asm/unaligned.h>
 #include <asm/byteorder.h>
index ad2b3431b7253091505e726a72d4857b6f708dde..7d3f15d32fdfee8c1829d0f985cbb46331e7fbfa 100644 (file)
@@ -357,7 +357,7 @@ static const struct abituguru3_motherboard_info abituguru3_motherboards[] = {
                { "AUX5 Fan",           39, 2, 60, 1, 0 },
                { NULL, 0, 0, 0, 0, 0 } }
        },
-       { 0x0014, NULL /* Abit AB9 Pro, need DMI string */, {
+       { 0x0014, "AB9", /* + AB9 Pro */ {
                { "CPU Core",            0, 0, 10, 1, 0 },
                { "DDR",                 1, 0, 10, 1, 0 },
                { "DDR VTT",             2, 0, 10, 1, 0 },
@@ -455,7 +455,7 @@ static const struct abituguru3_motherboard_info abituguru3_motherboards[] = {
                { "AUX3 FAN",           37, 2, 60, 1, 0 },
                { NULL, 0, 0, 0, 0, 0 } }
        },
-       { 0x0018, NULL /* Unknown, need DMI string */, {
+       { 0x0018, "AB9 QuadGT", {
                { "CPU Core",            0, 0, 10, 1, 0 },
                { "DDR2",                1, 0, 20, 1, 0 },
                { "DDR2 VTT",            2, 0, 10, 1, 0 },
@@ -564,7 +564,7 @@ static const struct abituguru3_motherboard_info abituguru3_motherboards[] = {
                { "AUX3 Fan",           36, 2, 60, 1, 0 },
                { NULL, 0, 0, 0, 0, 0 } }
        },
-       { 0x001C, NULL /* Unknown, need DMI string */, {
+       { 0x001C, "IX38 QuadGT", {
                { "CPU Core",            0, 0, 10, 1, 0 },
                { "DDR2",                1, 0, 20, 1, 0 },
                { "DDR2 VTT",            2, 0, 10, 1, 0 },
index 86142a858238b8ddc0ccf65282ef56e34bd0b8ff..58f66be61b1fbb5e91498c87829b8c912cedc5bc 100644 (file)
@@ -418,6 +418,7 @@ static ssize_t set_div(struct device *dev, struct device_attribute *devattr,
                data->count = 3;
                break;
        default:
+               mutex_unlock(&data->update_lock);
                dev_err(&client->dev,
                        "illegal value for fan divider (%d)\n", div);
                return -EINVAL;
index 56cd6004da36e1ec08f94e05b890f61239323c08..6290a259456e8fbae6d5df180cd9825033b46217 100644 (file)
@@ -257,7 +257,7 @@ static inline int sht15_update_single_val(struct sht15_data *data,
                                 (data->flag == SHT15_READING_NOTHING),
                                 msecs_to_jiffies(timeout_msecs));
        if (ret == 0) {/* timeout occurred */
-               disable_irq_nosync(gpio_to_irq(data->pdata->gpio_data));;
+               disable_irq_nosync(gpio_to_irq(data->pdata->gpio_data));
                sht15_connection_reset(data);
                return -ETIME;
        }
index 3c259ee7ddda01d61b9462dae9d9d9bfc7625178..8206442fbabd80eab83424a5997d4c3eeddd2f35 100644 (file)
@@ -326,6 +326,16 @@ config I2C_DAVINCI
          devices such as DaVinci NIC.
          For details please see http://www.ti.com/davinci
 
+config I2C_DESIGNWARE
+       tristate "Synopsys DesignWare"
+       depends on HAVE_CLK
+       help
+         If you say yes to this option, support will be included for the
+         Synopsys DesignWare I2C adapter. Only master mode is supported.
+
+         This driver can also be built as a module.  If so, the module
+         will be called i2c-designware.
+
 config I2C_GPIO
        tristate "GPIO-based bitbanging I2C"
        depends on GENERIC_GPIO
index edeabf00310600830caa27dd96e88e038762f078..e654263bfc01df6442f52b5c39df95589203b698 100644 (file)
@@ -30,6 +30,7 @@ obj-$(CONFIG_I2C_AU1550)      += i2c-au1550.o
 obj-$(CONFIG_I2C_BLACKFIN_TWI) += i2c-bfin-twi.o
 obj-$(CONFIG_I2C_CPM)          += i2c-cpm.o
 obj-$(CONFIG_I2C_DAVINCI)      += i2c-davinci.o
+obj-$(CONFIG_I2C_DESIGNWARE)   += i2c-designware.o
 obj-$(CONFIG_I2C_GPIO)         += i2c-gpio.o
 obj-$(CONFIG_I2C_HIGHLANDER)   += i2c-highlander.o
 obj-$(CONFIG_I2C_IBM_IIC)      += i2c-ibm_iic.o
index 3fae3a91ce5b4acb1d6284a838a348229e2d682b..c89687a10835538307212949317042f40042129c 100644 (file)
@@ -187,6 +187,11 @@ static int i2c_davinci_init(struct davinci_i2c_dev *dev)
        davinci_i2c_write_reg(dev, DAVINCI_I2C_CLKH_REG, clkh);
        davinci_i2c_write_reg(dev, DAVINCI_I2C_CLKL_REG, clkl);
 
+       /* Respond at reserved "SMBus Host" slave address" (and zero);
+        * we seem to have no option to not respond...
+        */
+       davinci_i2c_write_reg(dev, DAVINCI_I2C_OAR_REG, 0x08);
+
        dev_dbg(dev->dev, "input_clock = %d, CLK = %d\n", input_clock, clk);
        dev_dbg(dev->dev, "PSC  = %d\n",
                davinci_i2c_read_reg(dev, DAVINCI_I2C_PSC_REG));
@@ -387,7 +392,7 @@ static void terminate_write(struct davinci_i2c_dev *dev)
        davinci_i2c_write_reg(dev, DAVINCI_I2C_MDR_REG, w);
 
        if (!dev->terminate)
-               dev_err(dev->dev, "TDR IRQ while no data to send\n");
+               dev_dbg(dev->dev, "TDR IRQ while no data to send\n");
 }
 
 /*
@@ -473,9 +478,14 @@ static irqreturn_t i2c_davinci_isr(int this_irq, void *dev_id)
                        break;
 
                case DAVINCI_I2C_IVR_AAS:
-                       dev_warn(dev->dev, "Address as slave interrupt\n");
-               }/* switch */
-       }/* while */
+                       dev_dbg(dev->dev, "Address as slave interrupt\n");
+                       break;
+
+               default:
+                       dev_warn(dev->dev, "Unrecognized irq stat %d\n", stat);
+                       break;
+               }
+       }
 
        return count ? IRQ_HANDLED : IRQ_NONE;
 }
@@ -505,7 +515,7 @@ static int davinci_i2c_probe(struct platform_device *pdev)
                return -ENODEV;
        }
 
-       ioarea = request_mem_region(mem->start, (mem->end - mem->start) + 1,
+       ioarea = request_mem_region(mem->start, resource_size(mem),
                                    pdev->name);
        if (!ioarea) {
                dev_err(&pdev->dev, "I2C region already claimed\n");
@@ -523,7 +533,7 @@ static int davinci_i2c_probe(struct platform_device *pdev)
        dev->irq = irq->start;
        platform_set_drvdata(pdev, dev);
 
-       dev->clk = clk_get(&pdev->dev, "I2CCLK");
+       dev->clk = clk_get(&pdev->dev, NULL);
        if (IS_ERR(dev->clk)) {
                r = -ENODEV;
                goto err_free_mem;
@@ -568,7 +578,7 @@ err_free_mem:
        put_device(&pdev->dev);
        kfree(dev);
 err_release_region:
-       release_mem_region(mem->start, (mem->end - mem->start) + 1);
+       release_mem_region(mem->start, resource_size(mem));
 
        return r;
 }
@@ -591,7 +601,7 @@ static int davinci_i2c_remove(struct platform_device *pdev)
        kfree(dev);
 
        mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       release_mem_region(mem->start, (mem->end - mem->start) + 1);
+       release_mem_region(mem->start, resource_size(mem));
        return 0;
 }
 
diff --git a/drivers/i2c/busses/i2c-designware.c b/drivers/i2c/busses/i2c-designware.c
new file mode 100644 (file)
index 0000000..b444762
--- /dev/null
@@ -0,0 +1,624 @@
+/*
+ * Synopsys Designware I2C adapter driver (master only).
+ *
+ * Based on the TI DAVINCI I2C adapter driver.
+ *
+ * Copyright (C) 2006 Texas Instruments.
+ * Copyright (C) 2007 MontaVista Software Inc.
+ * Copyright (C) 2009 Provigent Ltd.
+ *
+ * ----------------------------------------------------------------------------
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ * ----------------------------------------------------------------------------
+ *
+ */
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/i2c.h>
+#include <linux/clk.h>
+#include <linux/errno.h>
+#include <linux/sched.h>
+#include <linux/err.h>
+#include <linux/interrupt.h>
+#include <linux/platform_device.h>
+#include <linux/io.h>
+
+/*
+ * Registers offset
+ */
+#define DW_IC_CON              0x0
+#define DW_IC_TAR              0x4
+#define DW_IC_DATA_CMD         0x10
+#define DW_IC_SS_SCL_HCNT      0x14
+#define DW_IC_SS_SCL_LCNT      0x18
+#define DW_IC_FS_SCL_HCNT      0x1c
+#define DW_IC_FS_SCL_LCNT      0x20
+#define DW_IC_INTR_STAT                0x2c
+#define DW_IC_INTR_MASK                0x30
+#define DW_IC_CLR_INTR         0x40
+#define DW_IC_ENABLE           0x6c
+#define DW_IC_STATUS           0x70
+#define DW_IC_TXFLR            0x74
+#define DW_IC_RXFLR            0x78
+#define DW_IC_COMP_PARAM_1     0xf4
+#define DW_IC_TX_ABRT_SOURCE   0x80
+
+#define DW_IC_CON_MASTER               0x1
+#define DW_IC_CON_SPEED_STD            0x2
+#define DW_IC_CON_SPEED_FAST           0x4
+#define DW_IC_CON_10BITADDR_MASTER     0x10
+#define DW_IC_CON_RESTART_EN           0x20
+#define DW_IC_CON_SLAVE_DISABLE                0x40
+
+#define DW_IC_INTR_TX_EMPTY    0x10
+#define DW_IC_INTR_TX_ABRT     0x40
+#define DW_IC_INTR_STOP_DET    0x200
+
+#define DW_IC_STATUS_ACTIVITY  0x1
+
+#define DW_IC_ERR_TX_ABRT      0x1
+
+/*
+ * status codes
+ */
+#define STATUS_IDLE                    0x0
+#define STATUS_WRITE_IN_PROGRESS       0x1
+#define STATUS_READ_IN_PROGRESS                0x2
+
+#define TIMEOUT                        20 /* ms */
+
+/*
+ * hardware abort codes from the DW_IC_TX_ABRT_SOURCE register
+ *
+ * only expected abort codes are listed here
+ * refer to the datasheet for the full list
+ */
+#define ABRT_7B_ADDR_NOACK     0
+#define ABRT_10ADDR1_NOACK     1
+#define ABRT_10ADDR2_NOACK     2
+#define ABRT_TXDATA_NOACK      3
+#define ABRT_GCALL_NOACK       4
+#define ABRT_GCALL_READ                5
+#define ABRT_SBYTE_ACKDET      7
+#define ABRT_SBYTE_NORSTRT     9
+#define ABRT_10B_RD_NORSTRT    10
+#define ARB_MASTER_DIS         11
+#define ARB_LOST               12
+
+static char *abort_sources[] = {
+       [ABRT_7B_ADDR_NOACK]    =
+               "slave address not acknowledged (7bit mode)",
+       [ABRT_10ADDR1_NOACK]    =
+               "first address byte not acknowledged (10bit mode)",
+       [ABRT_10ADDR2_NOACK]    =
+               "second address byte not acknowledged (10bit mode)",
+       [ABRT_TXDATA_NOACK]             =
+               "data not acknowledged",
+       [ABRT_GCALL_NOACK]              =
+               "no acknowledgement for a general call",
+       [ABRT_GCALL_READ]               =
+               "read after general call",
+       [ABRT_SBYTE_ACKDET]             =
+               "start byte acknowledged",
+       [ABRT_SBYTE_NORSTRT]    =
+               "trying to send start byte when restart is disabled",
+       [ABRT_10B_RD_NORSTRT]   =
+               "trying to read when restart is disabled (10bit mode)",
+       [ARB_MASTER_DIS]                =
+               "trying to use disabled adapter",
+       [ARB_LOST]                      =
+               "lost arbitration",
+};
+
+/**
+ * struct dw_i2c_dev - private i2c-designware data
+ * @dev: driver model device node
+ * @base: IO registers pointer
+ * @cmd_complete: tx completion indicator
+ * @pump_msg: continue in progress transfers
+ * @lock: protect this struct and IO registers
+ * @clk: input reference clock
+ * @cmd_err: run time hadware error code
+ * @msgs: points to an array of messages currently being transfered
+ * @msgs_num: the number of elements in msgs
+ * @msg_write_idx: the element index of the current tx message in the msgs
+ *     array
+ * @tx_buf_len: the length of the current tx buffer
+ * @tx_buf: the current tx buffer
+ * @msg_read_idx: the element index of the current rx message in the msgs
+ *     array
+ * @rx_buf_len: the length of the current rx buffer
+ * @rx_buf: the current rx buffer
+ * @msg_err: error status of the current transfer
+ * @status: i2c master status, one of STATUS_*
+ * @abort_source: copy of the TX_ABRT_SOURCE register
+ * @irq: interrupt number for the i2c master
+ * @adapter: i2c subsystem adapter node
+ * @tx_fifo_depth: depth of the hardware tx fifo
+ * @rx_fifo_depth: depth of the hardware rx fifo
+ */
+struct dw_i2c_dev {
+       struct device           *dev;
+       void __iomem            *base;
+       struct completion       cmd_complete;
+       struct tasklet_struct   pump_msg;
+       struct mutex            lock;
+       struct clk              *clk;
+       int                     cmd_err;
+       struct i2c_msg          *msgs;
+       int                     msgs_num;
+       int                     msg_write_idx;
+       u16                     tx_buf_len;
+       u8                      *tx_buf;
+       int                     msg_read_idx;
+       u16                     rx_buf_len;
+       u8                      *rx_buf;
+       int                     msg_err;
+       unsigned int            status;
+       u16                     abort_source;
+       int                     irq;
+       struct i2c_adapter      adapter;
+       unsigned int            tx_fifo_depth;
+       unsigned int            rx_fifo_depth;
+};
+
+/**
+ * i2c_dw_init() - initialize the designware i2c master hardware
+ * @dev: device private data
+ *
+ * This functions configures and enables the I2C master.
+ * This function is called during I2C init function, and in case of timeout at
+ * run time.
+ */
+static void i2c_dw_init(struct dw_i2c_dev *dev)
+{
+       u32 input_clock_khz = clk_get_rate(dev->clk) / 1000;
+       u16 ic_con;
+
+       /* Disable the adapter */
+       writeb(0, dev->base + DW_IC_ENABLE);
+
+       /* set standard and fast speed deviders for high/low periods */
+       writew((input_clock_khz * 40 / 10000)+1, /* std speed high, 4us */
+                       dev->base + DW_IC_SS_SCL_HCNT);
+       writew((input_clock_khz * 47 / 10000)+1, /* std speed low, 4.7us */
+                       dev->base + DW_IC_SS_SCL_LCNT);
+       writew((input_clock_khz *  6 / 10000)+1, /* fast speed high, 0.6us */
+                       dev->base + DW_IC_FS_SCL_HCNT);
+       writew((input_clock_khz * 13 / 10000)+1, /* fast speed low, 1.3us */
+                       dev->base + DW_IC_FS_SCL_LCNT);
+
+       /* configure the i2c master */
+       ic_con = DW_IC_CON_MASTER | DW_IC_CON_SLAVE_DISABLE |
+               DW_IC_CON_RESTART_EN | DW_IC_CON_SPEED_FAST;
+       writew(ic_con, dev->base + DW_IC_CON);
+}
+
+/*
+ * Waiting for bus not busy
+ */
+static int i2c_dw_wait_bus_not_busy(struct dw_i2c_dev *dev)
+{
+       int timeout = TIMEOUT;
+
+       while (readb(dev->base + DW_IC_STATUS) & DW_IC_STATUS_ACTIVITY) {
+               if (timeout <= 0) {
+                       dev_warn(dev->dev, "timeout waiting for bus ready\n");
+                       return -ETIMEDOUT;
+               }
+               timeout--;
+               mdelay(1);
+       }
+
+       return 0;
+}
+
+/*
+ * Initiate low level master read/write transaction.
+ * This function is called from i2c_dw_xfer when starting a transfer.
+ * This function is also called from dw_i2c_pump_msg to continue a transfer
+ * that is longer than the size of the TX FIFO.
+ */
+static void
+i2c_dw_xfer_msg(struct i2c_adapter *adap)
+{
+       struct dw_i2c_dev *dev = i2c_get_adapdata(adap);
+       struct i2c_msg *msgs = dev->msgs;
+       int num = dev->msgs_num;
+       u16 ic_con, intr_mask;
+       int tx_limit = dev->tx_fifo_depth - readb(dev->base + DW_IC_TXFLR);
+       int rx_limit = dev->rx_fifo_depth - readb(dev->base + DW_IC_RXFLR);
+       u16 addr = msgs[dev->msg_write_idx].addr;
+       u16 buf_len = dev->tx_buf_len;
+
+       if (!(dev->status & STATUS_WRITE_IN_PROGRESS)) {
+               /* Disable the adapter */
+               writeb(0, dev->base + DW_IC_ENABLE);
+
+               /* set the slave (target) address */
+               writew(msgs[dev->msg_write_idx].addr, dev->base + DW_IC_TAR);
+
+               /* if the slave address is ten bit address, enable 10BITADDR */
+               ic_con = readw(dev->base + DW_IC_CON);
+               if (msgs[dev->msg_write_idx].flags & I2C_M_TEN)
+                       ic_con |= DW_IC_CON_10BITADDR_MASTER;
+               else
+                       ic_con &= ~DW_IC_CON_10BITADDR_MASTER;
+               writew(ic_con, dev->base + DW_IC_CON);
+
+               /* Enable the adapter */
+               writeb(1, dev->base + DW_IC_ENABLE);
+       }
+
+       for (; dev->msg_write_idx < num; dev->msg_write_idx++) {
+               /* if target address has changed, we need to
+                * reprogram the target address in the i2c
+                * adapter when we are done with this transfer
+                */
+               if (msgs[dev->msg_write_idx].addr != addr)
+                       return;
+
+               if (msgs[dev->msg_write_idx].len == 0) {
+                       dev_err(dev->dev,
+                               "%s: invalid message length\n", __func__);
+                       dev->msg_err = -EINVAL;
+                       return;
+               }
+
+               if (!(dev->status & STATUS_WRITE_IN_PROGRESS)) {
+                       /* new i2c_msg */
+                       dev->tx_buf = msgs[dev->msg_write_idx].buf;
+                       buf_len = msgs[dev->msg_write_idx].len;
+               }
+
+               while (buf_len > 0 && tx_limit > 0 && rx_limit > 0) {
+                       if (msgs[dev->msg_write_idx].flags & I2C_M_RD) {
+                               writew(0x100, dev->base + DW_IC_DATA_CMD);
+                               rx_limit--;
+                       } else
+                               writew(*(dev->tx_buf++),
+                                               dev->base + DW_IC_DATA_CMD);
+                       tx_limit--; buf_len--;
+               }
+       }
+
+       intr_mask = DW_IC_INTR_STOP_DET | DW_IC_INTR_TX_ABRT;
+       if (buf_len > 0) { /* more bytes to be written */
+               intr_mask |= DW_IC_INTR_TX_EMPTY;
+               dev->status |= STATUS_WRITE_IN_PROGRESS;
+       } else
+               dev->status &= ~STATUS_WRITE_IN_PROGRESS;
+       writew(intr_mask, dev->base + DW_IC_INTR_MASK);
+
+       dev->tx_buf_len = buf_len;
+}
+
+static void
+i2c_dw_read(struct i2c_adapter *adap)
+{
+       struct dw_i2c_dev *dev = i2c_get_adapdata(adap);
+       struct i2c_msg *msgs = dev->msgs;
+       int num = dev->msgs_num;
+       u16 addr = msgs[dev->msg_read_idx].addr;
+       int rx_valid = readw(dev->base + DW_IC_RXFLR);
+
+       for (; dev->msg_read_idx < num; dev->msg_read_idx++) {
+               u16 len;
+               u8 *buf;
+
+               if (!(msgs[dev->msg_read_idx].flags & I2C_M_RD))
+                       continue;
+
+               /* different i2c client, reprogram the i2c adapter */
+               if (msgs[dev->msg_read_idx].addr != addr)
+                       return;
+
+               if (!(dev->status & STATUS_READ_IN_PROGRESS)) {
+                       len = msgs[dev->msg_read_idx].len;
+                       buf = msgs[dev->msg_read_idx].buf;
+               } else {
+                       len = dev->rx_buf_len;
+                       buf = dev->rx_buf;
+               }
+
+               for (; len > 0 && rx_valid > 0; len--, rx_valid--)
+                       *buf++ = readb(dev->base + DW_IC_DATA_CMD);
+
+               if (len > 0) {
+                       dev->status |= STATUS_READ_IN_PROGRESS;
+                       dev->rx_buf_len = len;
+                       dev->rx_buf = buf;
+                       return;
+               } else
+                       dev->status &= ~STATUS_READ_IN_PROGRESS;
+       }
+}
+
+/*
+ * Prepare controller for a transaction and call i2c_dw_xfer_msg
+ */
+static int
+i2c_dw_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num)
+{
+       struct dw_i2c_dev *dev = i2c_get_adapdata(adap);
+       int ret;
+
+       dev_dbg(dev->dev, "%s: msgs: %d\n", __func__, num);
+
+       mutex_lock(&dev->lock);
+
+       INIT_COMPLETION(dev->cmd_complete);
+       dev->msgs = msgs;
+       dev->msgs_num = num;
+       dev->cmd_err = 0;
+       dev->msg_write_idx = 0;
+       dev->msg_read_idx = 0;
+       dev->msg_err = 0;
+       dev->status = STATUS_IDLE;
+
+       ret = i2c_dw_wait_bus_not_busy(dev);
+       if (ret < 0)
+               goto done;
+
+       /* start the transfers */
+       i2c_dw_xfer_msg(adap);
+
+       /* wait for tx to complete */
+       ret = wait_for_completion_interruptible_timeout(&dev->cmd_complete, HZ);
+       if (ret == 0) {
+               dev_err(dev->dev, "controller timed out\n");
+               i2c_dw_init(dev);
+               ret = -ETIMEDOUT;
+               goto done;
+       } else if (ret < 0)
+               goto done;
+
+       if (dev->msg_err) {
+               ret = dev->msg_err;
+               goto done;
+       }
+
+       /* no error */
+       if (likely(!dev->cmd_err)) {
+               /* read rx fifo, and disable the adapter */
+               do {
+                       i2c_dw_read(adap);
+               } while (dev->status & STATUS_READ_IN_PROGRESS);
+               writeb(0, dev->base + DW_IC_ENABLE);
+               ret = num;
+               goto done;
+       }
+
+       /* We have an error */
+       if (dev->cmd_err == DW_IC_ERR_TX_ABRT) {
+               unsigned long abort_source = dev->abort_source;
+               int i;
+
+               for_each_bit(i, &abort_source, ARRAY_SIZE(abort_sources)) {
+                   dev_err(dev->dev, "%s: %s\n", __func__, abort_sources[i]);
+               }
+       }
+       ret = -EIO;
+
+done:
+       mutex_unlock(&dev->lock);
+
+       return ret;
+}
+
+static u32 i2c_dw_func(struct i2c_adapter *adap)
+{
+       return I2C_FUNC_I2C | I2C_FUNC_10BIT_ADDR;
+}
+
+static void dw_i2c_pump_msg(unsigned long data)
+{
+       struct dw_i2c_dev *dev = (struct dw_i2c_dev *) data;
+       u16 intr_mask;
+
+       i2c_dw_read(&dev->adapter);
+       i2c_dw_xfer_msg(&dev->adapter);
+
+       intr_mask = DW_IC_INTR_STOP_DET | DW_IC_INTR_TX_ABRT;
+       if (dev->status & STATUS_WRITE_IN_PROGRESS)
+               intr_mask |= DW_IC_INTR_TX_EMPTY;
+       writew(intr_mask, dev->base + DW_IC_INTR_MASK);
+}
+
+/*
+ * Interrupt service routine. This gets called whenever an I2C interrupt
+ * occurs.
+ */
+static irqreturn_t i2c_dw_isr(int this_irq, void *dev_id)
+{
+       struct dw_i2c_dev *dev = dev_id;
+       u16 stat;
+
+       stat = readw(dev->base + DW_IC_INTR_STAT);
+       dev_dbg(dev->dev, "%s: stat=0x%x\n", __func__, stat);
+       if (stat & DW_IC_INTR_TX_ABRT) {
+               dev->abort_source = readw(dev->base + DW_IC_TX_ABRT_SOURCE);
+               dev->cmd_err |= DW_IC_ERR_TX_ABRT;
+               dev->status = STATUS_IDLE;
+       } else if (stat & DW_IC_INTR_TX_EMPTY)
+               tasklet_schedule(&dev->pump_msg);
+
+       readb(dev->base + DW_IC_CLR_INTR);      /* clear interrupts */
+       writew(0, dev->base + DW_IC_INTR_MASK); /* disable interrupts */
+       if (stat & (DW_IC_INTR_TX_ABRT | DW_IC_INTR_STOP_DET))
+               complete(&dev->cmd_complete);
+
+       return IRQ_HANDLED;
+}
+
+static struct i2c_algorithm i2c_dw_algo = {
+       .master_xfer    = i2c_dw_xfer,
+       .functionality  = i2c_dw_func,
+};
+
+static int __devinit dw_i2c_probe(struct platform_device *pdev)
+{
+       struct dw_i2c_dev *dev;
+       struct i2c_adapter *adap;
+       struct resource *mem, *irq, *ioarea;
+       int r;
+
+       /* NOTE: driver uses the static register mapping */
+       mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (!mem) {
+               dev_err(&pdev->dev, "no mem resource?\n");
+               return -EINVAL;
+       }
+
+       irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+       if (!irq) {
+               dev_err(&pdev->dev, "no irq resource?\n");
+               return -EINVAL;
+       }
+
+       ioarea = request_mem_region(mem->start, resource_size(mem),
+                       pdev->name);
+       if (!ioarea) {
+               dev_err(&pdev->dev, "I2C region already claimed\n");
+               return -EBUSY;
+       }
+
+       dev = kzalloc(sizeof(struct dw_i2c_dev), GFP_KERNEL);
+       if (!dev) {
+               r = -ENOMEM;
+               goto err_release_region;
+       }
+
+       init_completion(&dev->cmd_complete);
+       tasklet_init(&dev->pump_msg, dw_i2c_pump_msg, (unsigned long) dev);
+       mutex_init(&dev->lock);
+       dev->dev = get_device(&pdev->dev);
+       dev->irq = irq->start;
+       platform_set_drvdata(pdev, dev);
+
+       dev->clk = clk_get(&pdev->dev, NULL);
+       if (IS_ERR(dev->clk)) {
+               r = -ENODEV;
+               goto err_free_mem;
+       }
+       clk_enable(dev->clk);
+
+       dev->base = ioremap(mem->start, resource_size(mem));
+       if (dev->base == NULL) {
+               dev_err(&pdev->dev, "failure mapping io resources\n");
+               r = -EBUSY;
+               goto err_unuse_clocks;
+       }
+       {
+               u32 param1 = readl(dev->base + DW_IC_COMP_PARAM_1);
+
+               dev->tx_fifo_depth = ((param1 >> 16) & 0xff) + 1;
+               dev->rx_fifo_depth = ((param1 >> 8)  & 0xff) + 1;
+       }
+       i2c_dw_init(dev);
+
+       writew(0, dev->base + DW_IC_INTR_MASK); /* disable IRQ */
+       r = request_irq(dev->irq, i2c_dw_isr, 0, pdev->name, dev);
+       if (r) {
+               dev_err(&pdev->dev, "failure requesting irq %i\n", dev->irq);
+               goto err_iounmap;
+       }
+
+       adap = &dev->adapter;
+       i2c_set_adapdata(adap, dev);
+       adap->owner = THIS_MODULE;
+       adap->class = I2C_CLASS_HWMON;
+       strlcpy(adap->name, "Synopsys DesignWare I2C adapter",
+                       sizeof(adap->name));
+       adap->algo = &i2c_dw_algo;
+       adap->dev.parent = &pdev->dev;
+
+       adap->nr = pdev->id;
+       r = i2c_add_numbered_adapter(adap);
+       if (r) {
+               dev_err(&pdev->dev, "failure adding adapter\n");
+               goto err_free_irq;
+       }
+
+       return 0;
+
+err_free_irq:
+       free_irq(dev->irq, dev);
+err_iounmap:
+       iounmap(dev->base);
+err_unuse_clocks:
+       clk_disable(dev->clk);
+       clk_put(dev->clk);
+       dev->clk = NULL;
+err_free_mem:
+       platform_set_drvdata(pdev, NULL);
+       put_device(&pdev->dev);
+       kfree(dev);
+err_release_region:
+       release_mem_region(mem->start, resource_size(mem));
+
+       return r;
+}
+
+static int __devexit dw_i2c_remove(struct platform_device *pdev)
+{
+       struct dw_i2c_dev *dev = platform_get_drvdata(pdev);
+       struct resource *mem;
+
+       platform_set_drvdata(pdev, NULL);
+       i2c_del_adapter(&dev->adapter);
+       put_device(&pdev->dev);
+
+       clk_disable(dev->clk);
+       clk_put(dev->clk);
+       dev->clk = NULL;
+
+       writeb(0, dev->base + DW_IC_ENABLE);
+       free_irq(dev->irq, dev);
+       kfree(dev);
+
+       mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       release_mem_region(mem->start, resource_size(mem));
+       return 0;
+}
+
+/* work with hotplug and coldplug */
+MODULE_ALIAS("platform:i2c_designware");
+
+static struct platform_driver dw_i2c_driver = {
+       .remove         = __devexit_p(dw_i2c_remove),
+       .driver         = {
+               .name   = "i2c_designware",
+               .owner  = THIS_MODULE,
+       },
+};
+
+static int __init dw_i2c_init_driver(void)
+{
+       return platform_driver_probe(&dw_i2c_driver, dw_i2c_probe);
+}
+module_init(dw_i2c_init_driver);
+
+static void __exit dw_i2c_exit_driver(void)
+{
+       platform_driver_unregister(&dw_i2c_driver);
+}
+module_exit(dw_i2c_exit_driver);
+
+MODULE_AUTHOR("Baruch Siach <baruch@tkos.co.il>");
+MODULE_DESCRIPTION("Synopsys DesignWare I2C bus adapter");
+MODULE_LICENSE("GPL");
index e4476743f20330e4653e856ff42cee68b8952469..b1bc6e277d2a1eff1db0876b2e464dd12fba8094 100644 (file)
@@ -85,10 +85,11 @@ static void dump_iic_regs(const char* header, struct ibm_iic_private* dev)
 {
        volatile struct iic_regs __iomem *iic = dev->vaddr;
        printk(KERN_DEBUG "ibm-iic%d: %s\n", dev->idx, header);
-       printk(KERN_DEBUG "  cntl     = 0x%02x, mdcntl = 0x%02x\n"
-              KERN_DEBUG "  sts      = 0x%02x, extsts = 0x%02x\n"
-              KERN_DEBUG "  clkdiv   = 0x%02x, xfrcnt = 0x%02x\n"
-              KERN_DEBUG "  xtcntlss = 0x%02x, directcntl = 0x%02x\n",
+       printk(KERN_DEBUG
+              "  cntl     = 0x%02x, mdcntl = 0x%02x\n"
+              "  sts      = 0x%02x, extsts = 0x%02x\n"
+              "  clkdiv   = 0x%02x, xfrcnt = 0x%02x\n"
+              "  xtcntlss = 0x%02x, directcntl = 0x%02x\n",
                in_8(&iic->cntl), in_8(&iic->mdcntl), in_8(&iic->sts),
                in_8(&iic->extsts), in_8(&iic->clkdiv), in_8(&iic->xfrcnt),
                in_8(&iic->xtcntlss), in_8(&iic->directcntl));
index ad8d2010c9211cf0f28f9201aa7346662357626b..fdd83277c8a81ac22441ce7ddea5188b0247e34f 100644 (file)
@@ -806,7 +806,7 @@ omap_i2c_probe(struct platform_device *pdev)
                return -ENODEV;
        }
 
-       ioarea = request_mem_region(mem->start, (mem->end - mem->start) + 1,
+       ioarea = request_mem_region(mem->start, resource_size(mem),
                        pdev->name);
        if (!ioarea) {
                dev_err(&pdev->dev, "I2C region already claimed\n");
@@ -905,7 +905,7 @@ err_free_mem:
        platform_set_drvdata(pdev, NULL);
        kfree(dev);
 err_release_region:
-       release_mem_region(mem->start, (mem->end - mem->start) + 1);
+       release_mem_region(mem->start, resource_size(mem));
 
        return r;
 }
@@ -925,7 +925,7 @@ omap_i2c_remove(struct platform_device *pdev)
        iounmap(dev->base);
        kfree(dev);
        mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       release_mem_region(mem->start, (mem->end - mem->start) + 1);
+       release_mem_region(mem->start, resource_size(mem));
        return 0;
 }
 
index 1c01083b01b5ac0bc3f7eac54a657a72fb049ea0..4f3d99cd16927c2d9ae57c6bbda6d3894e5a9f6b 100644 (file)
@@ -563,7 +563,7 @@ static int sh_mobile_i2c_probe(struct platform_device *dev)
                goto err_irq;
        }
 
-       size = (res->end - res->start) + 1;
+       size = resource_size(res);
 
        pd->reg = ioremap(res->start, size);
        if (pd->reg == NULL) {
index 042fda295f3a557cd56c623a6aab980ae362271e..6407f47bda82db92b5ba2f2926851f774a938e91 100644 (file)
@@ -92,7 +92,7 @@ static int simtec_i2c_probe(struct platform_device *dev)
                goto err;
        }
 
-       size = (res->end-res->start)+1;
+       size = resource_size(res);
 
        pd->ioarea = request_mem_region(res->start, size, dev->name);
        if (pd->ioarea == NULL) {
index bd066bb9d61105262c342329fce891f38b015393..09f98ed0731fa251bfb08f46eea0e369eefe3f05 100644 (file)
@@ -135,6 +135,7 @@ static int __devinit cs5520_init_one(struct pci_dev *dev, const struct pci_devic
 
        ide_pci_setup_ports(dev, d, &hw[0], &hws[0]);
        hw[0].irq = 14;
+       hw[1].irq = 15;
 
        return ide_host_add(d, hws, 2, NULL);
 }
index 77f79d26b2648acebfd12ae44d396fd6c0481e34..c509c9916464db7c7819a92e2e9888e0340a67a1 100644 (file)
@@ -92,6 +92,11 @@ int ide_acpi_init(void)
        return 0;
 }
 
+bool ide_port_acpi(ide_hwif_t *hwif)
+{
+       return ide_noacpi == 0 && hwif->acpidata;
+}
+
 /**
  * ide_get_dev_handle - finds acpi_handle and PCI device.function
  * @dev: device to locate
@@ -352,9 +357,6 @@ int ide_acpi_exec_tfs(ide_drive_t *drive)
        unsigned long   gtf_address;
        unsigned long   obj_loc;
 
-       if (ide_noacpi)
-               return 0;
-
        DEBPRINT("call get_GTF, drive=%s port=%d\n", drive->name, drive->dn);
 
        ret = do_drive_get_GTF(drive, &gtf_length, &gtf_address, &obj_loc);
@@ -389,16 +391,6 @@ void ide_acpi_get_timing(ide_hwif_t *hwif)
        struct acpi_buffer      output;
        union acpi_object       *out_obj;
 
-       if (ide_noacpi)
-               return;
-
-       DEBPRINT("ENTER:\n");
-
-       if (!hwif->acpidata) {
-               DEBPRINT("no ACPI data for %s\n", hwif->name);
-               return;
-       }
-
        /* Setting up output buffer for _GTM */
        output.length = ACPI_ALLOCATE_BUFFER;
        output.pointer = NULL;  /* ACPI-CA sets this; save/free it later */
@@ -479,16 +471,6 @@ void ide_acpi_push_timing(ide_hwif_t *hwif)
        struct ide_acpi_drive_link      *master = &hwif->acpidata->master;
        struct ide_acpi_drive_link      *slave = &hwif->acpidata->slave;
 
-       if (ide_noacpi)
-               return;
-
-       DEBPRINT("ENTER:\n");
-
-       if (!hwif->acpidata) {
-               DEBPRINT("no ACPI data for %s\n", hwif->name);
-               return;
-       }
-
        /* Give the GTM buffer + drive Identify data to the channel via the
         * _STM method: */
        /* setup input parameters buffer for _STM */
@@ -527,16 +509,11 @@ void ide_acpi_set_state(ide_hwif_t *hwif, int on)
        ide_drive_t *drive;
        int i;
 
-       if (ide_noacpi || ide_noacpi_psx)
+       if (ide_noacpi_psx)
                return;
 
        DEBPRINT("ENTER:\n");
 
-       if (!hwif->acpidata) {
-               DEBPRINT("no ACPI data for %s\n", hwif->name);
-               return;
-       }
-
        /* channel first and then drives for power on and verse versa for power off */
        if (on)
                acpi_bus_set_power(hwif->acpidata->obj_handle, ACPI_STATE_D0);
@@ -616,7 +593,7 @@ void ide_acpi_port_init_devices(ide_hwif_t *hwif)
                                 drive->name, err);
        }
 
-       if (!ide_acpionboot) {
+       if (ide_noacpi || ide_acpionboot == 0) {
                DEBPRINT("ACPI methods disabled on boot\n");
                return;
        }
index 4a19686fcfe9a922ead806d98b62f07144f0c832..6a9a769bffc1993736064c54570aeeeef0c1b989 100644 (file)
@@ -592,9 +592,19 @@ static ide_startstop_t cdrom_newpc_intr(ide_drive_t *drive)
                        }
                } else if (!blk_pc_request(rq)) {
                        ide_cd_request_sense_fixup(drive, cmd);
-                       /* complain if we still have data left to transfer */
+
                        uptodate = cmd->nleft ? 0 : 1;
-                       if (uptodate == 0)
+
+                       /*
+                        * suck out the remaining bytes from the drive in an
+                        * attempt to complete the data xfer. (see BZ#13399)
+                        */
+                       if (!(stat & ATA_ERR) && !uptodate && thislen) {
+                               ide_pio_bytes(drive, cmd, write, thislen);
+                               uptodate = cmd->nleft ? 0 : 1;
+                       }
+
+                       if (!uptodate)
                                rq->cmd_flags |= REQ_FAILED;
                }
                goto out_end;
@@ -876,9 +886,12 @@ static int cdrom_read_capacity(ide_drive_t *drive, unsigned long *capacity,
                return stat;
 
        /*
-        * Sanity check the given block size
+        * Sanity check the given block size, in so far as making
+        * sure the sectors_per_frame we give to the caller won't
+        * end up being bogus.
         */
        blocklen = be32_to_cpu(capbuf.blocklen);
+       blocklen = (blocklen >> SECTOR_BITS) << SECTOR_BITS;
        switch (blocklen) {
        case 512:
        case 1024:
@@ -886,10 +899,9 @@ static int cdrom_read_capacity(ide_drive_t *drive, unsigned long *capacity,
        case 4096:
                break;
        default:
-               printk(KERN_ERR PFX "%s: weird block size %u\n",
+               printk_once(KERN_ERR PFX "%s: weird block size %u; "
+                               "setting default block size to 2048\n",
                                drive->name, blocklen);
-               printk(KERN_ERR PFX "%s: default to 2kb block size\n",
-                               drive->name);
                blocklen = 2048;
                break;
        }
index 5bf958e5b1d5fabe5019266448fe623065e69a82..1099bf7cf968ac216818e7ed0b6973e6cd6741ce 100644 (file)
@@ -183,6 +183,6 @@ ide_startstop_t ide_do_devset(ide_drive_t *drive, struct request *rq)
        err = setfunc(drive, *(int *)&rq->cmd[1]);
        if (err)
                rq->errors = err;
-       ide_complete_rq(drive, err, ide_rq_bytes(rq));
+       ide_complete_rq(drive, err, blk_rq_bytes(rq));
        return ide_stopped;
 }
index 219e6fb78dc6414304ff8b707c59554f9c82db75..ee58c88dee5a61f51d437d1f618fd89745144785 100644 (file)
@@ -361,9 +361,6 @@ static int ide_tune_dma(ide_drive_t *drive)
        if (__ide_dma_bad_drive(drive))
                return 0;
 
-       if (ide_id_dma_bug(drive))
-               return 0;
-
        if (hwif->host_flags & IDE_HFLAG_TRUST_BIOS_FOR_DMA)
                return config_drive_for_dma(drive);
 
@@ -394,24 +391,6 @@ static int ide_dma_check(ide_drive_t *drive)
        return -1;
 }
 
-int ide_id_dma_bug(ide_drive_t *drive)
-{
-       u16 *id = drive->id;
-
-       if (id[ATA_ID_FIELD_VALID] & 4) {
-               if ((id[ATA_ID_UDMA_MODES] >> 8) &&
-                   (id[ATA_ID_MWDMA_MODES] >> 8))
-                       goto err_out;
-       } else if ((id[ATA_ID_MWDMA_MODES] >> 8) &&
-                  (id[ATA_ID_SWDMA_MODES] >> 8))
-               goto err_out;
-
-       return 0;
-err_out:
-       printk(KERN_ERR "%s: bad DMA info in identify block\n", drive->name);
-       return 1;
-}
-
 int ide_set_dma(ide_drive_t *drive)
 {
        int rc;
index 2b91419796136e24b4a98a27dd85aab0c6caccc0..e9abf2c3c33544c047ec2db7f29f1f295da0a397 100644 (file)
@@ -149,7 +149,7 @@ static inline void ide_complete_drive_reset(ide_drive_t *drive, int err)
        if (rq && blk_special_request(rq) && rq->cmd[0] == REQ_DRIVE_RESET) {
                if (err <= 0 && rq->errors == 0)
                        rq->errors = -EIO;
-               ide_complete_rq(drive, err ? err : 0, ide_rq_bytes(rq));
+               ide_complete_rq(drive, err ? err : 0, blk_rq_bytes(rq));
        }
 }
 
index 8b3f204f7d7325955b52b277ede13ab83984aa2e..fefbdfc8db068868afe0dadb0914a948219ea824 100644 (file)
@@ -293,7 +293,7 @@ out_end:
        drive->failed_pc = NULL;
        if (blk_fs_request(rq) == 0 && rq->errors == 0)
                rq->errors = -EIO;
-       ide_complete_rq(drive, -EIO, ide_rq_bytes(rq));
+       ide_complete_rq(drive, -EIO, blk_rq_bytes(rq));
        return ide_stopped;
 }
 
index 1059f809b809bb0f94048361d8b03e990953ccee..db96138fefcdef55f923580a0404674f8178314b 100644 (file)
@@ -112,16 +112,6 @@ void ide_complete_cmd(ide_drive_t *drive, struct ide_cmd *cmd, u8 stat, u8 err)
        }
 }
 
-/* obsolete, blk_rq_bytes() should be used instead */
-unsigned int ide_rq_bytes(struct request *rq)
-{
-       if (blk_pc_request(rq))
-               return blk_rq_bytes(rq);
-       else
-               return blk_rq_cur_sectors(rq) << 9;
-}
-EXPORT_SYMBOL_GPL(ide_rq_bytes);
-
 int ide_complete_rq(ide_drive_t *drive, int error, unsigned int nr_bytes)
 {
        ide_hwif_t *hwif = drive->hwif;
@@ -152,14 +142,14 @@ void ide_kill_rq(ide_drive_t *drive, struct request *rq)
 
        if ((media == ide_floppy || media == ide_tape) && drv_req) {
                rq->errors = 0;
-               ide_complete_rq(drive, 0, blk_rq_bytes(rq));
        } else {
                if (media == ide_tape)
                        rq->errors = IDE_DRV_ERROR_GENERAL;
                else if (blk_fs_request(rq) == 0 && rq->errors == 0)
                        rq->errors = -EIO;
-               ide_complete_rq(drive, -EIO, ide_rq_bytes(rq));
        }
+
+       ide_complete_rq(drive, -EIO, blk_rq_bytes(rq));
 }
 
 static void ide_tf_set_specify_cmd(ide_drive_t *drive, struct ide_taskfile *tf)
index 82f252c3ee6e500eb85fc466f1fc26e5c71b6d5a..e246d3d3fbcc5c280ff520b090c297eb42c05a1e 100644 (file)
@@ -64,7 +64,8 @@ static int ide_get_identity_ioctl(ide_drive_t *drive, unsigned int cmd,
                goto out;
        }
 
-       id = kmalloc(size, GFP_KERNEL);
+       /* ata_id_to_hd_driveid() relies on 'id' to be fully allocated. */
+       id = kmalloc(ATA_ID_WORDS * 2, GFP_KERNEL);
        if (id == NULL) {
                rc = -ENOMEM;
                goto out;
index fa047150a1c691f47f9c74a8404810d451332619..2892b242bbe1c84feed1a343bdbb6494135f9e9a 100644 (file)
@@ -210,6 +210,7 @@ EXPORT_SYMBOL_GPL(ide_in_drive_list);
  */
 static const struct drive_list_entry ivb_list[] = {
        { "QUANTUM FIREBALLlct10 05"    , "A03.0900"    },
+       { "QUANTUM FIREBALLlct20 30"    , "APL.0900"    },
        { "TSSTcorp CDDVDW SH-S202J"    , "SB00"        },
        { "TSSTcorp CDDVDW SH-S202J"    , "SB01"        },
        { "TSSTcorp CDDVDW SH-S202N"    , "SB00"        },
@@ -329,9 +330,6 @@ int ide_driveid_update(ide_drive_t *drive)
 
        kfree(id);
 
-       if ((drive->dev_flags & IDE_DFLAG_USING_DMA) && ide_id_dma_bug(drive))
-               ide_dma_off(drive);
-
        return 1;
 out_err:
        if (rc == 2)
index c14ca144cffe035d7722b6bb9fb8720652ad11bc..ad7be2669dcb9020bc5b91612079d80f21fd6869 100644 (file)
@@ -10,9 +10,11 @@ int generic_ide_suspend(struct device *dev, pm_message_t mesg)
        struct request_pm_state rqpm;
        int ret;
 
-       /* call ACPI _GTM only once */
-       if ((drive->dn & 1) == 0 || pair == NULL)
-               ide_acpi_get_timing(hwif);
+       if (ide_port_acpi(hwif)) {
+               /* call ACPI _GTM only once */
+               if ((drive->dn & 1) == 0 || pair == NULL)
+                       ide_acpi_get_timing(hwif);
+       }
 
        memset(&rqpm, 0, sizeof(rqpm));
        rq = blk_get_request(drive->queue, READ, __GFP_WAIT);
@@ -26,9 +28,11 @@ int generic_ide_suspend(struct device *dev, pm_message_t mesg)
        ret = blk_execute_rq(drive->queue, NULL, rq, 0);
        blk_put_request(rq);
 
-       /* call ACPI _PS3 only after both devices are suspended */
-       if (ret == 0 && ((drive->dn & 1) || pair == NULL))
-               ide_acpi_set_state(hwif, 0);
+       if (ret == 0 && ide_port_acpi(hwif)) {
+               /* call ACPI _PS3 only after both devices are suspended */
+               if ((drive->dn & 1) || pair == NULL)
+                       ide_acpi_set_state(hwif, 0);
+       }
 
        return ret;
 }
@@ -42,13 +46,15 @@ int generic_ide_resume(struct device *dev)
        struct request_pm_state rqpm;
        int err;
 
-       /* call ACPI _PS0 / _STM only once */
-       if ((drive->dn & 1) == 0 || pair == NULL) {
-               ide_acpi_set_state(hwif, 1);
-               ide_acpi_push_timing(hwif);
-       }
+       if (ide_port_acpi(hwif)) {
+               /* call ACPI _PS0 / _STM only once */
+               if ((drive->dn & 1) == 0 || pair == NULL) {
+                       ide_acpi_set_state(hwif, 1);
+                       ide_acpi_push_timing(hwif);
+               }
 
-       ide_acpi_exec_tfs(drive);
+               ide_acpi_exec_tfs(drive);
+       }
 
        memset(&rqpm, 0, sizeof(rqpm));
        rq = blk_get_request(drive->queue, READ, __GFP_WAIT);
index 51af4eea0d367440d69a9c6db98e097f50ad2d12..1bb106f6221a5aad84aa6385158b23d53b9eaa69 100644 (file)
@@ -818,6 +818,24 @@ static int ide_port_setup_devices(ide_hwif_t *hwif)
        return j;
 }
 
+static void ide_host_enable_irqs(struct ide_host *host)
+{
+       ide_hwif_t *hwif;
+       int i;
+
+       ide_host_for_each_port(i, hwif, host) {
+               if (hwif == NULL)
+                       continue;
+
+               /* clear any pending IRQs */
+               hwif->tp_ops->read_status(hwif);
+
+               /* unmask IRQs */
+               if (hwif->io_ports.ctl_addr)
+                       hwif->tp_ops->write_devctl(hwif, ATA_DEVCTL_OBS);
+       }
+}
+
 /*
  * This routine sets up the IRQ for an IDE interface.
  */
@@ -831,9 +849,6 @@ static int init_irq (ide_hwif_t *hwif)
        if (irq_handler == NULL)
                irq_handler = ide_intr;
 
-       if (io_ports->ctl_addr)
-               hwif->tp_ops->write_devctl(hwif, ATA_DEVCTL_OBS);
-
        if (request_irq(hwif->irq, irq_handler, sa, hwif->name, hwif))
                goto out_up;
 
@@ -1404,6 +1419,8 @@ int ide_host_register(struct ide_host *host, const struct ide_port_info *d,
                        ide_port_tune_devices(hwif);
        }
 
+       ide_host_enable_irqs(host);
+
        ide_host_for_each_port(i, hwif, host) {
                if (hwif == NULL)
                        continue;
index 83b734aec923f795a5e4d79dcc162e68f5efaf5d..52b25f8b111d73fad2b4e6b1252b823854190ec2 100644 (file)
@@ -880,6 +880,7 @@ static struct sbp2_lu *sbp2_alloc_device(struct unit_directory *ud)
        }
 
        shost->hostdata[0] = (unsigned long)lu;
+       shost->max_cmd_len = SBP2_MAX_CDB_SIZE;
 
        if (!scsi_add_host(shost, &ud->device)) {
                lu->shost = shost;
index c5036f1cc5b0d674155ea2a89087e9ba5e981eb5..64a3a66a8a396fdc45d0e09d4f663cacb528f714 100644 (file)
 
 #define SBP2_DEVICE_NAME               "sbp2"
 
+/*
+ * There is no transport protocol limit to the CDB length,  but we implement
+ * a fixed length only.  16 bytes is enough for disks larger than 2 TB.
+ */
+#define SBP2_MAX_CDB_SIZE              16
+
 /*
  * SBP-2 specific definitions
  */
@@ -51,7 +57,7 @@ struct sbp2_command_orb {
        u32 data_descriptor_hi;
        u32 data_descriptor_lo;
        u32 misc;
-       u8 cdb[12];
+       u8 cdb[SBP2_MAX_CDB_SIZE];
 } __attribute__((packed));
 
 #define SBP2_LOGIN_REQUEST             0x0
index 9d8f796c6745291f3bd5bccf3a52177c3583c06f..a6b989a9dc07eee021d90e1d6f4ae902da547056 100644 (file)
@@ -12,6 +12,42 @@ menuconfig INPUT_KEYBOARD
 
 if INPUT_KEYBOARD
 
+config KEYBOARD_AAED2000
+       tristate "AAED-2000 keyboard"
+       depends on MACH_AAED2000
+       select INPUT_POLLDEV
+       default y
+       help
+         Say Y here to enable the keyboard on the Agilent AAED-2000
+         development board.
+
+         To compile this driver as a module, choose M here: the
+         module will be called aaed2000_kbd.
+
+config KEYBOARD_AMIGA
+       tristate "Amiga keyboard"
+       depends on AMIGA
+       help
+         Say Y here if you are running Linux on any AMIGA and have a keyboard
+         attached.
+
+         To compile this driver as a module, choose M here: the
+         module will be called amikbd.
+
+config ATARI_KBD_CORE
+       bool
+
+config KEYBOARD_ATARI
+       tristate "Atari keyboard"
+       depends on ATARI
+       select ATARI_KBD_CORE
+       help
+         Say Y here if you are running Linux on any Atari and have a keyboard
+         attached.
+
+         To compile this driver as a module, choose M here: the
+         module will be called atakbd.
+
 config KEYBOARD_ATKBD
        tristate "AT keyboard" if EMBEDDED || !X86
        default y
@@ -68,69 +104,14 @@ config KEYBOARD_ATKBD_RDI_KEYCODES
          right-hand column will be interpreted as the key shown in the
          left-hand column.
 
-config KEYBOARD_SUNKBD
-       tristate "Sun Type 4 and Type 5 keyboard"
-       select SERIO
-       help
-         Say Y here if you want to use a Sun Type 4 or Type 5 keyboard,
-         connected either to the Sun keyboard connector or to an serial
-         (RS-232) port via a simple adapter.
-
-         To compile this driver as a module, choose M here: the
-         module will be called sunkbd.
-
-config KEYBOARD_LKKBD
-       tristate "DECstation/VAXstation LK201/LK401 keyboard"
-       select SERIO
-       help
-         Say Y here if you want to use a LK201 or LK401 style serial
-         keyboard. This keyboard is also useable on PCs if you attach
-         it with the inputattach program. The connector pinout is
-         described within lkkbd.c.
-
-         To compile this driver as a module, choose M here: the
-         module will be called lkkbd.
-
-config KEYBOARD_LOCOMO
-       tristate "LoCoMo Keyboard Support"
-       depends on SHARP_LOCOMO && INPUT_KEYBOARD
-       help
-         Say Y here if you are running Linux on a Sharp Zaurus Collie or Poodle based PDA
-
-         To compile this driver as a module, choose M here: the
-         module will be called locomokbd.
-
-config KEYBOARD_XTKBD
-       tristate "XT keyboard"
-       select SERIO
-       help
-         Say Y here if you want to use the old IBM PC/XT keyboard (or
-         compatible) on your system. This is only possible with a
-         parallel port keyboard adapter, you cannot connect it to the
-         keyboard port on a PC that runs Linux.
-
-         To compile this driver as a module, choose M here: the
-         module will be called xtkbd.
-
-config KEYBOARD_NEWTON
-       tristate "Newton keyboard"
-       select SERIO
-       help
-         Say Y here if you have a Newton keyboard on a serial port.
-
-         To compile this driver as a module, choose M here: the
-         module will be called newtonkbd.
-
-config KEYBOARD_STOWAWAY
-       tristate "Stowaway keyboard"
-       select SERIO
+config KEYBOARD_BFIN
+       tristate "Blackfin BF54x keypad support"
+       depends on (BF54x && !BF544)
        help
-         Say Y here if you have a Stowaway keyboard on a serial port.
-         Stowaway compatible keyboards like Dicota Input-PDA keyboard
-         are also supported by this driver.
+         Say Y here if you want to use the BF54x keypad.
 
          To compile this driver as a module, choose M here: the
-         module will be called stowaway.
+         module will be called bf54x-keys.
 
 config KEYBOARD_CORGI
        tristate "Corgi keyboard"
@@ -143,61 +124,50 @@ config KEYBOARD_CORGI
          To compile this driver as a module, choose M here: the
          module will be called corgikbd.
 
-config KEYBOARD_SPITZ
-       tristate "Spitz keyboard"
-       depends on PXA_SHARPSL
-       default y
+config KEYBOARD_LKKBD
+       tristate "DECstation/VAXstation LK201/LK401 keyboard"
+       select SERIO
        help
-         Say Y here to enable the keyboard on the Sharp Zaurus SL-C1000,
-         SL-C3000 and Sl-C3100 series of PDAs.
+         Say Y here if you want to use a LK201 or LK401 style serial
+         keyboard. This keyboard is also useable on PCs if you attach
+         it with the inputattach program. The connector pinout is
+         described within lkkbd.c.
 
          To compile this driver as a module, choose M here: the
-         module will be called spitzkbd.
+         module will be called lkkbd.
 
-config KEYBOARD_TOSA
-       tristate "Tosa keyboard"
-       depends on MACH_TOSA
-       default y
+config KEYBOARD_EP93XX
+       tristate "EP93xx Matrix Keypad support"
+       depends on ARCH_EP93XX
        help
-         Say Y here to enable the keyboard on the Sharp Zaurus SL-6000x (Tosa)
+         Say Y here to enable the matrix keypad on the Cirrus EP93XX.
 
          To compile this driver as a module, choose M here: the
-         module will be called tosakbd.
+         module will be called ep93xx_keypad.
 
-config KEYBOARD_TOSA_USE_EXT_KEYCODES
-       bool "Tosa keyboard: use extended keycodes"
-       depends on KEYBOARD_TOSA
-       default n
+config KEYBOARD_GPIO
+       tristate "GPIO Buttons"
+       depends on GENERIC_GPIO
        help
-         Say Y here to enable the tosa keyboard driver to generate extended
-         (>= 127) keycodes. Be aware, that they can't be correctly interpreted
-         by either console keyboard driver or by Kdrive keybd driver.
-
-         Say Y only if you know, what you are doing!
+         This driver implements support for buttons connected
+         to GPIO pins of various CPUs (and some other chips).
 
-config KEYBOARD_AMIGA
-       tristate "Amiga keyboard"
-       depends on AMIGA
-       help
-         Say Y here if you are running Linux on any AMIGA and have a keyboard
-         attached.
+         Say Y here if your device has buttons connected
+         directly to such GPIO pins.  Your board-specific
+         setup logic must also provide a platform device,
+         with configuration data saying which GPIOs are used.
 
          To compile this driver as a module, choose M here: the
-         module will be called amikbd.
+         module will be called gpio_keys.
 
-config ATARI_KBD_CORE
-       bool
-
-config KEYBOARD_ATARI
-       tristate "Atari keyboard"
-       depends on ATARI
-       select ATARI_KBD_CORE
+config KEYBOARD_MATRIX
+       tristate "GPIO driven matrix keypad support"
+       depends on GENERIC_GPIO
        help
-         Say Y here if you are running Linux on any Atari and have a keyboard
-         attached.
+         Enable support for GPIO driven matrix keypad.
 
          To compile this driver as a module, choose M here: the
-         module will be called atakbd.
+         module will be called matrix_keypad.
 
 config KEYBOARD_HIL_OLD
        tristate "HP HIL keyboard support (simple driver)"
@@ -261,20 +231,39 @@ config KEYBOARD_LM8323
          To compile this driver as a module, choose M here: the
          module will be called lm8323.
 
-config KEYBOARD_OMAP
-       tristate "TI OMAP keypad support"
-       depends on (ARCH_OMAP1 || ARCH_OMAP2)
+config KEYBOARD_LOCOMO
+       tristate "LoCoMo Keyboard Support"
+       depends on SHARP_LOCOMO
        help
-         Say Y here if you want to use the OMAP keypad.
+         Say Y here if you are running Linux on a Sharp Zaurus Collie or Poodle based PDA
 
          To compile this driver as a module, choose M here: the
-         module will be called omap-keypad.
+         module will be called locomokbd.
+
+config KEYBOARD_MAPLE
+       tristate "Maple bus keyboard"
+       depends on SH_DREAMCAST && MAPLE
+       help
+         Say Y here if you have a Dreamcast console running Linux and have
+         a keyboard attached to its Maple bus.
+
+         To compile this driver as a module, choose M here: the
+         module will be called maple_keyb.
+
+config KEYBOARD_NEWTON
+       tristate "Newton keyboard"
+       select SERIO
+       help
+         Say Y here if you have a Newton keyboard on a serial port.
+
+         To compile this driver as a module, choose M here: the
+         module will be called newtonkbd.
 
 config KEYBOARD_PXA27x
        tristate "PXA27x/PXA3xx keypad support"
        depends on PXA27x || PXA3xx
        help
-         Enable support for PXA27x/PXA3xx keypad controller
+         Enable support for PXA27x/PXA3xx keypad controller.
 
          To compile this driver as a module, choose M here: the
          module will be called pxa27x_keypad.
@@ -288,51 +277,38 @@ config KEYBOARD_PXA930_ROTARY
          To compile this driver as a module, choose M here: the
          module will be called pxa930_rotary.
 
-config KEYBOARD_AAED2000
-       tristate "AAED-2000 keyboard"
-       depends on MACH_AAED2000
-       select INPUT_POLLDEV
+config KEYBOARD_SPITZ
+       tristate "Spitz keyboard"
+       depends on PXA_SHARPSL
        default y
        help
-         Say Y here to enable the keyboard on the Agilent AAED-2000
-         development board.
-
-         To compile this driver as a module, choose M here: the
-         module will be called aaed2000_kbd.
-
-config KEYBOARD_GPIO
-       tristate "GPIO Buttons"
-       depends on GENERIC_GPIO
-       help
-         This driver implements support for buttons connected
-         to GPIO pins of various CPUs (and some other chips).
-
-         Say Y here if your device has buttons connected
-         directly to such GPIO pins.  Your board-specific
-         setup logic must also provide a platform device,
-         with configuration data saying which GPIOs are used.
+         Say Y here to enable the keyboard on the Sharp Zaurus SL-C1000,
+         SL-C3000 and Sl-C3100 series of PDAs.
 
          To compile this driver as a module, choose M here: the
-         module will be called gpio-keys.
+         module will be called spitzkbd.
 
-config KEYBOARD_MAPLE
-       tristate "Maple bus keyboard"
-       depends on SH_DREAMCAST && MAPLE
+config KEYBOARD_STOWAWAY
+       tristate "Stowaway keyboard"
+       select SERIO
        help
-         Say Y here if you have a Dreamcast console running Linux and have
-         a keyboard attached to its Maple bus.
+         Say Y here if you have a Stowaway keyboard on a serial port.
+         Stowaway compatible keyboards like Dicota Input-PDA keyboard
+         are also supported by this driver.
 
          To compile this driver as a module, choose M here: the
-         module will be called maple_keyb.
+         module will be called stowaway.
 
-config KEYBOARD_BFIN
-       tristate "Blackfin BF54x keypad support"
-       depends on (BF54x && !BF544)
+config KEYBOARD_SUNKBD
+       tristate "Sun Type 4 and Type 5 keyboard"
+       select SERIO
        help
-         Say Y here if you want to use the BF54x keypad.
+         Say Y here if you want to use a Sun Type 4 or Type 5 keyboard,
+         connected either to the Sun keyboard connector or to an serial
+         (RS-232) port via a simple adapter.
 
          To compile this driver as a module, choose M here: the
-         module will be called bf54x-keys.
+         module will be called sunkbd.
 
 config KEYBOARD_SH_KEYSC
        tristate "SuperH KEYSC keypad support"
@@ -344,13 +320,45 @@ config KEYBOARD_SH_KEYSC
          To compile this driver as a module, choose M here: the
          module will be called sh_keysc.
 
-config KEYBOARD_EP93XX
-       tristate "EP93xx Matrix Keypad support"
-       depends on ARCH_EP93XX
+config KEYBOARD_OMAP
+       tristate "TI OMAP keypad support"
+       depends on (ARCH_OMAP1 || ARCH_OMAP2)
        help
-         Say Y here to enable the matrix keypad on the Cirrus EP93XX.
+         Say Y here if you want to use the OMAP keypad.
 
          To compile this driver as a module, choose M here: the
-         module will be called ep93xx_keypad.
+         module will be called omap-keypad.
+
+config KEYBOARD_TOSA
+       tristate "Tosa keyboard"
+       depends on MACH_TOSA
+       default y
+       help
+         Say Y here to enable the keyboard on the Sharp Zaurus SL-6000x (Tosa)
+
+         To compile this driver as a module, choose M here: the
+         module will be called tosakbd.
+
+config KEYBOARD_TOSA_USE_EXT_KEYCODES
+       bool "Tosa keyboard: use extended keycodes"
+       depends on KEYBOARD_TOSA
+       help
+         Say Y here to enable the tosa keyboard driver to generate extended
+         (>= 127) keycodes. Be aware, that they can't be correctly interpreted
+         by either console keyboard driver or by Kdrive keybd driver.
+
+         Say Y only if you know, what you are doing!
+
+config KEYBOARD_XTKBD
+       tristate "XT keyboard"
+       select SERIO
+       help
+         Say Y here if you want to use the old IBM PC/XT keyboard (or
+         compatible) on your system. This is only possible with a
+         parallel port keyboard adapter, you cannot connect it to the
+         keyboard port on a PC that runs Linux.
+
+         To compile this driver as a module, choose M here: the
+         module will be called xtkbd.
 
 endif
index 156b647a259b776b07c64b9e2e99ca6d2bad7286..b5b5eae9724fa5f49b651bcd987ebeb5d0707c18 100644 (file)
@@ -4,29 +4,30 @@
 
 # Each configuration option enables a list of files.
 
-obj-$(CONFIG_KEYBOARD_ATKBD)           += atkbd.o
-obj-$(CONFIG_KEYBOARD_SUNKBD)          += sunkbd.o
-obj-$(CONFIG_KEYBOARD_LKKBD)           += lkkbd.o
-obj-$(CONFIG_KEYBOARD_XTKBD)           += xtkbd.o
+obj-$(CONFIG_KEYBOARD_AAED2000)                += aaed2000_kbd.o
 obj-$(CONFIG_KEYBOARD_AMIGA)           += amikbd.o
 obj-$(CONFIG_KEYBOARD_ATARI)           += atakbd.o
-obj-$(CONFIG_KEYBOARD_LOCOMO)          += locomokbd.o
-obj-$(CONFIG_KEYBOARD_NEWTON)          += newtonkbd.o
-obj-$(CONFIG_KEYBOARD_STOWAWAY)                += stowaway.o
+obj-$(CONFIG_KEYBOARD_ATKBD)           += atkbd.o
+obj-$(CONFIG_KEYBOARD_BFIN)            += bf54x-keys.o
 obj-$(CONFIG_KEYBOARD_CORGI)           += corgikbd.o
-obj-$(CONFIG_KEYBOARD_SPITZ)           += spitzkbd.o
-obj-$(CONFIG_KEYBOARD_TOSA)            += tosakbd.o
+obj-$(CONFIG_KEYBOARD_EP93XX)          += ep93xx_keypad.o
+obj-$(CONFIG_KEYBOARD_GPIO)            += gpio_keys.o
 obj-$(CONFIG_KEYBOARD_HIL)             += hil_kbd.o
 obj-$(CONFIG_KEYBOARD_HIL_OLD)         += hilkbd.o
+obj-$(CONFIG_KEYBOARD_HP6XX)           += jornada680_kbd.o
+obj-$(CONFIG_KEYBOARD_HP7XX)           += jornada720_kbd.o
+obj-$(CONFIG_KEYBOARD_LKKBD)           += lkkbd.o
 obj-$(CONFIG_KEYBOARD_LM8323)          += lm8323.o
+obj-$(CONFIG_KEYBOARD_LOCOMO)          += locomokbd.o
+obj-$(CONFIG_KEYBOARD_MAPLE)           += maple_keyb.o
+obj-$(CONFIG_KEYBOARD_MATRIX)          += matrix_keypad.o
+obj-$(CONFIG_KEYBOARD_NEWTON)          += newtonkbd.o
 obj-$(CONFIG_KEYBOARD_OMAP)            += omap-keypad.o
 obj-$(CONFIG_KEYBOARD_PXA27x)          += pxa27x_keypad.o
 obj-$(CONFIG_KEYBOARD_PXA930_ROTARY)   += pxa930_rotary.o
-obj-$(CONFIG_KEYBOARD_AAED2000)                += aaed2000_kbd.o
-obj-$(CONFIG_KEYBOARD_GPIO)            += gpio_keys.o
-obj-$(CONFIG_KEYBOARD_HP6XX)           += jornada680_kbd.o
-obj-$(CONFIG_KEYBOARD_HP7XX)           += jornada720_kbd.o
-obj-$(CONFIG_KEYBOARD_MAPLE)           += maple_keyb.o
-obj-$(CONFIG_KEYBOARD_BFIN)            += bf54x-keys.o
 obj-$(CONFIG_KEYBOARD_SH_KEYSC)                += sh_keysc.o
-obj-$(CONFIG_KEYBOARD_EP93XX)          += ep93xx_keypad.o
+obj-$(CONFIG_KEYBOARD_SPITZ)           += spitzkbd.o
+obj-$(CONFIG_KEYBOARD_STOWAWAY)                += stowaway.o
+obj-$(CONFIG_KEYBOARD_SUNKBD)          += sunkbd.o
+obj-$(CONFIG_KEYBOARD_TOSA)            += tosakbd.o
+obj-$(CONFIG_KEYBOARD_XTKBD)           += xtkbd.o
index 2157cd7de00ced20c2d253bce59f6a5f37401841..efed0c9e242ed1880f618aa73c67ae0a1eab470b 100644 (file)
@@ -29,7 +29,8 @@
 struct gpio_button_data {
        struct gpio_keys_button *button;
        struct input_dev *input;
-       struct delayed_work work;
+       struct timer_list timer;
+       struct work_struct work;
 };
 
 struct gpio_keys_drvdata {
@@ -40,7 +41,7 @@ struct gpio_keys_drvdata {
 static void gpio_keys_report_event(struct work_struct *work)
 {
        struct gpio_button_data *bdata =
-               container_of(work, struct gpio_button_data, work.work);
+               container_of(work, struct gpio_button_data, work);
        struct gpio_keys_button *button = bdata->button;
        struct input_dev *input = bdata->input;
        unsigned int type = button->type ?: EV_KEY;
@@ -50,17 +51,25 @@ static void gpio_keys_report_event(struct work_struct *work)
        input_sync(input);
 }
 
+static void gpio_keys_timer(unsigned long _data)
+{
+       struct gpio_button_data *data = (struct gpio_button_data *)_data;
+
+       schedule_work(&data->work);
+}
+
 static irqreturn_t gpio_keys_isr(int irq, void *dev_id)
 {
        struct gpio_button_data *bdata = dev_id;
        struct gpio_keys_button *button = bdata->button;
-       unsigned long delay;
 
        BUG_ON(irq != gpio_to_irq(button->gpio));
 
-       delay = button->debounce_interval ?
-                       msecs_to_jiffies(button->debounce_interval) : 0;
-       schedule_delayed_work(&bdata->work, delay);
+       if (button->debounce_interval)
+               mod_timer(&bdata->timer,
+                       jiffies + msecs_to_jiffies(button->debounce_interval));
+       else
+               schedule_work(&bdata->work);
 
        return IRQ_HANDLED;
 }
@@ -107,7 +116,9 @@ static int __devinit gpio_keys_probe(struct platform_device *pdev)
 
                bdata->input = input;
                bdata->button = button;
-               INIT_DELAYED_WORK(&bdata->work, gpio_keys_report_event);
+               setup_timer(&bdata->timer,
+                           gpio_keys_timer, (unsigned long)bdata);
+               INIT_WORK(&bdata->work, gpio_keys_report_event);
 
                error = gpio_request(button->gpio, button->desc ?: "gpio_keys");
                if (error < 0) {
@@ -166,7 +177,9 @@ static int __devinit gpio_keys_probe(struct platform_device *pdev)
  fail2:
        while (--i >= 0) {
                free_irq(gpio_to_irq(pdata->buttons[i].gpio), &ddata->data[i]);
-               cancel_delayed_work_sync(&ddata->data[i].work);
+               if (pdata->buttons[i].debounce_interval)
+                       del_timer_sync(&ddata->data[i].timer);
+               cancel_work_sync(&ddata->data[i].work);
                gpio_free(pdata->buttons[i].gpio);
        }
 
@@ -190,7 +203,9 @@ static int __devexit gpio_keys_remove(struct platform_device *pdev)
        for (i = 0; i < pdata->nbuttons; i++) {
                int irq = gpio_to_irq(pdata->buttons[i].gpio);
                free_irq(irq, &ddata->data[i]);
-               cancel_delayed_work_sync(&ddata->data[i].work);
+               if (pdata->buttons[i].debounce_interval)
+                       del_timer_sync(&ddata->data[i].timer);
+               cancel_work_sync(&ddata->data[i].work);
                gpio_free(pdata->buttons[i].gpio);
        }
 
diff --git a/drivers/input/keyboard/matrix_keypad.c b/drivers/input/keyboard/matrix_keypad.c
new file mode 100644 (file)
index 0000000..e9b2e7c
--- /dev/null
@@ -0,0 +1,453 @@
+/*
+ *  GPIO driven matrix keyboard driver
+ *
+ *  Copyright (c) 2008 Marek Vasut <marek.vasut@gmail.com>
+ *
+ *  Based on corgikbd.c
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License version 2 as
+ *  published by the Free Software Foundation.
+ *
+ */
+
+#include <linux/types.h>
+#include <linux/delay.h>
+#include <linux/platform_device.h>
+#include <linux/init.h>
+#include <linux/input.h>
+#include <linux/irq.h>
+#include <linux/interrupt.h>
+#include <linux/jiffies.h>
+#include <linux/module.h>
+#include <linux/gpio.h>
+#include <linux/input/matrix_keypad.h>
+
+struct matrix_keypad {
+       const struct matrix_keypad_platform_data *pdata;
+       struct input_dev *input_dev;
+       unsigned short *keycodes;
+
+       uint32_t last_key_state[MATRIX_MAX_COLS];
+       struct delayed_work work;
+       bool scan_pending;
+       bool stopped;
+       spinlock_t lock;
+};
+
+/*
+ * NOTE: normally the GPIO has to be put into HiZ when de-activated to cause
+ * minmal side effect when scanning other columns, here it is configured to
+ * be input, and it should work on most platforms.
+ */
+static void __activate_col(const struct matrix_keypad_platform_data *pdata,
+                          int col, bool on)
+{
+       bool level_on = !pdata->active_low;
+
+       if (on) {
+               gpio_direction_output(pdata->col_gpios[col], level_on);
+       } else {
+               gpio_set_value_cansleep(pdata->col_gpios[col], !level_on);
+               gpio_direction_input(pdata->col_gpios[col]);
+       }
+}
+
+static void activate_col(const struct matrix_keypad_platform_data *pdata,
+                        int col, bool on)
+{
+       __activate_col(pdata, col, on);
+
+       if (on && pdata->col_scan_delay_us)
+               udelay(pdata->col_scan_delay_us);
+}
+
+static void activate_all_cols(const struct matrix_keypad_platform_data *pdata,
+                             bool on)
+{
+       int col;
+
+       for (col = 0; col < pdata->num_col_gpios; col++)
+               __activate_col(pdata, col, on);
+}
+
+static bool row_asserted(const struct matrix_keypad_platform_data *pdata,
+                        int row)
+{
+       return gpio_get_value_cansleep(pdata->row_gpios[row]) ?
+                       !pdata->active_low : pdata->active_low;
+}
+
+static void enable_row_irqs(struct matrix_keypad *keypad)
+{
+       const struct matrix_keypad_platform_data *pdata = keypad->pdata;
+       int i;
+
+       for (i = 0; i < pdata->num_row_gpios; i++)
+               enable_irq(gpio_to_irq(pdata->row_gpios[i]));
+}
+
+static void disable_row_irqs(struct matrix_keypad *keypad)
+{
+       const struct matrix_keypad_platform_data *pdata = keypad->pdata;
+       int i;
+
+       for (i = 0; i < pdata->num_row_gpios; i++)
+               disable_irq_nosync(gpio_to_irq(pdata->row_gpios[i]));
+}
+
+/*
+ * This gets the keys from keyboard and reports it to input subsystem
+ */
+static void matrix_keypad_scan(struct work_struct *work)
+{
+       struct matrix_keypad *keypad =
+               container_of(work, struct matrix_keypad, work.work);
+       struct input_dev *input_dev = keypad->input_dev;
+       const struct matrix_keypad_platform_data *pdata = keypad->pdata;
+       uint32_t new_state[MATRIX_MAX_COLS];
+       int row, col, code;
+
+       /* de-activate all columns for scanning */
+       activate_all_cols(pdata, false);
+
+       memset(new_state, 0, sizeof(new_state));
+
+       /* assert each column and read the row status out */
+       for (col = 0; col < pdata->num_col_gpios; col++) {
+
+               activate_col(pdata, col, true);
+
+               for (row = 0; row < pdata->num_row_gpios; row++)
+                       new_state[col] |=
+                               row_asserted(pdata, row) ? (1 << row) : 0;
+
+               activate_col(pdata, col, false);
+       }
+
+       for (col = 0; col < pdata->num_col_gpios; col++) {
+               uint32_t bits_changed;
+
+               bits_changed = keypad->last_key_state[col] ^ new_state[col];
+               if (bits_changed == 0)
+                       continue;
+
+               for (row = 0; row < pdata->num_row_gpios; row++) {
+                       if ((bits_changed & (1 << row)) == 0)
+                               continue;
+
+                       code = (row << 4) + col;
+                       input_event(input_dev, EV_MSC, MSC_SCAN, code);
+                       input_report_key(input_dev,
+                                        keypad->keycodes[code],
+                                        new_state[col] & (1 << row));
+               }
+       }
+       input_sync(input_dev);
+
+       memcpy(keypad->last_key_state, new_state, sizeof(new_state));
+
+       activate_all_cols(pdata, true);
+
+       /* Enable IRQs again */
+       spin_lock_irq(&keypad->lock);
+       keypad->scan_pending = false;
+       enable_row_irqs(keypad);
+       spin_unlock_irq(&keypad->lock);
+}
+
+static irqreturn_t matrix_keypad_interrupt(int irq, void *id)
+{
+       struct matrix_keypad *keypad = id;
+       unsigned long flags;
+
+       spin_lock_irqsave(&keypad->lock, flags);
+
+       /*
+        * See if another IRQ beaten us to it and scheduled the
+        * scan already. In that case we should not try to
+        * disable IRQs again.
+        */
+       if (unlikely(keypad->scan_pending || keypad->stopped))
+               goto out;
+
+       disable_row_irqs(keypad);
+       keypad->scan_pending = true;
+       schedule_delayed_work(&keypad->work,
+               msecs_to_jiffies(keypad->pdata->debounce_ms));
+
+out:
+       spin_unlock_irqrestore(&keypad->lock, flags);
+       return IRQ_HANDLED;
+}
+
+static int matrix_keypad_start(struct input_dev *dev)
+{
+       struct matrix_keypad *keypad = input_get_drvdata(dev);
+
+       keypad->stopped = false;
+       mb();
+
+       /*
+        * Schedule an immediate key scan to capture current key state;
+        * columns will be activated and IRQs be enabled after the scan.
+        */
+       schedule_delayed_work(&keypad->work, 0);
+
+       return 0;
+}
+
+static void matrix_keypad_stop(struct input_dev *dev)
+{
+       struct matrix_keypad *keypad = input_get_drvdata(dev);
+
+       keypad->stopped = true;
+       mb();
+       flush_work(&keypad->work.work);
+       /*
+        * matrix_keypad_scan() will leave IRQs enabled;
+        * we should disable them now.
+        */
+       disable_row_irqs(keypad);
+}
+
+#ifdef CONFIG_PM
+static int matrix_keypad_suspend(struct platform_device *pdev, pm_message_t state)
+{
+       struct matrix_keypad *keypad = platform_get_drvdata(pdev);
+       const struct matrix_keypad_platform_data *pdata = keypad->pdata;
+       int i;
+
+       matrix_keypad_stop(keypad->input_dev);
+
+       if (device_may_wakeup(&pdev->dev))
+               for (i = 0; i < pdata->num_row_gpios; i++)
+                       enable_irq_wake(gpio_to_irq(pdata->row_gpios[i]));
+
+       return 0;
+}
+
+static int matrix_keypad_resume(struct platform_device *pdev)
+{
+       struct matrix_keypad *keypad = platform_get_drvdata(pdev);
+       const struct matrix_keypad_platform_data *pdata = keypad->pdata;
+       int i;
+
+       if (device_may_wakeup(&pdev->dev))
+               for (i = 0; i < pdata->num_row_gpios; i++)
+                       disable_irq_wake(gpio_to_irq(pdata->row_gpios[i]));
+
+       matrix_keypad_start(keypad->input_dev);
+
+       return 0;
+}
+#else
+#define matrix_keypad_suspend  NULL
+#define matrix_keypad_resume   NULL
+#endif
+
+static int __devinit init_matrix_gpio(struct platform_device *pdev,
+                                       struct matrix_keypad *keypad)
+{
+       const struct matrix_keypad_platform_data *pdata = keypad->pdata;
+       int i, err = -EINVAL;
+
+       /* initialized strobe lines as outputs, activated */
+       for (i = 0; i < pdata->num_col_gpios; i++) {
+               err = gpio_request(pdata->col_gpios[i], "matrix_kbd_col");
+               if (err) {
+                       dev_err(&pdev->dev,
+                               "failed to request GPIO%d for COL%d\n",
+                               pdata->col_gpios[i], i);
+                       goto err_free_cols;
+               }
+
+               gpio_direction_output(pdata->col_gpios[i], !pdata->active_low);
+       }
+
+       for (i = 0; i < pdata->num_row_gpios; i++) {
+               err = gpio_request(pdata->row_gpios[i], "matrix_kbd_row");
+               if (err) {
+                       dev_err(&pdev->dev,
+                               "failed to request GPIO%d for ROW%d\n",
+                               pdata->row_gpios[i], i);
+                       goto err_free_rows;
+               }
+
+               gpio_direction_input(pdata->row_gpios[i]);
+       }
+
+       for (i = 0; i < pdata->num_row_gpios; i++) {
+               err = request_irq(gpio_to_irq(pdata->row_gpios[i]),
+                               matrix_keypad_interrupt,
+                               IRQF_DISABLED |
+                               IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
+                               "matrix-keypad", keypad);
+               if (err) {
+                       dev_err(&pdev->dev,
+                               "Unable to acquire interrupt for GPIO line %i\n",
+                               pdata->row_gpios[i]);
+                       goto err_free_irqs;
+               }
+       }
+
+       /* initialized as disabled - enabled by input->open */
+       disable_row_irqs(keypad);
+       return 0;
+
+err_free_irqs:
+       while (--i >= 0)
+               free_irq(gpio_to_irq(pdata->row_gpios[i]), keypad);
+       i = pdata->num_row_gpios;
+err_free_rows:
+       while (--i >= 0)
+               gpio_free(pdata->row_gpios[i]);
+       i = pdata->num_col_gpios;
+err_free_cols:
+       while (--i >= 0)
+               gpio_free(pdata->col_gpios[i]);
+
+       return err;
+}
+
+static int __devinit matrix_keypad_probe(struct platform_device *pdev)
+{
+       const struct matrix_keypad_platform_data *pdata;
+       const struct matrix_keymap_data *keymap_data;
+       struct matrix_keypad *keypad;
+       struct input_dev *input_dev;
+       unsigned short *keycodes;
+       int i;
+       int err;
+
+       pdata = pdev->dev.platform_data;
+       if (!pdata) {
+               dev_err(&pdev->dev, "no platform data defined\n");
+               return -EINVAL;
+       }
+
+       keymap_data = pdata->keymap_data;
+       if (!keymap_data) {
+               dev_err(&pdev->dev, "no keymap data defined\n");
+               return -EINVAL;
+       }
+
+       if (!keymap_data->max_keymap_size) {
+               dev_err(&pdev->dev, "invalid keymap data supplied\n");
+               return -EINVAL;
+       }
+
+       keypad = kzalloc(sizeof(struct matrix_keypad), GFP_KERNEL);
+       keycodes = kzalloc(keymap_data->max_keymap_size *
+                               sizeof(keypad->keycodes),
+                          GFP_KERNEL);
+       input_dev = input_allocate_device();
+       if (!keypad || !keycodes || !input_dev) {
+               err = -ENOMEM;
+               goto err_free_mem;
+       }
+
+       keypad->input_dev = input_dev;
+       keypad->pdata = pdata;
+       keypad->keycodes = keycodes;
+       keypad->stopped = true;
+       INIT_DELAYED_WORK(&keypad->work, matrix_keypad_scan);
+       spin_lock_init(&keypad->lock);
+
+       input_dev->name         = pdev->name;
+       input_dev->id.bustype   = BUS_HOST;
+       input_dev->dev.parent   = &pdev->dev;
+       input_dev->evbit[0]     = BIT_MASK(EV_KEY) | BIT_MASK(EV_REP);
+       input_dev->open         = matrix_keypad_start;
+       input_dev->close        = matrix_keypad_stop;
+
+       input_dev->keycode      = keycodes;
+       input_dev->keycodesize  = sizeof(*keycodes);
+       input_dev->keycodemax   = keymap_data->max_keymap_size;
+
+       for (i = 0; i < keymap_data->keymap_size; i++) {
+               unsigned int key = keymap_data->keymap[i];
+               unsigned int row = KEY_ROW(key);
+               unsigned int col = KEY_COL(key);
+               unsigned short code = KEY_VAL(key);
+
+               keycodes[(row << 4) + col] = code;
+               __set_bit(code, input_dev->keybit);
+       }
+       __clear_bit(KEY_RESERVED, input_dev->keybit);
+
+       input_set_capability(input_dev, EV_MSC, MSC_SCAN);
+       input_set_drvdata(input_dev, keypad);
+
+       err = init_matrix_gpio(pdev, keypad);
+       if (err)
+               goto err_free_mem;
+
+       err = input_register_device(keypad->input_dev);
+       if (err)
+               goto err_free_mem;
+
+       device_init_wakeup(&pdev->dev, pdata->wakeup);
+       platform_set_drvdata(pdev, keypad);
+
+       return 0;
+
+err_free_mem:
+       input_free_device(input_dev);
+       kfree(keycodes);
+       kfree(keypad);
+       return err;
+}
+
+static int __devexit matrix_keypad_remove(struct platform_device *pdev)
+{
+       struct matrix_keypad *keypad = platform_get_drvdata(pdev);
+       const struct matrix_keypad_platform_data *pdata = keypad->pdata;
+       int i;
+
+       device_init_wakeup(&pdev->dev, 0);
+
+       for (i = 0; i < pdata->num_row_gpios; i++) {
+               free_irq(gpio_to_irq(pdata->row_gpios[i]), keypad);
+               gpio_free(pdata->row_gpios[i]);
+       }
+
+       for (i = 0; i < pdata->num_col_gpios; i++)
+               gpio_free(pdata->col_gpios[i]);
+
+       input_unregister_device(keypad->input_dev);
+       platform_set_drvdata(pdev, NULL);
+       kfree(keypad->keycodes);
+       kfree(keypad);
+
+       return 0;
+}
+
+static struct platform_driver matrix_keypad_driver = {
+       .probe          = matrix_keypad_probe,
+       .remove         = __devexit_p(matrix_keypad_remove),
+       .suspend        = matrix_keypad_suspend,
+       .resume         = matrix_keypad_resume,
+       .driver         = {
+               .name   = "matrix-keypad",
+               .owner  = THIS_MODULE,
+       },
+};
+
+static int __init matrix_keypad_init(void)
+{
+       return platform_driver_register(&matrix_keypad_driver);
+}
+
+static void __exit matrix_keypad_exit(void)
+{
+       platform_driver_unregister(&matrix_keypad_driver);
+}
+
+module_init(matrix_keypad_init);
+module_exit(matrix_keypad_exit);
+
+MODULE_AUTHOR("Marek Vasut <marek.vasut@gmail.com>");
+MODULE_DESCRIPTION("GPIO Driven Matrix Keypad Driver");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:matrix-keypad");
index 2adf9cb265da69fd67b6d1b8bec3fa3841e95ec2..d114d3a9e1e94b7129870642943d7ac91a368cac 100644 (file)
@@ -1,7 +1,7 @@
 /*
  *  Cobalt button interface driver.
  *
- *  Copyright (C) 2007-2008  Yoichi Yuasa <yoichi_yuasa@tripeaks.co.jp>
+ *  Copyright (C) 2007-2008  Yoichi Yuasa <yuasa@linux-mips.org>
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
@@ -148,7 +148,7 @@ static int __devexit cobalt_buttons_remove(struct platform_device *pdev)
        return 0;
 }
 
-MODULE_AUTHOR("Yoichi Yuasa <yoichi_yuasa@tripeaks.co.jp>");
+MODULE_AUTHOR("Yoichi Yuasa <yuasa@linux-mips.org>");
 MODULE_DESCRIPTION("Cobalt button interface driver");
 MODULE_LICENSE("GPL");
 /* work with hotplug and coldplug */
index 5e5eb88d8d1e04e48b5a0668300ecf56cbe6017d..7b6ce178f1b67d64c92e2e969d256bbe381a86e7 100644 (file)
@@ -46,7 +46,7 @@ static void gpio_mouse_scan(struct input_polled_dev *dev)
        input_sync(input);
 }
 
-static int __init gpio_mouse_probe(struct platform_device *pdev)
+static int __devinit gpio_mouse_probe(struct platform_device *pdev)
 {
        struct gpio_mouse_platform_data *pdata = pdev->dev.platform_data;
        struct input_polled_dev *input_poll;
@@ -170,10 +170,8 @@ static int __devexit gpio_mouse_remove(struct platform_device *pdev)
        return 0;
 }
 
-/* work with hotplug and coldplug */
-MODULE_ALIAS("platform:gpio_mouse");
-
 static struct platform_driver gpio_mouse_device_driver = {
+       .probe          = gpio_mouse_probe,
        .remove         = __devexit_p(gpio_mouse_remove),
        .driver         = {
                .name   = "gpio_mouse",
@@ -183,8 +181,7 @@ static struct platform_driver gpio_mouse_device_driver = {
 
 static int __init gpio_mouse_init(void)
 {
-       return platform_driver_probe(&gpio_mouse_device_driver,
-                       gpio_mouse_probe);
+       return platform_driver_register(&gpio_mouse_device_driver);
 }
 module_init(gpio_mouse_init);
 
@@ -197,3 +194,5 @@ module_exit(gpio_mouse_exit);
 MODULE_AUTHOR("Hans-Christian Egtvedt <hcegtvedt@atmel.com>");
 MODULE_DESCRIPTION("GPIO mouse driver");
 MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:gpio_mouse"); /* work with hotplug and coldplug */
+
index fb8a3cd3ffd0ab4685e8e68f5f14b07068266b94..924e8ed7f2cf777f5d48767c18d5618027c031e6 100644 (file)
@@ -392,6 +392,34 @@ static struct dmi_system_id __initdata i8042_dmi_reset_table[] = {
                        DMI_MATCH(DMI_BOARD_VENDOR, "LG Electronics Inc."),
                },
        },
+       {
+               .ident = "Acer Aspire One 150",
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "AOA150"),
+               },
+       },
+       {
+               .ident = "Advent 4211",
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "DIXONSXP"),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "Advent 4211"),
+               },
+       },
+       {
+               .ident = "Medion Akoya Mini E1210",
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "MEDION"),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "E1210"),
+               },
+       },
+       {
+               .ident = "Mivvy M310",
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "VIOOO"),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "N10"),
+               },
+       },
        { }
 };
 
index f919bf57293c9fad56d625aa1e497655eda5a04a..582245c497ebfe1e6ff5b8fbe513a31e483de35f 100644 (file)
@@ -934,10 +934,11 @@ static bool i8042_suspended;
 
 static int i8042_suspend(struct platform_device *dev, pm_message_t state)
 {
-       if (!i8042_suspended && state.event == PM_EVENT_SUSPEND) {
+       if (!i8042_suspended && state.event == PM_EVENT_SUSPEND)
                i8042_controller_reset();
-               i8042_suspended = true;
-       }
+
+       i8042_suspended = state.event == PM_EVENT_SUSPEND ||
+                         state.event == PM_EVENT_FREEZE;
 
        return 0;
 }
index fb17573f8f2d90e88072714b0a8fc4b7eb142616..d66f4944f2a0efc0a18508d9c4707bf069567830 100644 (file)
@@ -935,10 +935,11 @@ static int serio_suspend(struct device *dev, pm_message_t state)
 {
        struct serio *serio = to_serio_port(dev);
 
-       if (!serio->suspended && state.event == PM_EVENT_SUSPEND) {
+       if (!serio->suspended && state.event == PM_EVENT_SUSPEND)
                serio_cleanup(serio);
-               serio->suspended = true;
-       }
+
+       serio->suspended = state.event == PM_EVENT_SUSPEND ||
+                          state.event == PM_EVENT_FREEZE;
 
        return 0;
 }
index 38bf86384aeba4d7b5393f43179e2c4bf55864b9..c896d6a21b7ee6fa53eb8853ff6535a65ae194af 100644 (file)
@@ -384,6 +384,8 @@ static int wacom_intuos_inout(struct wacom_wac *wacom, void *wcombo)
                        wacom_report_key(wcombo, BTN_STYLUS2, 0);
                        wacom_report_key(wcombo, BTN_TOUCH, 0);
                        wacom_report_abs(wcombo, ABS_WHEEL, 0);
+                       if (wacom->features->type >= INTUOS3S)
+                               wacom_report_abs(wcombo, ABS_Z, 0);
                }
                wacom_report_key(wcombo, wacom->tool[idx], 0);
                wacom_report_abs(wcombo, ABS_MISC, 0); /* reset tool id */
@@ -836,6 +838,7 @@ static struct wacom_features wacom_features[] = {
        { "Wacom DTU710",        8,  34080, 27660,  511,  0, PL },
        { "Wacom DTF521",        8,   6282,  4762,  511,  0, PL },
        { "Wacom DTF720",        8,   6858,  5506,  511,  0, PL },
+       { "Wacom DTF720a",       8,   6858,  5506,  511,  0, PL },
        { "Wacom Cintiq Partner",8,  20480, 15360,  511,  0, PTU },
        { "Wacom Intuos2 4x5",   10, 12700, 10600, 1023, 31, INTUOS },
        { "Wacom Intuos2 6x8",   10, 20320, 16240, 1023, 31, INTUOS },
@@ -897,8 +900,9 @@ static struct usb_device_id wacom_ids[] = {
        { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x37) },
        { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x38) },
        { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x39) },
-       { USB_DEVICE(USB_VENDOR_ID_WACOM, 0xC0) },
        { USB_DEVICE(USB_VENDOR_ID_WACOM, 0xC4) },
+       { USB_DEVICE(USB_VENDOR_ID_WACOM, 0xC0) },
+       { USB_DEVICE(USB_VENDOR_ID_WACOM, 0xC2) },
        { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x03) },
        { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x41) },
        { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x42) },
index ec5169604a6a93dd714efcb9648390dea5075eee..2d91049571a4ce20470acb86d7120bee326b911c 100644 (file)
@@ -294,32 +294,33 @@ struct reply_t gigaset_tab_cid[] =
        {RSP_OK,      604,604, -1,                605, 5, {ACT_CMD+AT_MSN}},
        {RSP_OK,      605,605, -1,                606, 5, {ACT_CMD+AT_ISO}},
        {RSP_NULL,    605,605, -1,                606, 5, {ACT_CMD+AT_ISO}},
-       {RSP_OK,      606,606, -1,                607, 5, {0},             "+VLS=17\r"}, /* set "Endgeraetemodus" */
+       {RSP_OK,      606,606, -1,                607, 5, {0}, "+VLS=17\r"},
        {RSP_OK,      607,607, -1,                608,-1},
-       //{RSP_ZSAU,    608,608,ZSAU_PROCEEDING,    608, 0, {ACT_ERROR}},//DELETE
        {RSP_ZSAU,    608,608,ZSAU_PROCEEDING,    609, 5, {ACT_CMD+AT_DIAL}},
        {RSP_OK,      609,609, -1,                650, 0, {ACT_DIALING}},
 
-       {RSP_ZVLS,    608,608, 17,                 -1,-1, {ACT_DEBUG}},
-       {RSP_ZCTP,    609,609, -1,                 -1,-1, {ACT_DEBUG}},
-       {RSP_ZCPN,    609,609, -1,                 -1,-1, {ACT_DEBUG}},
        {RSP_ERROR,   601,609, -1,                  0, 0, {ACT_ABORTDIAL}},
        {EV_TIMEOUT,  601,609, -1,                  0, 0, {ACT_ABORTDIAL}},
 
-       /* dialing */
-       {RSP_ZCTP,    650,650, -1,                 -1,-1, {ACT_DEBUG}},
-       {RSP_ZCPN,    650,650, -1,                 -1,-1, {ACT_DEBUG}},
-       {RSP_ZSAU,    650,650,ZSAU_CALL_DELIVERED, -1,-1, {ACT_DEBUG}}, /* some devices don't send this */
-
-       /* connection established  */
-       {RSP_ZSAU,    650,650,ZSAU_ACTIVE,        800,-1, {ACT_CONNECT}}, //FIXME -> DLE1
-       {RSP_ZSAU,    750,750,ZSAU_ACTIVE,        800,-1, {ACT_CONNECT}}, //FIXME -> DLE1
-
-       {EV_BC_OPEN,  800,800, -1,                800,-1, {ACT_NOTIFY_BC_UP}}, //FIXME new constate + timeout
+       /* optional dialing responses */
+       {EV_BC_OPEN,  650,650, -1,                651,-1},
+       {RSP_ZVLS,    608,651, 17,                 -1,-1, {ACT_DEBUG}},
+       {RSP_ZCTP,    609,651, -1,                 -1,-1, {ACT_DEBUG}},
+       {RSP_ZCPN,    609,651, -1,                 -1,-1, {ACT_DEBUG}},
+       {RSP_ZSAU,    650,651,ZSAU_CALL_DELIVERED, -1,-1, {ACT_DEBUG}},
+
+       /* connect */
+       {RSP_ZSAU,    650,650,ZSAU_ACTIVE,        800,-1, {ACT_CONNECT}},
+       {RSP_ZSAU,    651,651,ZSAU_ACTIVE,        800,-1, {ACT_CONNECT,
+                                                          ACT_NOTIFY_BC_UP}},
+       {RSP_ZSAU,    750,750,ZSAU_ACTIVE,        800,-1, {ACT_CONNECT}},
+       {RSP_ZSAU,    751,751,ZSAU_ACTIVE,        800,-1, {ACT_CONNECT,
+                                                          ACT_NOTIFY_BC_UP}},
+       {EV_BC_OPEN,  800,800, -1,                800,-1, {ACT_NOTIFY_BC_UP}},
 
        /* remote hangup */
-       {RSP_ZSAU,    650,650,ZSAU_DISCONNECT_IND,  0, 0, {ACT_REMOTEREJECT}},
-       {RSP_ZSAU,    750,750,ZSAU_DISCONNECT_IND,  0, 0, {ACT_REMOTEHUP}},
+       {RSP_ZSAU,    650,651,ZSAU_DISCONNECT_IND,  0, 0, {ACT_REMOTEREJECT}},
+       {RSP_ZSAU,    750,751,ZSAU_DISCONNECT_IND,  0, 0, {ACT_REMOTEHUP}},
        {RSP_ZSAU,    800,800,ZSAU_DISCONNECT_IND,  0, 0, {ACT_REMOTEHUP}},
 
        /* hangup */
@@ -358,7 +359,8 @@ struct reply_t gigaset_tab_cid[] =
        {RSP_ZSAU,    700,729,ZSAU_ACTIVE,          0, 0, {ACT_ABORTACCEPT}},
        {RSP_ZSAU,    700,729,ZSAU_DISCONNECT_IND,  0, 0, {ACT_ABORTACCEPT}},
 
-       {EV_TIMEOUT,  750,750, -1,                  0, 0, {ACT_CONNTIMEOUT}},
+       {EV_BC_OPEN,  750,750, -1,                751,-1},
+       {EV_TIMEOUT,  750,751, -1,                  0, 0, {ACT_CONNTIMEOUT}},
 
        /* B channel closed (general case) */
        {EV_BC_CLOSED, -1, -1, -1,                 -1,-1, {ACT_NOTIFY_BC_DOWN}}, //FIXME
@@ -876,12 +878,6 @@ static void bchannel_down(struct bc_state *bcs)
 
 static void bchannel_up(struct bc_state *bcs)
 {
-       if (!(bcs->chstate & CHS_D_UP)) {
-               dev_notice(bcs->cs->dev, "%s: D channel not up\n", __func__);
-               bcs->chstate |= CHS_D_UP;
-               gigaset_i4l_channel_cmd(bcs, ISDN_STAT_DCONN);
-       }
-
        if (bcs->chstate & CHS_B_UP) {
                dev_notice(bcs->cs->dev, "%s: B channel already up\n",
                           __func__);
index db3a1e4cd4893e62af25041d478318035c2bad96..bed38fcc432b62b8a88335a697dfa93295110a2e 100644 (file)
@@ -174,12 +174,6 @@ int gigaset_isowbuf_getbytes(struct isowbuf_t *iwb, int size)
                pr_err("invalid size %d\n", size);
                return -EINVAL;
        }
-       src = iwb->read;
-       if (unlikely(limit >= BAS_OUTBUFSIZE + BAS_OUTBUFPAD ||
-                    (read < src && limit >= src))) {
-               pr_err("isoc write buffer frame reservation violated\n");
-               return -EFAULT;
-       }
 #endif
 
        if (read < write) {
index 8df889b0c1a97b1a6c3546545840bc3279755486..9de54202c90c84828c86cefeeb3408b090ea0bdc 100644 (file)
@@ -37,7 +37,6 @@
 #include <linux/kernel_stat.h>
 #include <linux/usb.h>
 #include <linux/kernel.h>
-#include <linux/smp_lock.h>
 #include <linux/sched.h>
 #include <linux/moduleparam.h>
 #include "hisax.h"
index b4d4522e50718347f02b88345cc93d50608d9252..2881a66c1aa97c2e78e0c9f3029bbbd44ef0046a 100644 (file)
@@ -13,6 +13,7 @@
 
 #include <linux/isdn.h>
 #include <linux/delay.h>
+#include <linux/smp_lock.h>
 #include "isdn_common.h"
 #include "isdn_tty.h"
 #ifdef CONFIG_ISDN_AUDIO
index e2f45019ebf0be504bdcd68538cd47f51109c588..3e1532a180ff172df2c92f2c19e8bb3ecdc9f1cd 100644 (file)
@@ -17,6 +17,7 @@
 
 #include <linux/mISDNif.h>
 #include <linux/kthread.h>
+#include <linux/smp_lock.h>
 #include "core.h"
 
 static u_int   *debug;
index 9b60b6b684d9cd7c5a62c843d827e6071491a51f..7c8e7122aaa906785694bca49ff730c9b5712c83 100644 (file)
@@ -75,6 +75,7 @@ config LEDS_ALIX2
        depends on LEDS_CLASS && X86 && EXPERIMENTAL
        help
          This option enables support for the PCEngines ALIX.2 and ALIX.3 LEDs.
+         You have to set leds-alix2.force=1 for boards with Award BIOS.
 
 config LEDS_H1940
        tristate "LED Support for iPAQ H1940 device"
@@ -145,15 +146,16 @@ config LEDS_GPIO_OF
          of_platform devices.  For instance, LEDs which are listed in a "dts"
          file.
 
-config LEDS_LP5521
-       tristate "LED Support for the LP5521 LEDs"
+config LEDS_LP3944
+       tristate "LED Support for N.S. LP3944 (Fun Light) I2C chip"
        depends on LEDS_CLASS && I2C
        help
-         If you say 'Y' here you get support for the National Semiconductor
-         LP5521 LED driver used in n8x0 boards.
+    This option enables support for LEDs connected to the National
+    Semiconductor LP3944 Lighting Management Unit (LMU) also known as
+    Fun Light Chip.
 
-         This driver can be built as a module by choosing 'M'. The module
-         will be called leds-lp5521.
+         To compile this driver as a module, choose M here: the
+         module will be called leds-lp3944.
 
 config LEDS_CLEVO_MAIL
        tristate "Mail LED on Clevo notebook"
index 2d41c4dcf92ff9a8db515aac17aee9dc9482db96..e8cdcf77a4c358f7cf1d4ba839f5db6a84df858e 100644 (file)
@@ -20,6 +20,7 @@ obj-$(CONFIG_LEDS_COBALT_RAQ)         += leds-cobalt-raq.o
 obj-$(CONFIG_LEDS_SUNFIRE)             += leds-sunfire.o
 obj-$(CONFIG_LEDS_PCA9532)             += leds-pca9532.o
 obj-$(CONFIG_LEDS_GPIO)                        += leds-gpio.o
+obj-$(CONFIG_LEDS_LP3944)              += leds-lp3944.o
 obj-$(CONFIG_LEDS_CLEVO_MAIL)          += leds-clevo-mail.o
 obj-$(CONFIG_LEDS_HP6XX)               += leds-hp6xx.o
 obj-$(CONFIG_LEDS_FSG)                 += leds-fsg.o
index ddbd7730dfc84dfdcb4e9c776f81fdeb8b5b877e..731d4eef342590dca6566f229d60d7f8add6b872 100644 (file)
@@ -14,7 +14,7 @@
 
 static int force = 0;
 module_param(force, bool, 0444);
-MODULE_PARM_DESC(force, "Assume system has ALIX.2 style LEDs");
+MODULE_PARM_DESC(force, "Assume system has ALIX.2/ALIX.3 style LEDs");
 
 struct alix_led {
        struct led_classdev cdev;
@@ -155,6 +155,11 @@ static int __init alix_led_init(void)
                goto out;
        }
 
+       /* enable output on GPIO for LED 1,2,3 */
+       outl(1 << 6, 0x6104);
+       outl(1 << 9, 0x6184);
+       outl(1 << 11, 0x6184);
+
        pdev = platform_device_register_simple(KBUILD_MODNAME, -1, NULL, 0);
        if (!IS_ERR(pdev)) {
                ret = platform_driver_probe(&alix_led_driver, alix_led_probe);
index 4149ecb3a9b2fda0a22cb93c2575ea16096c4bcd..779d7f262c04c39f1355e0dd2a190ca02fb067e3 100644 (file)
@@ -97,6 +97,10 @@ struct bd2802_led {
        enum led_ids                    led_id;
        enum led_colors                 color;
        enum led_bits                   state;
+
+       /* General attributes of RGB LEDs */
+       int                             wave_pattern;
+       int                             rgb_current;
 };
 
 
@@ -254,7 +258,7 @@ static void bd2802_set_on(struct bd2802_led *led, enum led_ids id,
                bd2802_reset_cancel(led);
 
        reg = bd2802_get_reg_addr(id, color, BD2802_REG_CURRENT1SETUP);
-       bd2802_write_byte(led->client, reg, BD2802_CURRENT_032);
+       bd2802_write_byte(led->client, reg, led->rgb_current);
        reg = bd2802_get_reg_addr(id, color, BD2802_REG_CURRENT2SETUP);
        bd2802_write_byte(led->client, reg, BD2802_CURRENT_000);
        reg = bd2802_get_reg_addr(id, color, BD2802_REG_WAVEPATTERN);
@@ -275,9 +279,9 @@ static void bd2802_set_blink(struct bd2802_led *led, enum led_ids id,
        reg = bd2802_get_reg_addr(id, color, BD2802_REG_CURRENT1SETUP);
        bd2802_write_byte(led->client, reg, BD2802_CURRENT_000);
        reg = bd2802_get_reg_addr(id, color, BD2802_REG_CURRENT2SETUP);
-       bd2802_write_byte(led->client, reg, BD2802_CURRENT_032);
+       bd2802_write_byte(led->client, reg, led->rgb_current);
        reg = bd2802_get_reg_addr(id, color, BD2802_REG_WAVEPATTERN);
-       bd2802_write_byte(led->client, reg, BD2802_PATTERN_HALF);
+       bd2802_write_byte(led->client, reg, led->wave_pattern);
 
        bd2802_enable(led, id);
        bd2802_update_state(led, id, color, BD2802_BLINK);
@@ -406,7 +410,7 @@ static void bd2802_enable_adv_conf(struct bd2802_led *led)
                ret = device_create_file(&led->client->dev,
                                                bd2802_addr_attributes[i]);
                if (ret) {
-                       dev_err(&led->client->dev, "failed to sysfs file %s\n",
+                       dev_err(&led->client->dev, "failed: sysfs file %s\n",
                                        bd2802_addr_attributes[i]->attr.name);
                        goto failed_remove_files;
                }
@@ -483,6 +487,52 @@ static struct device_attribute bd2802_adv_conf_attr = {
        .store = bd2802_store_adv_conf,
 };
 
+#define BD2802_CONTROL_ATTR(attr_name, name_str)                       \
+static ssize_t bd2802_show_##attr_name(struct device *dev,             \
+       struct device_attribute *attr, char *buf)                       \
+{                                                                      \
+       struct bd2802_led *led = i2c_get_clientdata(to_i2c_client(dev));\
+       ssize_t ret;                                                    \
+       down_read(&led->rwsem);                                         \
+       ret = sprintf(buf, "0x%02x\n", led->attr_name);                 \
+       up_read(&led->rwsem);                                           \
+       return ret;                                                     \
+}                                                                      \
+static ssize_t bd2802_store_##attr_name(struct device *dev,            \
+       struct device_attribute *attr, const char *buf, size_t count)   \
+{                                                                      \
+       struct bd2802_led *led = i2c_get_clientdata(to_i2c_client(dev));\
+       unsigned long val;                                              \
+       int ret;                                                        \
+       if (!count)                                                     \
+               return -EINVAL;                                         \
+       ret = strict_strtoul(buf, 16, &val);                            \
+       if (ret)                                                        \
+               return ret;                                             \
+       down_write(&led->rwsem);                                        \
+       led->attr_name = val;                                           \
+       up_write(&led->rwsem);                                          \
+       return count;                                                   \
+}                                                                      \
+static struct device_attribute bd2802_##attr_name##_attr = {           \
+       .attr = {                                                       \
+               .name = name_str,                                       \
+               .mode = 0644,                                           \
+               .owner = THIS_MODULE                                    \
+       },                                                              \
+       .show = bd2802_show_##attr_name,                                \
+       .store = bd2802_store_##attr_name,                              \
+};
+
+BD2802_CONTROL_ATTR(wave_pattern, "wave_pattern");
+BD2802_CONTROL_ATTR(rgb_current, "rgb_current");
+
+static struct device_attribute *bd2802_attributes[] = {
+       &bd2802_adv_conf_attr,
+       &bd2802_wave_pattern_attr,
+       &bd2802_rgb_current_attr,
+};
+
 static void bd2802_led_work(struct work_struct *work)
 {
        struct bd2802_led *led = container_of(work, struct bd2802_led, work);
@@ -538,7 +588,6 @@ static int bd2802_register_led_classdev(struct bd2802_led *led)
        led->cdev_led1r.brightness = LED_OFF;
        led->cdev_led1r.brightness_set = bd2802_set_led1r_brightness;
        led->cdev_led1r.blink_set = bd2802_set_led1r_blink;
-       led->cdev_led1r.flags |= LED_CORE_SUSPENDRESUME;
 
        ret = led_classdev_register(&led->client->dev, &led->cdev_led1r);
        if (ret < 0) {
@@ -551,7 +600,6 @@ static int bd2802_register_led_classdev(struct bd2802_led *led)
        led->cdev_led1g.brightness = LED_OFF;
        led->cdev_led1g.brightness_set = bd2802_set_led1g_brightness;
        led->cdev_led1g.blink_set = bd2802_set_led1g_blink;
-       led->cdev_led1g.flags |= LED_CORE_SUSPENDRESUME;
 
        ret = led_classdev_register(&led->client->dev, &led->cdev_led1g);
        if (ret < 0) {
@@ -564,7 +612,6 @@ static int bd2802_register_led_classdev(struct bd2802_led *led)
        led->cdev_led1b.brightness = LED_OFF;
        led->cdev_led1b.brightness_set = bd2802_set_led1b_brightness;
        led->cdev_led1b.blink_set = bd2802_set_led1b_blink;
-       led->cdev_led1b.flags |= LED_CORE_SUSPENDRESUME;
 
        ret = led_classdev_register(&led->client->dev, &led->cdev_led1b);
        if (ret < 0) {
@@ -577,7 +624,6 @@ static int bd2802_register_led_classdev(struct bd2802_led *led)
        led->cdev_led2r.brightness = LED_OFF;
        led->cdev_led2r.brightness_set = bd2802_set_led2r_brightness;
        led->cdev_led2r.blink_set = bd2802_set_led2r_blink;
-       led->cdev_led2r.flags |= LED_CORE_SUSPENDRESUME;
 
        ret = led_classdev_register(&led->client->dev, &led->cdev_led2r);
        if (ret < 0) {
@@ -590,7 +636,6 @@ static int bd2802_register_led_classdev(struct bd2802_led *led)
        led->cdev_led2g.brightness = LED_OFF;
        led->cdev_led2g.brightness_set = bd2802_set_led2g_brightness;
        led->cdev_led2g.blink_set = bd2802_set_led2g_blink;
-       led->cdev_led2g.flags |= LED_CORE_SUSPENDRESUME;
 
        ret = led_classdev_register(&led->client->dev, &led->cdev_led2g);
        if (ret < 0) {
@@ -640,7 +685,7 @@ static int __devinit bd2802_probe(struct i2c_client *client,
 {
        struct bd2802_led *led;
        struct bd2802_led_platform_data *pdata;
-       int ret;
+       int ret, i;
 
        led = kzalloc(sizeof(struct bd2802_led), GFP_KERNEL);
        if (!led) {
@@ -670,13 +715,20 @@ static int __devinit bd2802_probe(struct i2c_client *client,
        /* To save the power, reset BD2802 after detecting */
        gpio_set_value(led->pdata->reset_gpio, 0);
 
+       /* Default attributes */
+       led->wave_pattern = BD2802_PATTERN_HALF;
+       led->rgb_current = BD2802_CURRENT_032;
+
        init_rwsem(&led->rwsem);
 
-       ret = device_create_file(&client->dev, &bd2802_adv_conf_attr);
-       if (ret) {
-               dev_err(&client->dev, "failed to create sysfs file %s\n",
-                                       bd2802_adv_conf_attr.attr.name);
-               goto failed_free;
+       for (i = 0; i < ARRAY_SIZE(bd2802_attributes); i++) {
+               ret = device_create_file(&led->client->dev,
+                                               bd2802_attributes[i]);
+               if (ret) {
+                       dev_err(&led->client->dev, "failed: sysfs file %s\n",
+                                       bd2802_attributes[i]->attr.name);
+                       goto failed_unregister_dev_file;
+               }
        }
 
        ret = bd2802_register_led_classdev(led);
@@ -686,7 +738,8 @@ static int __devinit bd2802_probe(struct i2c_client *client,
        return 0;
 
 failed_unregister_dev_file:
-       device_remove_file(&client->dev, &bd2802_adv_conf_attr);
+       for (i--; i >= 0; i--)
+               device_remove_file(&led->client->dev, bd2802_attributes[i]);
 failed_free:
        i2c_set_clientdata(client, NULL);
        kfree(led);
@@ -697,12 +750,14 @@ failed_free:
 static int __exit bd2802_remove(struct i2c_client *client)
 {
        struct bd2802_led *led = i2c_get_clientdata(client);
+       int i;
 
-       bd2802_unregister_led_classdev(led);
        gpio_set_value(led->pdata->reset_gpio, 0);
+       bd2802_unregister_led_classdev(led);
        if (led->adf_on)
                bd2802_disable_adv_conf(led);
-       device_remove_file(&client->dev, &bd2802_adv_conf_attr);
+       for (i = 0; i < ARRAY_SIZE(bd2802_attributes); i++)
+               device_remove_file(&led->client->dev, bd2802_attributes[i]);
        i2c_set_clientdata(client, NULL);
        kfree(led);
 
@@ -723,8 +778,7 @@ static int bd2802_resume(struct i2c_client *client)
        struct bd2802_led *led = i2c_get_clientdata(client);
 
        if (!bd2802_is_all_off(led) || led->adf_on) {
-               gpio_set_value(led->pdata->reset_gpio, 1);
-               udelay(100);
+               bd2802_reset_cancel(led);
                bd2802_restore_state(led);
        }
 
@@ -762,4 +816,4 @@ module_exit(bd2802_exit);
 
 MODULE_AUTHOR("Kim Kyuwon <q1.kim@samsung.com>");
 MODULE_DESCRIPTION("BD2802 LED driver");
-MODULE_LICENSE("GPL");
+MODULE_LICENSE("GPL v2");
index ff0e8c3fbf9b79d61365d456d1d78f314390402e..5f1ce810815f51cb150c7f4c2b203505d10447a5 100644 (file)
@@ -1,7 +1,7 @@
 /*
  *  LEDs driver for the Cobalt Raq series.
  *
- *  Copyright (C) 2007  Yoichi Yuasa <yoichi_yuasa@tripeaks.co.jp>
+ *  Copyright (C) 2007  Yoichi Yuasa <yuasa@linux-mips.org>
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
index d2109054de858b95402ee7d0489704561d6750a2..6b06638eb5b42f40ca9c858a4e5d1626c07a0688 100644 (file)
@@ -76,7 +76,7 @@ static int __devinit create_gpio_led(const struct gpio_led *template,
        struct gpio_led_data *led_dat, struct device *parent,
        int (*blink_set)(unsigned, unsigned long *, unsigned long *))
 {
-       int ret;
+       int ret, state;
 
        /* skip leds that aren't available */
        if (!gpio_is_valid(template->gpio)) {
@@ -99,11 +99,15 @@ static int __devinit create_gpio_led(const struct gpio_led *template,
                led_dat->cdev.blink_set = gpio_blink_set;
        }
        led_dat->cdev.brightness_set = gpio_led_set;
-       led_dat->cdev.brightness = LED_OFF;
+       if (template->default_state == LEDS_GPIO_DEFSTATE_KEEP)
+               state = !!gpio_get_value(led_dat->gpio) ^ led_dat->active_low;
+       else
+               state = (template->default_state == LEDS_GPIO_DEFSTATE_ON);
+       led_dat->cdev.brightness = state ? LED_FULL : LED_OFF;
        if (!template->retain_state_suspended)
                led_dat->cdev.flags |= LED_CORE_SUSPENDRESUME;
 
-       ret = gpio_direction_output(led_dat->gpio, led_dat->active_low);
+       ret = gpio_direction_output(led_dat->gpio, led_dat->active_low ^ state);
        if (ret < 0)
                goto err;
 
@@ -129,7 +133,7 @@ static void delete_gpio_led(struct gpio_led_data *led)
 }
 
 #ifdef CONFIG_LEDS_GPIO_PLATFORM
-static int gpio_led_probe(struct platform_device *pdev)
+static int __devinit gpio_led_probe(struct platform_device *pdev)
 {
        struct gpio_led_platform_data *pdata = pdev->dev.platform_data;
        struct gpio_led_data *leds_data;
@@ -223,12 +227,22 @@ static int __devinit of_gpio_leds_probe(struct of_device *ofdev,
        memset(&led, 0, sizeof(led));
        for_each_child_of_node(np, child) {
                enum of_gpio_flags flags;
+               const char *state;
 
                led.gpio = of_get_gpio_flags(child, 0, &flags);
                led.active_low = flags & OF_GPIO_ACTIVE_LOW;
                led.name = of_get_property(child, "label", NULL) ? : child->name;
                led.default_trigger =
                        of_get_property(child, "linux,default-trigger", NULL);
+               state = of_get_property(child, "default-state", NULL);
+               if (state) {
+                       if (!strcmp(state, "keep"))
+                               led.default_state = LEDS_GPIO_DEFSTATE_KEEP;
+                       else if(!strcmp(state, "on"))
+                               led.default_state = LEDS_GPIO_DEFSTATE_ON;
+                       else
+                               led.default_state = LEDS_GPIO_DEFSTATE_OFF;
+               }
 
                ret = create_gpio_led(&led, &pdata->led_data[pdata->num_leds++],
                                      &ofdev->dev, NULL);
diff --git a/drivers/leds/leds-lp3944.c b/drivers/leds/leds-lp3944.c
new file mode 100644 (file)
index 0000000..5946208
--- /dev/null
@@ -0,0 +1,466 @@
+/*
+ * leds-lp3944.c - driver for National Semiconductor LP3944 Funlight Chip
+ *
+ * Copyright (C) 2009 Antonio Ospite <ospite@studenti.unina.it>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ */
+
+/*
+ * I2C driver for National Semiconductor LP3944 Funlight Chip
+ * http://www.national.com/pf/LP/LP3944.html
+ *
+ * This helper chip can drive up to 8 leds, with two programmable DIM modes;
+ * it could even be used as a gpio expander but this driver assumes it is used
+ * as a led controller.
+ *
+ * The DIM modes are used to set _blink_ patterns for leds, the pattern is
+ * specified supplying two parameters:
+ *   - period: from 0s to 1.6s
+ *   - duty cycle: percentage of the period the led is on, from 0 to 100
+ *
+ * LP3944 can be found on Motorola A910 smartphone, where it drives the rgb
+ * leds, the camera flash light and the displays backlights.
+ */
+
+#include <linux/module.h>
+#include <linux/i2c.h>
+#include <linux/leds.h>
+#include <linux/mutex.h>
+#include <linux/workqueue.h>
+#include <linux/leds-lp3944.h>
+
+/* Read Only Registers */
+#define LP3944_REG_INPUT1     0x00 /* LEDs 0-7 InputRegister (Read Only) */
+#define LP3944_REG_REGISTER1  0x01 /* None (Read Only) */
+
+#define LP3944_REG_PSC0       0x02 /* Frequency Prescaler 0 (R/W) */
+#define LP3944_REG_PWM0       0x03 /* PWM Register 0 (R/W) */
+#define LP3944_REG_PSC1       0x04 /* Frequency Prescaler 1 (R/W) */
+#define LP3944_REG_PWM1       0x05 /* PWM Register 1 (R/W) */
+#define LP3944_REG_LS0        0x06 /* LEDs 0-3 Selector (R/W) */
+#define LP3944_REG_LS1        0x07 /* LEDs 4-7 Selector (R/W) */
+
+/* These registers are not used to control leds in LP3944, they can store
+ * arbitrary values which the chip will ignore.
+ */
+#define LP3944_REG_REGISTER8  0x08
+#define LP3944_REG_REGISTER9  0x09
+
+#define LP3944_DIM0 0
+#define LP3944_DIM1 1
+
+/* period in ms */
+#define LP3944_PERIOD_MIN 0
+#define LP3944_PERIOD_MAX 1600
+
+/* duty cycle is a percentage */
+#define LP3944_DUTY_CYCLE_MIN 0
+#define LP3944_DUTY_CYCLE_MAX 100
+
+#define ldev_to_led(c)       container_of(c, struct lp3944_led_data, ldev)
+
+/* Saved data */
+struct lp3944_led_data {
+       u8 id;
+       enum lp3944_type type;
+       enum lp3944_status status;
+       struct led_classdev ldev;
+       struct i2c_client *client;
+       struct work_struct work;
+};
+
+struct lp3944_data {
+       struct mutex lock;
+       struct i2c_client *client;
+       struct lp3944_led_data leds[LP3944_LEDS_MAX];
+};
+
+static int lp3944_reg_read(struct i2c_client *client, u8 reg, u8 *value)
+{
+       int tmp;
+
+       tmp = i2c_smbus_read_byte_data(client, reg);
+       if (tmp < 0)
+               return -EINVAL;
+
+       *value = tmp;
+
+       return 0;
+}
+
+static int lp3944_reg_write(struct i2c_client *client, u8 reg, u8 value)
+{
+       return i2c_smbus_write_byte_data(client, reg, value);
+}
+
+/**
+ * Set the period for DIM status
+ *
+ * @client: the i2c client
+ * @dim: either LP3944_DIM0 or LP3944_DIM1
+ * @period: period of a blink, that is a on/off cycle, expressed in ms.
+ */
+static int lp3944_dim_set_period(struct i2c_client *client, u8 dim, u16 period)
+{
+       u8 psc_reg;
+       u8 psc_value;
+       int err;
+
+       if (dim == LP3944_DIM0)
+               psc_reg = LP3944_REG_PSC0;
+       else if (dim == LP3944_DIM1)
+               psc_reg = LP3944_REG_PSC1;
+       else
+               return -EINVAL;
+
+       /* Convert period to Prescaler value */
+       if (period > LP3944_PERIOD_MAX)
+               return -EINVAL;
+
+       psc_value = (period * 255) / LP3944_PERIOD_MAX;
+
+       err = lp3944_reg_write(client, psc_reg, psc_value);
+
+       return err;
+}
+
+/**
+ * Set the duty cycle for DIM status
+ *
+ * @client: the i2c client
+ * @dim: either LP3944_DIM0 or LP3944_DIM1
+ * @duty_cycle: percentage of a period during which a led is ON
+ */
+static int lp3944_dim_set_dutycycle(struct i2c_client *client, u8 dim,
+                                   u8 duty_cycle)
+{
+       u8 pwm_reg;
+       u8 pwm_value;
+       int err;
+
+       if (dim == LP3944_DIM0)
+               pwm_reg = LP3944_REG_PWM0;
+       else if (dim == LP3944_DIM1)
+               pwm_reg = LP3944_REG_PWM1;
+       else
+               return -EINVAL;
+
+       /* Convert duty cycle to PWM value */
+       if (duty_cycle > LP3944_DUTY_CYCLE_MAX)
+               return -EINVAL;
+
+       pwm_value = (duty_cycle * 255) / LP3944_DUTY_CYCLE_MAX;
+
+       err = lp3944_reg_write(client, pwm_reg, pwm_value);
+
+       return err;
+}
+
+/**
+ * Set the led status
+ *
+ * @led: a lp3944_led_data structure
+ * @status: one of LP3944_LED_STATUS_OFF
+ *                 LP3944_LED_STATUS_ON
+ *                 LP3944_LED_STATUS_DIM0
+ *                 LP3944_LED_STATUS_DIM1
+ */
+static int lp3944_led_set(struct lp3944_led_data *led, u8 status)
+{
+       struct lp3944_data *data = i2c_get_clientdata(led->client);
+       u8 id = led->id;
+       u8 reg;
+       u8 val = 0;
+       int err;
+
+       dev_dbg(&led->client->dev, "%s: %s, status before normalization:%d\n",
+               __func__, led->ldev.name, status);
+
+       switch (id) {
+       case LP3944_LED0:
+       case LP3944_LED1:
+       case LP3944_LED2:
+       case LP3944_LED3:
+               reg = LP3944_REG_LS0;
+               break;
+       case LP3944_LED4:
+       case LP3944_LED5:
+       case LP3944_LED6:
+       case LP3944_LED7:
+               id -= LP3944_LED4;
+               reg = LP3944_REG_LS1;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       if (status > LP3944_LED_STATUS_DIM1)
+               return -EINVAL;
+
+       /* invert only 0 and 1, leave unchanged the other values,
+        * remember we are abusing status to set blink patterns
+        */
+       if (led->type == LP3944_LED_TYPE_LED_INVERTED && status < 2)
+               status = 1 - status;
+
+       mutex_lock(&data->lock);
+       lp3944_reg_read(led->client, reg, &val);
+
+       val &= ~(LP3944_LED_STATUS_MASK << (id << 1));
+       val |= (status << (id << 1));
+
+       dev_dbg(&led->client->dev, "%s: %s, reg:%d id:%d status:%d val:%#x\n",
+               __func__, led->ldev.name, reg, id, status, val);
+
+       /* set led status */
+       err = lp3944_reg_write(led->client, reg, val);
+       mutex_unlock(&data->lock);
+
+       return err;
+}
+
+static int lp3944_led_set_blink(struct led_classdev *led_cdev,
+                               unsigned long *delay_on,
+                               unsigned long *delay_off)
+{
+       struct lp3944_led_data *led = ldev_to_led(led_cdev);
+       u16 period;
+       u8 duty_cycle;
+       int err;
+
+       /* units are in ms */
+       if (*delay_on + *delay_off > LP3944_PERIOD_MAX)
+               return -EINVAL;
+
+       if (*delay_on == 0 && *delay_off == 0) {
+               /* Special case: the leds subsystem requires a default user
+                * friendly blink pattern for the LED.  Let's blink the led
+                * slowly (1Hz).
+                */
+               *delay_on = 500;
+               *delay_off = 500;
+       }
+
+       period = (*delay_on) + (*delay_off);
+
+       /* duty_cycle is the percentage of period during which the led is ON */
+       duty_cycle = 100 * (*delay_on) / period;
+
+       /* invert duty cycle for inverted leds, this has the same effect of
+        * swapping delay_on and delay_off
+        */
+       if (led->type == LP3944_LED_TYPE_LED_INVERTED)
+               duty_cycle = 100 - duty_cycle;
+
+       /* NOTE: using always the first DIM mode, this means that all leds
+        * will have the same blinking pattern.
+        *
+        * We could find a way later to have two leds blinking in hardware
+        * with different patterns at the same time, falling back to software
+        * control for the other ones.
+        */
+       err = lp3944_dim_set_period(led->client, LP3944_DIM0, period);
+       if (err)
+               return err;
+
+       err = lp3944_dim_set_dutycycle(led->client, LP3944_DIM0, duty_cycle);
+       if (err)
+               return err;
+
+       dev_dbg(&led->client->dev, "%s: OK hardware accelerated blink!\n",
+               __func__);
+
+       led->status = LP3944_LED_STATUS_DIM0;
+       schedule_work(&led->work);
+
+       return 0;
+}
+
+static void lp3944_led_set_brightness(struct led_classdev *led_cdev,
+                                     enum led_brightness brightness)
+{
+       struct lp3944_led_data *led = ldev_to_led(led_cdev);
+
+       dev_dbg(&led->client->dev, "%s: %s, %d\n",
+               __func__, led_cdev->name, brightness);
+
+       led->status = brightness;
+       schedule_work(&led->work);
+}
+
+static void lp3944_led_work(struct work_struct *work)
+{
+       struct lp3944_led_data *led;
+
+       led = container_of(work, struct lp3944_led_data, work);
+       lp3944_led_set(led, led->status);
+}
+
+static int lp3944_configure(struct i2c_client *client,
+                           struct lp3944_data *data,
+                           struct lp3944_platform_data *pdata)
+{
+       int i, err = 0;
+
+       for (i = 0; i < pdata->leds_size; i++) {
+               struct lp3944_led *pled = &pdata->leds[i];
+               struct lp3944_led_data *led = &data->leds[i];
+               led->client = client;
+               led->id = i;
+
+               switch (pled->type) {
+
+               case LP3944_LED_TYPE_LED:
+               case LP3944_LED_TYPE_LED_INVERTED:
+                       led->type = pled->type;
+                       led->status = pled->status;
+                       led->ldev.name = pled->name;
+                       led->ldev.max_brightness = 1;
+                       led->ldev.brightness_set = lp3944_led_set_brightness;
+                       led->ldev.blink_set = lp3944_led_set_blink;
+                       led->ldev.flags = LED_CORE_SUSPENDRESUME;
+
+                       INIT_WORK(&led->work, lp3944_led_work);
+                       err = led_classdev_register(&client->dev, &led->ldev);
+                       if (err < 0) {
+                               dev_err(&client->dev,
+                                       "couldn't register LED %s\n",
+                                       led->ldev.name);
+                               goto exit;
+                       }
+
+                       /* to expose the default value to userspace */
+                       led->ldev.brightness = led->status;
+
+                       /* Set the default led status */
+                       err = lp3944_led_set(led, led->status);
+                       if (err < 0) {
+                               dev_err(&client->dev,
+                                       "%s couldn't set STATUS %d\n",
+                                       led->ldev.name, led->status);
+                               goto exit;
+                       }
+                       break;
+
+               case LP3944_LED_TYPE_NONE:
+               default:
+                       break;
+
+               }
+       }
+       return 0;
+
+exit:
+       if (i > 0)
+               for (i = i - 1; i >= 0; i--)
+                       switch (pdata->leds[i].type) {
+
+                       case LP3944_LED_TYPE_LED:
+                       case LP3944_LED_TYPE_LED_INVERTED:
+                               led_classdev_unregister(&data->leds[i].ldev);
+                               cancel_work_sync(&data->leds[i].work);
+                               break;
+
+                       case LP3944_LED_TYPE_NONE:
+                       default:
+                               break;
+                       }
+
+       return err;
+}
+
+static int __devinit lp3944_probe(struct i2c_client *client,
+                                 const struct i2c_device_id *id)
+{
+       struct lp3944_platform_data *lp3944_pdata = client->dev.platform_data;
+       struct lp3944_data *data;
+
+       if (lp3944_pdata == NULL) {
+               dev_err(&client->dev, "no platform data\n");
+               return -EINVAL;
+       }
+
+       /* Let's see whether this adapter can support what we need. */
+       if (!i2c_check_functionality(client->adapter,
+                               I2C_FUNC_SMBUS_BYTE_DATA)) {
+               dev_err(&client->dev, "insufficient functionality!\n");
+               return -ENODEV;
+       }
+
+       data = kzalloc(sizeof(struct lp3944_data), GFP_KERNEL);
+       if (!data)
+               return -ENOMEM;
+
+       data->client = client;
+       i2c_set_clientdata(client, data);
+
+       mutex_init(&data->lock);
+
+       dev_info(&client->dev, "lp3944 enabled\n");
+
+       lp3944_configure(client, data, lp3944_pdata);
+       return 0;
+}
+
+static int __devexit lp3944_remove(struct i2c_client *client)
+{
+       struct lp3944_platform_data *pdata = client->dev.platform_data;
+       struct lp3944_data *data = i2c_get_clientdata(client);
+       int i;
+
+       for (i = 0; i < pdata->leds_size; i++)
+               switch (data->leds[i].type) {
+               case LP3944_LED_TYPE_LED:
+               case LP3944_LED_TYPE_LED_INVERTED:
+                       led_classdev_unregister(&data->leds[i].ldev);
+                       cancel_work_sync(&data->leds[i].work);
+                       break;
+
+               case LP3944_LED_TYPE_NONE:
+               default:
+                       break;
+               }
+
+       kfree(data);
+       i2c_set_clientdata(client, NULL);
+
+       return 0;
+}
+
+/* lp3944 i2c driver struct */
+static const struct i2c_device_id lp3944_id[] = {
+       {"lp3944", 0},
+       {}
+};
+
+MODULE_DEVICE_TABLE(i2c, lp3944_id);
+
+static struct i2c_driver lp3944_driver = {
+       .driver   = {
+                  .name = "lp3944",
+       },
+       .probe    = lp3944_probe,
+       .remove   = __devexit_p(lp3944_remove),
+       .id_table = lp3944_id,
+};
+
+static int __init lp3944_module_init(void)
+{
+       return i2c_add_driver(&lp3944_driver);
+}
+
+static void __exit lp3944_module_exit(void)
+{
+       i2c_del_driver(&lp3944_driver);
+}
+
+module_init(lp3944_module_init);
+module_exit(lp3944_module_exit);
+
+MODULE_AUTHOR("Antonio Ospite <ospite@studenti.unina.it>");
+MODULE_DESCRIPTION("LP3944 Fun Light Chip");
+MODULE_LICENSE("GPL");
index 3937244fdcab8bf31562337430996a6cd7a943c2..dba8921240f262f5fbc70a7dcc0dddfc1bd73161 100644 (file)
@@ -35,7 +35,7 @@ struct pca9532_data {
        struct pca9532_led leds[16];
        struct mutex update_lock;
        struct input_dev    *idev;
-       struct work_struct work;
+       struct work_struct work;
        u8 pwm[2];
        u8 psc[2];
 };
@@ -87,14 +87,14 @@ static int pca9532_calcpwm(struct i2c_client *client, int pwm, int blink,
        if (b > 0xFF)
                return -EINVAL;
        data->pwm[pwm] = b;
-       data->psc[pwm] = blink;
-       return 0;
+       data->psc[pwm] = blink;
+       return 0;
 }
 
 static int pca9532_setpwm(struct i2c_client *client, int pwm)
 {
-       struct pca9532_data *data = i2c_get_clientdata(client);
-       mutex_lock(&data->update_lock);
+       struct pca9532_data *data = i2c_get_clientdata(client);
+       mutex_lock(&data->update_lock);
        i2c_smbus_write_byte_data(client, PCA9532_REG_PWM(pwm),
                data->pwm[pwm]);
        i2c_smbus_write_byte_data(client, PCA9532_REG_PSC(pwm),
@@ -132,11 +132,11 @@ static void pca9532_set_brightness(struct led_classdev *led_cdev,
                led->state = PCA9532_ON;
        else {
                led->state = PCA9532_PWM0; /* Thecus: hardcode one pwm */
-               err = pca9532_calcpwm(led->client, 0, 0, value);
+               err = pca9532_calcpwm(led->client, 0, 0, value);
                if (err)
                        return; /* XXX: led api doesn't allow error code? */
        }
-       schedule_work(&led->work);
+       schedule_work(&led->work);
 }
 
 static int pca9532_set_blink(struct led_classdev *led_cdev,
@@ -145,7 +145,7 @@ static int pca9532_set_blink(struct led_classdev *led_cdev,
        struct pca9532_led *led = ldev_to_led(led_cdev);
        struct i2c_client *client = led->client;
        int psc;
-       int err = 0;
+       int err = 0;
 
        if (*delay_on == 0 && *delay_off == 0) {
        /* led subsystem ask us for a blink rate */
@@ -157,11 +157,11 @@ static int pca9532_set_blink(struct led_classdev *led_cdev,
 
        /* Thecus specific: only use PSC/PWM 0 */
        psc = (*delay_on * 152-1)/1000;
-       err = pca9532_calcpwm(client, 0, psc, led_cdev->brightness);
-       if (err)
-               return err;
-       schedule_work(&led->work);
-       return 0;
+       err = pca9532_calcpwm(client, 0, psc, led_cdev->brightness);
+       if (err)
+               return err;
+       schedule_work(&led->work);
+       return 0;
 }
 
 static int pca9532_event(struct input_dev *dev, unsigned int type,
@@ -178,15 +178,15 @@ static int pca9532_event(struct input_dev *dev, unsigned int type,
        else
                data->pwm[1] = 0;
 
-       schedule_work(&data->work);
+       schedule_work(&data->work);
 
-       return 0;
+       return 0;
 }
 
 static void pca9532_input_work(struct work_struct *work)
 {
-       struct pca9532_data *data;
-       data = container_of(work, struct pca9532_data, work);
+       struct pca9532_data *data;
+       data = container_of(work, struct pca9532_data, work);
        mutex_lock(&data->update_lock);
        i2c_smbus_write_byte_data(data->client, PCA9532_REG_PWM(1),
                data->pwm[1]);
@@ -195,11 +195,11 @@ static void pca9532_input_work(struct work_struct *work)
 
 static void pca9532_led_work(struct work_struct *work)
 {
-       struct pca9532_led *led;
-       led = container_of(work, struct pca9532_led, work);
-       if (led->state == PCA9532_PWM0)
-               pca9532_setpwm(led->client, 0);
-       pca9532_setled(led);
+       struct pca9532_led *led;
+       led = container_of(work, struct pca9532_led, work);
+       if (led->state == PCA9532_PWM0)
+               pca9532_setpwm(led->client, 0);
+       pca9532_setled(led);
 }
 
 static int pca9532_configure(struct i2c_client *client,
@@ -232,7 +232,7 @@ static int pca9532_configure(struct i2c_client *client,
                        led->ldev.brightness = LED_OFF;
                        led->ldev.brightness_set = pca9532_set_brightness;
                        led->ldev.blink_set = pca9532_set_blink;
-                       INIT_WORK(&led->work, pca9532_led_work);
+                       INIT_WORK(&led->work, pca9532_led_work);
                        err = led_classdev_register(&client->dev, &led->ldev);
                        if (err < 0) {
                                dev_err(&client->dev,
@@ -262,11 +262,11 @@ static int pca9532_configure(struct i2c_client *client,
                                                BIT_MASK(SND_TONE);
                        data->idev->event = pca9532_event;
                        input_set_drvdata(data->idev, data);
-                       INIT_WORK(&data->work, pca9532_input_work);
+                       INIT_WORK(&data->work, pca9532_input_work);
                        err = input_register_device(data->idev);
                        if (err) {
                                input_free_device(data->idev);
-                               cancel_work_sync(&data->work);
+                               cancel_work_sync(&data->work);
                                data->idev = NULL;
                                goto exit;
                        }
@@ -283,13 +283,13 @@ exit:
                                break;
                        case PCA9532_TYPE_LED:
                                led_classdev_unregister(&data->leds[i].ldev);
-                               cancel_work_sync(&data->leds[i].work);
+                               cancel_work_sync(&data->leds[i].work);
                                break;
                        case PCA9532_TYPE_N2100_BEEP:
                                if (data->idev != NULL) {
                                        input_unregister_device(data->idev);
                                        input_free_device(data->idev);
-                                       cancel_work_sync(&data->work);
+                                       cancel_work_sync(&data->work);
                                        data->idev = NULL;
                                }
                                break;
@@ -340,13 +340,13 @@ static int pca9532_remove(struct i2c_client *client)
                        break;
                case PCA9532_TYPE_LED:
                        led_classdev_unregister(&data->leds[i].ldev);
-                       cancel_work_sync(&data->leds[i].work);
+                       cancel_work_sync(&data->leds[i].work);
                        break;
                case PCA9532_TYPE_N2100_BEEP:
                        if (data->idev != NULL) {
                                input_unregister_device(data->idev);
                                input_free_device(data->idev);
-                               cancel_work_sync(&data->work);
+                               cancel_work_sync(&data->work);
                                data->idev = NULL;
                        }
                        break;
index d4e8979735cb002f9f97cf929a1b45a900f2ddc6..01c591923793f4d494fffef7d86a17f0da43f479 100644 (file)
@@ -38,8 +38,6 @@ struct lguest_pages
 #define CHANGED_GDT_TLS                4 /* Actually a subset of CHANGED_GDT */
 #define CHANGED_ALL            3
 
-struct lguest;
-
 struct lg_cpu {
        unsigned int id;
        struct lguest *lg;
@@ -82,7 +80,7 @@ struct lg_cpu {
 
 struct lg_eventfd {
        unsigned long addr;
-       struct file *event;
+       struct eventfd_ctx *event;
 };
 
 struct lg_eventfd_map {
index 32e297121058a3d7dc52fbd6d347eab496c08252..9f9a2953b3830dd42b9f1eb1f06649ed9870e5e3 100644 (file)
@@ -50,7 +50,7 @@ static int add_eventfd(struct lguest *lg, unsigned long addr, int fd)
 
        /* Now append new entry. */
        new->map[new->num].addr = addr;
-       new->map[new->num].event = eventfd_fget(fd);
+       new->map[new->num].event = eventfd_ctx_fdget(fd);
        if (IS_ERR(new->map[new->num].event)) {
                kfree(new);
                return PTR_ERR(new->map[new->num].event);
@@ -357,7 +357,7 @@ static int close(struct inode *inode, struct file *file)
 
        /* Release any eventfds they registered. */
        for (i = 0; i < lg->eventfds->num; i++)
-               fput(lg->eventfds->map[i].event);
+               eventfd_ctx_put(lg->eventfds->map[i].event);
        kfree(lg->eventfds);
 
        /* If lg->dead doesn't contain an error code it will be NULL or a
index 6e149f4a1fff6d1b21decd90fe5109cdc06fa2db..a0f68386c12f3b5aa026f8cae8b470f23be41faa 100644 (file)
@@ -378,6 +378,17 @@ static struct macio_dev * macio_add_one_device(struct macio_chip *chip,
        dev->ofdev.dev.bus = &macio_bus_type;
        dev->ofdev.dev.release = macio_release_dev;
 
+#ifdef CONFIG_PCI
+       /* Set the DMA ops to the ones from the PCI device, this could be
+        * fishy if we didn't know that on PowerMac it's always direct ops
+        * or iommu ops that will work fine
+        */
+       dev->ofdev.dev.archdata.dma_ops =
+               chip->lbus.pdev->dev.archdata.dma_ops;
+       dev->ofdev.dev.archdata.dma_data =
+               chip->lbus.pdev->dev.archdata.dma_data;
+#endif /* CONFIG_PCI */
+
 #ifdef DEBUG
        printk("preparing mdev @%p, ofdev @%p, dev @%p, kobj @%p\n",
               dev, &dev->ofdev, &dev->ofdev.dev, &dev->ofdev.dev.kobj);
index 36e0675be9f72fe5793687c85c3ed0d7db67efae..020f9573fd82011babb4ad666a2966a44d088aba 100644 (file)
@@ -231,6 +231,17 @@ config DM_MIRROR
          Allow volume managers to mirror logical volumes, also
          needed for live data migration tools such as 'pvmove'.
 
+config DM_LOG_USERSPACE
+       tristate "Mirror userspace logging (EXPERIMENTAL)"
+       depends on DM_MIRROR && EXPERIMENTAL && NET
+       select CONNECTOR
+       ---help---
+         The userspace logging module provides a mechanism for
+         relaying the dm-dirty-log API to userspace.  Log designs
+         which are more suited to userspace implementation (e.g.
+         shared storage logs) or experimental logs can be implemented
+         by leveraging this framework.
+
 config DM_ZERO
        tristate "Zero target"
        depends on BLK_DEV_DM
@@ -249,6 +260,25 @@ config DM_MULTIPATH
        ---help---
          Allow volume managers to support multipath hardware.
 
+config DM_MULTIPATH_QL
+       tristate "I/O Path Selector based on the number of in-flight I/Os"
+       depends on DM_MULTIPATH
+       ---help---
+         This path selector is a dynamic load balancer which selects
+         the path with the least number of in-flight I/Os.
+
+         If unsure, say N.
+
+config DM_MULTIPATH_ST
+       tristate "I/O Path Selector based on the service time"
+       depends on DM_MULTIPATH
+       ---help---
+         This path selector is a dynamic load balancer which selects
+         the path expected to complete the incoming I/O in the shortest
+         time.
+
+         If unsure, say N.
+
 config DM_DELAY
        tristate "I/O delaying target (EXPERIMENTAL)"
        depends on BLK_DEV_DM && EXPERIMENTAL
index 45cc5951d9287030df73363a20659482aa55414d..1dc4185bd781f3137b86e3f29e53c2dd3de5e745 100644 (file)
@@ -8,6 +8,8 @@ dm-multipath-y  += dm-path-selector.o dm-mpath.o
 dm-snapshot-y  += dm-snap.o dm-exception-store.o dm-snap-transient.o \
                    dm-snap-persistent.o
 dm-mirror-y    += dm-raid1.o
+dm-log-userspace-y \
+               += dm-log-userspace-base.o dm-log-userspace-transfer.o
 md-mod-y       += md.o bitmap.o
 raid456-y      += raid5.o
 raid6_pq-y     += raid6algos.o raid6recov.o raid6tables.o \
@@ -36,8 +38,11 @@ obj-$(CONFIG_BLK_DEV_DM)     += dm-mod.o
 obj-$(CONFIG_DM_CRYPT)         += dm-crypt.o
 obj-$(CONFIG_DM_DELAY)         += dm-delay.o
 obj-$(CONFIG_DM_MULTIPATH)     += dm-multipath.o dm-round-robin.o
+obj-$(CONFIG_DM_MULTIPATH_QL)  += dm-queue-length.o
+obj-$(CONFIG_DM_MULTIPATH_ST)  += dm-service-time.o
 obj-$(CONFIG_DM_SNAPSHOT)      += dm-snapshot.o
 obj-$(CONFIG_DM_MIRROR)                += dm-mirror.o dm-log.o dm-region-hash.o
+obj-$(CONFIG_DM_LOG_USERSPACE) += dm-log-userspace.o
 obj-$(CONFIG_DM_ZERO)          += dm-zero.o
 
 quiet_cmd_unroll = UNROLL  $@
index 53394e863c749db9444ab4ae4780b06a61afb8f1..529e2ba505c30055440be381d908c52b3113f44d 100644 (file)
@@ -776,7 +776,7 @@ static void kcryptd_crypt_write_convert(struct dm_crypt_io *io)
                 * But don't wait if split was due to the io size restriction
                 */
                if (unlikely(out_of_pages))
-                       congestion_wait(WRITE, HZ/100);
+                       congestion_wait(BLK_RW_ASYNC, HZ/100);
 
                /*
                 * With async crypto it is unsafe to share the crypto context
@@ -1132,6 +1132,7 @@ static int crypt_ctr(struct dm_target *ti, unsigned int argc, char **argv)
                goto bad_crypt_queue;
        }
 
+       ti->num_flush_requests = 1;
        ti->private = cc;
        return 0;
 
@@ -1189,6 +1190,13 @@ static int crypt_map(struct dm_target *ti, struct bio *bio,
                     union map_info *map_context)
 {
        struct dm_crypt_io *io;
+       struct crypt_config *cc;
+
+       if (unlikely(bio_empty_barrier(bio))) {
+               cc = ti->private;
+               bio->bi_bdev = cc->dev->bdev;
+               return DM_MAPIO_REMAPPED;
+       }
 
        io = crypt_io_alloc(ti, bio, bio->bi_sector - ti->begin);
 
@@ -1305,9 +1313,17 @@ static int crypt_merge(struct dm_target *ti, struct bvec_merge_data *bvm,
        return min(max_size, q->merge_bvec_fn(q, bvm, biovec));
 }
 
+static int crypt_iterate_devices(struct dm_target *ti,
+                                iterate_devices_callout_fn fn, void *data)
+{
+       struct crypt_config *cc = ti->private;
+
+       return fn(ti, cc->dev, cc->start, data);
+}
+
 static struct target_type crypt_target = {
        .name   = "crypt",
-       .version= {1, 6, 0},
+       .version = {1, 7, 0},
        .module = THIS_MODULE,
        .ctr    = crypt_ctr,
        .dtr    = crypt_dtr,
@@ -1318,6 +1334,7 @@ static struct target_type crypt_target = {
        .resume = crypt_resume,
        .message = crypt_message,
        .merge  = crypt_merge,
+       .iterate_devices = crypt_iterate_devices,
 };
 
 static int __init dm_crypt_init(void)
index 559dbb52bc851039702692e201a00a700e402187..4e5b843cd4d77fb388920991eefd5540e2399aef 100644 (file)
@@ -197,6 +197,7 @@ out:
        mutex_init(&dc->timer_lock);
        atomic_set(&dc->may_delay, 1);
 
+       ti->num_flush_requests = 1;
        ti->private = dc;
        return 0;
 
@@ -278,8 +279,9 @@ static int delay_map(struct dm_target *ti, struct bio *bio,
 
        if ((bio_data_dir(bio) == WRITE) && (dc->dev_write)) {
                bio->bi_bdev = dc->dev_write->bdev;
-               bio->bi_sector = dc->start_write +
-                                (bio->bi_sector - ti->begin);
+               if (bio_sectors(bio))
+                       bio->bi_sector = dc->start_write +
+                                        (bio->bi_sector - ti->begin);
 
                return delay_bio(dc, dc->write_delay, bio);
        }
@@ -316,9 +318,26 @@ static int delay_status(struct dm_target *ti, status_type_t type,
        return 0;
 }
 
+static int delay_iterate_devices(struct dm_target *ti,
+                                iterate_devices_callout_fn fn, void *data)
+{
+       struct delay_c *dc = ti->private;
+       int ret = 0;
+
+       ret = fn(ti, dc->dev_read, dc->start_read, data);
+       if (ret)
+               goto out;
+
+       if (dc->dev_write)
+               ret = fn(ti, dc->dev_write, dc->start_write, data);
+
+out:
+       return ret;
+}
+
 static struct target_type delay_target = {
        .name        = "delay",
-       .version     = {1, 0, 2},
+       .version     = {1, 1, 0},
        .module      = THIS_MODULE,
        .ctr         = delay_ctr,
        .dtr         = delay_dtr,
@@ -326,6 +345,7 @@ static struct target_type delay_target = {
        .presuspend  = delay_presuspend,
        .resume      = delay_resume,
        .status      = delay_status,
+       .iterate_devices = delay_iterate_devices,
 };
 
 static int __init dm_delay_init(void)
index 75d8081a904175bcff7d3199c2deba4140fc6086..3710ff88fc1018a093fafcdd54777a6b9f630b14 100644 (file)
@@ -195,7 +195,7 @@ int dm_exception_store_create(struct dm_target *ti, int argc, char **argv,
                              struct dm_exception_store **store)
 {
        int r = 0;
-       struct dm_exception_store_type *type;
+       struct dm_exception_store_type *type = NULL;
        struct dm_exception_store *tmp_store;
        char persistent;
 
@@ -211,12 +211,15 @@ int dm_exception_store_create(struct dm_target *ti, int argc, char **argv,
        }
 
        persistent = toupper(*argv[1]);
-       if (persistent != 'P' && persistent != 'N') {
+       if (persistent == 'P')
+               type = get_type("P");
+       else if (persistent == 'N')
+               type = get_type("N");
+       else {
                ti->error = "Persistent flag is not P or N";
                return -EINVAL;
        }
 
-       type = get_type(argv[1]);
        if (!type) {
                ti->error = "Exception store type not recognised";
                r = -EINVAL;
index c92701dc50016ff2f1eb87f40a76b8a8dce1b208..2442c8c0789808607089722a2157ca94f4176c92 100644 (file)
@@ -156,7 +156,7 @@ static inline void dm_consecutive_chunk_count_inc(struct dm_snap_exception *e)
  */
 static inline sector_t get_dev_size(struct block_device *bdev)
 {
-       return bdev->bd_inode->i_size >> SECTOR_SHIFT;
+       return i_size_read(bdev->bd_inode) >> SECTOR_SHIFT;
 }
 
 static inline chunk_t sector_to_chunk(struct dm_exception_store *store,
index e73aabd61cd78abdbc63996704c177e6aea399d1..3a2e6a2f8bdd336f863807108c9ca3ebbfbba917 100644 (file)
@@ -22,6 +22,7 @@ struct dm_io_client {
 /* FIXME: can we shrink this ? */
 struct io {
        unsigned long error_bits;
+       unsigned long eopnotsupp_bits;
        atomic_t count;
        struct task_struct *sleeper;
        struct dm_io_client *client;
@@ -107,8 +108,11 @@ static inline unsigned bio_get_region(struct bio *bio)
  *---------------------------------------------------------------*/
 static void dec_count(struct io *io, unsigned int region, int error)
 {
-       if (error)
+       if (error) {
                set_bit(region, &io->error_bits);
+               if (error == -EOPNOTSUPP)
+                       set_bit(region, &io->eopnotsupp_bits);
+       }
 
        if (atomic_dec_and_test(&io->count)) {
                if (io->sleeper)
@@ -360,7 +364,9 @@ static int sync_io(struct dm_io_client *client, unsigned int num_regions,
                return -EIO;
        }
 
+retry:
        io.error_bits = 0;
+       io.eopnotsupp_bits = 0;
        atomic_set(&io.count, 1); /* see dispatch_io() */
        io.sleeper = current;
        io.client = client;
@@ -377,6 +383,11 @@ static int sync_io(struct dm_io_client *client, unsigned int num_regions,
        }
        set_current_state(TASK_RUNNING);
 
+       if (io.eopnotsupp_bits && (rw & (1 << BIO_RW_BARRIER))) {
+               rw &= ~(1 << BIO_RW_BARRIER);
+               goto retry;
+       }
+
        if (error_bits)
                *error_bits = io.error_bits;
 
@@ -397,6 +408,7 @@ static int async_io(struct dm_io_client *client, unsigned int num_regions,
 
        io = mempool_alloc(client->pool, GFP_NOIO);
        io->error_bits = 0;
+       io->eopnotsupp_bits = 0;
        atomic_set(&io->count, 1); /* see dispatch_io() */
        io->sleeper = NULL;
        io->client = client;
index 1128d3fba797f38a89f39849eea012bc9daa22d1..7f77f18fcafa662e07139600716865780c1afcdc 100644 (file)
@@ -276,7 +276,7 @@ retry:
        up_write(&_hash_lock);
 }
 
-static int dm_hash_rename(const char *old, const char *new)
+static int dm_hash_rename(uint32_t cookie, const char *old, const char *new)
 {
        char *new_name, *old_name;
        struct hash_cell *hc;
@@ -333,7 +333,7 @@ static int dm_hash_rename(const char *old, const char *new)
                dm_table_put(table);
        }
 
-       dm_kobject_uevent(hc->md);
+       dm_kobject_uevent(hc->md, KOBJ_CHANGE, cookie);
 
        dm_put(hc->md);
        up_write(&_hash_lock);
@@ -680,6 +680,9 @@ static int dev_remove(struct dm_ioctl *param, size_t param_size)
 
        __hash_remove(hc);
        up_write(&_hash_lock);
+
+       dm_kobject_uevent(md, KOBJ_REMOVE, param->event_nr);
+
        dm_put(md);
        param->data_size = 0;
        return 0;
@@ -715,7 +718,7 @@ static int dev_rename(struct dm_ioctl *param, size_t param_size)
                return r;
 
        param->data_size = 0;
-       return dm_hash_rename(param->name, new_name);
+       return dm_hash_rename(param->event_nr, param->name, new_name);
 }
 
 static int dev_set_geometry(struct dm_ioctl *param, size_t param_size)
@@ -842,8 +845,11 @@ static int do_resume(struct dm_ioctl *param)
        if (dm_suspended(md))
                r = dm_resume(md);
 
-       if (!r)
+
+       if (!r) {
+               dm_kobject_uevent(md, KOBJ_CHANGE, param->event_nr);
                r = __dev_status(md, param);
+       }
 
        dm_put(md);
        return r;
@@ -1044,6 +1050,12 @@ static int populate_table(struct dm_table *table,
                next = spec->next;
        }
 
+       r = dm_table_set_type(table);
+       if (r) {
+               DMWARN("unable to set table type");
+               return r;
+       }
+
        return dm_table_complete(table);
 }
 
@@ -1089,6 +1101,13 @@ static int table_load(struct dm_ioctl *param, size_t param_size)
                goto out;
        }
 
+       r = dm_table_alloc_md_mempools(t);
+       if (r) {
+               DMWARN("unable to allocate mempools for this table");
+               dm_table_destroy(t);
+               goto out;
+       }
+
        down_write(&_hash_lock);
        hc = dm_get_mdptr(md);
        if (!hc || hc->md != md) {
index 79fb53e51c709e2875382c517bc61413e50fd978..9184b6deb8685dc3660e21dd438f6aa8fcd200b3 100644 (file)
@@ -53,6 +53,7 @@ static int linear_ctr(struct dm_target *ti, unsigned int argc, char **argv)
                goto bad;
        }
 
+       ti->num_flush_requests = 1;
        ti->private = lc;
        return 0;
 
@@ -81,7 +82,8 @@ static void linear_map_bio(struct dm_target *ti, struct bio *bio)
        struct linear_c *lc = ti->private;
 
        bio->bi_bdev = lc->dev->bdev;
-       bio->bi_sector = linear_map_sector(ti, bio->bi_sector);
+       if (bio_sectors(bio))
+               bio->bi_sector = linear_map_sector(ti, bio->bi_sector);
 }
 
 static int linear_map(struct dm_target *ti, struct bio *bio,
@@ -132,9 +134,17 @@ static int linear_merge(struct dm_target *ti, struct bvec_merge_data *bvm,
        return min(max_size, q->merge_bvec_fn(q, bvm, biovec));
 }
 
+static int linear_iterate_devices(struct dm_target *ti,
+                                 iterate_devices_callout_fn fn, void *data)
+{
+       struct linear_c *lc = ti->private;
+
+       return fn(ti, lc->dev, lc->start, data);
+}
+
 static struct target_type linear_target = {
        .name   = "linear",
-       .version= {1, 0, 3},
+       .version = {1, 1, 0},
        .module = THIS_MODULE,
        .ctr    = linear_ctr,
        .dtr    = linear_dtr,
@@ -142,6 +152,7 @@ static struct target_type linear_target = {
        .status = linear_status,
        .ioctl  = linear_ioctl,
        .merge  = linear_merge,
+       .iterate_devices = linear_iterate_devices,
 };
 
 int __init dm_linear_init(void)
diff --git a/drivers/md/dm-log-userspace-base.c b/drivers/md/dm-log-userspace-base.c
new file mode 100644 (file)
index 0000000..e69b965
--- /dev/null
@@ -0,0 +1,696 @@
+/*
+ * Copyright (C) 2006-2009 Red Hat, Inc.
+ *
+ * This file is released under the LGPL.
+ */
+
+#include <linux/bio.h>
+#include <linux/dm-dirty-log.h>
+#include <linux/device-mapper.h>
+#include <linux/dm-log-userspace.h>
+
+#include "dm-log-userspace-transfer.h"
+
+struct flush_entry {
+       int type;
+       region_t region;
+       struct list_head list;
+};
+
+struct log_c {
+       struct dm_target *ti;
+       uint32_t region_size;
+       region_t region_count;
+       char uuid[DM_UUID_LEN];
+
+       char *usr_argv_str;
+       uint32_t usr_argc;
+
+       /*
+        * in_sync_hint gets set when doing is_remote_recovering.  It
+        * represents the first region that needs recovery.  IOW, the
+        * first zero bit of sync_bits.  This can be useful for to limit
+        * traffic for calls like is_remote_recovering and get_resync_work,
+        * but be take care in its use for anything else.
+        */
+       uint64_t in_sync_hint;
+
+       spinlock_t flush_lock;
+       struct list_head flush_list;  /* only for clear and mark requests */
+};
+
+static mempool_t *flush_entry_pool;
+
+static void *flush_entry_alloc(gfp_t gfp_mask, void *pool_data)
+{
+       return kmalloc(sizeof(struct flush_entry), gfp_mask);
+}
+
+static void flush_entry_free(void *element, void *pool_data)
+{
+       kfree(element);
+}
+
+static int userspace_do_request(struct log_c *lc, const char *uuid,
+                               int request_type, char *data, size_t data_size,
+                               char *rdata, size_t *rdata_size)
+{
+       int r;
+
+       /*
+        * If the server isn't there, -ESRCH is returned,
+        * and we must keep trying until the server is
+        * restored.
+        */
+retry:
+       r = dm_consult_userspace(uuid, request_type, data,
+                                data_size, rdata, rdata_size);
+
+       if (r != -ESRCH)
+               return r;
+
+       DMERR(" Userspace log server not found.");
+       while (1) {
+               set_current_state(TASK_INTERRUPTIBLE);
+               schedule_timeout(2*HZ);
+               DMWARN("Attempting to contact userspace log server...");
+               r = dm_consult_userspace(uuid, DM_ULOG_CTR, lc->usr_argv_str,
+                                        strlen(lc->usr_argv_str) + 1,
+                                        NULL, NULL);
+               if (!r)
+                       break;
+       }
+       DMINFO("Reconnected to userspace log server... DM_ULOG_CTR complete");
+       r = dm_consult_userspace(uuid, DM_ULOG_RESUME, NULL,
+                                0, NULL, NULL);
+       if (!r)
+               goto retry;
+
+       DMERR("Error trying to resume userspace log: %d", r);
+
+       return -ESRCH;
+}
+
+static int build_constructor_string(struct dm_target *ti,
+                                   unsigned argc, char **argv,
+                                   char **ctr_str)
+{
+       int i, str_size;
+       char *str = NULL;
+
+       *ctr_str = NULL;
+
+       for (i = 0, str_size = 0; i < argc; i++)
+               str_size += strlen(argv[i]) + 1; /* +1 for space between args */
+
+       str_size += 20; /* Max number of chars in a printed u64 number */
+
+       str = kzalloc(str_size, GFP_KERNEL);
+       if (!str) {
+               DMWARN("Unable to allocate memory for constructor string");
+               return -ENOMEM;
+       }
+
+       for (i = 0, str_size = 0; i < argc; i++)
+               str_size += sprintf(str + str_size, "%s ", argv[i]);
+       str_size += sprintf(str + str_size, "%llu",
+                           (unsigned long long)ti->len);
+
+       *ctr_str = str;
+       return str_size;
+}
+
+/*
+ * userspace_ctr
+ *
+ * argv contains:
+ *     <UUID> <other args>
+ * Where 'other args' is the userspace implementation specific log
+ * arguments.  An example might be:
+ *     <UUID> clustered_disk <arg count> <log dev> <region_size> [[no]sync]
+ *
+ * So, this module will strip off the <UUID> for identification purposes
+ * when communicating with userspace about a log; but will pass on everything
+ * else.
+ */
+static int userspace_ctr(struct dm_dirty_log *log, struct dm_target *ti,
+                        unsigned argc, char **argv)
+{
+       int r = 0;
+       int str_size;
+       char *ctr_str = NULL;
+       struct log_c *lc = NULL;
+       uint64_t rdata;
+       size_t rdata_size = sizeof(rdata);
+
+       if (argc < 3) {
+               DMWARN("Too few arguments to userspace dirty log");
+               return -EINVAL;
+       }
+
+       lc = kmalloc(sizeof(*lc), GFP_KERNEL);
+       if (!lc) {
+               DMWARN("Unable to allocate userspace log context.");
+               return -ENOMEM;
+       }
+
+       lc->ti = ti;
+
+       if (strlen(argv[0]) > (DM_UUID_LEN - 1)) {
+               DMWARN("UUID argument too long.");
+               kfree(lc);
+               return -EINVAL;
+       }
+
+       strncpy(lc->uuid, argv[0], DM_UUID_LEN);
+       spin_lock_init(&lc->flush_lock);
+       INIT_LIST_HEAD(&lc->flush_list);
+
+       str_size = build_constructor_string(ti, argc - 1, argv + 1, &ctr_str);
+       if (str_size < 0) {
+               kfree(lc);
+               return str_size;
+       }
+
+       /* Send table string */
+       r = dm_consult_userspace(lc->uuid, DM_ULOG_CTR,
+                                ctr_str, str_size, NULL, NULL);
+
+       if (r == -ESRCH) {
+               DMERR("Userspace log server not found");
+               goto out;
+       }
+
+       /* Since the region size does not change, get it now */
+       rdata_size = sizeof(rdata);
+       r = dm_consult_userspace(lc->uuid, DM_ULOG_GET_REGION_SIZE,
+                                NULL, 0, (char *)&rdata, &rdata_size);
+
+       if (r) {
+               DMERR("Failed to get region size of dirty log");
+               goto out;
+       }
+
+       lc->region_size = (uint32_t)rdata;
+       lc->region_count = dm_sector_div_up(ti->len, lc->region_size);
+
+out:
+       if (r) {
+               kfree(lc);
+               kfree(ctr_str);
+       } else {
+               lc->usr_argv_str = ctr_str;
+               lc->usr_argc = argc;
+               log->context = lc;
+       }
+
+       return r;
+}
+
+static void userspace_dtr(struct dm_dirty_log *log)
+{
+       int r;
+       struct log_c *lc = log->context;
+
+       r = dm_consult_userspace(lc->uuid, DM_ULOG_DTR,
+                                NULL, 0,
+                                NULL, NULL);
+
+       kfree(lc->usr_argv_str);
+       kfree(lc);
+
+       return;
+}
+
+static int userspace_presuspend(struct dm_dirty_log *log)
+{
+       int r;
+       struct log_c *lc = log->context;
+
+       r = dm_consult_userspace(lc->uuid, DM_ULOG_PRESUSPEND,
+                                NULL, 0,
+                                NULL, NULL);
+
+       return r;
+}
+
+static int userspace_postsuspend(struct dm_dirty_log *log)
+{
+       int r;
+       struct log_c *lc = log->context;
+
+       r = dm_consult_userspace(lc->uuid, DM_ULOG_POSTSUSPEND,
+                                NULL, 0,
+                                NULL, NULL);
+
+       return r;
+}
+
+static int userspace_resume(struct dm_dirty_log *log)
+{
+       int r;
+       struct log_c *lc = log->context;
+
+       lc->in_sync_hint = 0;
+       r = dm_consult_userspace(lc->uuid, DM_ULOG_RESUME,
+                                NULL, 0,
+                                NULL, NULL);
+
+       return r;
+}
+
+static uint32_t userspace_get_region_size(struct dm_dirty_log *log)
+{
+       struct log_c *lc = log->context;
+
+       return lc->region_size;
+}
+
+/*
+ * userspace_is_clean
+ *
+ * Check whether a region is clean.  If there is any sort of
+ * failure when consulting the server, we return not clean.
+ *
+ * Returns: 1 if clean, 0 otherwise
+ */
+static int userspace_is_clean(struct dm_dirty_log *log, region_t region)
+{
+       int r;
+       uint64_t region64 = (uint64_t)region;
+       int64_t is_clean;
+       size_t rdata_size;
+       struct log_c *lc = log->context;
+
+       rdata_size = sizeof(is_clean);
+       r = userspace_do_request(lc, lc->uuid, DM_ULOG_IS_CLEAN,
+                                (char *)&region64, sizeof(region64),
+                                (char *)&is_clean, &rdata_size);
+
+       return (r) ? 0 : (int)is_clean;
+}
+
+/*
+ * userspace_in_sync
+ *
+ * Check if the region is in-sync.  If there is any sort
+ * of failure when consulting the server, we assume that
+ * the region is not in sync.
+ *
+ * If 'can_block' is set, return immediately
+ *
+ * Returns: 1 if in-sync, 0 if not-in-sync, -EWOULDBLOCK
+ */
+static int userspace_in_sync(struct dm_dirty_log *log, region_t region,
+                            int can_block)
+{
+       int r;
+       uint64_t region64 = region;
+       int64_t in_sync;
+       size_t rdata_size;
+       struct log_c *lc = log->context;
+
+       /*
+        * We can never respond directly - even if in_sync_hint is
+        * set.  This is because another machine could see a device
+        * failure and mark the region out-of-sync.  If we don't go
+        * to userspace to ask, we might think the region is in-sync
+        * and allow a read to pick up data that is stale.  (This is
+        * very unlikely if a device actually fails; but it is very
+        * likely if a connection to one device from one machine fails.)
+        *
+        * There still might be a problem if the mirror caches the region
+        * state as in-sync... but then this call would not be made.  So,
+        * that is a mirror problem.
+        */
+       if (!can_block)
+               return -EWOULDBLOCK;
+
+       rdata_size = sizeof(in_sync);
+       r = userspace_do_request(lc, lc->uuid, DM_ULOG_IN_SYNC,
+                                (char *)&region64, sizeof(region64),
+                                (char *)&in_sync, &rdata_size);
+       return (r) ? 0 : (int)in_sync;
+}
+
+/*
+ * userspace_flush
+ *
+ * This function is ok to block.
+ * The flush happens in two stages.  First, it sends all
+ * clear/mark requests that are on the list.  Then it
+ * tells the server to commit them.  This gives the
+ * server a chance to optimise the commit, instead of
+ * doing it for every request.
+ *
+ * Additionally, we could implement another thread that
+ * sends the requests up to the server - reducing the
+ * load on flush.  Then the flush would have less in
+ * the list and be responsible for the finishing commit.
+ *
+ * Returns: 0 on success, < 0 on failure
+ */
+static int userspace_flush(struct dm_dirty_log *log)
+{
+       int r = 0;
+       unsigned long flags;
+       struct log_c *lc = log->context;
+       LIST_HEAD(flush_list);
+       struct flush_entry *fe, *tmp_fe;
+
+       spin_lock_irqsave(&lc->flush_lock, flags);
+       list_splice_init(&lc->flush_list, &flush_list);
+       spin_unlock_irqrestore(&lc->flush_lock, flags);
+
+       if (list_empty(&flush_list))
+               return 0;
+
+       /*
+        * FIXME: Count up requests, group request types,
+        * allocate memory to stick all requests in and
+        * send to server in one go.  Failing the allocation,
+        * do it one by one.
+        */
+
+       list_for_each_entry(fe, &flush_list, list) {
+               r = userspace_do_request(lc, lc->uuid, fe->type,
+                                        (char *)&fe->region,
+                                        sizeof(fe->region),
+                                        NULL, NULL);
+               if (r)
+                       goto fail;
+       }
+
+       r = userspace_do_request(lc, lc->uuid, DM_ULOG_FLUSH,
+                                NULL, 0, NULL, NULL);
+
+fail:
+       /*
+        * We can safely remove these entries, even if failure.
+        * Calling code will receive an error and will know that
+        * the log facility has failed.
+        */
+       list_for_each_entry_safe(fe, tmp_fe, &flush_list, list) {
+               list_del(&fe->list);
+               mempool_free(fe, flush_entry_pool);
+       }
+
+       if (r)
+               dm_table_event(lc->ti->table);
+
+       return r;
+}
+
+/*
+ * userspace_mark_region
+ *
+ * This function should avoid blocking unless absolutely required.
+ * (Memory allocation is valid for blocking.)
+ */
+static void userspace_mark_region(struct dm_dirty_log *log, region_t region)
+{
+       unsigned long flags;
+       struct log_c *lc = log->context;
+       struct flush_entry *fe;
+
+       /* Wait for an allocation, but _never_ fail */
+       fe = mempool_alloc(flush_entry_pool, GFP_NOIO);
+       BUG_ON(!fe);
+
+       spin_lock_irqsave(&lc->flush_lock, flags);
+       fe->type = DM_ULOG_MARK_REGION;
+       fe->region = region;
+       list_add(&fe->list, &lc->flush_list);
+       spin_unlock_irqrestore(&lc->flush_lock, flags);
+
+       return;
+}
+
+/*
+ * userspace_clear_region
+ *
+ * This function must not block.
+ * So, the alloc can't block.  In the worst case, it is ok to
+ * fail.  It would simply mean we can't clear the region.
+ * Does nothing to current sync context, but does mean
+ * the region will be re-sync'ed on a reload of the mirror
+ * even though it is in-sync.
+ */
+static void userspace_clear_region(struct dm_dirty_log *log, region_t region)
+{
+       unsigned long flags;
+       struct log_c *lc = log->context;
+       struct flush_entry *fe;
+
+       /*
+        * If we fail to allocate, we skip the clearing of
+        * the region.  This doesn't hurt us in any way, except
+        * to cause the region to be resync'ed when the
+        * device is activated next time.
+        */
+       fe = mempool_alloc(flush_entry_pool, GFP_ATOMIC);
+       if (!fe) {
+               DMERR("Failed to allocate memory to clear region.");
+               return;
+       }
+
+       spin_lock_irqsave(&lc->flush_lock, flags);
+       fe->type = DM_ULOG_CLEAR_REGION;
+       fe->region = region;
+       list_add(&fe->list, &lc->flush_list);
+       spin_unlock_irqrestore(&lc->flush_lock, flags);
+
+       return;
+}
+
+/*
+ * userspace_get_resync_work
+ *
+ * Get a region that needs recovery.  It is valid to return
+ * an error for this function.
+ *
+ * Returns: 1 if region filled, 0 if no work, <0 on error
+ */
+static int userspace_get_resync_work(struct dm_dirty_log *log, region_t *region)
+{
+       int r;
+       size_t rdata_size;
+       struct log_c *lc = log->context;
+       struct {
+               int64_t i; /* 64-bit for mix arch compatibility */
+               region_t r;
+       } pkg;
+
+       if (lc->in_sync_hint >= lc->region_count)
+               return 0;
+
+       rdata_size = sizeof(pkg);
+       r = userspace_do_request(lc, lc->uuid, DM_ULOG_GET_RESYNC_WORK,
+                                NULL, 0,
+                                (char *)&pkg, &rdata_size);
+
+       *region = pkg.r;
+       return (r) ? r : (int)pkg.i;
+}
+
+/*
+ * userspace_set_region_sync
+ *
+ * Set the sync status of a given region.  This function
+ * must not fail.
+ */
+static void userspace_set_region_sync(struct dm_dirty_log *log,
+                                     region_t region, int in_sync)
+{
+       int r;
+       struct log_c *lc = log->context;
+       struct {
+               region_t r;
+               int64_t i;
+       } pkg;
+
+       pkg.r = region;
+       pkg.i = (int64_t)in_sync;
+
+       r = userspace_do_request(lc, lc->uuid, DM_ULOG_SET_REGION_SYNC,
+                                (char *)&pkg, sizeof(pkg),
+                                NULL, NULL);
+
+       /*
+        * It would be nice to be able to report failures.
+        * However, it is easy emough to detect and resolve.
+        */
+       return;
+}
+
+/*
+ * userspace_get_sync_count
+ *
+ * If there is any sort of failure when consulting the server,
+ * we assume that the sync count is zero.
+ *
+ * Returns: sync count on success, 0 on failure
+ */
+static region_t userspace_get_sync_count(struct dm_dirty_log *log)
+{
+       int r;
+       size_t rdata_size;
+       uint64_t sync_count;
+       struct log_c *lc = log->context;
+
+       rdata_size = sizeof(sync_count);
+       r = userspace_do_request(lc, lc->uuid, DM_ULOG_GET_SYNC_COUNT,
+                                NULL, 0,
+                                (char *)&sync_count, &rdata_size);
+
+       if (r)
+               return 0;
+
+       if (sync_count >= lc->region_count)
+               lc->in_sync_hint = lc->region_count;
+
+       return (region_t)sync_count;
+}
+
+/*
+ * userspace_status
+ *
+ * Returns: amount of space consumed
+ */
+static int userspace_status(struct dm_dirty_log *log, status_type_t status_type,
+                           char *result, unsigned maxlen)
+{
+       int r = 0;
+       size_t sz = (size_t)maxlen;
+       struct log_c *lc = log->context;
+
+       switch (status_type) {
+       case STATUSTYPE_INFO:
+               r = userspace_do_request(lc, lc->uuid, DM_ULOG_STATUS_INFO,
+                                        NULL, 0,
+                                        result, &sz);
+
+               if (r) {
+                       sz = 0;
+                       DMEMIT("%s 1 COM_FAILURE", log->type->name);
+               }
+               break;
+       case STATUSTYPE_TABLE:
+               sz = 0;
+               DMEMIT("%s %u %s %s", log->type->name, lc->usr_argc + 1,
+                      lc->uuid, lc->usr_argv_str);
+               break;
+       }
+       return (r) ? 0 : (int)sz;
+}
+
+/*
+ * userspace_is_remote_recovering
+ *
+ * Returns: 1 if region recovering, 0 otherwise
+ */
+static int userspace_is_remote_recovering(struct dm_dirty_log *log,
+                                         region_t region)
+{
+       int r;
+       uint64_t region64 = region;
+       struct log_c *lc = log->context;
+       static unsigned long long limit;
+       struct {
+               int64_t is_recovering;
+               uint64_t in_sync_hint;
+       } pkg;
+       size_t rdata_size = sizeof(pkg);
+
+       /*
+        * Once the mirror has been reported to be in-sync,
+        * it will never again ask for recovery work.  So,
+        * we can safely say there is not a remote machine
+        * recovering if the device is in-sync.  (in_sync_hint
+        * must be reset at resume time.)
+        */
+       if (region < lc->in_sync_hint)
+               return 0;
+       else if (jiffies < limit)
+               return 1;
+
+       limit = jiffies + (HZ / 4);
+       r = userspace_do_request(lc, lc->uuid, DM_ULOG_IS_REMOTE_RECOVERING,
+                                (char *)&region64, sizeof(region64),
+                                (char *)&pkg, &rdata_size);
+       if (r)
+               return 1;
+
+       lc->in_sync_hint = pkg.in_sync_hint;
+
+       return (int)pkg.is_recovering;
+}
+
+static struct dm_dirty_log_type _userspace_type = {
+       .name = "userspace",
+       .module = THIS_MODULE,
+       .ctr = userspace_ctr,
+       .dtr = userspace_dtr,
+       .presuspend = userspace_presuspend,
+       .postsuspend = userspace_postsuspend,
+       .resume = userspace_resume,
+       .get_region_size = userspace_get_region_size,
+       .is_clean = userspace_is_clean,
+       .in_sync = userspace_in_sync,
+       .flush = userspace_flush,
+       .mark_region = userspace_mark_region,
+       .clear_region = userspace_clear_region,
+       .get_resync_work = userspace_get_resync_work,
+       .set_region_sync = userspace_set_region_sync,
+       .get_sync_count = userspace_get_sync_count,
+       .status = userspace_status,
+       .is_remote_recovering = userspace_is_remote_recovering,
+};
+
+static int __init userspace_dirty_log_init(void)
+{
+       int r = 0;
+
+       flush_entry_pool = mempool_create(100, flush_entry_alloc,
+                                         flush_entry_free, NULL);
+
+       if (!flush_entry_pool) {
+               DMWARN("Unable to create flush_entry_pool:  No memory.");
+               return -ENOMEM;
+       }
+
+       r = dm_ulog_tfr_init();
+       if (r) {
+               DMWARN("Unable to initialize userspace log communications");
+               mempool_destroy(flush_entry_pool);
+               return r;
+       }
+
+       r = dm_dirty_log_type_register(&_userspace_type);
+       if (r) {
+               DMWARN("Couldn't register userspace dirty log type");
+               dm_ulog_tfr_exit();
+               mempool_destroy(flush_entry_pool);
+               return r;
+       }
+
+       DMINFO("version 1.0.0 loaded");
+       return 0;
+}
+
+static void __exit userspace_dirty_log_exit(void)
+{
+       dm_dirty_log_type_unregister(&_userspace_type);
+       dm_ulog_tfr_exit();
+       mempool_destroy(flush_entry_pool);
+
+       DMINFO("version 1.0.0 unloaded");
+       return;
+}
+
+module_init(userspace_dirty_log_init);
+module_exit(userspace_dirty_log_exit);
+
+MODULE_DESCRIPTION(DM_NAME " userspace dirty log link");
+MODULE_AUTHOR("Jonathan Brassow <dm-devel@redhat.com>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/md/dm-log-userspace-transfer.c b/drivers/md/dm-log-userspace-transfer.c
new file mode 100644 (file)
index 0000000..0ca1ee7
--- /dev/null
@@ -0,0 +1,276 @@
+/*
+ * Copyright (C) 2006-2009 Red Hat, Inc.
+ *
+ * This file is released under the LGPL.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <net/sock.h>
+#include <linux/workqueue.h>
+#include <linux/connector.h>
+#include <linux/device-mapper.h>
+#include <linux/dm-log-userspace.h>
+
+#include "dm-log-userspace-transfer.h"
+
+static uint32_t dm_ulog_seq;
+
+/*
+ * Netlink/Connector is an unreliable protocol.  How long should
+ * we wait for a response before assuming it was lost and retrying?
+ * (If we do receive a response after this time, it will be discarded
+ * and the response to the resent request will be waited for.
+ */
+#define DM_ULOG_RETRY_TIMEOUT (15 * HZ)
+
+/*
+ * Pre-allocated space for speed
+ */
+#define DM_ULOG_PREALLOCED_SIZE 512
+static struct cn_msg *prealloced_cn_msg;
+static struct dm_ulog_request *prealloced_ulog_tfr;
+
+static struct cb_id ulog_cn_id = {
+       .idx = CN_IDX_DM,
+       .val = CN_VAL_DM_USERSPACE_LOG
+};
+
+static DEFINE_MUTEX(dm_ulog_lock);
+
+struct receiving_pkg {
+       struct list_head list;
+       struct completion complete;
+
+       uint32_t seq;
+
+       int error;
+       size_t *data_size;
+       char *data;
+};
+
+static DEFINE_SPINLOCK(receiving_list_lock);
+static struct list_head receiving_list;
+
+static int dm_ulog_sendto_server(struct dm_ulog_request *tfr)
+{
+       int r;
+       struct cn_msg *msg = prealloced_cn_msg;
+
+       memset(msg, 0, sizeof(struct cn_msg));
+
+       msg->id.idx = ulog_cn_id.idx;
+       msg->id.val = ulog_cn_id.val;
+       msg->ack = 0;
+       msg->seq = tfr->seq;
+       msg->len = sizeof(struct dm_ulog_request) + tfr->data_size;
+
+       r = cn_netlink_send(msg, 0, gfp_any());
+
+       return r;
+}
+
+/*
+ * Parameters for this function can be either msg or tfr, but not
+ * both.  This function fills in the reply for a waiting request.
+ * If just msg is given, then the reply is simply an ACK from userspace
+ * that the request was received.
+ *
+ * Returns: 0 on success, -ENOENT on failure
+ */
+static int fill_pkg(struct cn_msg *msg, struct dm_ulog_request *tfr)
+{
+       uint32_t rtn_seq = (msg) ? msg->seq : (tfr) ? tfr->seq : 0;
+       struct receiving_pkg *pkg;
+
+       /*
+        * The 'receiving_pkg' entries in this list are statically
+        * allocated on the stack in 'dm_consult_userspace'.
+        * Each process that is waiting for a reply from the user
+        * space server will have an entry in this list.
+        *
+        * We are safe to do it this way because the stack space
+        * is unique to each process, but still addressable by
+        * other processes.
+        */
+       list_for_each_entry(pkg, &receiving_list, list) {
+               if (rtn_seq != pkg->seq)
+                       continue;
+
+               if (msg) {
+                       pkg->error = -msg->ack;
+                       /*
+                        * If we are trying again, we will need to know our
+                        * storage capacity.  Otherwise, along with the
+                        * error code, we make explicit that we have no data.
+                        */
+                       if (pkg->error != -EAGAIN)
+                               *(pkg->data_size) = 0;
+               } else if (tfr->data_size > *(pkg->data_size)) {
+                       DMERR("Insufficient space to receive package [%u] "
+                             "(%u vs %lu)", tfr->request_type,
+                             tfr->data_size, *(pkg->data_size));
+
+                       *(pkg->data_size) = 0;
+                       pkg->error = -ENOSPC;
+               } else {
+                       pkg->error = tfr->error;
+                       memcpy(pkg->data, tfr->data, tfr->data_size);
+                       *(pkg->data_size) = tfr->data_size;
+               }
+               complete(&pkg->complete);
+               return 0;
+       }
+
+       return -ENOENT;
+}
+
+/*
+ * This is the connector callback that delivers data
+ * that was sent from userspace.
+ */
+static void cn_ulog_callback(void *data)
+{
+       struct cn_msg *msg = (struct cn_msg *)data;
+       struct dm_ulog_request *tfr = (struct dm_ulog_request *)(msg + 1);
+
+       spin_lock(&receiving_list_lock);
+       if (msg->len == 0)
+               fill_pkg(msg, NULL);
+       else if (msg->len < sizeof(*tfr))
+               DMERR("Incomplete message received (expected %u, got %u): [%u]",
+                     (unsigned)sizeof(*tfr), msg->len, msg->seq);
+       else
+               fill_pkg(NULL, tfr);
+       spin_unlock(&receiving_list_lock);
+}
+
+/**
+ * dm_consult_userspace
+ * @uuid: log's uuid (must be DM_UUID_LEN in size)
+ * @request_type:  found in include/linux/dm-log-userspace.h
+ * @data: data to tx to the server
+ * @data_size: size of data in bytes
+ * @rdata: place to put return data from server
+ * @rdata_size: value-result (amount of space given/amount of space used)
+ *
+ * rdata_size is undefined on failure.
+ *
+ * Memory used to communicate with userspace is zero'ed
+ * before populating to ensure that no unwanted bits leak
+ * from kernel space to user-space.  All userspace log communications
+ * between kernel and user space go through this function.
+ *
+ * Returns: 0 on success, -EXXX on failure
+ **/
+int dm_consult_userspace(const char *uuid, int request_type,
+                        char *data, size_t data_size,
+                        char *rdata, size_t *rdata_size)
+{
+       int r = 0;
+       size_t dummy = 0;
+       int overhead_size =
+               sizeof(struct dm_ulog_request *) + sizeof(struct cn_msg);
+       struct dm_ulog_request *tfr = prealloced_ulog_tfr;
+       struct receiving_pkg pkg;
+
+       if (data_size > (DM_ULOG_PREALLOCED_SIZE - overhead_size)) {
+               DMINFO("Size of tfr exceeds preallocated size");
+               return -EINVAL;
+       }
+
+       if (!rdata_size)
+               rdata_size = &dummy;
+resend:
+       /*
+        * We serialize the sending of requests so we can
+        * use the preallocated space.
+        */
+       mutex_lock(&dm_ulog_lock);
+
+       memset(tfr, 0, DM_ULOG_PREALLOCED_SIZE - overhead_size);
+       memcpy(tfr->uuid, uuid, DM_UUID_LEN);
+       tfr->seq = dm_ulog_seq++;
+
+       /*
+        * Must be valid request type (all other bits set to
+        * zero).  This reserves other bits for possible future
+        * use.
+        */
+       tfr->request_type = request_type & DM_ULOG_REQUEST_MASK;
+
+       tfr->data_size = data_size;
+       if (data && data_size)
+               memcpy(tfr->data, data, data_size);
+
+       memset(&pkg, 0, sizeof(pkg));
+       init_completion(&pkg.complete);
+       pkg.seq = tfr->seq;
+       pkg.data_size = rdata_size;
+       pkg.data = rdata;
+       spin_lock(&receiving_list_lock);
+       list_add(&(pkg.list), &receiving_list);
+       spin_unlock(&receiving_list_lock);
+
+       r = dm_ulog_sendto_server(tfr);
+
+       mutex_unlock(&dm_ulog_lock);
+
+       if (r) {
+               DMERR("Unable to send log request [%u] to userspace: %d",
+                     request_type, r);
+               spin_lock(&receiving_list_lock);
+               list_del_init(&(pkg.list));
+               spin_unlock(&receiving_list_lock);
+
+               goto out;
+       }
+
+       r = wait_for_completion_timeout(&(pkg.complete), DM_ULOG_RETRY_TIMEOUT);
+       spin_lock(&receiving_list_lock);
+       list_del_init(&(pkg.list));
+       spin_unlock(&receiving_list_lock);
+       if (!r) {
+               DMWARN("[%s] Request timed out: [%u/%u] - retrying",
+                      (strlen(uuid) > 8) ?
+                      (uuid + (strlen(uuid) - 8)) : (uuid),
+                      request_type, pkg.seq);
+               goto resend;
+       }
+
+       r = pkg.error;
+       if (r == -EAGAIN)
+               goto resend;
+
+out:
+       return r;
+}
+
+int dm_ulog_tfr_init(void)
+{
+       int r;
+       void *prealloced;
+
+       INIT_LIST_HEAD(&receiving_list);
+
+       prealloced = kmalloc(DM_ULOG_PREALLOCED_SIZE, GFP_KERNEL);
+       if (!prealloced)
+               return -ENOMEM;
+
+       prealloced_cn_msg = prealloced;
+       prealloced_ulog_tfr = prealloced + sizeof(struct cn_msg);
+
+       r = cn_add_callback(&ulog_cn_id, "dmlogusr", cn_ulog_callback);
+       if (r) {
+               cn_del_callback(&ulog_cn_id);
+               return r;
+       }
+
+       return 0;
+}
+
+void dm_ulog_tfr_exit(void)
+{
+       cn_del_callback(&ulog_cn_id);
+       kfree(prealloced_cn_msg);
+}
diff --git a/drivers/md/dm-log-userspace-transfer.h b/drivers/md/dm-log-userspace-transfer.h
new file mode 100644 (file)
index 0000000..c26d8e4
--- /dev/null
@@ -0,0 +1,18 @@
+/*
+ * Copyright (C) 2006-2009 Red Hat, Inc.
+ *
+ * This file is released under the LGPL.
+ */
+
+#ifndef __DM_LOG_USERSPACE_TRANSFER_H__
+#define __DM_LOG_USERSPACE_TRANSFER_H__
+
+#define DM_MSG_PREFIX "dm-log-userspace"
+
+int dm_ulog_tfr_init(void);
+void dm_ulog_tfr_exit(void);
+int dm_consult_userspace(const char *uuid, int request_type,
+                        char *data, size_t data_size,
+                        char *rdata, size_t *rdata_size);
+
+#endif /* __DM_LOG_USERSPACE_TRANSFER_H__ */
index 6fa8ccf91c70e70174d578e10b8793b884a86406..9443896ede070152020046d15979bb9f1dc55b29 100644 (file)
@@ -412,11 +412,12 @@ static int create_log_context(struct dm_dirty_log *log, struct dm_target *ti,
                /*
                 * Buffer holds both header and bitset.
                 */
-               buf_size = dm_round_up((LOG_OFFSET << SECTOR_SHIFT) +
-                                      bitset_size,
-                                      ti->limits.logical_block_size);
+               buf_size =
+                   dm_round_up((LOG_OFFSET << SECTOR_SHIFT) + bitset_size,
+                               bdev_logical_block_size(lc->header_location.
+                                                           bdev));
 
-               if (buf_size > dev->bdev->bd_inode->i_size) {
+               if (buf_size > i_size_read(dev->bdev->bd_inode)) {
                        DMWARN("log device %s too small: need %llu bytes",
                                dev->name, (unsigned long long)buf_size);
                        kfree(lc);
index 6a386ab4f7ebb898bdfd529682f240b2beed20c3..c70604a208979b4b1f87e4a9e98f10b5ce00036d 100644 (file)
@@ -8,7 +8,6 @@
 #include <linux/device-mapper.h>
 
 #include "dm-path-selector.h"
-#include "dm-bio-record.h"
 #include "dm-uevent.h"
 
 #include <linux/ctype.h>
@@ -35,6 +34,7 @@ struct pgpath {
 
        struct dm_path path;
        struct work_struct deactivate_path;
+       struct work_struct activate_path;
 };
 
 #define path_to_pgpath(__pgp) container_of((__pgp), struct pgpath, path)
@@ -64,8 +64,6 @@ struct multipath {
        spinlock_t lock;
 
        const char *hw_handler_name;
-       struct work_struct activate_path;
-       struct pgpath *pgpath_to_activate;
        unsigned nr_priority_groups;
        struct list_head priority_groups;
        unsigned pg_init_required;      /* pg_init needs calling? */
@@ -84,7 +82,7 @@ struct multipath {
        unsigned pg_init_count;         /* Number of times pg_init called */
 
        struct work_struct process_queued_ios;
-       struct bio_list queued_ios;
+       struct list_head queued_ios;
        unsigned queue_size;
 
        struct work_struct trigger_event;
@@ -101,7 +99,7 @@ struct multipath {
  */
 struct dm_mpath_io {
        struct pgpath *pgpath;
-       struct dm_bio_details details;
+       size_t nr_bytes;
 };
 
 typedef int (*action_fn) (struct pgpath *pgpath);
@@ -128,6 +126,7 @@ static struct pgpath *alloc_pgpath(void)
        if (pgpath) {
                pgpath->is_active = 1;
                INIT_WORK(&pgpath->deactivate_path, deactivate_path);
+               INIT_WORK(&pgpath->activate_path, activate_path);
        }
 
        return pgpath;
@@ -160,7 +159,6 @@ static struct priority_group *alloc_priority_group(void)
 
 static void free_pgpaths(struct list_head *pgpaths, struct dm_target *ti)
 {
-       unsigned long flags;
        struct pgpath *pgpath, *tmp;
        struct multipath *m = ti->private;
 
@@ -169,10 +167,6 @@ static void free_pgpaths(struct list_head *pgpaths, struct dm_target *ti)
                if (m->hw_handler_name)
                        scsi_dh_detach(bdev_get_queue(pgpath->path.dev->bdev));
                dm_put_device(ti, pgpath->path.dev);
-               spin_lock_irqsave(&m->lock, flags);
-               if (m->pgpath_to_activate == pgpath)
-                       m->pgpath_to_activate = NULL;
-               spin_unlock_irqrestore(&m->lock, flags);
                free_pgpath(pgpath);
        }
 }
@@ -198,11 +192,11 @@ static struct multipath *alloc_multipath(struct dm_target *ti)
        m = kzalloc(sizeof(*m), GFP_KERNEL);
        if (m) {
                INIT_LIST_HEAD(&m->priority_groups);
+               INIT_LIST_HEAD(&m->queued_ios);
                spin_lock_init(&m->lock);
                m->queue_io = 1;
                INIT_WORK(&m->process_queued_ios, process_queued_ios);
                INIT_WORK(&m->trigger_event, trigger_event);
-               INIT_WORK(&m->activate_path, activate_path);
                m->mpio_pool = mempool_create_slab_pool(MIN_IOS, _mpio_cache);
                if (!m->mpio_pool) {
                        kfree(m);
@@ -250,11 +244,12 @@ static void __switch_pg(struct multipath *m, struct pgpath *pgpath)
        m->pg_init_count = 0;
 }
 
-static int __choose_path_in_pg(struct multipath *m, struct priority_group *pg)
+static int __choose_path_in_pg(struct multipath *m, struct priority_group *pg,
+                              size_t nr_bytes)
 {
        struct dm_path *path;
 
-       path = pg->ps.type->select_path(&pg->ps, &m->repeat_count);
+       path = pg->ps.type->select_path(&pg->ps, &m->repeat_count, nr_bytes);
        if (!path)
                return -ENXIO;
 
@@ -266,7 +261,7 @@ static int __choose_path_in_pg(struct multipath *m, struct priority_group *pg)
        return 0;
 }
 
-static void __choose_pgpath(struct multipath *m)
+static void __choose_pgpath(struct multipath *m, size_t nr_bytes)
 {
        struct priority_group *pg;
        unsigned bypassed = 1;
@@ -278,12 +273,12 @@ static void __choose_pgpath(struct multipath *m)
        if (m->next_pg) {
                pg = m->next_pg;
                m->next_pg = NULL;
-               if (!__choose_path_in_pg(m, pg))
+               if (!__choose_path_in_pg(m, pg, nr_bytes))
                        return;
        }
 
        /* Don't change PG until it has no remaining paths */
-       if (m->current_pg && !__choose_path_in_pg(m, m->current_pg))
+       if (m->current_pg && !__choose_path_in_pg(m, m->current_pg, nr_bytes))
                return;
 
        /*
@@ -295,7 +290,7 @@ static void __choose_pgpath(struct multipath *m)
                list_for_each_entry(pg, &m->priority_groups, list) {
                        if (pg->bypassed == bypassed)
                                continue;
-                       if (!__choose_path_in_pg(m, pg))
+                       if (!__choose_path_in_pg(m, pg, nr_bytes))
                                return;
                }
        } while (bypassed--);
@@ -322,19 +317,21 @@ static int __must_push_back(struct multipath *m)
                dm_noflush_suspending(m->ti));
 }
 
-static int map_io(struct multipath *m, struct bio *bio,
+static int map_io(struct multipath *m, struct request *clone,
                  struct dm_mpath_io *mpio, unsigned was_queued)
 {
        int r = DM_MAPIO_REMAPPED;
+       size_t nr_bytes = blk_rq_bytes(clone);
        unsigned long flags;
        struct pgpath *pgpath;
+       struct block_device *bdev;
 
        spin_lock_irqsave(&m->lock, flags);
 
        /* Do we need to select a new pgpath? */
        if (!m->current_pgpath ||
            (!m->queue_io && (m->repeat_count && --m->repeat_count == 0)))
-               __choose_pgpath(m);
+               __choose_pgpath(m, nr_bytes);
 
        pgpath = m->current_pgpath;
 
@@ -344,21 +341,28 @@ static int map_io(struct multipath *m, struct bio *bio,
        if ((pgpath && m->queue_io) ||
            (!pgpath && m->queue_if_no_path)) {
                /* Queue for the daemon to resubmit */
-               bio_list_add(&m->queued_ios, bio);
+               list_add_tail(&clone->queuelist, &m->queued_ios);
                m->queue_size++;
                if ((m->pg_init_required && !m->pg_init_in_progress) ||
                    !m->queue_io)
                        queue_work(kmultipathd, &m->process_queued_ios);
                pgpath = NULL;
                r = DM_MAPIO_SUBMITTED;
-       } else if (pgpath)
-               bio->bi_bdev = pgpath->path.dev->bdev;
-       else if (__must_push_back(m))
+       } else if (pgpath) {
+               bdev = pgpath->path.dev->bdev;
+               clone->q = bdev_get_queue(bdev);
+               clone->rq_disk = bdev->bd_disk;
+       } else if (__must_push_back(m))
                r = DM_MAPIO_REQUEUE;
        else
                r = -EIO;       /* Failed */
 
        mpio->pgpath = pgpath;
+       mpio->nr_bytes = nr_bytes;
+
+       if (r == DM_MAPIO_REMAPPED && pgpath->pg->ps.type->start_io)
+               pgpath->pg->ps.type->start_io(&pgpath->pg->ps, &pgpath->path,
+                                             nr_bytes);
 
        spin_unlock_irqrestore(&m->lock, flags);
 
@@ -396,30 +400,31 @@ static void dispatch_queued_ios(struct multipath *m)
 {
        int r;
        unsigned long flags;
-       struct bio *bio = NULL, *next;
        struct dm_mpath_io *mpio;
        union map_info *info;
+       struct request *clone, *n;
+       LIST_HEAD(cl);
 
        spin_lock_irqsave(&m->lock, flags);
-       bio = bio_list_get(&m->queued_ios);
+       list_splice_init(&m->queued_ios, &cl);
        spin_unlock_irqrestore(&m->lock, flags);
 
-       while (bio) {
-               next = bio->bi_next;
-               bio->bi_next = NULL;
+       list_for_each_entry_safe(clone, n, &cl, queuelist) {
+               list_del_init(&clone->queuelist);
 
-               info = dm_get_mapinfo(bio);
+               info = dm_get_rq_mapinfo(clone);
                mpio = info->ptr;
 
-               r = map_io(m, bio, mpio, 1);
-               if (r < 0)
-                       bio_endio(bio, r);
-               else if (r == DM_MAPIO_REMAPPED)
-                       generic_make_request(bio);
-               else if (r == DM_MAPIO_REQUEUE)
-                       bio_endio(bio, -EIO);
-
-               bio = next;
+               r = map_io(m, clone, mpio, 1);
+               if (r < 0) {
+                       mempool_free(mpio, m->mpio_pool);
+                       dm_kill_unmapped_request(clone, r);
+               } else if (r == DM_MAPIO_REMAPPED)
+                       dm_dispatch_request(clone);
+               else if (r == DM_MAPIO_REQUEUE) {
+                       mempool_free(mpio, m->mpio_pool);
+                       dm_requeue_unmapped_request(clone);
+               }
        }
 }
 
@@ -427,8 +432,8 @@ static void process_queued_ios(struct work_struct *work)
 {
        struct multipath *m =
                container_of(work, struct multipath, process_queued_ios);
-       struct pgpath *pgpath = NULL;
-       unsigned init_required = 0, must_queue = 1;
+       struct pgpath *pgpath = NULL, *tmp;
+       unsigned must_queue = 1;
        unsigned long flags;
 
        spin_lock_irqsave(&m->lock, flags);
@@ -437,7 +442,7 @@ static void process_queued_ios(struct work_struct *work)
                goto out;
 
        if (!m->current_pgpath)
-               __choose_pgpath(m);
+               __choose_pgpath(m, 0);
 
        pgpath = m->current_pgpath;
 
@@ -446,19 +451,15 @@ static void process_queued_ios(struct work_struct *work)
                must_queue = 0;
 
        if (m->pg_init_required && !m->pg_init_in_progress && pgpath) {
-               m->pgpath_to_activate = pgpath;
                m->pg_init_count++;
                m->pg_init_required = 0;
-               m->pg_init_in_progress = 1;
-               init_required = 1;
+               list_for_each_entry(tmp, &pgpath->pg->pgpaths, list) {
+                       if (queue_work(kmpath_handlerd, &tmp->activate_path))
+                               m->pg_init_in_progress++;
+               }
        }
-
 out:
        spin_unlock_irqrestore(&m->lock, flags);
-
-       if (init_required)
-               queue_work(kmpath_handlerd, &m->activate_path);
-
        if (!must_queue)
                dispatch_queued_ios(m);
 }
@@ -553,6 +554,12 @@ static int parse_path_selector(struct arg_set *as, struct priority_group *pg,
                return -EINVAL;
        }
 
+       if (ps_argc > as->argc) {
+               dm_put_path_selector(pst);
+               ti->error = "not enough arguments for path selector";
+               return -EINVAL;
+       }
+
        r = pst->create(&pg->ps, ps_argc, as->argv);
        if (r) {
                dm_put_path_selector(pst);
@@ -591,9 +598,20 @@ static struct pgpath *parse_path(struct arg_set *as, struct path_selector *ps,
        }
 
        if (m->hw_handler_name) {
-               r = scsi_dh_attach(bdev_get_queue(p->path.dev->bdev),
-                                  m->hw_handler_name);
+               struct request_queue *q = bdev_get_queue(p->path.dev->bdev);
+
+               r = scsi_dh_attach(q, m->hw_handler_name);
+               if (r == -EBUSY) {
+                       /*
+                        * Already attached to different hw_handler,
+                        * try to reattach with correct one.
+                        */
+                       scsi_dh_detach(q);
+                       r = scsi_dh_attach(q, m->hw_handler_name);
+               }
+
                if (r < 0) {
+                       ti->error = "error attaching hardware handler";
                        dm_put_device(ti, p->path.dev);
                        goto bad;
                }
@@ -699,6 +717,11 @@ static int parse_hw_handler(struct arg_set *as, struct multipath *m)
        if (!hw_argc)
                return 0;
 
+       if (hw_argc > as->argc) {
+               ti->error = "not enough arguments for hardware handler";
+               return -EINVAL;
+       }
+
        m->hw_handler_name = kstrdup(shift(as), GFP_KERNEL);
        request_module("scsi_dh_%s", m->hw_handler_name);
        if (scsi_dh_handler_exist(m->hw_handler_name) == 0) {
@@ -823,6 +846,8 @@ static int multipath_ctr(struct dm_target *ti, unsigned int argc,
                goto bad;
        }
 
+       ti->num_flush_requests = 1;
+
        return 0;
 
  bad:
@@ -836,25 +861,29 @@ static void multipath_dtr(struct dm_target *ti)
 
        flush_workqueue(kmpath_handlerd);
        flush_workqueue(kmultipathd);
+       flush_scheduled_work();
        free_multipath(m);
 }
 
 /*
- * Map bios, recording original fields for later in case we have to resubmit
+ * Map cloned requests
  */
-static int multipath_map(struct dm_target *ti, struct bio *bio,
+static int multipath_map(struct dm_target *ti, struct request *clone,
                         union map_info *map_context)
 {
        int r;
        struct dm_mpath_io *mpio;
        struct multipath *m = (struct multipath *) ti->private;
 
-       mpio = mempool_alloc(m->mpio_pool, GFP_NOIO);
-       dm_bio_record(&mpio->details, bio);
+       mpio = mempool_alloc(m->mpio_pool, GFP_ATOMIC);
+       if (!mpio)
+               /* ENOMEM, requeue */
+               return DM_MAPIO_REQUEUE;
+       memset(mpio, 0, sizeof(*mpio));
 
        map_context->ptr = mpio;
-       bio->bi_rw |= (1 << BIO_RW_FAILFAST_TRANSPORT);
-       r = map_io(m, bio, mpio, 0);
+       clone->cmd_flags |= REQ_FAILFAST_TRANSPORT;
+       r = map_io(m, clone, mpio, 0);
        if (r < 0 || r == DM_MAPIO_REQUEUE)
                mempool_free(mpio, m->mpio_pool);
 
@@ -924,9 +953,13 @@ static int reinstate_path(struct pgpath *pgpath)
 
        pgpath->is_active = 1;
 
-       m->current_pgpath = NULL;
-       if (!m->nr_valid_paths++ && m->queue_size)
+       if (!m->nr_valid_paths++ && m->queue_size) {
+               m->current_pgpath = NULL;
                queue_work(kmultipathd, &m->process_queued_ios);
+       } else if (m->hw_handler_name && (m->current_pg == pgpath->pg)) {
+               if (queue_work(kmpath_handlerd, &pgpath->activate_path))
+                       m->pg_init_in_progress++;
+       }
 
        dm_path_uevent(DM_UEVENT_PATH_REINSTATED, m->ti,
                      pgpath->path.dev->name, m->nr_valid_paths);
@@ -1102,87 +1135,70 @@ static void pg_init_done(struct dm_path *path, int errors)
 
        spin_lock_irqsave(&m->lock, flags);
        if (errors) {
-               DMERR("Could not failover device. Error %d.", errors);
-               m->current_pgpath = NULL;
-               m->current_pg = NULL;
+               if (pgpath == m->current_pgpath) {
+                       DMERR("Could not failover device. Error %d.", errors);
+                       m->current_pgpath = NULL;
+                       m->current_pg = NULL;
+               }
        } else if (!m->pg_init_required) {
                m->queue_io = 0;
                pg->bypassed = 0;
        }
 
-       m->pg_init_in_progress = 0;
-       queue_work(kmultipathd, &m->process_queued_ios);
+       m->pg_init_in_progress--;
+       if (!m->pg_init_in_progress)
+               queue_work(kmultipathd, &m->process_queued_ios);
        spin_unlock_irqrestore(&m->lock, flags);
 }
 
 static void activate_path(struct work_struct *work)
 {
        int ret;
-       struct multipath *m =
-               container_of(work, struct multipath, activate_path);
-       struct dm_path *path;
-       unsigned long flags;
+       struct pgpath *pgpath =
+               container_of(work, struct pgpath, activate_path);
 
-       spin_lock_irqsave(&m->lock, flags);
-       path = &m->pgpath_to_activate->path;
-       m->pgpath_to_activate = NULL;
-       spin_unlock_irqrestore(&m->lock, flags);
-       if (!path)
-               return;
-       ret = scsi_dh_activate(bdev_get_queue(path->dev->bdev));
-       pg_init_done(path, ret);
+       ret = scsi_dh_activate(bdev_get_queue(pgpath->path.dev->bdev));
+       pg_init_done(&pgpath->path, ret);
 }
 
 /*
  * end_io handling
  */
-static int do_end_io(struct multipath *m, struct bio *bio,
+static int do_end_io(struct multipath *m, struct request *clone,
                     int error, struct dm_mpath_io *mpio)
 {
+       /*
+        * We don't queue any clone request inside the multipath target
+        * during end I/O handling, since those clone requests don't have
+        * bio clones.  If we queue them inside the multipath target,
+        * we need to make bio clones, that requires memory allocation.
+        * (See drivers/md/dm.c:end_clone_bio() about why the clone requests
+        *  don't have bio clones.)
+        * Instead of queueing the clone request here, we queue the original
+        * request into dm core, which will remake a clone request and
+        * clone bios for it and resubmit it later.
+        */
+       int r = DM_ENDIO_REQUEUE;
        unsigned long flags;
 
-       if (!error)
+       if (!error && !clone->errors)
                return 0;       /* I/O complete */
 
-       if ((error == -EWOULDBLOCK) && bio_rw_ahead(bio))
-               return error;
-
        if (error == -EOPNOTSUPP)
                return error;
 
-       spin_lock_irqsave(&m->lock, flags);
-       if (!m->nr_valid_paths) {
-               if (__must_push_back(m)) {
-                       spin_unlock_irqrestore(&m->lock, flags);
-                       return DM_ENDIO_REQUEUE;
-               } else if (!m->queue_if_no_path) {
-                       spin_unlock_irqrestore(&m->lock, flags);
-                       return -EIO;
-               } else {
-                       spin_unlock_irqrestore(&m->lock, flags);
-                       goto requeue;
-               }
-       }
-       spin_unlock_irqrestore(&m->lock, flags);
-
        if (mpio->pgpath)
                fail_path(mpio->pgpath);
 
-      requeue:
-       dm_bio_restore(&mpio->details, bio);
-
-       /* queue for the daemon to resubmit or fail */
        spin_lock_irqsave(&m->lock, flags);
-       bio_list_add(&m->queued_ios, bio);
-       m->queue_size++;
-       if (!m->queue_io)
-               queue_work(kmultipathd, &m->process_queued_ios);
+       if (!m->nr_valid_paths && !m->queue_if_no_path && !__must_push_back(m))
+               r = -EIO;
        spin_unlock_irqrestore(&m->lock, flags);
 
-       return DM_ENDIO_INCOMPLETE;     /* io not complete */
+       return r;
 }
 
-static int multipath_end_io(struct dm_target *ti, struct bio *bio,
+static int multipath_end_io(struct dm_target *ti, struct request *clone,
                            int error, union map_info *map_context)
 {
        struct multipath *m = ti->private;
@@ -1191,14 +1207,13 @@ static int multipath_end_io(struct dm_target *ti, struct bio *bio,
        struct path_selector *ps;
        int r;
 
-       r  = do_end_io(m, bio, error, mpio);
+       r  = do_end_io(m, clone, error, mpio);
        if (pgpath) {
                ps = &pgpath->pg->ps;
                if (ps->type->end_io)
-                       ps->type->end_io(ps, &pgpath->path);
+                       ps->type->end_io(ps, &pgpath->path, mpio->nr_bytes);
        }
-       if (r != DM_ENDIO_INCOMPLETE)
-               mempool_free(mpio, m->mpio_pool);
+       mempool_free(mpio, m->mpio_pool);
 
        return r;
 }
@@ -1411,7 +1426,7 @@ static int multipath_ioctl(struct dm_target *ti, unsigned int cmd,
        spin_lock_irqsave(&m->lock, flags);
 
        if (!m->current_pgpath)
-               __choose_pgpath(m);
+               __choose_pgpath(m, 0);
 
        if (m->current_pgpath) {
                bdev = m->current_pgpath->path.dev->bdev;
@@ -1428,22 +1443,113 @@ static int multipath_ioctl(struct dm_target *ti, unsigned int cmd,
        return r ? : __blkdev_driver_ioctl(bdev, mode, cmd, arg);
 }
 
+static int multipath_iterate_devices(struct dm_target *ti,
+                                    iterate_devices_callout_fn fn, void *data)
+{
+       struct multipath *m = ti->private;
+       struct priority_group *pg;
+       struct pgpath *p;
+       int ret = 0;
+
+       list_for_each_entry(pg, &m->priority_groups, list) {
+               list_for_each_entry(p, &pg->pgpaths, list) {
+                       ret = fn(ti, p->path.dev, ti->begin, data);
+                       if (ret)
+                               goto out;
+               }
+       }
+
+out:
+       return ret;
+}
+
+static int __pgpath_busy(struct pgpath *pgpath)
+{
+       struct request_queue *q = bdev_get_queue(pgpath->path.dev->bdev);
+
+       return dm_underlying_device_busy(q);
+}
+
+/*
+ * We return "busy", only when we can map I/Os but underlying devices
+ * are busy (so even if we map I/Os now, the I/Os will wait on
+ * the underlying queue).
+ * In other words, if we want to kill I/Os or queue them inside us
+ * due to map unavailability, we don't return "busy".  Otherwise,
+ * dm core won't give us the I/Os and we can't do what we want.
+ */
+static int multipath_busy(struct dm_target *ti)
+{
+       int busy = 0, has_active = 0;
+       struct multipath *m = ti->private;
+       struct priority_group *pg;
+       struct pgpath *pgpath;
+       unsigned long flags;
+
+       spin_lock_irqsave(&m->lock, flags);
+
+       /* Guess which priority_group will be used at next mapping time */
+       if (unlikely(!m->current_pgpath && m->next_pg))
+               pg = m->next_pg;
+       else if (likely(m->current_pg))
+               pg = m->current_pg;
+       else
+               /*
+                * We don't know which pg will be used at next mapping time.
+                * We don't call __choose_pgpath() here to avoid to trigger
+                * pg_init just by busy checking.
+                * So we don't know whether underlying devices we will be using
+                * at next mapping time are busy or not. Just try mapping.
+                */
+               goto out;
+
+       /*
+        * If there is one non-busy active path at least, the path selector
+        * will be able to select it. So we consider such a pg as not busy.
+        */
+       busy = 1;
+       list_for_each_entry(pgpath, &pg->pgpaths, list)
+               if (pgpath->is_active) {
+                       has_active = 1;
+
+                       if (!__pgpath_busy(pgpath)) {
+                               busy = 0;
+                               break;
+                       }
+               }
+
+       if (!has_active)
+               /*
+                * No active path in this pg, so this pg won't be used and
+                * the current_pg will be changed at next mapping time.
+                * We need to try mapping to determine it.
+                */
+               busy = 0;
+
+out:
+       spin_unlock_irqrestore(&m->lock, flags);
+
+       return busy;
+}
+
 /*-----------------------------------------------------------------
  * Module setup
  *---------------------------------------------------------------*/
 static struct target_type multipath_target = {
        .name = "multipath",
-       .version = {1, 0, 5},
+       .version = {1, 1, 0},
        .module = THIS_MODULE,
        .ctr = multipath_ctr,
        .dtr = multipath_dtr,
-       .map = multipath_map,
-       .end_io = multipath_end_io,
+       .map_rq = multipath_map,
+       .rq_end_io = multipath_end_io,
        .presuspend = multipath_presuspend,
        .resume = multipath_resume,
        .status = multipath_status,
        .message = multipath_message,
        .ioctl  = multipath_ioctl,
+       .iterate_devices = multipath_iterate_devices,
+       .busy = multipath_busy,
 };
 
 static int __init dm_multipath_init(void)
index 27357b85d73d7495cbcb2d61e8522ac942317901..e7d1fa8b0459f3deaadc16a34a09231764073fbc 100644 (file)
@@ -56,7 +56,8 @@ struct path_selector_type {
         * the path fails.
         */
        struct dm_path *(*select_path) (struct path_selector *ps,
-                                    unsigned *repeat_count);
+                                       unsigned *repeat_count,
+                                       size_t nr_bytes);
 
        /*
         * Notify the selector that a path has failed.
@@ -75,7 +76,10 @@ struct path_selector_type {
        int (*status) (struct path_selector *ps, struct dm_path *path,
                       status_type_t type, char *result, unsigned int maxlen);
 
-       int (*end_io) (struct path_selector *ps, struct dm_path *path);
+       int (*start_io) (struct path_selector *ps, struct dm_path *path,
+                        size_t nr_bytes);
+       int (*end_io) (struct path_selector *ps, struct dm_path *path,
+                      size_t nr_bytes);
 };
 
 /* Register a path selector */
diff --git a/drivers/md/dm-queue-length.c b/drivers/md/dm-queue-length.c
new file mode 100644 (file)
index 0000000..f92b6ce
--- /dev/null
@@ -0,0 +1,263 @@
+/*
+ * Copyright (C) 2004-2005 IBM Corp.  All Rights Reserved.
+ * Copyright (C) 2006-2009 NEC Corporation.
+ *
+ * dm-queue-length.c
+ *
+ * Module Author: Stefan Bader, IBM
+ * Modified by: Kiyoshi Ueda, NEC
+ *
+ * This file is released under the GPL.
+ *
+ * queue-length path selector - choose a path with the least number of
+ * in-flight I/Os.
+ */
+
+#include "dm.h"
+#include "dm-path-selector.h"
+
+#include <linux/slab.h>
+#include <linux/ctype.h>
+#include <linux/errno.h>
+#include <linux/module.h>
+#include <asm/atomic.h>
+
+#define DM_MSG_PREFIX  "multipath queue-length"
+#define QL_MIN_IO      128
+#define QL_VERSION     "0.1.0"
+
+struct selector {
+       struct list_head        valid_paths;
+       struct list_head        failed_paths;
+};
+
+struct path_info {
+       struct list_head        list;
+       struct dm_path          *path;
+       unsigned                repeat_count;
+       atomic_t                qlen;   /* the number of in-flight I/Os */
+};
+
+static struct selector *alloc_selector(void)
+{
+       struct selector *s = kmalloc(sizeof(*s), GFP_KERNEL);
+
+       if (s) {
+               INIT_LIST_HEAD(&s->valid_paths);
+               INIT_LIST_HEAD(&s->failed_paths);
+       }
+
+       return s;
+}
+
+static int ql_create(struct path_selector *ps, unsigned argc, char **argv)
+{
+       struct selector *s = alloc_selector();
+
+       if (!s)
+               return -ENOMEM;
+
+       ps->context = s;
+       return 0;
+}
+
+static void ql_free_paths(struct list_head *paths)
+{
+       struct path_info *pi, *next;
+
+       list_for_each_entry_safe(pi, next, paths, list) {
+               list_del(&pi->list);
+               kfree(pi);
+       }
+}
+
+static void ql_destroy(struct path_selector *ps)
+{
+       struct selector *s = ps->context;
+
+       ql_free_paths(&s->valid_paths);
+       ql_free_paths(&s->failed_paths);
+       kfree(s);
+       ps->context = NULL;
+}
+
+static int ql_status(struct path_selector *ps, struct dm_path *path,
+                    status_type_t type, char *result, unsigned maxlen)
+{
+       unsigned sz = 0;
+       struct path_info *pi;
+
+       /* When called with NULL path, return selector status/args. */
+       if (!path)
+               DMEMIT("0 ");
+       else {
+               pi = path->pscontext;
+
+               switch (type) {
+               case STATUSTYPE_INFO:
+                       DMEMIT("%d ", atomic_read(&pi->qlen));
+                       break;
+               case STATUSTYPE_TABLE:
+                       DMEMIT("%u ", pi->repeat_count);
+                       break;
+               }
+       }
+
+       return sz;
+}
+
+static int ql_add_path(struct path_selector *ps, struct dm_path *path,
+                      int argc, char **argv, char **error)
+{
+       struct selector *s = ps->context;
+       struct path_info *pi;
+       unsigned repeat_count = QL_MIN_IO;
+
+       /*
+        * Arguments: [<repeat_count>]
+        *      <repeat_count>: The number of I/Os before switching path.
+        *                      If not given, default (QL_MIN_IO) is used.
+        */
+       if (argc > 1) {
+               *error = "queue-length ps: incorrect number of arguments";
+               return -EINVAL;
+       }
+
+       if ((argc == 1) && (sscanf(argv[0], "%u", &repeat_count) != 1)) {
+               *error = "queue-length ps: invalid repeat count";
+               return -EINVAL;
+       }
+
+       /* Allocate the path information structure */
+       pi = kmalloc(sizeof(*pi), GFP_KERNEL);
+       if (!pi) {
+               *error = "queue-length ps: Error allocating path information";
+               return -ENOMEM;
+       }
+
+       pi->path = path;
+       pi->repeat_count = repeat_count;
+       atomic_set(&pi->qlen, 0);
+
+       path->pscontext = pi;
+
+       list_add_tail(&pi->list, &s->valid_paths);
+
+       return 0;
+}
+
+static void ql_fail_path(struct path_selector *ps, struct dm_path *path)
+{
+       struct selector *s = ps->context;
+       struct path_info *pi = path->pscontext;
+
+       list_move(&pi->list, &s->failed_paths);
+}
+
+static int ql_reinstate_path(struct path_selector *ps, struct dm_path *path)
+{
+       struct selector *s = ps->context;
+       struct path_info *pi = path->pscontext;
+
+       list_move_tail(&pi->list, &s->valid_paths);
+
+       return 0;
+}
+
+/*
+ * Select a path having the minimum number of in-flight I/Os
+ */
+static struct dm_path *ql_select_path(struct path_selector *ps,
+                                     unsigned *repeat_count, size_t nr_bytes)
+{
+       struct selector *s = ps->context;
+       struct path_info *pi = NULL, *best = NULL;
+
+       if (list_empty(&s->valid_paths))
+               return NULL;
+
+       /* Change preferred (first in list) path to evenly balance. */
+       list_move_tail(s->valid_paths.next, &s->valid_paths);
+
+       list_for_each_entry(pi, &s->valid_paths, list) {
+               if (!best ||
+                   (atomic_read(&pi->qlen) < atomic_read(&best->qlen)))
+                       best = pi;
+
+               if (!atomic_read(&best->qlen))
+                       break;
+       }
+
+       if (!best)
+               return NULL;
+
+       *repeat_count = best->repeat_count;
+
+       return best->path;
+}
+
+static int ql_start_io(struct path_selector *ps, struct dm_path *path,
+                      size_t nr_bytes)
+{
+       struct path_info *pi = path->pscontext;
+
+       atomic_inc(&pi->qlen);
+
+       return 0;
+}
+
+static int ql_end_io(struct path_selector *ps, struct dm_path *path,
+                    size_t nr_bytes)
+{
+       struct path_info *pi = path->pscontext;
+
+       atomic_dec(&pi->qlen);
+
+       return 0;
+}
+
+static struct path_selector_type ql_ps = {
+       .name           = "queue-length",
+       .module         = THIS_MODULE,
+       .table_args     = 1,
+       .info_args      = 1,
+       .create         = ql_create,
+       .destroy        = ql_destroy,
+       .status         = ql_status,
+       .add_path       = ql_add_path,
+       .fail_path      = ql_fail_path,
+       .reinstate_path = ql_reinstate_path,
+       .select_path    = ql_select_path,
+       .start_io       = ql_start_io,
+       .end_io         = ql_end_io,
+};
+
+static int __init dm_ql_init(void)
+{
+       int r = dm_register_path_selector(&ql_ps);
+
+       if (r < 0)
+               DMERR("register failed %d", r);
+
+       DMINFO("version " QL_VERSION " loaded");
+
+       return r;
+}
+
+static void __exit dm_ql_exit(void)
+{
+       int r = dm_unregister_path_selector(&ql_ps);
+
+       if (r < 0)
+               DMERR("unregister failed %d", r);
+}
+
+module_init(dm_ql_init);
+module_exit(dm_ql_exit);
+
+MODULE_AUTHOR("Stefan Bader <Stefan.Bader at de.ibm.com>");
+MODULE_DESCRIPTION(
+       "(C) Copyright IBM Corp. 2004,2005   All Rights Reserved.\n"
+       DM_NAME " path selector to balance the number of in-flight I/Os"
+);
+MODULE_LICENSE("GPL");
index 076fbb4e967a4a651116c029983237d942b3f1ac..ce8868c768cce1c411d3ba76d4eae5b9011bee64 100644 (file)
@@ -1283,9 +1283,23 @@ static int mirror_status(struct dm_target *ti, status_type_t type,
        return 0;
 }
 
+static int mirror_iterate_devices(struct dm_target *ti,
+                                 iterate_devices_callout_fn fn, void *data)
+{
+       struct mirror_set *ms = ti->private;
+       int ret = 0;
+       unsigned i;
+
+       for (i = 0; !ret && i < ms->nr_mirrors; i++)
+               ret = fn(ti, ms->mirror[i].dev,
+                        ms->mirror[i].offset, data);
+
+       return ret;
+}
+
 static struct target_type mirror_target = {
        .name    = "mirror",
-       .version = {1, 0, 20},
+       .version = {1, 12, 0},
        .module  = THIS_MODULE,
        .ctr     = mirror_ctr,
        .dtr     = mirror_dtr,
@@ -1295,6 +1309,7 @@ static struct target_type mirror_target = {
        .postsuspend = mirror_postsuspend,
        .resume  = mirror_resume,
        .status  = mirror_status,
+       .iterate_devices = mirror_iterate_devices,
 };
 
 static int __init dm_mirror_init(void)
index 7b899be0b0873d66499a4f3120ba3245cc828908..36dbe29f2fd60e775b05a0c0562e4741a42a8d08 100644 (file)
@@ -283,7 +283,7 @@ static struct dm_region *__rh_alloc(struct dm_region_hash *rh, region_t region)
 
        nreg = mempool_alloc(rh->region_pool, GFP_ATOMIC);
        if (unlikely(!nreg))
-               nreg = kmalloc(sizeof(*nreg), GFP_NOIO);
+               nreg = kmalloc(sizeof(*nreg), GFP_NOIO | __GFP_NOFAIL);
 
        nreg->state = rh->log->type->in_sync(rh->log, region, 1) ?
                      DM_RH_CLEAN : DM_RH_NOSYNC;
index cdfbf65b28cb0fb5d4af95d9e6718d80d69be760..24752f449bef8834b8ebb0329293491bdf4f07ed 100644 (file)
@@ -161,7 +161,7 @@ static int rr_reinstate_path(struct path_selector *ps, struct dm_path *p)
 }
 
 static struct dm_path *rr_select_path(struct path_selector *ps,
-                                  unsigned *repeat_count)
+                                     unsigned *repeat_count, size_t nr_bytes)
 {
        struct selector *s = (struct selector *) ps->context;
        struct path_info *pi = NULL;
diff --git a/drivers/md/dm-service-time.c b/drivers/md/dm-service-time.c
new file mode 100644 (file)
index 0000000..cfa668f
--- /dev/null
@@ -0,0 +1,339 @@
+/*
+ * Copyright (C) 2007-2009 NEC Corporation.  All Rights Reserved.
+ *
+ * Module Author: Kiyoshi Ueda
+ *
+ * This file is released under the GPL.
+ *
+ * Throughput oriented path selector.
+ */
+
+#include "dm.h"
+#include "dm-path-selector.h"
+
+#define DM_MSG_PREFIX  "multipath service-time"
+#define ST_MIN_IO      1
+#define ST_MAX_RELATIVE_THROUGHPUT     100
+#define ST_MAX_RELATIVE_THROUGHPUT_SHIFT       7
+#define ST_MAX_INFLIGHT_SIZE   ((size_t)-1 >> ST_MAX_RELATIVE_THROUGHPUT_SHIFT)
+#define ST_VERSION     "0.2.0"
+
+struct selector {
+       struct list_head valid_paths;
+       struct list_head failed_paths;
+};
+
+struct path_info {
+       struct list_head list;
+       struct dm_path *path;
+       unsigned repeat_count;
+       unsigned relative_throughput;
+       atomic_t in_flight_size;        /* Total size of in-flight I/Os */
+};
+
+static struct selector *alloc_selector(void)
+{
+       struct selector *s = kmalloc(sizeof(*s), GFP_KERNEL);
+
+       if (s) {
+               INIT_LIST_HEAD(&s->valid_paths);
+               INIT_LIST_HEAD(&s->failed_paths);
+       }
+
+       return s;
+}
+
+static int st_create(struct path_selector *ps, unsigned argc, char **argv)
+{
+       struct selector *s = alloc_selector();
+
+       if (!s)
+               return -ENOMEM;
+
+       ps->context = s;
+       return 0;
+}
+
+static void free_paths(struct list_head *paths)
+{
+       struct path_info *pi, *next;
+
+       list_for_each_entry_safe(pi, next, paths, list) {
+               list_del(&pi->list);
+               kfree(pi);
+       }
+}
+
+static void st_destroy(struct path_selector *ps)
+{
+       struct selector *s = ps->context;
+
+       free_paths(&s->valid_paths);
+       free_paths(&s->failed_paths);
+       kfree(s);
+       ps->context = NULL;
+}
+
+static int st_status(struct path_selector *ps, struct dm_path *path,
+                    status_type_t type, char *result, unsigned maxlen)
+{
+       unsigned sz = 0;
+       struct path_info *pi;
+
+       if (!path)
+               DMEMIT("0 ");
+       else {
+               pi = path->pscontext;
+
+               switch (type) {
+               case STATUSTYPE_INFO:
+                       DMEMIT("%d %u ", atomic_read(&pi->in_flight_size),
+                              pi->relative_throughput);
+                       break;
+               case STATUSTYPE_TABLE:
+                       DMEMIT("%u %u ", pi->repeat_count,
+                              pi->relative_throughput);
+                       break;
+               }
+       }
+
+       return sz;
+}
+
+static int st_add_path(struct path_selector *ps, struct dm_path *path,
+                      int argc, char **argv, char **error)
+{
+       struct selector *s = ps->context;
+       struct path_info *pi;
+       unsigned repeat_count = ST_MIN_IO;
+       unsigned relative_throughput = 1;
+
+       /*
+        * Arguments: [<repeat_count> [<relative_throughput>]]
+        *      <repeat_count>: The number of I/Os before switching path.
+        *                      If not given, default (ST_MIN_IO) is used.
+        *      <relative_throughput>: The relative throughput value of
+        *                      the path among all paths in the path-group.
+        *                      The valid range: 0-<ST_MAX_RELATIVE_THROUGHPUT>
+        *                      If not given, minimum value '1' is used.
+        *                      If '0' is given, the path isn't selected while
+        *                      other paths having a positive value are
+        *                      available.
+        */
+       if (argc > 2) {
+               *error = "service-time ps: incorrect number of arguments";
+               return -EINVAL;
+       }
+
+       if (argc && (sscanf(argv[0], "%u", &repeat_count) != 1)) {
+               *error = "service-time ps: invalid repeat count";
+               return -EINVAL;
+       }
+
+       if ((argc == 2) &&
+           (sscanf(argv[1], "%u", &relative_throughput) != 1 ||
+            relative_throughput > ST_MAX_RELATIVE_THROUGHPUT)) {
+               *error = "service-time ps: invalid relative_throughput value";
+               return -EINVAL;
+       }
+
+       /* allocate the path */
+       pi = kmalloc(sizeof(*pi), GFP_KERNEL);
+       if (!pi) {
+               *error = "service-time ps: Error allocating path context";
+               return -ENOMEM;
+       }
+
+       pi->path = path;
+       pi->repeat_count = repeat_count;
+       pi->relative_throughput = relative_throughput;
+       atomic_set(&pi->in_flight_size, 0);
+
+       path->pscontext = pi;
+
+       list_add_tail(&pi->list, &s->valid_paths);
+
+       return 0;
+}
+
+static void st_fail_path(struct path_selector *ps, struct dm_path *path)
+{
+       struct selector *s = ps->context;
+       struct path_info *pi = path->pscontext;
+
+       list_move(&pi->list, &s->failed_paths);
+}
+
+static int st_reinstate_path(struct path_selector *ps, struct dm_path *path)
+{
+       struct selector *s = ps->context;
+       struct path_info *pi = path->pscontext;
+
+       list_move_tail(&pi->list, &s->valid_paths);
+
+       return 0;
+}
+
+/*
+ * Compare the estimated service time of 2 paths, pi1 and pi2,
+ * for the incoming I/O.
+ *
+ * Returns:
+ * < 0 : pi1 is better
+ * 0   : no difference between pi1 and pi2
+ * > 0 : pi2 is better
+ *
+ * Description:
+ * Basically, the service time is estimated by:
+ *     ('pi->in-flight-size' + 'incoming') / 'pi->relative_throughput'
+ * To reduce the calculation, some optimizations are made.
+ * (See comments inline)
+ */
+static int st_compare_load(struct path_info *pi1, struct path_info *pi2,
+                          size_t incoming)
+{
+       size_t sz1, sz2, st1, st2;
+
+       sz1 = atomic_read(&pi1->in_flight_size);
+       sz2 = atomic_read(&pi2->in_flight_size);
+
+       /*
+        * Case 1: Both have same throughput value. Choose less loaded path.
+        */
+       if (pi1->relative_throughput == pi2->relative_throughput)
+               return sz1 - sz2;
+
+       /*
+        * Case 2a: Both have same load. Choose higher throughput path.
+        * Case 2b: One path has no throughput value. Choose the other one.
+        */
+       if (sz1 == sz2 ||
+           !pi1->relative_throughput || !pi2->relative_throughput)
+               return pi2->relative_throughput - pi1->relative_throughput;
+
+       /*
+        * Case 3: Calculate service time. Choose faster path.
+        *         Service time using pi1:
+        *             st1 = (sz1 + incoming) / pi1->relative_throughput
+        *         Service time using pi2:
+        *             st2 = (sz2 + incoming) / pi2->relative_throughput
+        *
+        *         To avoid the division, transform the expression to use
+        *         multiplication.
+        *         Because ->relative_throughput > 0 here, if st1 < st2,
+        *         the expressions below are the same meaning:
+        *             (sz1 + incoming) / pi1->relative_throughput <
+        *                 (sz2 + incoming) / pi2->relative_throughput
+        *             (sz1 + incoming) * pi2->relative_throughput <
+        *                 (sz2 + incoming) * pi1->relative_throughput
+        *         So use the later one.
+        */
+       sz1 += incoming;
+       sz2 += incoming;
+       if (unlikely(sz1 >= ST_MAX_INFLIGHT_SIZE ||
+                    sz2 >= ST_MAX_INFLIGHT_SIZE)) {
+               /*
+                * Size may be too big for multiplying pi->relative_throughput
+                * and overflow.
+                * To avoid the overflow and mis-selection, shift down both.
+                */
+               sz1 >>= ST_MAX_RELATIVE_THROUGHPUT_SHIFT;
+               sz2 >>= ST_MAX_RELATIVE_THROUGHPUT_SHIFT;
+       }
+       st1 = sz1 * pi2->relative_throughput;
+       st2 = sz2 * pi1->relative_throughput;
+       if (st1 != st2)
+               return st1 - st2;
+
+       /*
+        * Case 4: Service time is equal. Choose higher throughput path.
+        */
+       return pi2->relative_throughput - pi1->relative_throughput;
+}
+
+static struct dm_path *st_select_path(struct path_selector *ps,
+                                     unsigned *repeat_count, size_t nr_bytes)
+{
+       struct selector *s = ps->context;
+       struct path_info *pi = NULL, *best = NULL;
+
+       if (list_empty(&s->valid_paths))
+               return NULL;
+
+       /* Change preferred (first in list) path to evenly balance. */
+       list_move_tail(s->valid_paths.next, &s->valid_paths);
+
+       list_for_each_entry(pi, &s->valid_paths, list)
+               if (!best || (st_compare_load(pi, best, nr_bytes) < 0))
+                       best = pi;
+
+       if (!best)
+               return NULL;
+
+       *repeat_count = best->repeat_count;
+
+       return best->path;
+}
+
+static int st_start_io(struct path_selector *ps, struct dm_path *path,
+                      size_t nr_bytes)
+{
+       struct path_info *pi = path->pscontext;
+
+       atomic_add(nr_bytes, &pi->in_flight_size);
+
+       return 0;
+}
+
+static int st_end_io(struct path_selector *ps, struct dm_path *path,
+                    size_t nr_bytes)
+{
+       struct path_info *pi = path->pscontext;
+
+       atomic_sub(nr_bytes, &pi->in_flight_size);
+
+       return 0;
+}
+
+static struct path_selector_type st_ps = {
+       .name           = "service-time",
+       .module         = THIS_MODULE,
+       .table_args     = 2,
+       .info_args      = 2,
+       .create         = st_create,
+       .destroy        = st_destroy,
+       .status         = st_status,
+       .add_path       = st_add_path,
+       .fail_path      = st_fail_path,
+       .reinstate_path = st_reinstate_path,
+       .select_path    = st_select_path,
+       .start_io       = st_start_io,
+       .end_io         = st_end_io,
+};
+
+static int __init dm_st_init(void)
+{
+       int r = dm_register_path_selector(&st_ps);
+
+       if (r < 0)
+               DMERR("register failed %d", r);
+
+       DMINFO("version " ST_VERSION " loaded");
+
+       return r;
+}
+
+static void __exit dm_st_exit(void)
+{
+       int r = dm_unregister_path_selector(&st_ps);
+
+       if (r < 0)
+               DMERR("unregister failed %d", r);
+}
+
+module_init(dm_st_init);
+module_exit(dm_st_exit);
+
+MODULE_DESCRIPTION(DM_NAME " throughput oriented path selector");
+MODULE_AUTHOR("Kiyoshi Ueda <k-ueda@ct.jp.nec.com>");
+MODULE_LICENSE("GPL");
index 2662a41337e7813b370df2d61dbfc70e964e066a..6e3fe4f14934811ddd0f9bba845ebdd4bb504036 100644 (file)
@@ -636,7 +636,7 @@ static void persistent_commit_exception(struct dm_exception_store *store,
        /*
         * Commit exceptions to disk.
         */
-       if (ps->valid && area_io(ps, WRITE))
+       if (ps->valid && area_io(ps, WRITE_BARRIER))
                ps->valid = 0;
 
        /*
index d73f17fc777823968e4ab93d5a65dc30255233fc..d573165cd2b788968f7d274e03966b96c93da889 100644 (file)
@@ -678,6 +678,7 @@ static int snapshot_ctr(struct dm_target *ti, unsigned int argc, char **argv)
 
        ti->private = s;
        ti->split_io = s->store->chunk_size;
+       ti->num_flush_requests = 1;
 
        return 0;
 
@@ -1030,6 +1031,11 @@ static int snapshot_map(struct dm_target *ti, struct bio *bio,
        chunk_t chunk;
        struct dm_snap_pending_exception *pe = NULL;
 
+       if (unlikely(bio_empty_barrier(bio))) {
+               bio->bi_bdev = s->store->cow->bdev;
+               return DM_MAPIO_REMAPPED;
+       }
+
        chunk = sector_to_chunk(s->store, bio->bi_sector);
 
        /* Full snapshots are not usable */
@@ -1338,6 +1344,8 @@ static int origin_ctr(struct dm_target *ti, unsigned int argc, char **argv)
        }
 
        ti->private = dev;
+       ti->num_flush_requests = 1;
+
        return 0;
 }
 
@@ -1353,6 +1361,9 @@ static int origin_map(struct dm_target *ti, struct bio *bio,
        struct dm_dev *dev = ti->private;
        bio->bi_bdev = dev->bdev;
 
+       if (unlikely(bio_empty_barrier(bio)))
+               return DM_MAPIO_REMAPPED;
+
        /* Only tell snapshots if this is a write */
        return (bio_rw(bio) == WRITE) ? do_origin(dev, bio) : DM_MAPIO_REMAPPED;
 }
index 41569bc60abc9dfe2d8986beba23099ffd068d31..b240e85ae39aa4b444135b0a71823e35b03aac49 100644 (file)
@@ -167,6 +167,7 @@ static int stripe_ctr(struct dm_target *ti, unsigned int argc, char **argv)
        sc->stripes = stripes;
        sc->stripe_width = width;
        ti->split_io = chunk_size;
+       ti->num_flush_requests = stripes;
 
        sc->chunk_mask = ((sector_t) chunk_size) - 1;
        for (sc->chunk_shift = 0; chunk_size; sc->chunk_shift++)
@@ -211,10 +212,18 @@ static int stripe_map(struct dm_target *ti, struct bio *bio,
                      union map_info *map_context)
 {
        struct stripe_c *sc = (struct stripe_c *) ti->private;
+       sector_t offset, chunk;
+       uint32_t stripe;
 
-       sector_t offset = bio->bi_sector - ti->begin;
-       sector_t chunk = offset >> sc->chunk_shift;
-       uint32_t stripe = sector_div(chunk, sc->stripes);
+       if (unlikely(bio_empty_barrier(bio))) {
+               BUG_ON(map_context->flush_request >= sc->stripes);
+               bio->bi_bdev = sc->stripe[map_context->flush_request].dev->bdev;
+               return DM_MAPIO_REMAPPED;
+       }
+
+       offset = bio->bi_sector - ti->begin;
+       chunk = offset >> sc->chunk_shift;
+       stripe = sector_div(chunk, sc->stripes);
 
        bio->bi_bdev = sc->stripe[stripe].dev->bdev;
        bio->bi_sector = sc->stripe[stripe].physical_start +
@@ -304,15 +313,31 @@ static int stripe_end_io(struct dm_target *ti, struct bio *bio,
        return error;
 }
 
+static int stripe_iterate_devices(struct dm_target *ti,
+                                 iterate_devices_callout_fn fn, void *data)
+{
+       struct stripe_c *sc = ti->private;
+       int ret = 0;
+       unsigned i = 0;
+
+       do
+               ret = fn(ti, sc->stripe[i].dev,
+                        sc->stripe[i].physical_start, data);
+       while (!ret && ++i < sc->stripes);
+
+       return ret;
+}
+
 static struct target_type stripe_target = {
        .name   = "striped",
-       .version = {1, 1, 0},
+       .version = {1, 2, 0},
        .module = THIS_MODULE,
        .ctr    = stripe_ctr,
        .dtr    = stripe_dtr,
        .map    = stripe_map,
        .end_io = stripe_end_io,
        .status = stripe_status,
+       .iterate_devices = stripe_iterate_devices,
 };
 
 int __init dm_stripe_init(void)
index a2a45e6c7c8bb540fc0b3d28ab8c2795cca00c8c..4b045903a4e21e6ce6e0c06593c7ed7e867a13b1 100644 (file)
@@ -57,12 +57,21 @@ static ssize_t dm_attr_uuid_show(struct mapped_device *md, char *buf)
        return strlen(buf);
 }
 
+static ssize_t dm_attr_suspended_show(struct mapped_device *md, char *buf)
+{
+       sprintf(buf, "%d\n", dm_suspended(md));
+
+       return strlen(buf);
+}
+
 static DM_ATTR_RO(name);
 static DM_ATTR_RO(uuid);
+static DM_ATTR_RO(suspended);
 
 static struct attribute *dm_attrs[] = {
        &dm_attr_name.attr,
        &dm_attr_uuid.attr,
+       &dm_attr_suspended.attr,
        NULL,
 };
 
index e9a73bb242b0935eefae2ce0744ed97965a2143d..2cba557d9e61e10dad844dea12f134b4a4ee0d11 100644 (file)
@@ -41,6 +41,7 @@
 struct dm_table {
        struct mapped_device *md;
        atomic_t holders;
+       unsigned type;
 
        /* btree table */
        unsigned int depth;
@@ -62,15 +63,11 @@ struct dm_table {
        /* a list of devices used by this table */
        struct list_head devices;
 
-       /*
-        * These are optimistic limits taken from all the
-        * targets, some targets will need smaller limits.
-        */
-       struct io_restrictions limits;
-
        /* events get handed up using this callback */
        void (*event_fn)(void *);
        void *event_context;
+
+       struct dm_md_mempools *mempools;
 };
 
 /*
@@ -88,43 +85,6 @@ static unsigned int int_log(unsigned int n, unsigned int base)
        return result;
 }
 
-/*
- * Returns the minimum that is _not_ zero, unless both are zero.
- */
-#define min_not_zero(l, r) (l == 0) ? r : ((r == 0) ? l : min(l, r))
-
-/*
- * Combine two io_restrictions, always taking the lower value.
- */
-static void combine_restrictions_low(struct io_restrictions *lhs,
-                                    struct io_restrictions *rhs)
-{
-       lhs->max_sectors =
-               min_not_zero(lhs->max_sectors, rhs->max_sectors);
-
-       lhs->max_phys_segments =
-               min_not_zero(lhs->max_phys_segments, rhs->max_phys_segments);
-
-       lhs->max_hw_segments =
-               min_not_zero(lhs->max_hw_segments, rhs->max_hw_segments);
-
-       lhs->logical_block_size = max(lhs->logical_block_size,
-                                     rhs->logical_block_size);
-
-       lhs->max_segment_size =
-               min_not_zero(lhs->max_segment_size, rhs->max_segment_size);
-
-       lhs->max_hw_sectors =
-               min_not_zero(lhs->max_hw_sectors, rhs->max_hw_sectors);
-
-       lhs->seg_boundary_mask =
-               min_not_zero(lhs->seg_boundary_mask, rhs->seg_boundary_mask);
-
-       lhs->bounce_pfn = min_not_zero(lhs->bounce_pfn, rhs->bounce_pfn);
-
-       lhs->no_cluster |= rhs->no_cluster;
-}
-
 /*
  * Calculate the index of the child node of the n'th node k'th key.
  */
@@ -267,6 +227,8 @@ static void free_devices(struct list_head *devices)
        list_for_each_safe(tmp, next, devices) {
                struct dm_dev_internal *dd =
                    list_entry(tmp, struct dm_dev_internal, list);
+               DMWARN("dm_table_destroy: dm_put_device call missing for %s",
+                      dd->dm_dev.name);
                kfree(dd);
        }
 }
@@ -296,12 +258,10 @@ void dm_table_destroy(struct dm_table *t)
        vfree(t->highs);
 
        /* free the device list */
-       if (t->devices.next != &t->devices) {
-               DMWARN("devices still present during destroy: "
-                      "dm_table_remove_device calls missing");
-
+       if (t->devices.next != &t->devices)
                free_devices(&t->devices);
-       }
+
+       dm_free_md_mempools(t->mempools);
 
        kfree(t);
 }
@@ -385,15 +345,48 @@ static void close_dev(struct dm_dev_internal *d, struct mapped_device *md)
 /*
  * If possible, this checks an area of a destination device is valid.
  */
-static int check_device_area(struct dm_dev_internal *dd, sector_t start,
-                            sector_t len)
+static int device_area_is_valid(struct dm_target *ti, struct dm_dev *dev,
+                               sector_t start, void *data)
 {
-       sector_t dev_size = dd->dm_dev.bdev->bd_inode->i_size >> SECTOR_SHIFT;
+       struct queue_limits *limits = data;
+       struct block_device *bdev = dev->bdev;
+       sector_t dev_size =
+               i_size_read(bdev->bd_inode) >> SECTOR_SHIFT;
+       unsigned short logical_block_size_sectors =
+               limits->logical_block_size >> SECTOR_SHIFT;
+       char b[BDEVNAME_SIZE];
 
        if (!dev_size)
                return 1;
 
-       return ((start < dev_size) && (len <= (dev_size - start)));
+       if ((start >= dev_size) || (start + ti->len > dev_size)) {
+               DMWARN("%s: %s too small for target",
+                      dm_device_name(ti->table->md), bdevname(bdev, b));
+               return 0;
+       }
+
+       if (logical_block_size_sectors <= 1)
+               return 1;
+
+       if (start & (logical_block_size_sectors - 1)) {
+               DMWARN("%s: start=%llu not aligned to h/w "
+                      "logical block size %hu of %s",
+                      dm_device_name(ti->table->md),
+                      (unsigned long long)start,
+                      limits->logical_block_size, bdevname(bdev, b));
+               return 0;
+       }
+
+       if (ti->len & (logical_block_size_sectors - 1)) {
+               DMWARN("%s: len=%llu not aligned to h/w "
+                      "logical block size %hu of %s",
+                      dm_device_name(ti->table->md),
+                      (unsigned long long)ti->len,
+                      limits->logical_block_size, bdevname(bdev, b));
+               return 0;
+       }
+
+       return 1;
 }
 
 /*
@@ -479,38 +472,32 @@ static int __table_get_device(struct dm_table *t, struct dm_target *ti,
        }
        atomic_inc(&dd->count);
 
-       if (!check_device_area(dd, start, len)) {
-               DMWARN("device %s too small for target", path);
-               dm_put_device(ti, &dd->dm_dev);
-               return -EINVAL;
-       }
-
        *result = &dd->dm_dev;
-
        return 0;
 }
 
-void dm_set_device_limits(struct dm_target *ti, struct block_device *bdev)
+/*
+ * Returns the minimum that is _not_ zero, unless both are zero.
+ */
+#define min_not_zero(l, r) (l == 0) ? r : ((r == 0) ? l : min(l, r))
+
+int dm_set_device_limits(struct dm_target *ti, struct dm_dev *dev,
+                        sector_t start, void *data)
 {
+       struct queue_limits *limits = data;
+       struct block_device *bdev = dev->bdev;
        struct request_queue *q = bdev_get_queue(bdev);
-       struct io_restrictions *rs = &ti->limits;
        char b[BDEVNAME_SIZE];
 
        if (unlikely(!q)) {
                DMWARN("%s: Cannot set limits for nonexistent device %s",
                       dm_device_name(ti->table->md), bdevname(bdev, b));
-               return;
+               return 0;
        }
 
-       /*
-        * Combine the device limits low.
-        *
-        * FIXME: if we move an io_restriction struct
-        *        into q this would just be a call to
-        *        combine_restrictions_low()
-        */
-       rs->max_sectors =
-               min_not_zero(rs->max_sectors, queue_max_sectors(q));
+       if (blk_stack_limits(limits, &q->limits, start << 9) < 0)
+               DMWARN("%s: target device %s is misaligned",
+                      dm_device_name(ti->table->md), bdevname(bdev, b));
 
        /*
         * Check if merge fn is supported.
@@ -519,48 +506,21 @@ void dm_set_device_limits(struct dm_target *ti, struct block_device *bdev)
         */
 
        if (q->merge_bvec_fn && !ti->type->merge)
-               rs->max_sectors =
-                       min_not_zero(rs->max_sectors,
+               limits->max_sectors =
+                       min_not_zero(limits->max_sectors,
                                     (unsigned int) (PAGE_SIZE >> 9));
-
-       rs->max_phys_segments =
-               min_not_zero(rs->max_phys_segments,
-                            queue_max_phys_segments(q));
-
-       rs->max_hw_segments =
-               min_not_zero(rs->max_hw_segments, queue_max_hw_segments(q));
-
-       rs->logical_block_size = max(rs->logical_block_size,
-                                    queue_logical_block_size(q));
-
-       rs->max_segment_size =
-               min_not_zero(rs->max_segment_size, queue_max_segment_size(q));
-
-       rs->max_hw_sectors =
-               min_not_zero(rs->max_hw_sectors, queue_max_hw_sectors(q));
-
-       rs->seg_boundary_mask =
-               min_not_zero(rs->seg_boundary_mask,
-                            queue_segment_boundary(q));
-
-       rs->bounce_pfn = min_not_zero(rs->bounce_pfn, queue_bounce_pfn(q));
-
-       rs->no_cluster |= !test_bit(QUEUE_FLAG_CLUSTER, &q->queue_flags);
+       return 0;
 }
 EXPORT_SYMBOL_GPL(dm_set_device_limits);
 
 int dm_get_device(struct dm_target *ti, const char *path, sector_t start,
                  sector_t len, fmode_t mode, struct dm_dev **result)
 {
-       int r = __table_get_device(ti->table, ti, path,
-                                  start, len, mode, result);
-
-       if (!r)
-               dm_set_device_limits(ti, (*result)->bdev);
-
-       return r;
+       return __table_get_device(ti->table, ti, path,
+                                 start, len, mode, result);
 }
 
+
 /*
  * Decrement a devices use count and remove it if necessary.
  */
@@ -675,24 +635,78 @@ int dm_split_args(int *argc, char ***argvp, char *input)
        return 0;
 }
 
-static void check_for_valid_limits(struct io_restrictions *rs)
+/*
+ * Impose necessary and sufficient conditions on a devices's table such
+ * that any incoming bio which respects its logical_block_size can be
+ * processed successfully.  If it falls across the boundary between
+ * two or more targets, the size of each piece it gets split into must
+ * be compatible with the logical_block_size of the target processing it.
+ */
+static int validate_hardware_logical_block_alignment(struct dm_table *table,
+                                                struct queue_limits *limits)
 {
-       if (!rs->max_sectors)
-               rs->max_sectors = SAFE_MAX_SECTORS;
-       if (!rs->max_hw_sectors)
-               rs->max_hw_sectors = SAFE_MAX_SECTORS;
-       if (!rs->max_phys_segments)
-               rs->max_phys_segments = MAX_PHYS_SEGMENTS;
-       if (!rs->max_hw_segments)
-               rs->max_hw_segments = MAX_HW_SEGMENTS;
-       if (!rs->logical_block_size)
-               rs->logical_block_size = 1 << SECTOR_SHIFT;
-       if (!rs->max_segment_size)
-               rs->max_segment_size = MAX_SEGMENT_SIZE;
-       if (!rs->seg_boundary_mask)
-               rs->seg_boundary_mask = BLK_SEG_BOUNDARY_MASK;
-       if (!rs->bounce_pfn)
-               rs->bounce_pfn = -1;
+       /*
+        * This function uses arithmetic modulo the logical_block_size
+        * (in units of 512-byte sectors).
+        */
+       unsigned short device_logical_block_size_sects =
+               limits->logical_block_size >> SECTOR_SHIFT;
+
+       /*
+        * Offset of the start of the next table entry, mod logical_block_size.
+        */
+       unsigned short next_target_start = 0;
+
+       /*
+        * Given an aligned bio that extends beyond the end of a
+        * target, how many sectors must the next target handle?
+        */
+       unsigned short remaining = 0;
+
+       struct dm_target *uninitialized_var(ti);
+       struct queue_limits ti_limits;
+       unsigned i = 0;
+
+       /*
+        * Check each entry in the table in turn.
+        */
+       while (i < dm_table_get_num_targets(table)) {
+               ti = dm_table_get_target(table, i++);
+
+               blk_set_default_limits(&ti_limits);
+
+               /* combine all target devices' limits */
+               if (ti->type->iterate_devices)
+                       ti->type->iterate_devices(ti, dm_set_device_limits,
+                                                 &ti_limits);
+
+               /*
+                * If the remaining sectors fall entirely within this
+                * table entry are they compatible with its logical_block_size?
+                */
+               if (remaining < ti->len &&
+                   remaining & ((ti_limits.logical_block_size >>
+                                 SECTOR_SHIFT) - 1))
+                       break;  /* Error */
+
+               next_target_start =
+                   (unsigned short) ((next_target_start + ti->len) &
+                                     (device_logical_block_size_sects - 1));
+               remaining = next_target_start ?
+                   device_logical_block_size_sects - next_target_start : 0;
+       }
+
+       if (remaining) {
+               DMWARN("%s: table line %u (start sect %llu len %llu) "
+                      "not aligned to h/w logical block size %hu",
+                      dm_device_name(table->md), i,
+                      (unsigned long long) ti->begin,
+                      (unsigned long long) ti->len,
+                      limits->logical_block_size);
+               return -EINVAL;
+       }
+
+       return 0;
 }
 
 int dm_table_add_target(struct dm_table *t, const char *type,
@@ -747,9 +761,6 @@ int dm_table_add_target(struct dm_table *t, const char *type,
 
        t->highs[t->num_targets++] = tgt->begin + tgt->len - 1;
 
-       /* FIXME: the plan is to combine high here and then have
-        * the merge fn apply the target level restrictions. */
-       combine_restrictions_low(&t->limits, &tgt->limits);
        return 0;
 
  bad:
@@ -758,6 +769,104 @@ int dm_table_add_target(struct dm_table *t, const char *type,
        return r;
 }
 
+int dm_table_set_type(struct dm_table *t)
+{
+       unsigned i;
+       unsigned bio_based = 0, request_based = 0;
+       struct dm_target *tgt;
+       struct dm_dev_internal *dd;
+       struct list_head *devices;
+
+       for (i = 0; i < t->num_targets; i++) {
+               tgt = t->targets + i;
+               if (dm_target_request_based(tgt))
+                       request_based = 1;
+               else
+                       bio_based = 1;
+
+               if (bio_based && request_based) {
+                       DMWARN("Inconsistent table: different target types"
+                              " can't be mixed up");
+                       return -EINVAL;
+               }
+       }
+
+       if (bio_based) {
+               /* We must use this table as bio-based */
+               t->type = DM_TYPE_BIO_BASED;
+               return 0;
+       }
+
+       BUG_ON(!request_based); /* No targets in this table */
+
+       /* Non-request-stackable devices can't be used for request-based dm */
+       devices = dm_table_get_devices(t);
+       list_for_each_entry(dd, devices, list) {
+               if (!blk_queue_stackable(bdev_get_queue(dd->dm_dev.bdev))) {
+                       DMWARN("table load rejected: including"
+                              " non-request-stackable devices");
+                       return -EINVAL;
+               }
+       }
+
+       /*
+        * Request-based dm supports only tables that have a single target now.
+        * To support multiple targets, request splitting support is needed,
+        * and that needs lots of changes in the block-layer.
+        * (e.g. request completion process for partial completion.)
+        */
+       if (t->num_targets > 1) {
+               DMWARN("Request-based dm doesn't support multiple targets yet");
+               return -EINVAL;
+       }
+
+       t->type = DM_TYPE_REQUEST_BASED;
+
+       return 0;
+}
+
+unsigned dm_table_get_type(struct dm_table *t)
+{
+       return t->type;
+}
+
+bool dm_table_bio_based(struct dm_table *t)
+{
+       return dm_table_get_type(t) == DM_TYPE_BIO_BASED;
+}
+
+bool dm_table_request_based(struct dm_table *t)
+{
+       return dm_table_get_type(t) == DM_TYPE_REQUEST_BASED;
+}
+
+int dm_table_alloc_md_mempools(struct dm_table *t)
+{
+       unsigned type = dm_table_get_type(t);
+
+       if (unlikely(type == DM_TYPE_NONE)) {
+               DMWARN("no table type is set, can't allocate mempools");
+               return -EINVAL;
+       }
+
+       t->mempools = dm_alloc_md_mempools(type);
+       if (!t->mempools)
+               return -ENOMEM;
+
+       return 0;
+}
+
+void dm_table_free_md_mempools(struct dm_table *t)
+{
+       dm_free_md_mempools(t->mempools);
+       t->mempools = NULL;
+}
+
+struct dm_md_mempools *dm_table_get_md_mempools(struct dm_table *t)
+{
+       return t->mempools;
+}
+
 static int setup_indexes(struct dm_table *t)
 {
        int i;
@@ -792,8 +901,6 @@ int dm_table_complete(struct dm_table *t)
        int r = 0;
        unsigned int leaf_nodes;
 
-       check_for_valid_limits(&t->limits);
-
        /* how many indexes will the btree have ? */
        leaf_nodes = dm_div_up(t->num_targets, KEYS_PER_NODE);
        t->depth = 1 + int_log(leaf_nodes, CHILDREN_PER_NODE);
@@ -868,6 +975,57 @@ struct dm_target *dm_table_find_target(struct dm_table *t, sector_t sector)
        return &t->targets[(KEYS_PER_NODE * n) + k];
 }
 
+/*
+ * Establish the new table's queue_limits and validate them.
+ */
+int dm_calculate_queue_limits(struct dm_table *table,
+                             struct queue_limits *limits)
+{
+       struct dm_target *uninitialized_var(ti);
+       struct queue_limits ti_limits;
+       unsigned i = 0;
+
+       blk_set_default_limits(limits);
+
+       while (i < dm_table_get_num_targets(table)) {
+               blk_set_default_limits(&ti_limits);
+
+               ti = dm_table_get_target(table, i++);
+
+               if (!ti->type->iterate_devices)
+                       goto combine_limits;
+
+               /*
+                * Combine queue limits of all the devices this target uses.
+                */
+               ti->type->iterate_devices(ti, dm_set_device_limits,
+                                         &ti_limits);
+
+               /*
+                * Check each device area is consistent with the target's
+                * overall queue limits.
+                */
+               if (!ti->type->iterate_devices(ti, device_area_is_valid,
+                                              &ti_limits))
+                       return -EINVAL;
+
+combine_limits:
+               /*
+                * Merge this target's queue limits into the overall limits
+                * for the table.
+                */
+               if (blk_stack_limits(limits, &ti_limits, 0) < 0)
+                       DMWARN("%s: target device "
+                              "(start sect %llu len %llu) "
+                              "is misaligned",
+                              dm_device_name(table->md),
+                              (unsigned long long) ti->begin,
+                              (unsigned long long) ti->len);
+       }
+
+       return validate_hardware_logical_block_alignment(table, limits);
+}
+
 /*
  * Set the integrity profile for this device if all devices used have
  * matching profiles.
@@ -907,27 +1065,42 @@ no_integrity:
        return;
 }
 
-void dm_table_set_restrictions(struct dm_table *t, struct request_queue *q)
+void dm_table_set_restrictions(struct dm_table *t, struct request_queue *q,
+                              struct queue_limits *limits)
 {
        /*
-        * Make sure we obey the optimistic sub devices
-        * restrictions.
+        * Each target device in the table has a data area that should normally
+        * be aligned such that the DM device's alignment_offset is 0.
+        * FIXME: Propagate alignment_offsets up the stack and warn of
+        *        sub-optimal or inconsistent settings.
+        */
+       limits->alignment_offset = 0;
+       limits->misaligned = 0;
+
+       /*
+        * Copy table's limits to the DM device's request_queue
         */
-       blk_queue_max_sectors(q, t->limits.max_sectors);
-       blk_queue_max_phys_segments(q, t->limits.max_phys_segments);
-       blk_queue_max_hw_segments(q, t->limits.max_hw_segments);
-       blk_queue_logical_block_size(q, t->limits.logical_block_size);
-       blk_queue_max_segment_size(q, t->limits.max_segment_size);
-       blk_queue_max_hw_sectors(q, t->limits.max_hw_sectors);
-       blk_queue_segment_boundary(q, t->limits.seg_boundary_mask);
-       blk_queue_bounce_limit(q, t->limits.bounce_pfn);
-
-       if (t->limits.no_cluster)
+       q->limits = *limits;
+
+       if (limits->no_cluster)
                queue_flag_clear_unlocked(QUEUE_FLAG_CLUSTER, q);
        else
                queue_flag_set_unlocked(QUEUE_FLAG_CLUSTER, q);
 
        dm_table_set_integrity(t);
+
+       /*
+        * QUEUE_FLAG_STACKABLE must be set after all queue settings are
+        * visible to other CPUs because, once the flag is set, incoming bios
+        * are processed by request-based dm, which refers to the queue
+        * settings.
+        * Until the flag set, bios are passed to bio-based dm and queued to
+        * md->deferred where queue settings are not needed yet.
+        * Those bios are passed to request-based dm at the resume time.
+        */
+       smp_mb();
+       if (dm_table_request_based(t))
+               queue_flag_set_unlocked(QUEUE_FLAG_STACKABLE, q);
 }
 
 unsigned int dm_table_get_num_targets(struct dm_table *t)
@@ -1023,6 +1196,20 @@ int dm_table_any_congested(struct dm_table *t, int bdi_bits)
        return r;
 }
 
+int dm_table_any_busy_target(struct dm_table *t)
+{
+       unsigned i;
+       struct dm_target *ti;
+
+       for (i = 0; i < t->num_targets; i++) {
+               ti = t->targets + i;
+               if (ti->type->busy && ti->type->busy(ti))
+                       return 1;
+       }
+
+       return 0;
+}
+
 void dm_table_unplug_all(struct dm_table *t)
 {
        struct dm_dev_internal *dd;
index 48db308fae67103b221eeb1c10e4411560b88135..9acd54a5cffb3b875c699332c0bfaf597be3d19a 100644 (file)
 
 #define DM_MSG_PREFIX "core"
 
+/*
+ * Cookies are numeric values sent with CHANGE and REMOVE
+ * uevents while resuming, removing or renaming the device.
+ */
+#define DM_COOKIE_ENV_VAR_NAME "DM_COOKIE"
+#define DM_COOKIE_LENGTH 24
+
 static const char *_name = DM_NAME;
 
 static unsigned int major = 0;
@@ -71,7 +78,7 @@ struct dm_rq_target_io {
  */
 struct dm_rq_clone_bio_info {
        struct bio *orig;
-       struct request *rq;
+       struct dm_rq_target_io *tio;
 };
 
 union map_info *dm_get_mapinfo(struct bio *bio)
@@ -81,6 +88,14 @@ union map_info *dm_get_mapinfo(struct bio *bio)
        return NULL;
 }
 
+union map_info *dm_get_rq_mapinfo(struct request *rq)
+{
+       if (rq && rq->end_io_data)
+               return &((struct dm_rq_target_io *)rq->end_io_data)->info;
+       return NULL;
+}
+EXPORT_SYMBOL_GPL(dm_get_rq_mapinfo);
+
 #define MINOR_ALLOCED ((void *)-1)
 
 /*
@@ -157,13 +172,31 @@ struct mapped_device {
         * freeze/thaw support require holding onto a super block
         */
        struct super_block *frozen_sb;
-       struct block_device *suspended_bdev;
+       struct block_device *bdev;
 
        /* forced geometry settings */
        struct hd_geometry geometry;
 
+       /* marker of flush suspend for request-based dm */
+       struct request suspend_rq;
+
+       /* For saving the address of __make_request for request based dm */
+       make_request_fn *saved_make_request_fn;
+
        /* sysfs handle */
        struct kobject kobj;
+
+       /* zero-length barrier that will be cloned and submitted to targets */
+       struct bio barrier_bio;
+};
+
+/*
+ * For mempools pre-allocation at the table loading time.
+ */
+struct dm_md_mempools {
+       mempool_t *io_pool;
+       mempool_t *tio_pool;
+       struct bio_set *bs;
 };
 
 #define MIN_IOS 256
@@ -391,14 +424,29 @@ static void free_io(struct mapped_device *md, struct dm_io *io)
        mempool_free(io, md->io_pool);
 }
 
-static struct dm_target_io *alloc_tio(struct mapped_device *md)
+static void free_tio(struct mapped_device *md, struct dm_target_io *tio)
 {
-       return mempool_alloc(md->tio_pool, GFP_NOIO);
+       mempool_free(tio, md->tio_pool);
 }
 
-static void free_tio(struct mapped_device *md, struct dm_target_io *tio)
+static struct dm_rq_target_io *alloc_rq_tio(struct mapped_device *md)
 {
-       mempool_free(tio, md->tio_pool);
+       return mempool_alloc(md->tio_pool, GFP_ATOMIC);
+}
+
+static void free_rq_tio(struct dm_rq_target_io *tio)
+{
+       mempool_free(tio, tio->md->tio_pool);
+}
+
+static struct dm_rq_clone_bio_info *alloc_bio_info(struct mapped_device *md)
+{
+       return mempool_alloc(md->io_pool, GFP_ATOMIC);
+}
+
+static void free_bio_info(struct dm_rq_clone_bio_info *info)
+{
+       mempool_free(info, info->tio->md->io_pool);
 }
 
 static void start_io_acct(struct dm_io *io)
@@ -464,12 +512,13 @@ static void queue_io(struct mapped_device *md, struct bio *bio)
 struct dm_table *dm_get_table(struct mapped_device *md)
 {
        struct dm_table *t;
+       unsigned long flags;
 
-       read_lock(&md->map_lock);
+       read_lock_irqsave(&md->map_lock, flags);
        t = md->map;
        if (t)
                dm_table_get(t);
-       read_unlock(&md->map_lock);
+       read_unlock_irqrestore(&md->map_lock, flags);
 
        return t;
 }
@@ -536,9 +585,11 @@ static void dec_pending(struct dm_io *io, int error)
                         * Target requested pushing back the I/O.
                         */
                        spin_lock_irqsave(&md->deferred_lock, flags);
-                       if (__noflush_suspending(md))
-                               bio_list_add_head(&md->deferred, io->bio);
-                       else
+                       if (__noflush_suspending(md)) {
+                               if (!bio_barrier(io->bio))
+                                       bio_list_add_head(&md->deferred,
+                                                         io->bio);
+                       } else
                                /* noflush suspend was interrupted. */
                                io->error = -EIO;
                        spin_unlock_irqrestore(&md->deferred_lock, flags);
@@ -553,7 +604,8 @@ static void dec_pending(struct dm_io *io, int error)
                         * a per-device variable for error reporting.
                         * Note that you can't touch the bio after end_io_acct
                         */
-                       md->barrier_error = io_error;
+                       if (!md->barrier_error && io_error != -EOPNOTSUPP)
+                               md->barrier_error = io_error;
                        end_io_acct(io);
                } else {
                        end_io_acct(io);
@@ -607,6 +659,262 @@ static void clone_endio(struct bio *bio, int error)
        dec_pending(io, error);
 }
 
+/*
+ * Partial completion handling for request-based dm
+ */
+static void end_clone_bio(struct bio *clone, int error)
+{
+       struct dm_rq_clone_bio_info *info = clone->bi_private;
+       struct dm_rq_target_io *tio = info->tio;
+       struct bio *bio = info->orig;
+       unsigned int nr_bytes = info->orig->bi_size;
+
+       bio_put(clone);
+
+       if (tio->error)
+               /*
+                * An error has already been detected on the request.
+                * Once error occurred, just let clone->end_io() handle
+                * the remainder.
+                */
+               return;
+       else if (error) {
+               /*
+                * Don't notice the error to the upper layer yet.
+                * The error handling decision is made by the target driver,
+                * when the request is completed.
+                */
+               tio->error = error;
+               return;
+       }
+
+       /*
+        * I/O for the bio successfully completed.
+        * Notice the data completion to the upper layer.
+        */
+
+       /*
+        * bios are processed from the head of the list.
+        * So the completing bio should always be rq->bio.
+        * If it's not, something wrong is happening.
+        */
+       if (tio->orig->bio != bio)
+               DMERR("bio completion is going in the middle of the request");
+
+       /*
+        * Update the original request.
+        * Do not use blk_end_request() here, because it may complete
+        * the original request before the clone, and break the ordering.
+        */
+       blk_update_request(tio->orig, 0, nr_bytes);
+}
+
+/*
+ * Don't touch any member of the md after calling this function because
+ * the md may be freed in dm_put() at the end of this function.
+ * Or do dm_get() before calling this function and dm_put() later.
+ */
+static void rq_completed(struct mapped_device *md, int run_queue)
+{
+       int wakeup_waiters = 0;
+       struct request_queue *q = md->queue;
+       unsigned long flags;
+
+       spin_lock_irqsave(q->queue_lock, flags);
+       if (!queue_in_flight(q))
+               wakeup_waiters = 1;
+       spin_unlock_irqrestore(q->queue_lock, flags);
+
+       /* nudge anyone waiting on suspend queue */
+       if (wakeup_waiters)
+               wake_up(&md->wait);
+
+       if (run_queue)
+               blk_run_queue(q);
+
+       /*
+        * dm_put() must be at the end of this function. See the comment above
+        */
+       dm_put(md);
+}
+
+static void dm_unprep_request(struct request *rq)
+{
+       struct request *clone = rq->special;
+       struct dm_rq_target_io *tio = clone->end_io_data;
+
+       rq->special = NULL;
+       rq->cmd_flags &= ~REQ_DONTPREP;
+
+       blk_rq_unprep_clone(clone);
+       free_rq_tio(tio);
+}
+
+/*
+ * Requeue the original request of a clone.
+ */
+void dm_requeue_unmapped_request(struct request *clone)
+{
+       struct dm_rq_target_io *tio = clone->end_io_data;
+       struct mapped_device *md = tio->md;
+       struct request *rq = tio->orig;
+       struct request_queue *q = rq->q;
+       unsigned long flags;
+
+       dm_unprep_request(rq);
+
+       spin_lock_irqsave(q->queue_lock, flags);
+       if (elv_queue_empty(q))
+               blk_plug_device(q);
+       blk_requeue_request(q, rq);
+       spin_unlock_irqrestore(q->queue_lock, flags);
+
+       rq_completed(md, 0);
+}
+EXPORT_SYMBOL_GPL(dm_requeue_unmapped_request);
+
+static void __stop_queue(struct request_queue *q)
+{
+       blk_stop_queue(q);
+}
+
+static void stop_queue(struct request_queue *q)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(q->queue_lock, flags);
+       __stop_queue(q);
+       spin_unlock_irqrestore(q->queue_lock, flags);
+}
+
+static void __start_queue(struct request_queue *q)
+{
+       if (blk_queue_stopped(q))
+               blk_start_queue(q);
+}
+
+static void start_queue(struct request_queue *q)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(q->queue_lock, flags);
+       __start_queue(q);
+       spin_unlock_irqrestore(q->queue_lock, flags);
+}
+
+/*
+ * Complete the clone and the original request.
+ * Must be called without queue lock.
+ */
+static void dm_end_request(struct request *clone, int error)
+{
+       struct dm_rq_target_io *tio = clone->end_io_data;
+       struct mapped_device *md = tio->md;
+       struct request *rq = tio->orig;
+
+       if (blk_pc_request(rq)) {
+               rq->errors = clone->errors;
+               rq->resid_len = clone->resid_len;
+
+               if (rq->sense)
+                       /*
+                        * We are using the sense buffer of the original
+                        * request.
+                        * So setting the length of the sense data is enough.
+                        */
+                       rq->sense_len = clone->sense_len;
+       }
+
+       BUG_ON(clone->bio);
+       free_rq_tio(tio);
+
+       blk_end_request_all(rq, error);
+
+       rq_completed(md, 1);
+}
+
+/*
+ * Request completion handler for request-based dm
+ */
+static void dm_softirq_done(struct request *rq)
+{
+       struct request *clone = rq->completion_data;
+       struct dm_rq_target_io *tio = clone->end_io_data;
+       dm_request_endio_fn rq_end_io = tio->ti->type->rq_end_io;
+       int error = tio->error;
+
+       if (!(rq->cmd_flags & REQ_FAILED) && rq_end_io)
+               error = rq_end_io(tio->ti, clone, error, &tio->info);
+
+       if (error <= 0)
+               /* The target wants to complete the I/O */
+               dm_end_request(clone, error);
+       else if (error == DM_ENDIO_INCOMPLETE)
+               /* The target will handle the I/O */
+               return;
+       else if (error == DM_ENDIO_REQUEUE)
+               /* The target wants to requeue the I/O */
+               dm_requeue_unmapped_request(clone);
+       else {
+               DMWARN("unimplemented target endio return value: %d", error);
+               BUG();
+       }
+}
+
+/*
+ * Complete the clone and the original request with the error status
+ * through softirq context.
+ */
+static void dm_complete_request(struct request *clone, int error)
+{
+       struct dm_rq_target_io *tio = clone->end_io_data;
+       struct request *rq = tio->orig;
+
+       tio->error = error;
+       rq->completion_data = clone;
+       blk_complete_request(rq);
+}
+
+/*
+ * Complete the not-mapped clone and the original request with the error status
+ * through softirq context.
+ * Target's rq_end_io() function isn't called.
+ * This may be used when the target's map_rq() function fails.
+ */
+void dm_kill_unmapped_request(struct request *clone, int error)
+{
+       struct dm_rq_target_io *tio = clone->end_io_data;
+       struct request *rq = tio->orig;
+
+       rq->cmd_flags |= REQ_FAILED;
+       dm_complete_request(clone, error);
+}
+EXPORT_SYMBOL_GPL(dm_kill_unmapped_request);
+
+/*
+ * Called with the queue lock held
+ */
+static void end_clone_request(struct request *clone, int error)
+{
+       /*
+        * For just cleaning up the information of the queue in which
+        * the clone was dispatched.
+        * The clone is *NOT* freed actually here because it is alloced from
+        * dm own mempool and REQ_ALLOCED isn't set in clone->cmd_flags.
+        */
+       __blk_put_request(clone->q, clone);
+
+       /*
+        * Actual request completion is done in a softirq context which doesn't
+        * hold the queue lock.  Otherwise, deadlock could occur because:
+        *     - another request may be submitted by the upper level driver
+        *       of the stacking during the completion
+        *     - the submission which requires queue lock may be done
+        *       against this queue
+        */
+       dm_complete_request(clone, error);
+}
+
 static sector_t max_io_len(struct mapped_device *md,
                           sector_t sector, struct dm_target *ti)
 {
@@ -634,11 +942,6 @@ static void __map_bio(struct dm_target *ti, struct bio *clone,
        sector_t sector;
        struct mapped_device *md;
 
-       /*
-        * Sanity checks.
-        */
-       BUG_ON(!clone->bi_size);
-
        clone->bi_end_io = clone_endio;
        clone->bi_private = tio;
 
@@ -714,7 +1017,7 @@ static struct bio *split_bvec(struct bio *bio, sector_t sector,
        clone->bi_flags |= 1 << BIO_CLONED;
 
        if (bio_integrity(bio)) {
-               bio_integrity_clone(clone, bio, GFP_NOIO);
+               bio_integrity_clone(clone, bio, GFP_NOIO, bs);
                bio_integrity_trim(clone,
                                   bio_sector_offset(bio, idx, offset), len);
        }
@@ -742,7 +1045,7 @@ static struct bio *clone_bio(struct bio *bio, sector_t sector,
        clone->bi_flags &= ~(1 << BIO_SEG_VALID);
 
        if (bio_integrity(bio)) {
-               bio_integrity_clone(clone, bio, GFP_NOIO);
+               bio_integrity_clone(clone, bio, GFP_NOIO, bs);
 
                if (idx != bio->bi_idx || clone->bi_size < bio->bi_size)
                        bio_integrity_trim(clone,
@@ -752,6 +1055,48 @@ static struct bio *clone_bio(struct bio *bio, sector_t sector,
        return clone;
 }
 
+static struct dm_target_io *alloc_tio(struct clone_info *ci,
+                                     struct dm_target *ti)
+{
+       struct dm_target_io *tio = mempool_alloc(ci->md->tio_pool, GFP_NOIO);
+
+       tio->io = ci->io;
+       tio->ti = ti;
+       memset(&tio->info, 0, sizeof(tio->info));
+
+       return tio;
+}
+
+static void __flush_target(struct clone_info *ci, struct dm_target *ti,
+                         unsigned flush_nr)
+{
+       struct dm_target_io *tio = alloc_tio(ci, ti);
+       struct bio *clone;
+
+       tio->info.flush_request = flush_nr;
+
+       clone = bio_alloc_bioset(GFP_NOIO, 0, ci->md->bs);
+       __bio_clone(clone, ci->bio);
+       clone->bi_destructor = dm_bio_destructor;
+
+       __map_bio(ti, clone, tio);
+}
+
+static int __clone_and_map_empty_barrier(struct clone_info *ci)
+{
+       unsigned target_nr = 0, flush_nr;
+       struct dm_target *ti;
+
+       while ((ti = dm_table_get_target(ci->map, target_nr++)))
+               for (flush_nr = 0; flush_nr < ti->num_flush_requests;
+                    flush_nr++)
+                       __flush_target(ci, ti, flush_nr);
+
+       ci->sector_count = 0;
+
+       return 0;
+}
+
 static int __clone_and_map(struct clone_info *ci)
 {
        struct bio *clone, *bio = ci->bio;
@@ -759,6 +1104,9 @@ static int __clone_and_map(struct clone_info *ci)
        sector_t len = 0, max;
        struct dm_target_io *tio;
 
+       if (unlikely(bio_empty_barrier(bio)))
+               return __clone_and_map_empty_barrier(ci);
+
        ti = dm_table_find_target(ci->map, ci->sector);
        if (!dm_target_is_valid(ti))
                return -EIO;
@@ -768,10 +1116,7 @@ static int __clone_and_map(struct clone_info *ci)
        /*
         * Allocate a target io object.
         */
-       tio = alloc_tio(ci->md);
-       tio->io = ci->io;
-       tio->ti = ti;
-       memset(&tio->info, 0, sizeof(tio->info));
+       tio = alloc_tio(ci, ti);
 
        if (ci->sector_count <= max) {
                /*
@@ -827,10 +1172,7 @@ static int __clone_and_map(struct clone_info *ci)
 
                                max = max_io_len(ci->md, ci->sector, ti);
 
-                               tio = alloc_tio(ci->md);
-                               tio->io = ci->io;
-                               tio->ti = ti;
-                               memset(&tio->info, 0, sizeof(tio->info));
+                               tio = alloc_tio(ci, ti);
                        }
 
                        len = min(remaining, max);
@@ -865,7 +1207,8 @@ static void __split_and_process_bio(struct mapped_device *md, struct bio *bio)
                if (!bio_barrier(bio))
                        bio_io_error(bio);
                else
-                       md->barrier_error = -EIO;
+                       if (!md->barrier_error)
+                               md->barrier_error = -EIO;
                return;
        }
 
@@ -878,6 +1221,8 @@ static void __split_and_process_bio(struct mapped_device *md, struct bio *bio)
        ci.io->md = md;
        ci.sector = bio->bi_sector;
        ci.sector_count = bio_sectors(bio);
+       if (unlikely(bio_empty_barrier(bio)))
+               ci.sector_count = 1;
        ci.idx = bio->bi_idx;
 
        start_io_acct(ci.io);
@@ -925,6 +1270,16 @@ static int dm_merge_bvec(struct request_queue *q,
         */
        if (max_size && ti->type->merge)
                max_size = ti->type->merge(ti, bvm, biovec, max_size);
+       /*
+        * If the target doesn't support merge method and some of the devices
+        * provided their merge_bvec method (we know this by looking at
+        * queue_max_hw_sectors), then we can't allow bios with multiple vector
+        * entries.  So always set max_size to 0, and the code below allows
+        * just one page.
+        */
+       else if (queue_max_hw_sectors(q) <= PAGE_SIZE >> 9)
+
+               max_size = 0;
 
 out_table:
        dm_table_put(map);
@@ -943,7 +1298,7 @@ out:
  * The request function that just remaps the bio built up by
  * dm_merge_bvec.
  */
-static int dm_request(struct request_queue *q, struct bio *bio)
+static int _dm_request(struct request_queue *q, struct bio *bio)
 {
        int rw = bio_data_dir(bio);
        struct mapped_device *md = q->queuedata;
@@ -980,12 +1335,274 @@ static int dm_request(struct request_queue *q, struct bio *bio)
        return 0;
 }
 
+static int dm_make_request(struct request_queue *q, struct bio *bio)
+{
+       struct mapped_device *md = q->queuedata;
+
+       if (unlikely(bio_barrier(bio))) {
+               bio_endio(bio, -EOPNOTSUPP);
+               return 0;
+       }
+
+       return md->saved_make_request_fn(q, bio); /* call __make_request() */
+}
+
+static int dm_request_based(struct mapped_device *md)
+{
+       return blk_queue_stackable(md->queue);
+}
+
+static int dm_request(struct request_queue *q, struct bio *bio)
+{
+       struct mapped_device *md = q->queuedata;
+
+       if (dm_request_based(md))
+               return dm_make_request(q, bio);
+
+       return _dm_request(q, bio);
+}
+
+void dm_dispatch_request(struct request *rq)
+{
+       int r;
+
+       if (blk_queue_io_stat(rq->q))
+               rq->cmd_flags |= REQ_IO_STAT;
+
+       rq->start_time = jiffies;
+       r = blk_insert_cloned_request(rq->q, rq);
+       if (r)
+               dm_complete_request(rq, r);
+}
+EXPORT_SYMBOL_GPL(dm_dispatch_request);
+
+static void dm_rq_bio_destructor(struct bio *bio)
+{
+       struct dm_rq_clone_bio_info *info = bio->bi_private;
+       struct mapped_device *md = info->tio->md;
+
+       free_bio_info(info);
+       bio_free(bio, md->bs);
+}
+
+static int dm_rq_bio_constructor(struct bio *bio, struct bio *bio_orig,
+                                void *data)
+{
+       struct dm_rq_target_io *tio = data;
+       struct mapped_device *md = tio->md;
+       struct dm_rq_clone_bio_info *info = alloc_bio_info(md);
+
+       if (!info)
+               return -ENOMEM;
+
+       info->orig = bio_orig;
+       info->tio = tio;
+       bio->bi_end_io = end_clone_bio;
+       bio->bi_private = info;
+       bio->bi_destructor = dm_rq_bio_destructor;
+
+       return 0;
+}
+
+static int setup_clone(struct request *clone, struct request *rq,
+                      struct dm_rq_target_io *tio)
+{
+       int r = blk_rq_prep_clone(clone, rq, tio->md->bs, GFP_ATOMIC,
+                                 dm_rq_bio_constructor, tio);
+
+       if (r)
+               return r;
+
+       clone->cmd = rq->cmd;
+       clone->cmd_len = rq->cmd_len;
+       clone->sense = rq->sense;
+       clone->buffer = rq->buffer;
+       clone->end_io = end_clone_request;
+       clone->end_io_data = tio;
+
+       return 0;
+}
+
+static int dm_rq_flush_suspending(struct mapped_device *md)
+{
+       return !md->suspend_rq.special;
+}
+
+/*
+ * Called with the queue lock held.
+ */
+static int dm_prep_fn(struct request_queue *q, struct request *rq)
+{
+       struct mapped_device *md = q->queuedata;
+       struct dm_rq_target_io *tio;
+       struct request *clone;
+
+       if (unlikely(rq == &md->suspend_rq)) {
+               if (dm_rq_flush_suspending(md))
+                       return BLKPREP_OK;
+               else
+                       /* The flush suspend was interrupted */
+                       return BLKPREP_KILL;
+       }
+
+       if (unlikely(rq->special)) {
+               DMWARN("Already has something in rq->special.");
+               return BLKPREP_KILL;
+       }
+
+       tio = alloc_rq_tio(md); /* Only one for each original request */
+       if (!tio)
+               /* -ENOMEM */
+               return BLKPREP_DEFER;
+
+       tio->md = md;
+       tio->ti = NULL;
+       tio->orig = rq;
+       tio->error = 0;
+       memset(&tio->info, 0, sizeof(tio->info));
+
+       clone = &tio->clone;
+       if (setup_clone(clone, rq, tio)) {
+               /* -ENOMEM */
+               free_rq_tio(tio);
+               return BLKPREP_DEFER;
+       }
+
+       rq->special = clone;
+       rq->cmd_flags |= REQ_DONTPREP;
+
+       return BLKPREP_OK;
+}
+
+static void map_request(struct dm_target *ti, struct request *rq,
+                       struct mapped_device *md)
+{
+       int r;
+       struct request *clone = rq->special;
+       struct dm_rq_target_io *tio = clone->end_io_data;
+
+       /*
+        * Hold the md reference here for the in-flight I/O.
+        * We can't rely on the reference count by device opener,
+        * because the device may be closed during the request completion
+        * when all bios are completed.
+        * See the comment in rq_completed() too.
+        */
+       dm_get(md);
+
+       tio->ti = ti;
+       r = ti->type->map_rq(ti, clone, &tio->info);
+       switch (r) {
+       case DM_MAPIO_SUBMITTED:
+               /* The target has taken the I/O to submit by itself later */
+               break;
+       case DM_MAPIO_REMAPPED:
+               /* The target has remapped the I/O so dispatch it */
+               dm_dispatch_request(clone);
+               break;
+       case DM_MAPIO_REQUEUE:
+               /* The target wants to requeue the I/O */
+               dm_requeue_unmapped_request(clone);
+               break;
+       default:
+               if (r > 0) {
+                       DMWARN("unimplemented target map return value: %d", r);
+                       BUG();
+               }
+
+               /* The target wants to complete the I/O */
+               dm_kill_unmapped_request(clone, r);
+               break;
+       }
+}
+
+/*
+ * q->request_fn for request-based dm.
+ * Called with the queue lock held.
+ */
+static void dm_request_fn(struct request_queue *q)
+{
+       struct mapped_device *md = q->queuedata;
+       struct dm_table *map = dm_get_table(md);
+       struct dm_target *ti;
+       struct request *rq;
+
+       /*
+        * For noflush suspend, check blk_queue_stopped() to immediately
+        * quit I/O dispatching.
+        */
+       while (!blk_queue_plugged(q) && !blk_queue_stopped(q)) {
+               rq = blk_peek_request(q);
+               if (!rq)
+                       goto plug_and_out;
+
+               if (unlikely(rq == &md->suspend_rq)) { /* Flush suspend maker */
+                       if (queue_in_flight(q))
+                               /* Not quiet yet.  Wait more */
+                               goto plug_and_out;
+
+                       /* This device should be quiet now */
+                       __stop_queue(q);
+                       blk_start_request(rq);
+                       __blk_end_request_all(rq, 0);
+                       wake_up(&md->wait);
+                       goto out;
+               }
+
+               ti = dm_table_find_target(map, blk_rq_pos(rq));
+               if (ti->type->busy && ti->type->busy(ti))
+                       goto plug_and_out;
+
+               blk_start_request(rq);
+               spin_unlock(q->queue_lock);
+               map_request(ti, rq, md);
+               spin_lock_irq(q->queue_lock);
+       }
+
+       goto out;
+
+plug_and_out:
+       if (!elv_queue_empty(q))
+               /* Some requests still remain, retry later */
+               blk_plug_device(q);
+
+out:
+       dm_table_put(map);
+
+       return;
+}
+
+int dm_underlying_device_busy(struct request_queue *q)
+{
+       return blk_lld_busy(q);
+}
+EXPORT_SYMBOL_GPL(dm_underlying_device_busy);
+
+static int dm_lld_busy(struct request_queue *q)
+{
+       int r;
+       struct mapped_device *md = q->queuedata;
+       struct dm_table *map = dm_get_table(md);
+
+       if (!map || test_bit(DMF_BLOCK_IO_FOR_SUSPEND, &md->flags))
+               r = 1;
+       else
+               r = dm_table_any_busy_target(map);
+
+       dm_table_put(map);
+
+       return r;
+}
+
 static void dm_unplug_all(struct request_queue *q)
 {
        struct mapped_device *md = q->queuedata;
        struct dm_table *map = dm_get_table(md);
 
        if (map) {
+               if (dm_request_based(md))
+                       generic_unplug_device(q);
+
                dm_table_unplug_all(map);
                dm_table_put(map);
        }
@@ -1000,7 +1617,16 @@ static int dm_any_congested(void *congested_data, int bdi_bits)
        if (!test_bit(DMF_BLOCK_IO_FOR_SUSPEND, &md->flags)) {
                map = dm_get_table(md);
                if (map) {
-                       r = dm_table_any_congested(map, bdi_bits);
+                       /*
+                        * Request-based dm cares about only own queue for
+                        * the query about congestion status of request_queue
+                        */
+                       if (dm_request_based(md))
+                               r = md->queue->backing_dev_info.state &
+                                   bdi_bits;
+                       else
+                               r = dm_table_any_congested(map, bdi_bits);
+
                        dm_table_put(map);
                }
        }
@@ -1123,30 +1749,32 @@ static struct mapped_device *alloc_dev(int minor)
        INIT_LIST_HEAD(&md->uevent_list);
        spin_lock_init(&md->uevent_lock);
 
-       md->queue = blk_alloc_queue(GFP_KERNEL);
+       md->queue = blk_init_queue(dm_request_fn, NULL);
        if (!md->queue)
                goto bad_queue;
 
+       /*
+        * Request-based dm devices cannot be stacked on top of bio-based dm
+        * devices.  The type of this dm device has not been decided yet,
+        * although we initialized the queue using blk_init_queue().
+        * The type is decided at the first table loading time.
+        * To prevent problematic device stacking, clear the queue flag
+        * for request stacking support until then.
+        *
+        * This queue is new, so no concurrency on the queue_flags.
+        */
+       queue_flag_clear_unlocked(QUEUE_FLAG_STACKABLE, md->queue);
+       md->saved_make_request_fn = md->queue->make_request_fn;
        md->queue->queuedata = md;
        md->queue->backing_dev_info.congested_fn = dm_any_congested;
        md->queue->backing_dev_info.congested_data = md;
        blk_queue_make_request(md->queue, dm_request);
-       blk_queue_ordered(md->queue, QUEUE_ORDERED_DRAIN, NULL);
        blk_queue_bounce_limit(md->queue, BLK_BOUNCE_ANY);
        md->queue->unplug_fn = dm_unplug_all;
        blk_queue_merge_bvec(md->queue, dm_merge_bvec);
-
-       md->io_pool = mempool_create_slab_pool(MIN_IOS, _io_cache);
-       if (!md->io_pool)
-               goto bad_io_pool;
-
-       md->tio_pool = mempool_create_slab_pool(MIN_IOS, _tio_cache);
-       if (!md->tio_pool)
-               goto bad_tio_pool;
-
-       md->bs = bioset_create(16, 0);
-       if (!md->bs)
-               goto bad_no_bioset;
+       blk_queue_softirq_done(md->queue, dm_softirq_done);
+       blk_queue_prep_rq(md->queue, dm_prep_fn);
+       blk_queue_lld_busy(md->queue, dm_lld_busy);
 
        md->disk = alloc_disk(1);
        if (!md->disk)
@@ -1170,6 +1798,10 @@ static struct mapped_device *alloc_dev(int minor)
        if (!md->wq)
                goto bad_thread;
 
+       md->bdev = bdget_disk(md->disk, 0);
+       if (!md->bdev)
+               goto bad_bdev;
+
        /* Populate the mapping, nobody knows we exist yet */
        spin_lock(&_minor_lock);
        old_md = idr_replace(&_minor_idr, md, minor);
@@ -1179,15 +1811,11 @@ static struct mapped_device *alloc_dev(int minor)
 
        return md;
 
+bad_bdev:
+       destroy_workqueue(md->wq);
 bad_thread:
        put_disk(md->disk);
 bad_disk:
-       bioset_free(md->bs);
-bad_no_bioset:
-       mempool_destroy(md->tio_pool);
-bad_tio_pool:
-       mempool_destroy(md->io_pool);
-bad_io_pool:
        blk_cleanup_queue(md->queue);
 bad_queue:
        free_minor(minor);
@@ -1204,14 +1832,15 @@ static void free_dev(struct mapped_device *md)
 {
        int minor = MINOR(disk_devt(md->disk));
 
-       if (md->suspended_bdev) {
-               unlock_fs(md);
-               bdput(md->suspended_bdev);
-       }
+       unlock_fs(md);
+       bdput(md->bdev);
        destroy_workqueue(md->wq);
-       mempool_destroy(md->tio_pool);
-       mempool_destroy(md->io_pool);
-       bioset_free(md->bs);
+       if (md->tio_pool)
+               mempool_destroy(md->tio_pool);
+       if (md->io_pool)
+               mempool_destroy(md->io_pool);
+       if (md->bs)
+               bioset_free(md->bs);
        blk_integrity_unregister(md->disk);
        del_gendisk(md->disk);
        free_minor(minor);
@@ -1226,6 +1855,29 @@ static void free_dev(struct mapped_device *md)
        kfree(md);
 }
 
+static void __bind_mempools(struct mapped_device *md, struct dm_table *t)
+{
+       struct dm_md_mempools *p;
+
+       if (md->io_pool && md->tio_pool && md->bs)
+               /* the md already has necessary mempools */
+               goto out;
+
+       p = dm_table_get_md_mempools(t);
+       BUG_ON(!p || md->io_pool || md->tio_pool || md->bs);
+
+       md->io_pool = p->io_pool;
+       p->io_pool = NULL;
+       md->tio_pool = p->tio_pool;
+       p->tio_pool = NULL;
+       md->bs = p->bs;
+       p->bs = NULL;
+
+out:
+       /* mempool bind completed, now no need any mempools in the table */
+       dm_table_free_md_mempools(t);
+}
+
 /*
  * Bind a table to the device.
  */
@@ -1249,15 +1901,17 @@ static void __set_size(struct mapped_device *md, sector_t size)
 {
        set_capacity(md->disk, size);
 
-       mutex_lock(&md->suspended_bdev->bd_inode->i_mutex);
-       i_size_write(md->suspended_bdev->bd_inode, (loff_t)size << SECTOR_SHIFT);
-       mutex_unlock(&md->suspended_bdev->bd_inode->i_mutex);
+       mutex_lock(&md->bdev->bd_inode->i_mutex);
+       i_size_write(md->bdev->bd_inode, (loff_t)size << SECTOR_SHIFT);
+       mutex_unlock(&md->bdev->bd_inode->i_mutex);
 }
 
-static int __bind(struct mapped_device *md, struct dm_table *t)
+static int __bind(struct mapped_device *md, struct dm_table *t,
+                 struct queue_limits *limits)
 {
        struct request_queue *q = md->queue;
        sector_t size;
+       unsigned long flags;
 
        size = dm_table_get_size(t);
 
@@ -1267,8 +1921,7 @@ static int __bind(struct mapped_device *md, struct dm_table *t)
        if (size != get_capacity(md->disk))
                memset(&md->geometry, 0, sizeof(md->geometry));
 
-       if (md->suspended_bdev)
-               __set_size(md, size);
+       __set_size(md, size);
 
        if (!size) {
                dm_table_destroy(t);
@@ -1277,10 +1930,22 @@ static int __bind(struct mapped_device *md, struct dm_table *t)
 
        dm_table_event_callback(t, event_callback, md);
 
-       write_lock(&md->map_lock);
+       /*
+        * The queue hasn't been stopped yet, if the old table type wasn't
+        * for request-based during suspension.  So stop it to prevent
+        * I/O mapping before resume.
+        * This must be done before setting the queue restrictions,
+        * because request-based dm may be run just after the setting.
+        */
+       if (dm_table_request_based(t) && !blk_queue_stopped(q))
+               stop_queue(q);
+
+       __bind_mempools(md, t);
+
+       write_lock_irqsave(&md->map_lock, flags);
        md->map = t;
-       dm_table_set_restrictions(t, q);
-       write_unlock(&md->map_lock);
+       dm_table_set_restrictions(t, q, limits);
+       write_unlock_irqrestore(&md->map_lock, flags);
 
        return 0;
 }
@@ -1288,14 +1953,15 @@ static int __bind(struct mapped_device *md, struct dm_table *t)
 static void __unbind(struct mapped_device *md)
 {
        struct dm_table *map = md->map;
+       unsigned long flags;
 
        if (!map)
                return;
 
        dm_table_event_callback(map, NULL, NULL);
-       write_lock(&md->map_lock);
+       write_lock_irqsave(&md->map_lock, flags);
        md->map = NULL;
-       write_unlock(&md->map_lock);
+       write_unlock_irqrestore(&md->map_lock, flags);
        dm_table_destroy(map);
 }
 
@@ -1399,6 +2065,8 @@ static int dm_wait_for_completion(struct mapped_device *md, int interruptible)
 {
        int r = 0;
        DECLARE_WAITQUEUE(wait, current);
+       struct request_queue *q = md->queue;
+       unsigned long flags;
 
        dm_unplug_all(md->queue);
 
@@ -1408,7 +2076,14 @@ static int dm_wait_for_completion(struct mapped_device *md, int interruptible)
                set_current_state(interruptible);
 
                smp_mb();
-               if (!atomic_read(&md->pending))
+               if (dm_request_based(md)) {
+                       spin_lock_irqsave(q->queue_lock, flags);
+                       if (!queue_in_flight(q) && blk_queue_stopped(q)) {
+                               spin_unlock_irqrestore(q->queue_lock, flags);
+                               break;
+                       }
+                       spin_unlock_irqrestore(q->queue_lock, flags);
+               } else if (!atomic_read(&md->pending))
                        break;
 
                if (interruptible == TASK_INTERRUPTIBLE &&
@@ -1426,34 +2101,36 @@ static int dm_wait_for_completion(struct mapped_device *md, int interruptible)
        return r;
 }
 
-static int dm_flush(struct mapped_device *md)
+static void dm_flush(struct mapped_device *md)
 {
        dm_wait_for_completion(md, TASK_UNINTERRUPTIBLE);
-       return 0;
+
+       bio_init(&md->barrier_bio);
+       md->barrier_bio.bi_bdev = md->bdev;
+       md->barrier_bio.bi_rw = WRITE_BARRIER;
+       __split_and_process_bio(md, &md->barrier_bio);
+
+       dm_wait_for_completion(md, TASK_UNINTERRUPTIBLE);
 }
 
 static void process_barrier(struct mapped_device *md, struct bio *bio)
 {
-       int error = dm_flush(md);
-
-       if (unlikely(error)) {
-               bio_endio(bio, error);
-               return;
-       }
-       if (bio_empty_barrier(bio)) {
-               bio_endio(bio, 0);
-               return;
-       }
-
-       __split_and_process_bio(md, bio);
+       md->barrier_error = 0;
 
-       error = dm_flush(md);
+       dm_flush(md);
 
-       if (!error && md->barrier_error)
-               error = md->barrier_error;
+       if (!bio_empty_barrier(bio)) {
+               __split_and_process_bio(md, bio);
+               dm_flush(md);
+       }
 
        if (md->barrier_error != DM_ENDIO_REQUEUE)
-               bio_endio(bio, error);
+               bio_endio(bio, md->barrier_error);
+       else {
+               spin_lock_irq(&md->deferred_lock);
+               bio_list_add_head(&md->deferred, bio);
+               spin_unlock_irq(&md->deferred_lock);
+       }
 }
 
 /*
@@ -1479,10 +2156,14 @@ static void dm_wq_work(struct work_struct *work)
 
                up_write(&md->io_lock);
 
-               if (bio_barrier(c))
-                       process_barrier(md, c);
-               else
-                       __split_and_process_bio(md, c);
+               if (dm_request_based(md))
+                       generic_make_request(c);
+               else {
+                       if (bio_barrier(c))
+                               process_barrier(md, c);
+                       else
+                               __split_and_process_bio(md, c);
+               }
 
                down_write(&md->io_lock);
        }
@@ -1502,6 +2183,7 @@ static void dm_queue_flush(struct mapped_device *md)
  */
 int dm_swap_table(struct mapped_device *md, struct dm_table *table)
 {
+       struct queue_limits limits;
        int r = -EINVAL;
 
        mutex_lock(&md->suspend_lock);
@@ -1510,19 +2192,96 @@ int dm_swap_table(struct mapped_device *md, struct dm_table *table)
        if (!dm_suspended(md))
                goto out;
 
-       /* without bdev, the device size cannot be changed */
-       if (!md->suspended_bdev)
-               if (get_capacity(md->disk) != dm_table_get_size(table))
-                       goto out;
+       r = dm_calculate_queue_limits(table, &limits);
+       if (r)
+               goto out;
+
+       /* cannot change the device type, once a table is bound */
+       if (md->map &&
+           (dm_table_get_type(md->map) != dm_table_get_type(table))) {
+               DMWARN("can't change the device type after a table is bound");
+               goto out;
+       }
+
+       /*
+        * It is enought that blk_queue_ordered() is called only once when
+        * the first bio-based table is bound.
+        *
+        * This setting should be moved to alloc_dev() when request-based dm
+        * supports barrier.
+        */
+       if (!md->map && dm_table_bio_based(table))
+               blk_queue_ordered(md->queue, QUEUE_ORDERED_DRAIN, NULL);
 
        __unbind(md);
-       r = __bind(md, table);
+       r = __bind(md, table, &limits);
 
 out:
        mutex_unlock(&md->suspend_lock);
        return r;
 }
 
+static void dm_rq_invalidate_suspend_marker(struct mapped_device *md)
+{
+       md->suspend_rq.special = (void *)0x1;
+}
+
+static void dm_rq_abort_suspend(struct mapped_device *md, int noflush)
+{
+       struct request_queue *q = md->queue;
+       unsigned long flags;
+
+       spin_lock_irqsave(q->queue_lock, flags);
+       if (!noflush)
+               dm_rq_invalidate_suspend_marker(md);
+       __start_queue(q);
+       spin_unlock_irqrestore(q->queue_lock, flags);
+}
+
+static void dm_rq_start_suspend(struct mapped_device *md, int noflush)
+{
+       struct request *rq = &md->suspend_rq;
+       struct request_queue *q = md->queue;
+
+       if (noflush)
+               stop_queue(q);
+       else {
+               blk_rq_init(q, rq);
+               blk_insert_request(q, rq, 0, NULL);
+       }
+}
+
+static int dm_rq_suspend_available(struct mapped_device *md, int noflush)
+{
+       int r = 1;
+       struct request *rq = &md->suspend_rq;
+       struct request_queue *q = md->queue;
+       unsigned long flags;
+
+       if (noflush)
+               return r;
+
+       /* The marker must be protected by queue lock if it is in use */
+       spin_lock_irqsave(q->queue_lock, flags);
+       if (unlikely(rq->ref_count)) {
+               /*
+                * This can happen, when the previous flush suspend was
+                * interrupted, the marker is still in the queue and
+                * this flush suspend has been invoked, because we don't
+                * remove the marker at the time of suspend interruption.
+                * We have only one marker per mapped_device, so we can't
+                * start another flush suspend while it is in use.
+                */
+               BUG_ON(!rq->special); /* The marker should be invalidated */
+               DMWARN("Invalidating the previous flush suspend is still in"
+                      " progress.  Please retry later.");
+               r = 0;
+       }
+       spin_unlock_irqrestore(q->queue_lock, flags);
+
+       return r;
+}
+
 /*
  * Functions to lock and unlock any filesystem running on the
  * device.
@@ -1533,7 +2292,7 @@ static int lock_fs(struct mapped_device *md)
 
        WARN_ON(md->frozen_sb);
 
-       md->frozen_sb = freeze_bdev(md->suspended_bdev);
+       md->frozen_sb = freeze_bdev(md->bdev);
        if (IS_ERR(md->frozen_sb)) {
                r = PTR_ERR(md->frozen_sb);
                md->frozen_sb = NULL;
@@ -1542,9 +2301,6 @@ static int lock_fs(struct mapped_device *md)
 
        set_bit(DMF_FROZEN, &md->flags);
 
-       /* don't bdput right now, we don't want the bdev
-        * to go away while it is locked.
-        */
        return 0;
 }
 
@@ -1553,7 +2309,7 @@ static void unlock_fs(struct mapped_device *md)
        if (!test_bit(DMF_FROZEN, &md->flags))
                return;
 
-       thaw_bdev(md->suspended_bdev, md->frozen_sb);
+       thaw_bdev(md->bdev, md->frozen_sb);
        md->frozen_sb = NULL;
        clear_bit(DMF_FROZEN, &md->flags);
 }
@@ -1565,6 +2321,53 @@ static void unlock_fs(struct mapped_device *md)
  * dm_bind_table, dm_suspend must be called to flush any in
  * flight bios and ensure that any further io gets deferred.
  */
+/*
+ * Suspend mechanism in request-based dm.
+ *
+ * After the suspend starts, further incoming requests are kept in
+ * the request_queue and deferred.
+ * Remaining requests in the request_queue at the start of suspend are flushed
+ * if it is flush suspend.
+ * The suspend completes when the following conditions have been satisfied,
+ * so wait for it:
+ *    1. q->in_flight is 0 (which means no in_flight request)
+ *    2. queue has been stopped (which means no request dispatching)
+ *
+ *
+ * Noflush suspend
+ * ---------------
+ * Noflush suspend doesn't need to dispatch remaining requests.
+ * So stop the queue immediately.  Then, wait for all in_flight requests
+ * to be completed or requeued.
+ *
+ * To abort noflush suspend, start the queue.
+ *
+ *
+ * Flush suspend
+ * -------------
+ * Flush suspend needs to dispatch remaining requests.  So stop the queue
+ * after the remaining requests are completed. (Requeued request must be also
+ * re-dispatched and completed.  Until then, we can't stop the queue.)
+ *
+ * During flushing the remaining requests, further incoming requests are also
+ * inserted to the same queue.  To distinguish which requests are to be
+ * flushed, we insert a marker request to the queue at the time of starting
+ * flush suspend, like a barrier.
+ * The dispatching is blocked when the marker is found on the top of the queue.
+ * And the queue is stopped when all in_flight requests are completed, since
+ * that means the remaining requests are completely flushed.
+ * Then, the marker is removed from the queue.
+ *
+ * To abort flush suspend, we also need to take care of the marker, not only
+ * starting the queue.
+ * We don't remove the marker forcibly from the queue since it's against
+ * the block-layer manner.  Instead, we put a invalidated mark on the marker.
+ * When the invalidated marker is found on the top of the queue, it is
+ * immediately removed from the queue, so it doesn't block dispatching.
+ * Because we have only one marker per mapped_device, we can't start another
+ * flush suspend until the invalidated marker is removed from the queue.
+ * So fail and return with -EBUSY in such a case.
+ */
 int dm_suspend(struct mapped_device *md, unsigned suspend_flags)
 {
        struct dm_table *map = NULL;
@@ -1579,6 +2382,11 @@ int dm_suspend(struct mapped_device *md, unsigned suspend_flags)
                goto out_unlock;
        }
 
+       if (dm_request_based(md) && !dm_rq_suspend_available(md, noflush)) {
+               r = -EBUSY;
+               goto out_unlock;
+       }
+
        map = dm_get_table(md);
 
        /*
@@ -1591,24 +2399,14 @@ int dm_suspend(struct mapped_device *md, unsigned suspend_flags)
        /* This does not get reverted if there's an error later. */
        dm_table_presuspend_targets(map);
 
-       /* bdget() can stall if the pending I/Os are not flushed */
-       if (!noflush) {
-               md->suspended_bdev = bdget_disk(md->disk, 0);
-               if (!md->suspended_bdev) {
-                       DMWARN("bdget failed in dm_suspend");
-                       r = -ENOMEM;
+       /*
+        * Flush I/O to the device. noflush supersedes do_lockfs,
+        * because lock_fs() needs to flush I/Os.
+        */
+       if (!noflush && do_lockfs) {
+               r = lock_fs(md);
+               if (r)
                        goto out;
-               }
-
-               /*
-                * Flush I/O to the device. noflush supersedes do_lockfs,
-                * because lock_fs() needs to flush I/Os.
-                */
-               if (do_lockfs) {
-                       r = lock_fs(md);
-                       if (r)
-                               goto out;
-               }
        }
 
        /*
@@ -1634,6 +2432,9 @@ int dm_suspend(struct mapped_device *md, unsigned suspend_flags)
 
        flush_workqueue(md->wq);
 
+       if (dm_request_based(md))
+               dm_rq_start_suspend(md, noflush);
+
        /*
         * At this point no more requests are entering target request routines.
         * We call dm_wait_for_completion to wait for all existing requests
@@ -1650,6 +2451,9 @@ int dm_suspend(struct mapped_device *md, unsigned suspend_flags)
        if (r < 0) {
                dm_queue_flush(md);
 
+               if (dm_request_based(md))
+                       dm_rq_abort_suspend(md, noflush);
+
                unlock_fs(md);
                goto out; /* pushback list is already flushed, so skip flush */
        }
@@ -1665,11 +2469,6 @@ int dm_suspend(struct mapped_device *md, unsigned suspend_flags)
        set_bit(DMF_SUSPENDED, &md->flags);
 
 out:
-       if (r && md->suspended_bdev) {
-               bdput(md->suspended_bdev);
-               md->suspended_bdev = NULL;
-       }
-
        dm_table_put(map);
 
 out_unlock:
@@ -1696,21 +2495,20 @@ int dm_resume(struct mapped_device *md)
 
        dm_queue_flush(md);
 
-       unlock_fs(md);
+       /*
+        * Flushing deferred I/Os must be done after targets are resumed
+        * so that mapping of targets can work correctly.
+        * Request-based dm is queueing the deferred I/Os in its request_queue.
+        */
+       if (dm_request_based(md))
+               start_queue(md->queue);
 
-       if (md->suspended_bdev) {
-               bdput(md->suspended_bdev);
-               md->suspended_bdev = NULL;
-       }
+       unlock_fs(md);
 
        clear_bit(DMF_SUSPENDED, &md->flags);
 
        dm_table_unplug_all(map);
-
-       dm_kobject_uevent(md);
-
        r = 0;
-
 out:
        dm_table_put(map);
        mutex_unlock(&md->suspend_lock);
@@ -1721,9 +2519,19 @@ out:
 /*-----------------------------------------------------------------
  * Event notification.
  *---------------------------------------------------------------*/
-void dm_kobject_uevent(struct mapped_device *md)
-{
-       kobject_uevent(&disk_to_dev(md->disk)->kobj, KOBJ_CHANGE);
+void dm_kobject_uevent(struct mapped_device *md, enum kobject_action action,
+                      unsigned cookie)
+{
+       char udev_cookie[DM_COOKIE_LENGTH];
+       char *envp[] = { udev_cookie, NULL };
+
+       if (!cookie)
+               kobject_uevent(&disk_to_dev(md->disk)->kobj, action);
+       else {
+               snprintf(udev_cookie, DM_COOKIE_LENGTH, "%s=%u",
+                        DM_COOKIE_ENV_VAR_NAME, cookie);
+               kobject_uevent_env(&disk_to_dev(md->disk)->kobj, action, envp);
+       }
 }
 
 uint32_t dm_next_uevent_seq(struct mapped_device *md)
@@ -1777,6 +2585,10 @@ struct mapped_device *dm_get_from_kobject(struct kobject *kobj)
        if (&md->kobj != kobj)
                return NULL;
 
+       if (test_bit(DMF_FREEING, &md->flags) ||
+           test_bit(DMF_DELETING, &md->flags))
+               return NULL;
+
        dm_get(md);
        return md;
 }
@@ -1797,6 +2609,61 @@ int dm_noflush_suspending(struct dm_target *ti)
 }
 EXPORT_SYMBOL_GPL(dm_noflush_suspending);
 
+struct dm_md_mempools *dm_alloc_md_mempools(unsigned type)
+{
+       struct dm_md_mempools *pools = kmalloc(sizeof(*pools), GFP_KERNEL);
+
+       if (!pools)
+               return NULL;
+
+       pools->io_pool = (type == DM_TYPE_BIO_BASED) ?
+                        mempool_create_slab_pool(MIN_IOS, _io_cache) :
+                        mempool_create_slab_pool(MIN_IOS, _rq_bio_info_cache);
+       if (!pools->io_pool)
+               goto free_pools_and_out;
+
+       pools->tio_pool = (type == DM_TYPE_BIO_BASED) ?
+                         mempool_create_slab_pool(MIN_IOS, _tio_cache) :
+                         mempool_create_slab_pool(MIN_IOS, _rq_tio_cache);
+       if (!pools->tio_pool)
+               goto free_io_pool_and_out;
+
+       pools->bs = (type == DM_TYPE_BIO_BASED) ?
+                   bioset_create(16, 0) : bioset_create(MIN_IOS, 0);
+       if (!pools->bs)
+               goto free_tio_pool_and_out;
+
+       return pools;
+
+free_tio_pool_and_out:
+       mempool_destroy(pools->tio_pool);
+
+free_io_pool_and_out:
+       mempool_destroy(pools->io_pool);
+
+free_pools_and_out:
+       kfree(pools);
+
+       return NULL;
+}
+
+void dm_free_md_mempools(struct dm_md_mempools *pools)
+{
+       if (!pools)
+               return;
+
+       if (pools->io_pool)
+               mempool_destroy(pools->io_pool);
+
+       if (pools->tio_pool)
+               mempool_destroy(pools->tio_pool);
+
+       if (pools->bs)
+               bioset_free(pools->bs);
+
+       kfree(pools);
+}
+
 static struct block_device_operations dm_blk_dops = {
        .open = dm_blk_open,
        .release = dm_blk_close,
index a31506d93e9164115a7d1584d33f30714913f521..23278ae80f08dfc90c8458a3b6a700e4a2a87f8b 100644 (file)
 #define DM_SUSPEND_LOCKFS_FLAG         (1 << 0)
 #define DM_SUSPEND_NOFLUSH_FLAG                (1 << 1)
 
+/*
+ * Type of table and mapped_device's mempool
+ */
+#define DM_TYPE_NONE           0
+#define DM_TYPE_BIO_BASED      1
+#define DM_TYPE_REQUEST_BASED  2
+
 /*
  * List of devices that a metadevice uses and should open/close.
  */
@@ -32,6 +39,7 @@ struct dm_dev_internal {
 };
 
 struct dm_table;
+struct dm_md_mempools;
 
 /*-----------------------------------------------------------------
  * Internal table functions.
@@ -41,18 +49,34 @@ void dm_table_event_callback(struct dm_table *t,
                             void (*fn)(void *), void *context);
 struct dm_target *dm_table_get_target(struct dm_table *t, unsigned int index);
 struct dm_target *dm_table_find_target(struct dm_table *t, sector_t sector);
-void dm_table_set_restrictions(struct dm_table *t, struct request_queue *q);
+int dm_calculate_queue_limits(struct dm_table *table,
+                             struct queue_limits *limits);
+void dm_table_set_restrictions(struct dm_table *t, struct request_queue *q,
+                              struct queue_limits *limits);
 struct list_head *dm_table_get_devices(struct dm_table *t);
 void dm_table_presuspend_targets(struct dm_table *t);
 void dm_table_postsuspend_targets(struct dm_table *t);
 int dm_table_resume_targets(struct dm_table *t);
 int dm_table_any_congested(struct dm_table *t, int bdi_bits);
+int dm_table_any_busy_target(struct dm_table *t);
+int dm_table_set_type(struct dm_table *t);
+unsigned dm_table_get_type(struct dm_table *t);
+bool dm_table_bio_based(struct dm_table *t);
+bool dm_table_request_based(struct dm_table *t);
+int dm_table_alloc_md_mempools(struct dm_table *t);
+void dm_table_free_md_mempools(struct dm_table *t);
+struct dm_md_mempools *dm_table_get_md_mempools(struct dm_table *t);
 
 /*
  * To check the return value from dm_table_find_target().
  */
 #define dm_target_is_valid(t) ((t)->table)
 
+/*
+ * To check whether the target type is request-based or not (bio-based).
+ */
+#define dm_target_request_based(t) ((t)->type->map_rq != NULL)
+
 /*-----------------------------------------------------------------
  * A registry of target types.
  *---------------------------------------------------------------*/
@@ -92,9 +116,16 @@ void dm_stripe_exit(void);
 int dm_open_count(struct mapped_device *md);
 int dm_lock_for_deletion(struct mapped_device *md);
 
-void dm_kobject_uevent(struct mapped_device *md);
+void dm_kobject_uevent(struct mapped_device *md, enum kobject_action action,
+                      unsigned cookie);
 
 int dm_kcopyd_init(void);
 void dm_kcopyd_exit(void);
 
+/*
+ * Mempool operations
+ */
+struct dm_md_mempools *dm_alloc_md_mempools(unsigned type);
+void dm_free_md_mempools(struct dm_md_mempools *pools);
+
 #endif
index 15c8b7b25a9b9a053a7296e0ab7abc91efa88e05..5810fa906af08f21075fe903118725093e576c82 100644 (file)
@@ -166,8 +166,8 @@ static linear_conf_t *linear_conf(mddev_t *mddev, int raid_disks)
                        rdev->sectors = sectors * mddev->chunk_sectors;
                }
 
-               blk_queue_stack_limits(mddev->queue,
-                                      rdev->bdev->bd_disk->queue);
+               disk_stack_limits(mddev->gendisk, rdev->bdev,
+                                 rdev->data_offset << 9);
                /* as we don't honour merge_bvec_fn, we must never risk
                 * violating it, so limit ->max_sector to one PAGE, as
                 * a one page request is never in violation.
index 09be637d52cbb6041a67166807f948f9a00f08f2..d4351ff0849fb455974208b881348ce9baf2a801 100644 (file)
@@ -1756,9 +1756,10 @@ static void print_sb_1(struct mdp_superblock_1 *sb)
        __u8 *uuid;
 
        uuid = sb->set_uuid;
-       printk(KERN_INFO "md:  SB: (V:%u) (F:0x%08x) Array-ID:<%02x%02x%02x%02x"
-                       ":%02x%02x:%02x%02x:%02x%02x:%02x%02x%02x%02x%02x%02x>\n"
-              KERN_INFO "md:    Name: \"%s\" CT:%llu\n",
+       printk(KERN_INFO
+              "md:  SB: (V:%u) (F:0x%08x) Array-ID:<%02x%02x%02x%02x"
+              ":%02x%02x:%02x%02x:%02x%02x:%02x%02x%02x%02x%02x%02x>\n"
+              "md:    Name: \"%s\" CT:%llu\n",
                le32_to_cpu(sb->major_version),
                le32_to_cpu(sb->feature_map),
                uuid[0], uuid[1], uuid[2], uuid[3],
@@ -1770,12 +1771,13 @@ static void print_sb_1(struct mdp_superblock_1 *sb)
                       & MD_SUPERBLOCK_1_TIME_SEC_MASK);
 
        uuid = sb->device_uuid;
-       printk(KERN_INFO "md:       L%u SZ%llu RD:%u LO:%u CS:%u DO:%llu DS:%llu SO:%llu"
+       printk(KERN_INFO
+              "md:       L%u SZ%llu RD:%u LO:%u CS:%u DO:%llu DS:%llu SO:%llu"
                        " RO:%llu\n"
-              KERN_INFO "md:     Dev:%08x UUID: %02x%02x%02x%02x:%02x%02x:%02x%02x:%02x%02x"
-                       ":%02x%02x%02x%02x%02x%02x\n"
-              KERN_INFO "md:       (F:0x%08x) UT:%llu Events:%llu ResyncOffset:%llu CSUM:0x%08x\n"
-              KERN_INFO "md:         (MaxDev:%u) \n",
+              "md:     Dev:%08x UUID: %02x%02x%02x%02x:%02x%02x:%02x%02x:%02x%02x"
+                       ":%02x%02x%02x%02x%02x%02x\n"
+              "md:       (F:0x%08x) UT:%llu Events:%llu ResyncOffset:%llu CSUM:0x%08x\n"
+              "md:         (MaxDev:%u) \n",
                le32_to_cpu(sb->level),
                (unsigned long long)le64_to_cpu(sb->size),
                le32_to_cpu(sb->raid_disks),
@@ -3573,7 +3575,8 @@ suspend_lo_store(mddev_t *mddev, const char *buf, size_t len)
        char *e;
        unsigned long long new = simple_strtoull(buf, &e, 10);
 
-       if (mddev->pers->quiesce == NULL)
+       if (mddev->pers == NULL || 
+           mddev->pers->quiesce == NULL)
                return -EINVAL;
        if (buf == e || (*e && *e != '\n'))
                return -EINVAL;
@@ -3601,7 +3604,8 @@ suspend_hi_store(mddev_t *mddev, const char *buf, size_t len)
        char *e;
        unsigned long long new = simple_strtoull(buf, &e, 10);
 
-       if (mddev->pers->quiesce == NULL)
+       if (mddev->pers == NULL ||
+           mddev->pers->quiesce == NULL)
                return -EINVAL;
        if (buf == e || (*e && *e != '\n'))
                return -EINVAL;
@@ -3844,11 +3848,9 @@ static int md_alloc(dev_t dev, char *name)
        flush_scheduled_work();
 
        mutex_lock(&disks_mutex);
-       if (mddev->gendisk) {
-               mutex_unlock(&disks_mutex);
-               mddev_put(mddev);
-               return -EEXIST;
-       }
+       error = -EEXIST;
+       if (mddev->gendisk)
+               goto abort;
 
        if (name) {
                /* Need to ensure that 'name' is not a duplicate.
@@ -3860,17 +3862,15 @@ static int md_alloc(dev_t dev, char *name)
                        if (mddev2->gendisk &&
                            strcmp(mddev2->gendisk->disk_name, name) == 0) {
                                spin_unlock(&all_mddevs_lock);
-                               return -EEXIST;
+                               goto abort;
                        }
                spin_unlock(&all_mddevs_lock);
        }
 
+       error = -ENOMEM;
        mddev->queue = blk_alloc_queue(GFP_KERNEL);
-       if (!mddev->queue) {
-               mutex_unlock(&disks_mutex);
-               mddev_put(mddev);
-               return -ENOMEM;
-       }
+       if (!mddev->queue)
+               goto abort;
        mddev->queue->queuedata = mddev;
 
        /* Can be unlocked because the queue is new: no concurrency */
@@ -3880,11 +3880,9 @@ static int md_alloc(dev_t dev, char *name)
 
        disk = alloc_disk(1 << shift);
        if (!disk) {
-               mutex_unlock(&disks_mutex);
                blk_cleanup_queue(mddev->queue);
                mddev->queue = NULL;
-               mddev_put(mddev);
-               return -ENOMEM;
+               goto abort;
        }
        disk->major = MAJOR(mddev->unit);
        disk->first_minor = unit << shift;
@@ -3906,16 +3904,22 @@ static int md_alloc(dev_t dev, char *name)
        mddev->gendisk = disk;
        error = kobject_init_and_add(&mddev->kobj, &md_ktype,
                                     &disk_to_dev(disk)->kobj, "%s", "md");
-       mutex_unlock(&disks_mutex);
-       if (error)
+       if (error) {
+               /* This isn't possible, but as kobject_init_and_add is marked
+                * __must_check, we must do something with the result
+                */
                printk(KERN_WARNING "md: cannot register %s/md - name in use\n",
                       disk->disk_name);
-       else {
+               error = 0;
+       }
+ abort:
+       mutex_unlock(&disks_mutex);
+       if (!error) {
                kobject_uevent(&mddev->kobj, KOBJ_ADD);
                mddev->sysfs_state = sysfs_get_dirent(mddev->kobj.sd, "array_state");
        }
        mddev_put(mddev);
-       return 0;
+       return error;
 }
 
 static struct kobject *md_probe(dev_t dev, int *part, void *data)
@@ -6334,10 +6338,16 @@ void md_do_sync(mddev_t *mddev)
                        sysfs_notify(&mddev->kobj, NULL, "sync_completed");
                }
 
-               if (j >= mddev->resync_max)
-                       wait_event(mddev->recovery_wait,
-                                  mddev->resync_max > j
-                                  || kthread_should_stop());
+               while (j >= mddev->resync_max && !kthread_should_stop()) {
+                       /* As this condition is controlled by user-space,
+                        * we can block indefinitely, so use '_interruptible'
+                        * to avoid triggering warnings.
+                        */
+                       flush_signals(current); /* just in case */
+                       wait_event_interruptible(mddev->recovery_wait,
+                                                mddev->resync_max > j
+                                                || kthread_should_stop());
+               }
 
                if (kthread_should_stop())
                        goto interrupted;
index cbe368fa6598758da4d55b468acd8efd0d6c8710..237fe3fd235c86bd7648fedee32992f2660fb2df 100644 (file)
@@ -294,7 +294,8 @@ static int multipath_add_disk(mddev_t *mddev, mdk_rdev_t *rdev)
        for (path = first; path <= last; path++)
                if ((p=conf->multipaths+path)->rdev == NULL) {
                        q = rdev->bdev->bd_disk->queue;
-                       blk_queue_stack_limits(mddev->queue, q);
+                       disk_stack_limits(mddev->gendisk, rdev->bdev,
+                                         rdev->data_offset << 9);
 
                /* as we don't honour merge_bvec_fn, we must never risk
                 * violating it, so limit ->max_sector to one PAGE, as
@@ -463,9 +464,9 @@ static int multipath_run (mddev_t *mddev)
 
                disk = conf->multipaths + disk_idx;
                disk->rdev = rdev;
+               disk_stack_limits(mddev->gendisk, rdev->bdev,
+                                 rdev->data_offset << 9);
 
-               blk_queue_stack_limits(mddev->queue,
-                                      rdev->bdev->bd_disk->queue);
                /* as we don't honour merge_bvec_fn, we must never risk
                 * violating it, not that we ever expect a device with
                 * a merge_bvec_fn to be involved in multipath */
index ab4a489d8695f759e1ca4edc252f9636c5c31977..335f490dcad631ddaca2ad73509c900b2a505ad8 100644 (file)
@@ -170,8 +170,8 @@ static int create_strip_zones(mddev_t *mddev)
                }
                dev[j] = rdev1;
 
-               blk_queue_stack_limits(mddev->queue,
-                                      rdev1->bdev->bd_disk->queue);
+               disk_stack_limits(mddev->gendisk, rdev1->bdev,
+                                 rdev1->data_offset << 9);
                /* as we don't honour merge_bvec_fn, we must never risk
                 * violating it, so limit ->max_sector to one PAGE, as
                 * a one page request is never in violation.
@@ -250,6 +250,11 @@ static int create_strip_zones(mddev_t *mddev)
                       mddev->chunk_sectors << 9);
                goto abort;
        }
+
+       blk_queue_io_min(mddev->queue, mddev->chunk_sectors << 9);
+       blk_queue_io_opt(mddev->queue,
+                        (mddev->chunk_sectors << 9) * mddev->raid_disks);
+
        printk(KERN_INFO "raid0: done.\n");
        mddev->private = conf;
        return 0;
index 89939a7aef570b7673f163b0754bd87493646b25..0569efba0c02c379317b29d6c4ab82a57ec67ef7 100644 (file)
@@ -1123,8 +1123,8 @@ static int raid1_add_disk(mddev_t *mddev, mdk_rdev_t *rdev)
        for (mirror = first; mirror <= last; mirror++)
                if ( !(p=conf->mirrors+mirror)->rdev) {
 
-                       blk_queue_stack_limits(mddev->queue,
-                                              rdev->bdev->bd_disk->queue);
+                       disk_stack_limits(mddev->gendisk, rdev->bdev,
+                                         rdev->data_offset << 9);
                        /* as we don't honour merge_bvec_fn, we must never risk
                         * violating it, so limit ->max_sector to one PAGE, as
                         * a one page request is never in violation.
@@ -1988,9 +1988,8 @@ static int run(mddev_t *mddev)
                disk = conf->mirrors + disk_idx;
 
                disk->rdev = rdev;
-
-               blk_queue_stack_limits(mddev->queue,
-                                      rdev->bdev->bd_disk->queue);
+               disk_stack_limits(mddev->gendisk, rdev->bdev,
+                                 rdev->data_offset << 9);
                /* as we don't honour merge_bvec_fn, we must never risk
                 * violating it, so limit ->max_sector to one PAGE, as
                 * a one page request is never in violation.
index ae12ceafe10c557fa79d4e6c367ceae44d144327..7298a5e5a183f35f81e63706fe385dd125174a8b 100644 (file)
@@ -1151,8 +1151,8 @@ static int raid10_add_disk(mddev_t *mddev, mdk_rdev_t *rdev)
        for ( ; mirror <= last ; mirror++)
                if ( !(p=conf->mirrors+mirror)->rdev) {
 
-                       blk_queue_stack_limits(mddev->queue,
-                                              rdev->bdev->bd_disk->queue);
+                       disk_stack_limits(mddev->gendisk, rdev->bdev,
+                                         rdev->data_offset << 9);
                        /* as we don't honour merge_bvec_fn, we must never risk
                         * violating it, so limit ->max_sector to one PAGE, as
                         * a one page request is never in violation.
@@ -2044,7 +2044,7 @@ raid10_size(mddev_t *mddev, sector_t sectors, int raid_disks)
 static int run(mddev_t *mddev)
 {
        conf_t *conf;
-       int i, disk_idx;
+       int i, disk_idx, chunk_size;
        mirror_info_t *disk;
        mdk_rdev_t *rdev;
        int nc, fc, fo;
@@ -2130,6 +2130,14 @@ static int run(mddev_t *mddev)
        spin_lock_init(&conf->device_lock);
        mddev->queue->queue_lock = &conf->device_lock;
 
+       chunk_size = mddev->chunk_sectors << 9;
+       blk_queue_io_min(mddev->queue, chunk_size);
+       if (conf->raid_disks % conf->near_copies)
+               blk_queue_io_opt(mddev->queue, chunk_size * conf->raid_disks);
+       else
+               blk_queue_io_opt(mddev->queue, chunk_size *
+                                (conf->raid_disks / conf->near_copies));
+
        list_for_each_entry(rdev, &mddev->disks, same_set) {
                disk_idx = rdev->raid_disk;
                if (disk_idx >= mddev->raid_disks
@@ -2138,9 +2146,8 @@ static int run(mddev_t *mddev)
                disk = conf->mirrors + disk_idx;
 
                disk->rdev = rdev;
-
-               blk_queue_stack_limits(mddev->queue,
-                                      rdev->bdev->bd_disk->queue);
+               disk_stack_limits(mddev->gendisk, rdev->bdev,
+                                 rdev->data_offset << 9);
                /* as we don't honour merge_bvec_fn, we must never risk
                 * violating it, so limit ->max_sector to one PAGE, as
                 * a one page request is never in violation.
index f9f991e6e1389ffc90860571edf701ca13a6f292..37835538b58ef8aa4e07595274b1ea5ec27e7c81 100644 (file)
@@ -3699,13 +3699,21 @@ static int make_request(struct request_queue *q, struct bio * bi)
                                        goto retry;
                                }
                        }
-                       /* FIXME what if we get a false positive because these
-                        * are being updated.
-                        */
-                       if (logical_sector >= mddev->suspend_lo &&
+
+                       if (bio_data_dir(bi) == WRITE &&
+                           logical_sector >= mddev->suspend_lo &&
                            logical_sector < mddev->suspend_hi) {
                                release_stripe(sh);
-                               schedule();
+                               /* As the suspend_* range is controlled by
+                                * userspace, we want an interruptible
+                                * wait.
+                                */
+                               flush_signals(current);
+                               prepare_to_wait(&conf->wait_for_overlap,
+                                               &w, TASK_INTERRUPTIBLE);
+                               if (logical_sector >= mddev->suspend_lo &&
+                                   logical_sector < mddev->suspend_hi)
+                                       schedule();
                                goto retry;
                        }
 
@@ -4452,7 +4460,7 @@ static raid5_conf_t *setup_conf(mddev_t *mddev)
 static int run(mddev_t *mddev)
 {
        raid5_conf_t *conf;
-       int working_disks = 0;
+       int working_disks = 0, chunk_size;
        mdk_rdev_t *rdev;
 
        if (mddev->recovery_cp != MaxSector)
@@ -4607,6 +4615,14 @@ static int run(mddev_t *mddev)
        md_set_array_sectors(mddev, raid5_size(mddev, 0, 0));
 
        blk_queue_merge_bvec(mddev->queue, raid5_mergeable_bvec);
+       chunk_size = mddev->chunk_sectors << 9;
+       blk_queue_io_min(mddev->queue, chunk_size);
+       blk_queue_io_opt(mddev->queue, chunk_size *
+                        (conf->raid_disks - conf->max_degraded));
+
+       list_for_each_entry(rdev, &mddev->disks, same_set)
+               disk_stack_limits(mddev->gendisk, rdev->bdev,
+                                 rdev->data_offset << 9);
 
        return 0;
 abort:
index b6da9c3873fef280ba89d00234053d3a62b11ec6..aa20ce8cc668ba96b566d3aa45119a6b93e37889 100644 (file)
@@ -1096,8 +1096,19 @@ static int xc2028_set_params(struct dvb_frontend *fe,
        }
 
        /* All S-code tables need a 200kHz shift */
-       if (priv->ctrl.demod)
+       if (priv->ctrl.demod) {
                demod = priv->ctrl.demod + 200;
+               /*
+                * The DTV7 S-code table needs a 700 kHz shift.
+                * Thanks to Terry Wu <terrywu2009@gmail.com> for reporting this
+                *
+                * DTV7 is only used in Australia.  Germany or Italy may also
+                * use this firmware after initialization, but a tune to a UHF
+                * channel should then cause DTV78 to be used.
+                */
+               if (type & DTV7)
+                       demod += 500;
+       }
 
        return generic_set_freq(fe, p->frequency,
                                T_DIGITAL_TV, type, 0, demod);
index 4601b059b2b20008b7b277f725ec66d207c83e42..0e246eaad05ab441360963e02672945e6d61534b 100644 (file)
@@ -21,6 +21,7 @@
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/init.h>
+#include <linux/smp_lock.h>
 #include <linux/string.h>
 #include <linux/dvb/ca.h>
 #include "dvbdev.h"
index 79927305e84d42e63030e720a43c617c7f493b04..487919bea7ae0bf147004b6845611f24eea0537f 100644 (file)
@@ -27,7 +27,6 @@
 #include <linux/poll.h>
 #include <linux/fs.h>
 #include <linux/list.h>
-#include <linux/smp_lock.h>
 
 #define DVB_MAJOR 212
 
index 68eb4493f991f64d08dc078225dc599380379ccc..d8d4214fd65f2c7af9d3af1a263a30f9dc24e3a9 100644 (file)
@@ -1,5 +1,6 @@
 config TTPCI_EEPROM
        tristate
+       depends on I2C
        default n
 
 config DVB_AV7110
index d1d959ed37b7947562394af311273e0343aec2c6..8d65c652ba5062c5c51765b887ea82ddb616f6f0 100644 (file)
@@ -36,7 +36,6 @@
 #include <linux/fs.h>
 #include <linux/timer.h>
 #include <linux/poll.h>
-#include <linux/smp_lock.h>
 
 #include <linux/kernel.h>
 #include <linux/sched.h>
index 837467f93805e9c2f32b37c0f71cce6d3852ffef..575bf9d894193f83d465ced201bad022f1fb87b6 100644 (file)
@@ -58,6 +58,7 @@
 #include <linux/module.h>
 #include <linux/init.h>
 #include <linux/slab.h>
+#include <linux/smp_lock.h>
 #include <linux/input.h>
 #include <linux/videodev2.h>
 #include <media/v4l2-device.h>
index 640421ceb24a2a48918b1692367c5394c6fd7968..e85f318b4d2b4131ff00395e61d17c66eeeecc18 100644 (file)
 #include <linux/module.h>
 #include <linux/init.h>
 #include <linux/slab.h>
+#include <linux/smp_lock.h>
 #include <linux/input.h>
 #include <linux/usb.h>
 #include <linux/hid.h>
@@ -1200,7 +1201,7 @@ static int si470x_fops_release(struct file *file)
                        video_unregister_device(radio->videodev);
                        kfree(radio->buffer);
                        kfree(radio);
-                       goto done;
+                       goto unlock;
                }
 
                /* stop rds reception */
@@ -1213,9 +1214,8 @@ static int si470x_fops_release(struct file *file)
                retval = si470x_stop(radio);
                usb_autopm_put_interface(radio->intf);
        }
-
+unlock:
        mutex_unlock(&radio->disconnect_lock);
-
 done:
        return retval;
 }
index 061e147f6f2638d0c573e741a86d2e9dbe4a0630..84b6fc15519d13807cf8c3601e4551ac87d72f49 100644 (file)
@@ -312,6 +312,14 @@ config VIDEO_OV7670
          OV7670 VGA camera.  It currently only works with the M88ALP01
          controller.
 
+config VIDEO_MT9V011
+       tristate "Micron mt9v011 sensor support"
+       depends on I2C && VIDEO_V4L2
+       ---help---
+         This is a Video4Linux2 sensor-level driver for the Micron
+         mt0v011 1.3 Mpixel camera.  It currently only works with the
+         em28xx driver.
+
 config VIDEO_TCM825X
        tristate "TCM825x camera sensor support"
        depends on I2C && VIDEO_V4L2
index 7fb3add1b387916d9729279b2e78a2a786c7505a..9f2e3214a48207245dc2482b3f1f54777679c48a 100644 (file)
@@ -69,6 +69,7 @@ obj-$(CONFIG_VIDEO_UPD64083) += upd64083.o
 obj-$(CONFIG_VIDEO_OV7670)     += ov7670.o
 obj-$(CONFIG_VIDEO_TCM825X) += tcm825x.o
 obj-$(CONFIG_VIDEO_TVEEPROM) += tveeprom.o
+obj-$(CONFIG_VIDEO_MT9V011) += mt9v011.o
 
 obj-$(CONFIG_SOC_CAMERA_MT9M001)       += mt9m001.o
 obj-$(CONFIG_SOC_CAMERA_MT9M111)       += mt9m111.o
index 5eb1464af6703f3825599e05bc4683a2e09dc250..d147d29bb0d33144cf875bfe2a06044d7754f832 100644 (file)
@@ -41,6 +41,7 @@
 #include <linux/fs.h>
 #include <linux/kernel.h>
 #include <linux/sched.h>
+#include <linux/smp_lock.h>
 #include <linux/interrupt.h>
 #include <linux/kdev_t.h>
 #include "bttvp.h"
index c92a25036f0e291768a131ceff4b349b59dd34cd..36f2d76006fd419243472a206b5a78f27489e119 100644 (file)
@@ -198,11 +198,14 @@ static const struct cx18_card_pci_info cx18_pci_mpc718[] = {
 
 static const struct cx18_card cx18_card_mpc718 = {
        .type = CX18_CARD_YUAN_MPC718,
-       .name = "Yuan MPC718",
-       .comment = "Analog video capture works; some audio line in may not.\n",
+       .name = "Yuan MPC718 MiniPCI DVB-T/Analog",
+       .comment = "Experimenters needed for device to work well.\n"
+                 "\tTo help, mail the ivtv-devel list (www.ivtvdriver.org).\n",
        .v4l2_capabilities = CX18_CAP_ENCODER,
        .hw_audio_ctrl = CX18_HW_418_AV,
-       .hw_all = CX18_HW_418_AV | CX18_HW_TUNER | CX18_HW_GPIO_RESET_CTRL,
+       .hw_muxer = CX18_HW_GPIO_MUX,
+       .hw_all = CX18_HW_418_AV | CX18_HW_TUNER |
+                 CX18_HW_GPIO_MUX | CX18_HW_DVB | CX18_HW_GPIO_RESET_CTRL,
        .video_inputs = {
                { CX18_CARD_INPUT_VID_TUNER,  0, CX18_AV_COMPOSITE2 },
                { CX18_CARD_INPUT_SVIDEO1,    1,
@@ -211,27 +214,34 @@ static const struct cx18_card cx18_card_mpc718 = {
                { CX18_CARD_INPUT_SVIDEO2,    2,
                                CX18_AV_SVIDEO_LUMA7 | CX18_AV_SVIDEO_CHROMA8 },
                { CX18_CARD_INPUT_COMPOSITE2, 2, CX18_AV_COMPOSITE6 },
-               { CX18_CARD_INPUT_COMPOSITE3, 2, CX18_AV_COMPOSITE3 },
        },
        .audio_inputs = {
                { CX18_CARD_INPUT_AUD_TUNER, CX18_AV_AUDIO5,        0 },
-               { CX18_CARD_INPUT_LINE_IN1,  CX18_AV_AUDIO_SERIAL1, 0 },
-               { CX18_CARD_INPUT_LINE_IN2,  CX18_AV_AUDIO_SERIAL1, 0 },
+               { CX18_CARD_INPUT_LINE_IN1,  CX18_AV_AUDIO_SERIAL1, 1 },
+               { CX18_CARD_INPUT_LINE_IN2,  CX18_AV_AUDIO_SERIAL2, 1 },
        },
-       .radio_input = { CX18_CARD_INPUT_AUD_TUNER, CX18_AV_AUDIO_SERIAL1, 0 },
        .tuners = {
                /* XC3028 tuner */
                { .std = V4L2_STD_ALL, .tuner = TUNER_XC2028 },
        },
+       /* FIXME - the FM radio is just a guess and driver doesn't use SIF */
+       .radio_input = { CX18_CARD_INPUT_AUD_TUNER, CX18_AV_AUDIO5, 2 },
        .ddr = {
-               /* Probably Samsung K4D263238G-VC33 memory */
-               .chip_config = 0x003,
-               .refresh = 0x30c,
-               .timing1 = 0x23230b73,
-               .timing2 = 0x08,
+               /* Hynix HY5DU283222B DDR RAM */
+               .chip_config = 0x303,
+               .refresh = 0x3bd,
+               .timing1 = 0x36320966,
+               .timing2 = 0x1f,
                .tune_lane = 0,
                .initial_emrs = 2,
        },
+       .gpio_init.initial_value = 0x1,
+       .gpio_init.direction = 0x3,
+       /* FIXME - these GPIO's are just guesses */
+       .gpio_audio_input = { .mask   = 0x3,
+                             .tuner  = 0x1,
+                             .linein = 0x3,
+                             .radio  = 0x1 },
        .xceive_pin = 0,
        .pci_list = cx18_pci_mpc718,
        .i2c = &cx18_i2c_std,
index 6ea3fe623ef49470d9a900197f41a3768f440596..51a0c33b25b7fc84de53cce923672ee260ed8021 100644 (file)
 #include "s5h1409.h"
 #include "mxl5005s.h"
 #include "zl10353.h"
+
+#include <linux/firmware.h>
+#include "mt352.h"
+#include "mt352_priv.h"
 #include "tuner-xc2028.h"
 
 DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
@@ -38,6 +42,11 @@ DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
 #define CX18_CLOCK_ENABLE2              0xc71024
 #define CX18_DMUX_CLK_MASK              0x0080
 
+/*
+ * CX18_CARD_HVR_1600_ESMT
+ * CX18_CARD_HVR_1600_SAMSUNG
+ */
+
 static struct mxl5005s_config hauppauge_hvr1600_tuner = {
        .i2c_address     = 0xC6 >> 1,
        .if_freq         = IF_FREQ_5380000HZ,
@@ -65,6 +74,9 @@ static struct s5h1409_config hauppauge_hvr1600_config = {
        .mpeg_timing   = S5H1409_MPEGTIMING_CONTINOUS_NONINVERTING_CLOCK
 };
 
+/*
+ * CX18_CARD_LEADTEK_DVR3100H
+ */
 /* Information/confirmation of proper config values provided by Terry Wu */
 static struct zl10353_config leadtek_dvr3100h_demod = {
        .demod_address         = 0x1e >> 1, /* Datasheet suggested straps */
@@ -74,6 +86,121 @@ static struct zl10353_config leadtek_dvr3100h_demod = {
        .disable_i2c_gate_ctrl = 1,         /* Disable the I2C gate */
 };
 
+/*
+ * CX18_CARD_YUAN_MPC718
+ */
+/*
+ * Due to
+ *
+ * 1. an absence of information on how to prgram the MT352
+ * 2. the Linux mt352 module pushing MT352 initialzation off onto us here
+ *
+ * We have to use an init sequence that *you* must extract from the Windows
+ * driver (yuanrap.sys) and which we load as a firmware.
+ *
+ * If someone can provide me with a Zarlink MT352 (Intel CE6352?) Design Manual
+ * with chip programming details, then I can remove this annoyance.
+ */
+static int yuan_mpc718_mt352_reqfw(struct cx18_stream *stream,
+                                  const struct firmware **fw)
+{
+       struct cx18 *cx = stream->cx;
+       const char *fn = "dvb-cx18-mpc718-mt352.fw";
+       int ret;
+
+       ret = request_firmware(fw, fn, &cx->pci_dev->dev);
+       if (ret)
+               CX18_ERR("Unable to open firmware file %s\n", fn);
+       else {
+               size_t sz = (*fw)->size;
+               if (sz < 2 || sz > 64 || (sz % 2) != 0) {
+                       CX18_ERR("Firmware %s has a bad size: %lu bytes\n",
+                                fn, (unsigned long) sz);
+                       ret = -EILSEQ;
+                       release_firmware(*fw);
+                       *fw = NULL;
+               }
+       }
+
+       if (ret) {
+               CX18_ERR("The MPC718 board variant with the MT352 DVB-T"
+                         "demodualtor will not work without it\n");
+               CX18_ERR("Run 'linux/Documentation/dvb/get_dvb_firmware "
+                         "mpc718' if you need the firmware\n");
+       }
+       return ret;
+}
+
+static int yuan_mpc718_mt352_init(struct dvb_frontend *fe)
+{
+       struct cx18_dvb *dvb = container_of(fe->dvb,
+                                           struct cx18_dvb, dvb_adapter);
+       struct cx18_stream *stream = container_of(dvb, struct cx18_stream, dvb);
+       const struct firmware *fw = NULL;
+       int ret;
+       int i;
+       u8 buf[3];
+
+       ret = yuan_mpc718_mt352_reqfw(stream, &fw);
+       if (ret)
+               return ret;
+
+       /* Loop through all the register-value pairs in the firmware file */
+       for (i = 0; i < fw->size; i += 2) {
+               buf[0] = fw->data[i];
+               /* Intercept a few registers we want to set ourselves */
+               switch (buf[0]) {
+               case TRL_NOMINAL_RATE_0:
+                       /* Set our custom OFDM bandwidth in the case below */
+                       break;
+               case TRL_NOMINAL_RATE_1:
+                       /* 6 MHz: 64/7 * 6/8 / 20.48 * 2^16 = 0x55b6.db6 */
+                       /* 7 MHz: 64/7 * 7/8 / 20.48 * 2^16 = 0x6400 */
+                       /* 8 MHz: 64/7 * 8/8 / 20.48 * 2^16 = 0x7249.249 */
+                       buf[1] = 0x72;
+                       buf[2] = 0x49;
+                       mt352_write(fe, buf, 3);
+                       break;
+               case INPUT_FREQ_0:
+                       /* Set our custom IF in the case below */
+                       break;
+               case INPUT_FREQ_1:
+                       /* 4.56 MHz IF: (20.48 - 4.56)/20.48 * 2^14 = 0x31c0 */
+                       buf[1] = 0x31;
+                       buf[2] = 0xc0;
+                       mt352_write(fe, buf, 3);
+                       break;
+               default:
+                       /* Pass through the register-value pair from the fw */
+                       buf[1] = fw->data[i+1];
+                       mt352_write(fe, buf, 2);
+                       break;
+               }
+       }
+
+       buf[0] = (u8) TUNER_GO;
+       buf[1] = 0x01; /* Go */
+       mt352_write(fe, buf, 2);
+       release_firmware(fw);
+       return 0;
+}
+
+static struct mt352_config yuan_mpc718_mt352_demod = {
+       .demod_address = 0x1e >> 1,
+       .adc_clock     = 20480,     /* 20.480 MHz */
+       .if2           =  4560,     /*  4.560 MHz */
+       .no_tuner      = 1,         /* XC3028 is not behind the gate */
+       .demod_init    = yuan_mpc718_mt352_init,
+};
+
+static struct zl10353_config yuan_mpc718_zl10353_demod = {
+       .demod_address         = 0x1e >> 1, /* Datasheet suggested straps */
+       .if2                   = 45600,     /* 4.560 MHz IF from the XC3028 */
+       .parallel_ts           = 1,         /* Not a serial TS */
+       .no_tuner              = 1,         /* XC3028 is not behind the gate */
+       .disable_i2c_gate_ctrl = 1,         /* Disable the I2C gate */
+};
+
 static int dvb_register(struct cx18_stream *stream);
 
 /* Kernel DVB framework calls this when the feed needs to start.
@@ -113,6 +240,7 @@ static int cx18_dvb_start_feed(struct dvb_demux_feed *feed)
                break;
 
        case CX18_CARD_LEADTEK_DVR3100H:
+       case CX18_CARD_YUAN_MPC718:
        default:
                /* Assumption - Parallel transport - Signalling
                 * undefined or default.
@@ -326,6 +454,38 @@ static int dvb_register(struct cx18_stream *stream)
                                fe->ops.tuner_ops.set_config(fe, &ctrl);
                }
                break;
+       case CX18_CARD_YUAN_MPC718:
+               /*
+                * TODO
+                * Apparently, these cards also could instead have a
+                * DiBcom demod supported by one of the db7000 drivers
+                */
+               dvb->fe = dvb_attach(mt352_attach,
+                                    &yuan_mpc718_mt352_demod,
+                                    &cx->i2c_adap[1]);
+               if (dvb->fe == NULL)
+                       dvb->fe = dvb_attach(zl10353_attach,
+                                            &yuan_mpc718_zl10353_demod,
+                                            &cx->i2c_adap[1]);
+               if (dvb->fe != NULL) {
+                       struct dvb_frontend *fe;
+                       struct xc2028_config cfg = {
+                               .i2c_adap = &cx->i2c_adap[1],
+                               .i2c_addr = 0xc2 >> 1,
+                               .ctrl = NULL,
+                       };
+                       static struct xc2028_ctrl ctrl = {
+                               .fname   = XC2028_DEFAULT_FIRMWARE,
+                               .max_len = 64,
+                               .demod   = XC3028_FE_ZARLINK456,
+                               .type    = XC2028_AUTO,
+                       };
+
+                       fe = dvb_attach(xc2028_attach, dvb->fe, &cfg);
+                       if (fe != NULL && fe->ops.tuner_ops.set_config != NULL)
+                               fe->ops.tuner_ops.set_config(fe, &ctrl);
+               }
+               break;
        default:
                /* No Digital Tv Support */
                break;
index 2943bfd32a94a4b74acb19d6a9076abd7e1d3388..428f0c45e6b7dba778ff899d34793f57fadbcf54 100644 (file)
@@ -31,6 +31,7 @@
 #include <linux/delay.h>
 #include <linux/device.h>
 #include <linux/firmware.h>
+#include <linux/smp_lock.h>
 #include <media/v4l2-common.h>
 #include <media/v4l2-ioctl.h>
 #include <media/cx2341x.h>
index 48a975134ac5fba0c3d2ab05a85ca0d035a3eb80..86ac529e62be0be042ea6912225ddf9d7d1d89bc 100644 (file)
@@ -463,6 +463,30 @@ static struct xc5000_config mygica_x8506_xc5000_config = {
        .if_khz = 5380,
 };
 
+static int cx23885_dvb_set_frontend(struct dvb_frontend *fe,
+                                   struct dvb_frontend_parameters *param)
+{
+       struct cx23885_tsport *port = fe->dvb->priv;
+       struct cx23885_dev *dev = port->dev;
+
+       switch (dev->board) {
+       case CX23885_BOARD_HAUPPAUGE_HVR1275:
+               switch (param->u.vsb.modulation) {
+               case VSB_8:
+                       cx23885_gpio_clear(dev, GPIO_5);
+                       break;
+               case QAM_64:
+               case QAM_256:
+               default:
+                       cx23885_gpio_set(dev, GPIO_5);
+                       break;
+               }
+               break;
+       }
+       return (port->set_frontend_save) ?
+               port->set_frontend_save(fe, param) : -ENODEV;
+}
+
 static int dvb_register(struct cx23885_tsport *port)
 {
        struct cx23885_dev *dev = port->dev;
@@ -502,6 +526,12 @@ static int dvb_register(struct cx23885_tsport *port)
                                   0x60, &dev->i2c_bus[1].i2c_adap,
                                   &hauppauge_hvr127x_config);
                }
+
+               /* FIXME: temporary hack */
+               /* define bridge override to set_frontend */
+               port->set_frontend_save = fe0->dvb.frontend->ops.set_frontend;
+               fe0->dvb.frontend->ops.set_frontend = cx23885_dvb_set_frontend;
+
                break;
        case CX23885_BOARD_HAUPPAUGE_HVR1255:
                i2c_bus = &dev->i2c_bus[0];
index 70836af3ab4891a624a87225d6ec0bf2cdd8cf32..5d6093336300dc79731177dbaada479bcd40fcac 100644 (file)
@@ -26,6 +26,7 @@
 #include <linux/kmod.h>
 #include <linux/kernel.h>
 #include <linux/slab.h>
+#include <linux/smp_lock.h>
 #include <linux/interrupt.h>
 #include <linux/delay.h>
 #include <linux/kthread.h>
index 1a2ac518a3f1ae21362ae8694a4289d1d4c78cba..214a55e943b783dc7a6cfaab95bb25f4fe504ee1 100644 (file)
@@ -288,6 +288,10 @@ struct cx23885_tsport {
        /* Allow a single tsport to have multiple frontends */
        u32                        num_frontends;
        void                       *port_priv;
+
+       /* FIXME: temporary hack */
+       int (*set_frontend_save) (struct dvb_frontend *,
+                                 struct dvb_frontend_parameters *);
 };
 
 struct cx23885_dev {
index 44eacfb0d0d6073db886168e8d4120f99cd76ae7..356d6896da3f5877e5961fb4d009309fe68cae33 100644 (file)
@@ -32,6 +32,7 @@
 #include <linux/delay.h>
 #include <linux/device.h>
 #include <linux/firmware.h>
+#include <linux/smp_lock.h>
 #include <media/v4l2-common.h>
 #include <media/v4l2-ioctl.h>
 #include <media/cx2341x.h>
index b12770848c00161e5355fd05c0816fbb9e0c3134..2bb54c3ef5cdcefbc708718aebee684005f80e3d 100644 (file)
@@ -31,6 +31,7 @@
 #include <linux/kmod.h>
 #include <linux/kernel.h>
 #include <linux/slab.h>
+#include <linux/smp_lock.h>
 #include <linux/interrupt.h>
 #include <linux/dma-mapping.h>
 #include <linux/delay.h>
index ec2f45dde1643d72a849aa15004bbde91a1ff2c3..0664d111085f262db7e621d21f0ed20b41a85856 100644 (file)
@@ -32,6 +32,7 @@
 #include <linux/list.h>
 #include <linux/vmalloc.h>
 #include <linux/slab.h>
+#include <linux/smp_lock.h>
 #include <linux/init.h>
 #include <asm/uaccess.h>
 #include <asm/atomic.h>
index 16a5af30e9d1fd1e4184da4969d5956798f8a76a..6524b493e033ed5529d811bfbaaa488ec6618c16 100644 (file)
@@ -8,6 +8,8 @@ config VIDEO_EM28XX
        select VIDEO_SAA711X if VIDEO_HELPER_CHIPS_AUTO
        select VIDEO_TVP5150 if VIDEO_HELPER_CHIPS_AUTO
        select VIDEO_MSP3400 if VIDEO_HELPER_CHIPS_AUTO
+       select VIDEO_MT9V011 if VIDEO_HELPER_CHIPS_AUTO
+
        ---help---
          This is a video4linux driver for Empia 28xx based TV cards.
 
index c43fdb9bc88810c3f2f658f8cb3495d70940a3c2..ebd24a25fb8510043245cacfab39c1e4553ab624 100644 (file)
@@ -58,6 +58,8 @@ static unsigned int card[]     = {[0 ... (EM28XX_MAXBOARDS - 1)] = UNSET };
 module_param_array(card,  int, NULL, 0444);
 MODULE_PARM_DESC(card,     "card type");
 
+#define MT9V011_VERSION                 0x8243
+
 /* Bitmask marking allocated devices from 0 to EM28XX_MAXBOARDS */
 static unsigned long em28xx_devused;
 
@@ -191,6 +193,13 @@ static struct em28xx_reg_seq terratec_av350_unmute_gpio[] = {
        {EM28XX_R08_GPIO,       0xff,   0xff,           10},
        {       -1,             -1,     -1,             -1},
 };
+
+static struct em28xx_reg_seq silvercrest_reg_seq[] = {
+       {EM28XX_R08_GPIO,       0xff,   0xff,           10},
+       {EM28XX_R08_GPIO,       0x01,   0xf7,           10},
+       {       -1,             -1,     -1,             -1},
+};
+
 /*
  *  Board definitions
  */
@@ -438,6 +447,18 @@ struct em28xx_board em28xx_boards[] = {
                        .amux     = EM28XX_AMUX_VIDEO,
                } },
        },
+       [EM2820_BOARD_SILVERCREST_WEBCAM] = {
+               .name         = "Silvercrest Webcam 1.3mpix",
+               .tuner_type   = TUNER_ABSENT,
+               .is_27xx      = 1,
+               .decoder      = EM28XX_MT9V011,
+               .input        = { {
+                       .type     = EM28XX_VMUX_COMPOSITE1,
+                       .vmux     = 0,
+                       .amux     = EM28XX_AMUX_VIDEO,
+                       .gpio     = silvercrest_reg_seq,
+               } },
+       },
        [EM2821_BOARD_SUPERCOMP_USB_2] = {
                .name         = "Supercomp USB 2.0 TV",
                .valid        = EM28XX_BOARD_NOT_VALIDATED,
@@ -826,7 +847,7 @@ struct em28xx_board em28xx_boards[] = {
                .tuner_gpio     = default_tuner_gpio,
                .decoder        = EM28XX_TVP5150,
                .has_dvb        = 1,
-               .dvb_gpio       = default_analog,
+               .dvb_gpio       = default_digital,
                .input          = { {
                        .type     = EM28XX_VMUX_TELEVISION,
                        .vmux     = TVP5150_COMPOSITE0,
@@ -1639,6 +1660,11 @@ static unsigned short tvp5150_addrs[] = {
        I2C_CLIENT_END
 };
 
+static unsigned short mt9v011_addrs[] = {
+       0xba >> 1,
+       I2C_CLIENT_END
+};
+
 static unsigned short msp3400_addrs[] = {
        0x80 >> 1,
        0x88 >> 1,
@@ -1678,6 +1704,46 @@ static inline void em28xx_set_model(struct em28xx *dev)
                                       EM28XX_I2C_FREQ_100_KHZ;
 }
 
+/* HINT method: webcam I2C chips
+ *
+ * This method work for webcams with Micron sensors
+ */
+static int em28xx_hint_sensor(struct em28xx *dev)
+{
+       int rc;
+       char *sensor_name;
+       unsigned char cmd;
+       __be16 version_be;
+       u16 version;
+
+       if (dev->model != EM2820_BOARD_UNKNOWN)
+               return 0;
+
+       dev->i2c_client.addr = 0xba >> 1;
+       cmd = 0;
+       i2c_master_send(&dev->i2c_client, &cmd, 1);
+       rc = i2c_master_recv(&dev->i2c_client, (char *)&version_be, 2);
+       if (rc != 2)
+               return -EINVAL;
+
+       version = be16_to_cpu(version_be);
+
+       switch (version) {
+       case MT9V011_VERSION:
+               dev->model = EM2820_BOARD_SILVERCREST_WEBCAM;
+               sensor_name = "mt9v011";
+               break;
+       default:
+               printk("Unknown Sensor 0x%04x\n", be16_to_cpu(version));
+               return -EINVAL;
+       }
+
+       em28xx_errdev("Sensor is %s, assuming that webcam is %s\n",
+                     sensor_name, em28xx_boards[dev->model].name);
+
+       return 0;
+}
+
 /* Since em28xx_pre_card_setup() requires a proper dev->model,
  * this won't work for boards with generic PCI IDs
  */
@@ -1706,7 +1772,10 @@ void em28xx_pre_card_setup(struct em28xx *dev)
                        em28xx_info("chip ID is em2750\n");
                        break;
                case CHIP_ID_EM2820:
-                       em28xx_info("chip ID is em2820\n");
+                       if (dev->board.is_27xx)
+                               em28xx_info("chip is em2710\n");
+                       else
+                               em28xx_info("chip ID is em2820\n");
                        break;
                case CHIP_ID_EM2840:
                        em28xx_info("chip ID is em2840\n");
@@ -2158,6 +2227,10 @@ void em28xx_card_setup(struct em28xx *dev)
                   before probing the i2c bus. */
                em28xx_set_mode(dev, EM28XX_ANALOG_MODE);
                break;
+       case EM2820_BOARD_SILVERCREST_WEBCAM:
+               /* FIXME: need to document the registers bellow */
+               em28xx_write_reg(dev, 0x0d, 0x42);
+               em28xx_write_reg(dev, 0x13, 0x08);
        }
 
        if (dev->board.has_snapshot_button)
@@ -2189,6 +2262,10 @@ void em28xx_card_setup(struct em28xx *dev)
                v4l2_i2c_new_probed_subdev(&dev->v4l2_dev, &dev->i2c_adap,
                        "tvp5150", "tvp5150", tvp5150_addrs);
 
+       if (dev->board.decoder == EM28XX_MT9V011)
+               v4l2_i2c_new_probed_subdev(&dev->v4l2_dev, &dev->i2c_adap,
+                       "mt9v011", "mt9v011", mt9v011_addrs);
+
        if (dev->board.adecoder == EM28XX_TVAUDIO)
                v4l2_i2c_new_subdev(&dev->v4l2_dev, &dev->i2c_adap,
                        "tvaudio", "tvaudio", dev->board.tvaudio_addr);
@@ -2333,6 +2410,8 @@ static int em28xx_init_dev(struct em28xx **devhandle, struct usb_device *udev,
                return errCode;
        }
 
+       em28xx_hint_sensor(dev);
+
        /* Do board specific init and eeprom reading */
        em28xx_card_setup(dev);
 
@@ -2573,6 +2652,7 @@ static int em28xx_usb_probe(struct usb_interface *interface,
        retval = em28xx_init_dev(&dev, udev, interface, nr);
        if (retval) {
                em28xx_devused &= ~(1<<dev->devno);
+               mutex_unlock(&dev->lock);
                kfree(dev);
                goto err;
        }
index c8d7ce8fbd368a403c47e6260e036801182144e9..079ab4d563a62c4a41b6db6ff9d3df70a03a4e26 100644 (file)
@@ -648,17 +648,28 @@ int em28xx_capture_start(struct em28xx *dev, int start)
 int em28xx_set_outfmt(struct em28xx *dev)
 {
        int ret;
+       int vinmode, vinctl, outfmt;
+
+       outfmt  = dev->format->reg;
+
+       if (dev->board.is_27xx) {
+               vinmode = 0x0d;
+               vinctl  = 0x00;
+       } else {
+               vinmode = 0x10;
+               vinctl  = 0x11;
+       }
 
        ret = em28xx_write_reg_bits(dev, EM28XX_R27_OUTFMT,
-                                   dev->format->reg | 0x20, 0x3f);
+                               outfmt | 0x20, 0xff);
        if (ret < 0)
-               return ret;
+                       return ret;
 
-       ret = em28xx_write_reg(dev, EM28XX_R10_VINMODE, 0x10);
+       ret = em28xx_write_reg(dev, EM28XX_R10_VINMODE, vinmode);
        if (ret < 0)
                return ret;
 
-       return em28xx_write_reg(dev, EM28XX_R11_VINCTRL, 0x11);
+       return em28xx_write_reg(dev, EM28XX_R11_VINCTRL, vinctl);
 }
 
 static int em28xx_accumulator_set(struct em28xx *dev, u8 xmin, u8 xmax,
@@ -695,13 +706,19 @@ static int em28xx_scaler_set(struct em28xx *dev, u16 h, u16 v)
 {
        u8 mode;
        /* the em2800 scaler only supports scaling down to 50% */
-       if (dev->board.is_em2800)
+
+       if (dev->board.is_27xx) {
+               /* FIXME: Don't use the scaler yet */
+               mode = 0;
+       } else if (dev->board.is_em2800) {
                mode = (v ? 0x20 : 0x00) | (h ? 0x10 : 0x00);
-       else {
+       else {
                u8 buf[2];
+
                buf[0] = h;
                buf[1] = h >> 8;
                em28xx_write_regs(dev, EM28XX_R30_HSCALELOW, (char *)buf, 2);
+
                buf[0] = v;
                buf[1] = v >> 8;
                em28xx_write_regs(dev, EM28XX_R32_VSCALELOW, (char *)buf, 2);
@@ -720,8 +737,11 @@ int em28xx_resolution_set(struct em28xx *dev)
        height = norm_maxh(dev) >> 1;
 
        em28xx_set_outfmt(dev);
+
+
        em28xx_accumulator_set(dev, 1, (width - 4) >> 2, 1, (height - 4) >> 2);
        em28xx_capture_area_set(dev, 0, 0, width >> 2, height >> 2);
+
        return em28xx_scaler_set(dev, dev->hscale, dev->vscale);
 }
 
index e7b47c8da8f3e7732208d666d952391717526883..3da97c32b8fad9ee2c315572143ba52fa217eef2 100644 (file)
@@ -243,6 +243,14 @@ static struct s5h1409_config em28xx_s5h1409_with_xc3028 = {
        .mpeg_timing   = S5H1409_MPEGTIMING_CONTINOUS_NONINVERTING_CLOCK
 };
 
+static struct zl10353_config em28xx_terratec_xs_zl10353_xc3028 = {
+       .demod_address = (0x1e >> 1),
+       .no_tuner = 1,
+       .disable_i2c_gate_ctrl = 1,
+       .parallel_ts = 1,
+       .if2 = 45600,
+};
+
 #ifdef EM28XX_DRX397XD_SUPPORT
 /* [TODO] djh - not sure yet what the device config needs to contain */
 static struct drx397xD_config em28xx_drx397xD_with_xc3028 = {
@@ -433,7 +441,6 @@ static int dvb_init(struct em28xx *dev)
                }
                break;
        case EM2880_BOARD_HAUPPAUGE_WINTV_HVR_900:
-       case EM2880_BOARD_TERRATEC_HYBRID_XS:
        case EM2880_BOARD_KWORLD_DVB_310U:
        case EM2880_BOARD_EMPIRE_DUAL_TV:
                dvb->frontend = dvb_attach(zl10353_attach,
@@ -444,6 +451,25 @@ static int dvb_init(struct em28xx *dev)
                        goto out_free;
                }
                break;
+       case EM2880_BOARD_TERRATEC_HYBRID_XS:
+               dvb->frontend = dvb_attach(zl10353_attach,
+                                          &em28xx_terratec_xs_zl10353_xc3028,
+                                          &dev->i2c_adap);
+               if (dvb->frontend == NULL) {
+                       /* This board could have either a zl10353 or a mt352.
+                          If the chip id isn't for zl10353, try mt352 */
+
+                       /* FIXME: make support for mt352 work */
+                       printk(KERN_ERR "version of this board with mt352 not "
+                              "currently supported\n");
+                       result = -EINVAL;
+                       goto out_free;
+               }
+               if (attach_xc3028(0x61, dev) < 0) {
+                       result = -EINVAL;
+                       goto out_free;
+               }
+               break;
        case EM2883_BOARD_KWORLD_HYBRID_330U:
        case EM2882_BOARD_EVGA_INDTUBE:
                dvb->frontend = dvb_attach(s5h1409_attach,
index 2c86fcf089f59b45de048179e4be46fe76c989d4..27e33a287dfc8a53da271359aef3c08ac5283517 100644 (file)
@@ -483,7 +483,7 @@ static char *i2c_devs[128] = {
        [0xa0 >> 1] = "eeprom",
        [0xb0 >> 1] = "tda9874",
        [0xb8 >> 1] = "tvp5150a",
-       [0xba >> 1] = "tvp5150a",
+       [0xba >> 1] = "webcam sensor or tvp5150a",
        [0xc0 >> 1] = "tuner (analog)",
        [0xc2 >> 1] = "tuner (analog)",
        [0xc4 >> 1] = "tuner (analog)",
index 8fe1beecfffac0919d40a31e713510bad33d2559..14316c912179ab32b6b2ad456f10c83b66729d22 100644 (file)
@@ -90,10 +90,35 @@ MODULE_PARM_DESC(video_debug, "enable debug messages [video]");
 /* supported video standards */
 static struct em28xx_fmt format[] = {
        {
-               .name     = "16bpp YUY2, 4:2:2, packed",
+               .name     = "16 bpp YUY2, 4:2:2, packed",
                .fourcc   = V4L2_PIX_FMT_YUYV,
                .depth    = 16,
                .reg      = EM28XX_OUTFMT_YUV422_Y0UY1V,
+       }, {
+               .name     = "16 bpp RGB 565, LE",
+               .fourcc   = V4L2_PIX_FMT_RGB565,
+               .depth    = 16,
+               .reg      = EM28XX_OUTFMT_RGB_16_656,
+       }, {
+               .name     = "8 bpp Bayer BGBG..GRGR",
+               .fourcc   = V4L2_PIX_FMT_SBGGR8,
+               .depth    = 8,
+               .reg      = EM28XX_OUTFMT_RGB_8_BGBG,
+       }, {
+               .name     = "8 bpp Bayer GRGR..BGBG",
+               .fourcc   = V4L2_PIX_FMT_SGRBG8,
+               .depth    = 8,
+               .reg      = EM28XX_OUTFMT_RGB_8_GRGR,
+       }, {
+               .name     = "8 bpp Bayer GBGB..RGRG",
+               .fourcc   = V4L2_PIX_FMT_SGBRG8,
+               .depth    = 8,
+               .reg      = EM28XX_OUTFMT_RGB_8_GBGB,
+       }, {
+               .name     = "12 bpp YUV411",
+               .fourcc   = V4L2_PIX_FMT_YUV411P,
+               .depth    = 12,
+               .reg      = EM28XX_OUTFMT_YUV411,
        },
 };
 
@@ -701,7 +726,11 @@ static int vidioc_try_fmt_vid_cap(struct file *file, void *priv,
                return -EINVAL;
        }
 
-       if (dev->board.is_em2800) {
+       if (dev->board.is_27xx) {
+               /* FIXME: This is the only supported fmt */
+               width  = 640;
+               height = 480;
+       } else if (dev->board.is_em2800) {
                /* the em2800 can only scale down to 50% */
                height = height > (3 * maxh / 4) ? maxh : maxh / 2;
                width = width > (3 * maxw / 4) ? maxw : maxw / 2;
@@ -733,13 +762,40 @@ static int vidioc_try_fmt_vid_cap(struct file *file, void *priv,
        return 0;
 }
 
+static int em28xx_set_video_format(struct em28xx *dev, unsigned int fourcc,
+                                  unsigned width, unsigned height)
+{
+       struct em28xx_fmt     *fmt;
+
+       /* FIXME: This is the only supported fmt */
+       if (dev->board.is_27xx) {
+               width  = 640;
+               height = 480;
+       }
+
+       fmt = format_by_fourcc(fourcc);
+       if (!fmt)
+               return -EINVAL;
+
+       dev->format = fmt;
+       dev->width  = width;
+       dev->height = height;
+
+       /* set new image size */
+       get_scale(dev, dev->width, dev->height, &dev->hscale, &dev->vscale);
+
+       em28xx_set_alternate(dev);
+       em28xx_resolution_set(dev);
+
+       return 0;
+}
+
 static int vidioc_s_fmt_vid_cap(struct file *file, void *priv,
                        struct v4l2_format *f)
 {
        struct em28xx_fh      *fh  = priv;
        struct em28xx         *dev = fh->dev;
        int                   rc;
-       struct em28xx_fmt     *fmt;
 
        rc = check_dev(dev);
        if (rc < 0)
@@ -749,12 +805,6 @@ static int vidioc_s_fmt_vid_cap(struct file *file, void *priv,
 
        vidioc_try_fmt_vid_cap(file, priv, f);
 
-       fmt = format_by_fourcc(f->fmt.pix.pixelformat);
-       if (!fmt) {
-               rc = -EINVAL;
-               goto out;
-       }
-
        if (videobuf_queue_is_busy(&fh->vb_vidq)) {
                em28xx_errdev("%s queue busy\n", __func__);
                rc = -EBUSY;
@@ -767,16 +817,8 @@ static int vidioc_s_fmt_vid_cap(struct file *file, void *priv,
                goto out;
        }
 
-       /* set new image size */
-       dev->width = f->fmt.pix.width;
-       dev->height = f->fmt.pix.height;
-       dev->format = fmt;
-       get_scale(dev, dev->width, dev->height, &dev->hscale, &dev->vscale);
-
-       em28xx_set_alternate(dev);
-       em28xx_resolution_set(dev);
-
-       rc = 0;
+       rc = em28xx_set_video_format(dev, f->fmt.pix.pixelformat,
+                               f->fmt.pix.width, f->fmt.pix.height);
 
 out:
        mutex_unlock(&dev->lock);
@@ -1616,11 +1658,6 @@ static int em28xx_v4l2_open(struct file *filp)
        filp->private_data = fh;
 
        if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE && dev->users == 0) {
-               dev->width = norm_maxw(dev);
-               dev->height = norm_maxh(dev);
-               dev->hscale = 0;
-               dev->vscale = 0;
-
                em28xx_set_mode(dev, EM28XX_ANALOG_MODE);
                em28xx_set_alternate(dev);
                em28xx_resolution_set(dev);
@@ -1962,15 +1999,14 @@ int em28xx_register_analog_devices(struct em28xx *dev)
 
        /* set default norm */
        dev->norm = em28xx_video_template.current_norm;
-       dev->width = norm_maxw(dev);
-       dev->height = norm_maxh(dev);
        dev->interlaced = EM28XX_INTERLACED_DEFAULT;
-       dev->hscale = 0;
-       dev->vscale = 0;
        dev->ctl_input = 0;
 
        /* Analog specific initialization */
        dev->format = &format[0];
+       em28xx_set_video_format(dev, format[0].fourcc,
+                               norm_maxw(dev), norm_maxh(dev));
+
        video_mux(dev, dev->ctl_input);
 
        /* Audio defaults */
index 813ce45c2f997286f0df6fb99f1b718a491753ab..d90fef463764646697ffe9ff1a69eeca7976c2c5 100644 (file)
 #define EM2860_BOARD_TERRATEC_AV350              68
 #define EM2882_BOARD_KWORLD_ATSC_315U            69
 #define EM2882_BOARD_EVGA_INDTUBE                70
+#define EM2820_BOARD_SILVERCREST_WEBCAM           71
 
 /* Limits minimum and default number of buffers */
 #define EM28XX_MIN_BUF 4
@@ -360,6 +361,7 @@ enum em28xx_decoder {
        EM28XX_NODECODER,
        EM28XX_TVP5150,
        EM28XX_SAA711X,
+       EM28XX_MT9V011,
 };
 
 enum em28xx_adecoder {
@@ -388,6 +390,7 @@ struct em28xx_board {
        unsigned int max_range_640_480:1;
        unsigned int has_dvb:1;
        unsigned int has_snapshot_button:1;
+       unsigned int is_27xx:1;
        unsigned int valid:1;
 
        unsigned char xclk, i2c_speed;
index 9df7137fe67ec80c19db1a079b70a76688fc6279..992ce530f138d49265ffce759c5e5036c9400312 100644 (file)
 
 #define STV_ISOC_ENDPOINT_ADDR         0x81
 
-#ifndef V4L2_PIX_FMT_SGRBG8
-#define V4L2_PIX_FMT_SGRBG8 v4l2_fourcc('G', 'R', 'B', 'G')
-#endif
-
 #define STV_REG23                      0x0423
 
 /* Control registers of the STV0600 ASIC */
diff --git a/drivers/media/video/mt9v011.c b/drivers/media/video/mt9v011.c
new file mode 100644 (file)
index 0000000..1fe8fc9
--- /dev/null
@@ -0,0 +1,431 @@
+/*
+ * mt9v011 -Micron 1/4-Inch VGA Digital Image Sensor
+ *
+ * Copyright (c) 2009 Mauro Carvalho Chehab (mchehab@redhat.com)
+ * This code is placed under the terms of the GNU General Public License v2
+ */
+
+#include <linux/i2c.h>
+#include <linux/videodev2.h>
+#include <linux/delay.h>
+#include <media/v4l2-device.h>
+#include "mt9v011.h"
+#include <media/v4l2-i2c-drv.h>
+#include <media/v4l2-chip-ident.h>
+
+MODULE_DESCRIPTION("Micron mt9v011 sensor driver");
+MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@redhat.com>");
+MODULE_LICENSE("GPL");
+
+
+static int debug;
+module_param(debug, int, 0);
+MODULE_PARM_DESC(debug, "Debug level (0-2)");
+
+/* supported controls */
+static struct v4l2_queryctrl mt9v011_qctrl[] = {
+       {
+               .id = V4L2_CID_GAIN,
+               .type = V4L2_CTRL_TYPE_INTEGER,
+               .name = "Gain",
+               .minimum = 0,
+               .maximum = (1 << 10) - 1,
+               .step = 1,
+               .default_value = 0x0020,
+               .flags = 0,
+       }, {
+               .id = V4L2_CID_RED_BALANCE,
+               .type = V4L2_CTRL_TYPE_INTEGER,
+               .name = "Red Balance",
+               .minimum = -1 << 9,
+               .maximum = (1 << 9) - 1,
+               .step = 1,
+               .default_value = 0,
+               .flags = 0,
+       }, {
+               .id = V4L2_CID_BLUE_BALANCE,
+               .type = V4L2_CTRL_TYPE_INTEGER,
+               .name = "Blue Balance",
+               .minimum = -1 << 9,
+               .maximum = (1 << 9) - 1,
+               .step = 1,
+               .default_value = 0,
+               .flags = 0,
+       },
+};
+
+struct mt9v011 {
+       struct v4l2_subdev sd;
+       unsigned width, height;
+
+       u16 global_gain, red_bal, blue_bal;
+};
+
+static inline struct mt9v011 *to_mt9v011(struct v4l2_subdev *sd)
+{
+       return container_of(sd, struct mt9v011, sd);
+}
+
+static int mt9v011_read(struct v4l2_subdev *sd, unsigned char addr)
+{
+       struct i2c_client *c = v4l2_get_subdevdata(sd);
+       __be16 buffer;
+       int rc, val;
+
+       rc = i2c_master_send(c, &addr, 1);
+       if (rc != 1)
+               v4l2_dbg(0, debug, sd,
+                        "i2c i/o error: rc == %d (should be 1)\n", rc);
+
+       msleep(10);
+
+       rc = i2c_master_recv(c, (char *)&buffer, 2);
+       if (rc != 2)
+               v4l2_dbg(0, debug, sd,
+                        "i2c i/o error: rc == %d (should be 2)\n", rc);
+
+       val = be16_to_cpu(buffer);
+
+       v4l2_dbg(2, debug, sd, "mt9v011: read 0x%02x = 0x%04x\n", addr, val);
+
+       return val;
+}
+
+static void mt9v011_write(struct v4l2_subdev *sd, unsigned char addr,
+                                u16 value)
+{
+       struct i2c_client *c = v4l2_get_subdevdata(sd);
+       unsigned char buffer[3];
+       int rc;
+
+       buffer[0] = addr;
+       buffer[1] = value >> 8;
+       buffer[2] = value & 0xff;
+
+       v4l2_dbg(2, debug, sd,
+                "mt9v011: writing 0x%02x 0x%04x\n", buffer[0], value);
+       rc = i2c_master_send(c, buffer, 3);
+       if (rc != 3)
+               v4l2_dbg(0, debug, sd,
+                        "i2c i/o error: rc == %d (should be 3)\n", rc);
+}
+
+
+struct i2c_reg_value {
+       unsigned char reg;
+       u16           value;
+};
+
+/*
+ * Values used at the original driver
+ * Some values are marked as Reserved at the datasheet
+ */
+static const struct i2c_reg_value mt9v011_init_default[] = {
+               { R0D_MT9V011_RESET, 0x0001 },
+               { R0D_MT9V011_RESET, 0x0000 },
+
+               { R0C_MT9V011_SHUTTER_DELAY, 0x0000 },
+               { R09_MT9V011_SHUTTER_WIDTH, 0x1fc },
+
+               { R0A_MT9V011_CLK_SPEED, 0x0000 },
+               { R1E_MT9V011_DIGITAL_ZOOM,  0x0000 },
+               { R20_MT9V011_READ_MODE, 0x1000 },
+
+               { R07_MT9V011_OUT_CTRL, 0x000a },       /* chip enable */
+};
+
+static void set_balance(struct v4l2_subdev *sd)
+{
+       struct mt9v011 *core = to_mt9v011(sd);
+       u16 green1_gain, green2_gain, blue_gain, red_gain;
+
+       green1_gain = core->global_gain;
+       green2_gain = core->global_gain;
+
+       blue_gain = core->global_gain +
+                   core->global_gain * core->blue_bal / (1 << 9);
+
+       red_gain = core->global_gain +
+                  core->global_gain * core->blue_bal / (1 << 9);
+
+       mt9v011_write(sd, R2B_MT9V011_GREEN_1_GAIN, green1_gain);
+       mt9v011_write(sd, R2E_MT9V011_GREEN_2_GAIN,  green1_gain);
+       mt9v011_write(sd, R2C_MT9V011_BLUE_GAIN, blue_gain);
+       mt9v011_write(sd, R2D_MT9V011_RED_GAIN, red_gain);
+}
+
+static void set_res(struct v4l2_subdev *sd)
+{
+       struct mt9v011 *core = to_mt9v011(sd);
+       unsigned vstart, hstart;
+
+       /*
+        * The mt9v011 doesn't have scaling. So, in order to select the desired
+        * resolution, we're cropping at the middle of the sensor.
+        * hblank and vblank should be adjusted, in order to warrant that
+        * we'll preserve the line timings for 30 fps, no matter what resolution
+        * is selected.
+        * NOTE: datasheet says that width (and height) should be filled with
+        * width-1. However, this doesn't work, since one pixel per line will
+        * be missing.
+        */
+
+       hstart = 14 + (640 - core->width) / 2;
+       mt9v011_write(sd, R02_MT9V011_COLSTART, hstart);
+       mt9v011_write(sd, R04_MT9V011_WIDTH, core->width);
+       mt9v011_write(sd, R05_MT9V011_HBLANK, 771 - core->width);
+
+       vstart = 8 + (640 - core->height) / 2;
+       mt9v011_write(sd, R01_MT9V011_ROWSTART, vstart);
+       mt9v011_write(sd, R03_MT9V011_HEIGHT, core->height);
+       mt9v011_write(sd, R06_MT9V011_VBLANK, 508 - core->height);
+};
+
+static int mt9v011_reset(struct v4l2_subdev *sd, u32 val)
+{
+       int i;
+
+       for (i = 0; i < ARRAY_SIZE(mt9v011_init_default); i++)
+               mt9v011_write(sd, mt9v011_init_default[i].reg,
+                              mt9v011_init_default[i].value);
+
+       set_balance(sd);
+       set_res(sd);
+
+       return 0;
+};
+
+static int mt9v011_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
+{
+       struct mt9v011 *core = to_mt9v011(sd);
+
+       v4l2_dbg(1, debug, sd, "g_ctrl called\n");
+
+       switch (ctrl->id) {
+       case V4L2_CID_GAIN:
+               ctrl->value = core->global_gain;
+               return 0;
+       case V4L2_CID_RED_BALANCE:
+               ctrl->value = core->red_bal;
+               return 0;
+       case V4L2_CID_BLUE_BALANCE:
+               ctrl->value = core->blue_bal;
+               return 0;
+       }
+       return -EINVAL;
+}
+
+static int mt9v011_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
+{
+       struct mt9v011 *core = to_mt9v011(sd);
+       u8 i, n;
+       n = ARRAY_SIZE(mt9v011_qctrl);
+
+       for (i = 0; i < n; i++) {
+               if (ctrl->id != mt9v011_qctrl[i].id)
+                       continue;
+               if (ctrl->value < mt9v011_qctrl[i].minimum ||
+                   ctrl->value > mt9v011_qctrl[i].maximum)
+                       return -ERANGE;
+               v4l2_dbg(1, debug, sd, "s_ctrl: id=%d, value=%d\n",
+                                       ctrl->id, ctrl->value);
+               break;
+       }
+
+       switch (ctrl->id) {
+       case V4L2_CID_GAIN:
+               core->global_gain = ctrl->value;
+               break;
+       case V4L2_CID_RED_BALANCE:
+               core->red_bal = ctrl->value;
+               break;
+       case V4L2_CID_BLUE_BALANCE:
+               core->blue_bal = ctrl->value;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       set_balance(sd);
+
+       return 0;
+}
+
+static int mt9v011_enum_fmt(struct v4l2_subdev *sd, struct v4l2_fmtdesc *fmt)
+{
+       if (fmt->index > 0)
+               return -EINVAL;
+
+       fmt->flags = 0;
+       strcpy(fmt->description, "8 bpp Bayer GRGR..BGBG");
+       fmt->pixelformat = V4L2_PIX_FMT_SGRBG8;
+
+       return 0;
+}
+
+static int mt9v011_try_fmt(struct v4l2_subdev *sd, struct v4l2_format *fmt)
+{
+       struct v4l2_pix_format *pix = &fmt->fmt.pix;
+
+       if (pix->pixelformat != V4L2_PIX_FMT_SGRBG8)
+               return -EINVAL;
+
+       v4l_bound_align_image(&pix->width, 48, 639, 1,
+                             &pix->height, 32, 480, 1, 0);
+
+       return 0;
+}
+
+static int mt9v011_s_fmt(struct v4l2_subdev *sd, struct v4l2_format *fmt)
+{
+       struct v4l2_pix_format *pix = &fmt->fmt.pix;
+       struct mt9v011 *core = to_mt9v011(sd);
+       int rc;
+
+       rc = mt9v011_try_fmt(sd, fmt);
+       if (rc < 0)
+               return -EINVAL;
+
+       core->width = pix->width;
+       core->height = pix->height;
+
+       set_res(sd);
+
+       return 0;
+}
+
+
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+static int mt9v011_g_register(struct v4l2_subdev *sd,
+                             struct v4l2_dbg_register *reg)
+{
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
+
+       if (!v4l2_chip_match_i2c_client(client, &reg->match))
+               return -EINVAL;
+       if (!capable(CAP_SYS_ADMIN))
+               return -EPERM;
+
+       reg->val = mt9v011_read(sd, reg->reg & 0xff);
+       reg->size = 2;
+
+       return 0;
+}
+
+static int mt9v011_s_register(struct v4l2_subdev *sd,
+                             struct v4l2_dbg_register *reg)
+{
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
+
+       if (!v4l2_chip_match_i2c_client(client, &reg->match))
+               return -EINVAL;
+       if (!capable(CAP_SYS_ADMIN))
+               return -EPERM;
+
+       mt9v011_write(sd, reg->reg & 0xff, reg->val & 0xffff);
+
+       return 0;
+}
+#endif
+
+static int mt9v011_g_chip_ident(struct v4l2_subdev *sd,
+                               struct v4l2_dbg_chip_ident *chip)
+{
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
+
+       return v4l2_chip_ident_i2c_client(client, chip, V4L2_IDENT_MT9V011,
+                                         MT9V011_VERSION);
+}
+
+static const struct v4l2_subdev_core_ops mt9v011_core_ops = {
+       .g_ctrl = mt9v011_g_ctrl,
+       .s_ctrl = mt9v011_s_ctrl,
+       .reset = mt9v011_reset,
+       .g_chip_ident = mt9v011_g_chip_ident,
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+       .g_register = mt9v011_g_register,
+       .s_register = mt9v011_s_register,
+#endif
+};
+
+static const struct v4l2_subdev_video_ops mt9v011_video_ops = {
+       .enum_fmt = mt9v011_enum_fmt,
+       .try_fmt = mt9v011_try_fmt,
+       .s_fmt = mt9v011_s_fmt,
+};
+
+static const struct v4l2_subdev_ops mt9v011_ops = {
+       .core  = &mt9v011_core_ops,
+       .video = &mt9v011_video_ops,
+};
+
+
+/****************************************************************************
+                       I2C Client & Driver
+ ****************************************************************************/
+
+static int mt9v011_probe(struct i2c_client *c,
+                        const struct i2c_device_id *id)
+{
+       u16 version;
+       struct mt9v011 *core;
+       struct v4l2_subdev *sd;
+
+       /* Check if the adapter supports the needed features */
+       if (!i2c_check_functionality(c->adapter,
+            I2C_FUNC_SMBUS_READ_BYTE | I2C_FUNC_SMBUS_WRITE_BYTE_DATA))
+               return -EIO;
+
+       core = kzalloc(sizeof(struct mt9v011), GFP_KERNEL);
+       if (!core)
+               return -ENOMEM;
+
+       sd = &core->sd;
+       v4l2_i2c_subdev_init(sd, c, &mt9v011_ops);
+
+       /* Check if the sensor is really a MT9V011 */
+       version = mt9v011_read(sd, R00_MT9V011_CHIP_VERSION);
+       if (version != MT9V011_VERSION) {
+               v4l2_info(sd, "*** unknown micron chip detected (0x%04x.\n",
+                         version);
+               kfree(core);
+               return -EINVAL;
+       }
+
+       core->global_gain = 0x0024;
+       core->width  = 640;
+       core->height = 480;
+
+       v4l_info(c, "chip found @ 0x%02x (%s)\n",
+                c->addr << 1, c->adapter->name);
+
+       return 0;
+}
+
+static int mt9v011_remove(struct i2c_client *c)
+{
+       struct v4l2_subdev *sd = i2c_get_clientdata(c);
+
+       v4l2_dbg(1, debug, sd,
+               "mt9v011.c: removing mt9v011 adapter on address 0x%x\n",
+               c->addr << 1);
+
+       v4l2_device_unregister_subdev(sd);
+       kfree(to_mt9v011(sd));
+       return 0;
+}
+
+/* ----------------------------------------------------------------------- */
+
+static const struct i2c_device_id mt9v011_id[] = {
+       { "mt9v011", 0 },
+       { }
+};
+MODULE_DEVICE_TABLE(i2c, mt9v011_id);
+
+static struct v4l2_i2c_driver_data v4l2_i2c_data = {
+       .name = "mt9v011",
+       .probe = mt9v011_probe,
+       .remove = mt9v011_remove,
+       .id_table = mt9v011_id,
+};
diff --git a/drivers/media/video/mt9v011.h b/drivers/media/video/mt9v011.h
new file mode 100644 (file)
index 0000000..9e443ee
--- /dev/null
@@ -0,0 +1,35 @@
+/*
+ * mt9v011 -Micron 1/4-Inch VGA Digital Image Sensor
+ *
+ * Copyright (c) 2009 Mauro Carvalho Chehab (mchehab@redhat.com)
+ * This code is placed under the terms of the GNU General Public License v2
+ */
+
+#ifndef MT9V011_H_
+#define MT9V011_H_
+
+#define R00_MT9V011_CHIP_VERSION       0x00
+#define R01_MT9V011_ROWSTART           0x01
+#define R02_MT9V011_COLSTART           0x02
+#define R03_MT9V011_HEIGHT             0x03
+#define R04_MT9V011_WIDTH              0x04
+#define R05_MT9V011_HBLANK             0x05
+#define R06_MT9V011_VBLANK             0x06
+#define R07_MT9V011_OUT_CTRL           0x07
+#define R09_MT9V011_SHUTTER_WIDTH      0x09
+#define R0A_MT9V011_CLK_SPEED          0x0a
+#define R0B_MT9V011_RESTART            0x0b
+#define R0C_MT9V011_SHUTTER_DELAY      0x0c
+#define R0D_MT9V011_RESET              0x0d
+#define R1E_MT9V011_DIGITAL_ZOOM       0x1e
+#define R20_MT9V011_READ_MODE          0x20
+#define R2B_MT9V011_GREEN_1_GAIN       0x2b
+#define R2C_MT9V011_BLUE_GAIN          0x2c
+#define R2D_MT9V011_RED_GAIN           0x2d
+#define R2E_MT9V011_GREEN_2_GAIN       0x2e
+#define R35_MT9V011_GLOBAL_GAIN                0x35
+#define RF1_MT9V011_CHIP_ENABLE                0xf1
+
+#define MT9V011_VERSION                        0x8243
+
+#endif
index db25c3034c11be4e7deb4cc98bf41006b4e860f7..8d17cf61330671f1d71c94dfc82a689f7b0bbf69 100644 (file)
@@ -62,6 +62,7 @@
 #include <linux/module.h>
 #include <linux/poll.h>
 #include <linux/slab.h>
+#include <linux/smp_lock.h>
 #ifdef CONFIG_USB_PWC_INPUT_EVDEV
 #include <linux/usb/input.h>
 #endif
index 0be6f814f5396cb7615484201db3a45a46f98ac5..0b658dee05a41f047fa55f171c4972fc5b140aa3 100644 (file)
@@ -29,7 +29,6 @@
 #include <linux/usb.h>
 #include <linux/spinlock.h>
 #include <linux/wait.h>
-#include <linux/smp_lock.h>
 #include <linux/version.h>
 #include <linux/mutex.h>
 #include <linux/mm.h>
index 6be845ccc7d7e7412f97b2e65c32e6cd3deb091e..9e3262c0ba371b1c935100504b8e6444964f7d51 100644 (file)
@@ -48,6 +48,7 @@
 #include <linux/videodev2.h>
 #include <linux/version.h>
 #include <linux/mm.h>
+#include <linux/smp_lock.h>
 #include <media/videobuf-vmalloc.h>
 #include <media/v4l2-common.h>
 #include <media/v4l2-ioctl.h>
index 155804b061e948b091b997242dec8ab8c1edd5c1..b624a4c01fdc9faee6e2fe37ad0939da9fdbfee2 100644 (file)
@@ -43,7 +43,6 @@
 #include <linux/mm.h>
 #include <linux/init.h>
 #include <linux/i2c.h>
-#include <linux/smp_lock.h>
 #include <linux/mutex.h>
 #include <linux/videotext.h>
 #include <linux/videodev2.h>
index 271d6e931b750ecd9b7c0ee4a499f52a3833476f..12835fb82c9557c56d09d16825d954dd0d24920e 100644 (file)
@@ -46,7 +46,6 @@
 #include <linux/mm.h>
 #include <linux/init.h>
 #include <linux/i2c.h>
-#include <linux/smp_lock.h>
 #include <linux/mutex.h>
 #include <linux/delay.h>
 #include <linux/videotext.h>
index add1757f89303851afa45f49d5c6975641efde9b..296788c3bf0ecc6ddc14301fb10bf198216e155a 100644 (file)
@@ -22,6 +22,7 @@
 #include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/slab.h>
+#include <linux/smp_lock.h>
 #include <linux/delay.h>
 
 #include "saa7134-reg.h"
index c8f05297d0f0680acccc7513231a5e561c57b3db..85ffc2cba039b3e6114e5fc8d3bd4671bf9fea20 100644 (file)
@@ -31,6 +31,7 @@ static const char version[] = "0.24";
 #include <linux/init.h>
 #include <linux/vmalloc.h>
 #include <linux/slab.h>
+#include <linux/smp_lock.h>
 #include <linux/pagemap.h>
 #include <linux/usb.h>
 #include "se401.h"
index 16f595d4337abfb76b3c08d98bad1ced20cf0b9d..9f5ae81678553192b27ec5b41d384a858d603b40 100644 (file)
@@ -237,11 +237,11 @@ static int soc_camera_init_user_formats(struct soc_camera_device *icd)
                return -ENOMEM;
 
        icd->num_user_formats = fmts;
-       fmts = 0;
 
        dev_dbg(&icd->dev, "Found %d supported formats.\n", fmts);
 
        /* Second pass - actually fill data formats */
+       fmts = 0;
        for (i = 0; i < icd->num_formats; i++)
                if (!ici->ops->get_formats) {
                        icd->user_formats[i].host_fmt = icd->formats + i;
@@ -877,8 +877,11 @@ static int soc_camera_probe(struct device *dev)
                        (unsigned short)~0;
 
                ret = soc_camera_init_user_formats(icd);
-               if (ret < 0)
+               if (ret < 0) {
+                       if (icd->ops->remove)
+                               icd->ops->remove(icd);
                        goto eiufmt;
+               }
 
                icd->height     = DEFAULT_HEIGHT;
                icd->width      = DEFAULT_WIDTH;
@@ -902,8 +905,10 @@ static int soc_camera_remove(struct device *dev)
 {
        struct soc_camera_device *icd = to_soc_camera_dev(dev);
 
+       mutex_lock(&icd->video_lock);
        if (icd->ops->remove)
                icd->ops->remove(icd);
+       mutex_unlock(&icd->video_lock);
 
        soc_camera_free_user_formats(icd);
 
@@ -1145,6 +1150,7 @@ evidallocd:
 }
 EXPORT_SYMBOL(soc_camera_video_start);
 
+/* Called from client .remove() methods with .video_lock held */
 void soc_camera_video_stop(struct soc_camera_device *icd)
 {
        struct video_device *vdev = icd->vdev;
@@ -1154,10 +1160,8 @@ void soc_camera_video_stop(struct soc_camera_device *icd)
        if (!icd->dev.parent || !vdev)
                return;
 
-       mutex_lock(&icd->video_lock);
        video_unregister_device(vdev);
        icd->vdev = NULL;
-       mutex_unlock(&icd->video_lock);
 }
 EXPORT_SYMBOL(soc_camera_video_stop);
 
index 2e59370472788712ba3e08ae62dd2b5f2b62f2e0..4d6785e634556fbba9bc87a89708302907f40a0c 100644 (file)
@@ -27,6 +27,7 @@
 #include <linux/kernel.h>
 #include <linux/errno.h>
 #include <linux/slab.h>
+#include <linux/smp_lock.h>
 
 #include <linux/usb.h>
 #include <linux/mm.h>
index 0eb313082c973e78fcfe6e2e935ec1c5751ce5c6..eaada39c76fdfcf5d2273bd3c31af6dca0350da1 100644 (file)
@@ -26,6 +26,7 @@
 #include <linux/kernel.h>
 #include <linux/major.h>
 #include <linux/slab.h>
+#include <linux/smp_lock.h>
 #include <linux/mm.h>
 #include <linux/init.h>
 #include <linux/poll.h>
index 75f286f7a2e9939cfc9d24f25a06d6b50c8cab91..8b4e7dafce7b9d155c254a802282daa0f25f1570 100644 (file)
@@ -62,6 +62,7 @@
 #include <linux/init.h>
 #include <linux/vmalloc.h>
 #include <linux/slab.h>
+#include <linux/smp_lock.h>
 #include <linux/pagemap.h>
 #include <linux/errno.h>
 #include <linux/videodev.h>
index 8d73979596f9d9542c35e10aa158d6792878099a..45fce39ec9ad56b77c5b7db00eca8dccf3d5a0f3 100644 (file)
@@ -43,6 +43,7 @@
 #include <linux/vmalloc.h>
 #include <linux/mm.h>
 #include <linux/slab.h>
+#include <linux/smp_lock.h>
 #include <linux/mutex.h>
 #include <linux/firmware.h>
 #include <linux/ihex.h>
index 90b58914f98472644e289c97ce02297490c920d2..90d9b5c0e9a7bc407806e357a32988ed61df5b0e 100644 (file)
@@ -50,6 +50,7 @@
 #include <linux/list.h>
 #include <linux/timer.h>
 #include <linux/slab.h>
+#include <linux/smp_lock.h>
 #include <linux/mm.h>
 #include <linux/utsname.h>
 #include <linux/highmem.h>
index 31eac66411d736e4330119900e111aa921e841e4..a7f1b69a7dab398522ea9ca994c998be82719063 100644 (file)
@@ -25,7 +25,6 @@
 #include <linux/init.h>
 #include <linux/kmod.h>
 #include <linux/slab.h>
-#include <linux/smp_lock.h>
 #include <asm/uaccess.h>
 #include <asm/system.h>
 
index cd72668584626974a4c59b2bc0c739c09d2a3360..7705fc6baf00d6eab93fbf43eb17bfb9febece0a 100644 (file)
@@ -343,6 +343,53 @@ static struct bar_std bars[] = {
 #define TO_U(r, g, b) \
        (((-9714 * r - 19070 * g + 28784 * b + 32768) >> 16) + 128)
 
+/* precalculate color bar values to speed up rendering */
+static void precalculate_bars(struct vivi_fh *fh)
+{
+       struct vivi_dev *dev = fh->dev;
+       unsigned char r, g, b;
+       int k, is_yuv;
+
+       fh->input = dev->input;
+
+       for (k = 0; k < 8; k++) {
+               r = bars[fh->input].bar[k][0];
+               g = bars[fh->input].bar[k][1];
+               b = bars[fh->input].bar[k][2];
+               is_yuv = 0;
+
+               switch (fh->fmt->fourcc) {
+               case V4L2_PIX_FMT_YUYV:
+               case V4L2_PIX_FMT_UYVY:
+                       is_yuv = 1;
+                       break;
+               case V4L2_PIX_FMT_RGB565:
+               case V4L2_PIX_FMT_RGB565X:
+                       r >>= 3;
+                       g >>= 2;
+                       b >>= 3;
+                       break;
+               case V4L2_PIX_FMT_RGB555:
+               case V4L2_PIX_FMT_RGB555X:
+                       r >>= 3;
+                       g >>= 3;
+                       b >>= 3;
+                       break;
+               }
+
+               if (is_yuv) {
+                       fh->bars[k][0] = TO_Y(r, g, b); /* Luma */
+                       fh->bars[k][1] = TO_U(r, g, b); /* Cb */
+                       fh->bars[k][2] = TO_V(r, g, b); /* Cr */
+               } else {
+                       fh->bars[k][0] = r;
+                       fh->bars[k][1] = g;
+                       fh->bars[k][2] = b;
+               }
+       }
+
+}
+
 #define TSTAMP_MIN_Y   24
 #define TSTAMP_MAX_Y   (TSTAMP_MIN_Y + 15)
 #define TSTAMP_INPUT_X 10
@@ -755,6 +802,8 @@ buffer_prepare(struct videobuf_queue *vq, struct videobuf_buffer *vb,
        buf->vb.height = fh->height;
        buf->vb.field  = field;
 
+       precalculate_bars(fh);
+
        if (VIDEOBUF_NEEDS_INIT == buf->vb.state) {
                rc = videobuf_iolock(vq, &buf->vb, NULL);
                if (rc < 0)
@@ -893,53 +942,6 @@ static int vidioc_try_fmt_vid_cap(struct file *file, void *priv,
        return 0;
 }
 
-/* precalculate color bar values to speed up rendering */
-static void precalculate_bars(struct vivi_fh *fh)
-{
-       struct vivi_dev *dev = fh->dev;
-       unsigned char r, g, b;
-       int k, is_yuv;
-
-       fh->input = dev->input;
-
-       for (k = 0; k < 8; k++) {
-               r = bars[fh->input].bar[k][0];
-               g = bars[fh->input].bar[k][1];
-               b = bars[fh->input].bar[k][2];
-               is_yuv = 0;
-
-               switch (fh->fmt->fourcc) {
-               case V4L2_PIX_FMT_YUYV:
-               case V4L2_PIX_FMT_UYVY:
-                       is_yuv = 1;
-                       break;
-               case V4L2_PIX_FMT_RGB565:
-               case V4L2_PIX_FMT_RGB565X:
-                       r >>= 3;
-                       g >>= 2;
-                       b >>= 3;
-                       break;
-               case V4L2_PIX_FMT_RGB555:
-               case V4L2_PIX_FMT_RGB555X:
-                       r >>= 3;
-                       g >>= 3;
-                       b >>= 3;
-                       break;
-               }
-
-               if (is_yuv) {
-                       fh->bars[k][0] = TO_Y(r, g, b); /* Luma */
-                       fh->bars[k][1] = TO_U(r, g, b); /* Cb */
-                       fh->bars[k][2] = TO_V(r, g, b); /* Cr */
-               } else {
-                       fh->bars[k][0] = r;
-                       fh->bars[k][1] = g;
-                       fh->bars[k][2] = b;
-               }
-       }
-
-}
-
 /*FIXME: This seems to be generic enough to be at videodev2 */
 static int vidioc_s_fmt_vid_cap(struct file *file, void *priv,
                                        struct v4l2_format *f)
@@ -965,8 +967,6 @@ static int vidioc_s_fmt_vid_cap(struct file *file, void *priv,
        fh->vb_vidq.field = f->fmt.pix.field;
        fh->type          = f->type;
 
-       precalculate_bars(fh);
-
        ret = 0;
 out:
        mutex_unlock(&q->vb_lock);
@@ -1357,6 +1357,7 @@ static int __init vivi_create_instance(int inst)
                goto unreg_dev;
 
        *vfd = vivi_template;
+       vfd->debug = debug;
 
        ret = video_register_device(vfd, VFL_TYPE_GRABBER, video_nr);
        if (ret < 0)
index 3d7df32a3d8706d30ac56a88fcbc720e7a25a6d6..bcdefb1bcb3dc450a54b0c05fb9e58c7dd91c81b 100644 (file)
@@ -49,6 +49,7 @@
 #include <linux/module.h>
 #include <linux/delay.h>
 #include <linux/slab.h>
+#include <linux/smp_lock.h>
 #include <linux/pci.h>
 #include <linux/vmalloc.h>
 #include <linux/wait.h>
index 7ac12cb0be4a70f8b2bc30279ff56964e030ae0d..5b6e58a3ba46c3934e5ef96bdfcc2479172c20d7 100644 (file)
@@ -32,8 +32,7 @@
  * This driver was tested with firmware revision A4.
  */
 
-#if defined(CONFIG_KEYBOARD_DM355EVM) \
-               || defined(CONFIG_KEYBOARD_DM355EVM_MODULE)
+#if defined(CONFIG_INPUT_DM355EVM) || defined(CONFIG_INPUT_DM355EVM_MODULE)
 #define msp_has_keyboard()     true
 #else
 #define msp_has_keyboard()     false
index 671a7efe86a8b8404ad1e31aa50959ba3167a8a5..c1de4afa89a62fc79055d0bdaa47ad2a31c2adf3 100644 (file)
@@ -238,8 +238,10 @@ static irqreturn_t pcap_adc_irq(int irq, void *_pcap)
        mutex_lock(&pcap->adc_mutex);
        req = pcap->adc_queue[pcap->adc_head];
 
-       if (WARN(!req, KERN_WARNING "adc irq without pending request\n"))
+       if (WARN(!req, KERN_WARNING "adc irq without pending request\n")) {
+               mutex_unlock(&pcap->adc_mutex);
                return IRQ_HANDLED;
+       }
 
        /* read requested channels results */
        ezx_pcap_read(pcap, PCAP_REG_ADC, &tmp);
index 4c7b7962f6b8002b18ef57c0a6d4015bcf7c2fc1..0cc5eeff5ee8bf7cd5568eabfcc31e82b05675b3 100644 (file)
@@ -367,7 +367,8 @@ int sm501_unit_power(struct device *dev, unsigned int unit, unsigned int to)
                break;
 
        default:
-               return -1;
+               gate = -1;
+               goto already;
        }
 
        writel(mode, sm->regs + SM501_POWER_MODE_CONTROL);
index fa2d93a9fb8d7755de89a2f08badce29a07f8983..aed609832bc2bf1c0497dedbd0257bcfcbf7e70a 100644 (file)
@@ -29,7 +29,6 @@
 #include <linux/slab.h>
 #include <linux/mm.h>
 #include <linux/io.h>
-#include <linux/smp_lock.h>
 #include <linux/spinlock.h>
 #include <linux/device.h>
 #include <linux/miscdevice.h>
index eedbf9c32760f68b76a34726a8358244e1834389..79689b10f937e0b8405a6a3568d5503c532d64a9 100644 (file)
@@ -24,7 +24,6 @@
 #include <linux/errno.h>
 #include <linux/slab.h>
 #include <linux/mm.h>
-#include <linux/smp_lock.h>
 #include <linux/spinlock.h>
 #include <linux/device.h>
 #include <linux/miscdevice.h>
index 8d1c60a3f0df9cdb1e178ae85b6605b1557364fb..5d778ec8cdb2aa454224e7a5e5b9f76dc05a49fd 100644 (file)
@@ -235,7 +235,7 @@ xpnet_receive(short partid, int channel, struct xpnet_message *msg)
        skb->ip_summed = CHECKSUM_UNNECESSARY;
 
        dev_dbg(xpnet, "passing skb to network layer\n"
-               KERN_DEBUG "\tskb->head=0x%p skb->data=0x%p skb->tail=0x%p "
+               "\tskb->head=0x%p skb->data=0x%p skb->tail=0x%p "
                "skb->end=0x%p skb->len=%d\n",
                (void *)skb->head, (void *)skb->data, skb_tail_pointer(skb),
                skb_end_pointer(skb), skb->len);
@@ -399,7 +399,7 @@ xpnet_send(struct sk_buff *skb, struct xpnet_pending_msg *queued_msg,
        msg->buf_pa = xp_pa((void *)start_addr);
 
        dev_dbg(xpnet, "sending XPC message to %d:%d\n"
-               KERN_DEBUG "msg->buf_pa=0x%lx, msg->size=%u, "
+               "msg->buf_pa=0x%lx, msg->size=%u, "
                "msg->leadin_ignore=%u, msg->tailout_ignore=%u\n",
                dest_partid, XPC_NET_CHANNEL, msg->buf_pa, msg->size,
                msg->leadin_ignore, msg->tailout_ignore);
index 240608cc7ae9b853c46f696986a821048bebb35b..a461017ce5ce92b6c14c0ca73482f68fd6ad8d7c 100644 (file)
@@ -1313,6 +1313,12 @@ static int mmc_spi_probe(struct spi_device *spi)
        struct mmc_spi_host     *host;
        int                     status;
 
+       /* We rely on full duplex transfers, mostly to reduce
+        * per-transfer overheads (by making fewer transfers).
+        */
+       if (spi->master->flags & SPI_MASTER_HALF_DUPLEX)
+               return -EINVAL;
+
        /* MMC and SD specs only seem to care that sampling is on the
         * rising edge ... meaning SPI modes 0 or 3.  So either SPI mode
         * should be legit.  We'll use mode 0 since the steady state is 0,
index 5011fa73f91886302135ea08904908c2c6f89461..1479da6d3aa6d78f3462c7817a56dcfede8a764e 100644 (file)
@@ -194,7 +194,7 @@ static struct mtd_partition * newpart(char *s,
        parts[this_part].name = extra_mem;
        extra_mem += name_len + 1;
 
-       dbg(("partition %d: name <%s>, offset %x, size %x, mask flags %x\n",
+       dbg(("partition %d: name <%s>, offset %llx, size %llx, mask flags %x\n",
             this_part,
             parts[this_part].name,
             parts[this_part].offset,
index 59c46126a5ce3ddb63bf4a02aa52c7e621b1b80a..ae5fe91867e1530ae9636a73d1a05ccc9892e7f3 100644 (file)
@@ -54,7 +54,7 @@
 #define        SR_SRWD                 0x80    /* SR write protect */
 
 /* Define max times to check status register before we give up. */
-#define        MAX_READY_WAIT_JIFFIES  (10 * HZ)       /* eg. M25P128 specs 6s max sector erase */
+#define        MAX_READY_WAIT_JIFFIES  (40 * HZ)       /* M25P16 specs 40s max chip erase */
 #define        CMD_SIZE                4
 
 #ifdef CONFIG_M25PXX_USE_FAST_READ
index 73f05227dc8cb0607d11c6709a2233959f65d92a..d8cf29c01cc46ce6d9c26e01f85dad1630f456b6 100644 (file)
@@ -226,7 +226,7 @@ static u16 INFTL_findfreeblock(struct INFTLrecord *inftl, int desperate)
        if (!desperate && inftl->numfreeEUNs < 2) {
                DEBUG(MTD_DEBUG_LEVEL1, "INFTL: there are too few free "
                        "EUNs (%d)\n", inftl->numfreeEUNs);
-               return 0xffff;
+               return BLOCK_NIL;
        }
 
        /* Scan for a free block */
@@ -281,7 +281,8 @@ static u16 INFTL_foldchain(struct INFTLrecord *inftl, unsigned thisVUC, unsigned
        silly = MAX_LOOPS;
        while (thisEUN < inftl->nb_blocks) {
                for (block = 0; block < inftl->EraseSize/SECTORSIZE; block ++) {
-                       if ((BlockMap[block] != 0xffff) || BlockDeleted[block])
+                       if ((BlockMap[block] != BLOCK_NIL) ||
+                           BlockDeleted[block])
                                continue;
 
                        if (inftl_read_oob(mtd, (thisEUN * inftl->EraseSize)
@@ -525,7 +526,7 @@ static inline u16 INFTL_findwriteunit(struct INFTLrecord *inftl, unsigned block)
                        if (!silly--) {
                                printk(KERN_WARNING "INFTL: infinite loop in "
                                        "Virtual Unit Chain 0x%x\n", thisVUC);
-                               return 0xffff;
+                               return BLOCK_NIL;
                        }
 
                        /* Skip to next block in chain */
@@ -549,7 +550,7 @@ hitused:
                         * waiting to be picked up. We're going to have to fold
                         * a chain to make room.
                         */
-                       thisEUN = INFTL_makefreeblock(inftl, 0xffff);
+                       thisEUN = INFTL_makefreeblock(inftl, BLOCK_NIL);
 
                        /*
                         * Hopefully we free something, lets try again.
@@ -631,7 +632,7 @@ hitused:
 
        printk(KERN_WARNING "INFTL: error folding to make room for Virtual "
                "Unit Chain 0x%x\n", thisVUC);
-       return 0xffff;
+       return BLOCK_NIL;
 }
 
 /*
index b08a798ee254be0ed501758f0300df314c18078b..2aac41bde8b314feda6bf213472c76277881c6ca 100644 (file)
 #include <mach/hardware.h>
 #include <asm/system.h>
 
-#define SUBDEV_NAME_SIZE       (BUS_ID_SIZE + 2)
-
 struct armflash_subdev_info {
-       char                    name[SUBDEV_NAME_SIZE];
+       char                    *name;
        struct mtd_info         *mtd;
        struct map_info         map;
        struct flash_platform_data *plat;
@@ -134,6 +132,8 @@ static void armflash_subdev_remove(struct armflash_subdev_info *subdev)
                map_destroy(subdev->mtd);
        if (subdev->map.virt)
                iounmap(subdev->map.virt);
+       kfree(subdev->name);
+       subdev->name = NULL;
        release_mem_region(subdev->map.phys, subdev->map.size);
 }
 
@@ -177,16 +177,22 @@ static int armflash_probe(struct platform_device *dev)
 
                if (nr == 1)
                        /* No MTD concatenation, just use the default name */
-                       snprintf(subdev->name, SUBDEV_NAME_SIZE, "%s",
-                                dev_name(&dev->dev));
+                       subdev->name = kstrdup(dev_name(&dev->dev), GFP_KERNEL);
                else
-                       snprintf(subdev->name, SUBDEV_NAME_SIZE, "%s-%d",
-                                dev_name(&dev->dev), i);
+                       subdev->name = kasprintf(GFP_KERNEL, "%s-%d",
+                                                dev_name(&dev->dev), i);
+               if (!subdev->name) {
+                       err = -ENOMEM;
+                       break;
+               }
                subdev->plat = plat;
 
                err = armflash_subdev_probe(subdev, res);
-               if (err)
+               if (err) {
+                       kfree(subdev->name);
+                       subdev->name = NULL;
                        break;
+               }
        }
        info->nr_subdev = i;
 
index 2802992b39daf67ce5c917103f03501d113f290e..20c828ba94052daae1e7a79ac4b4edb8f6e51104 100644 (file)
@@ -534,7 +534,7 @@ static int __init atmel_nand_probe(struct platform_device *pdev)
                                                         &num_partitions);
 
        if ((!partitions) || (num_partitions == 0)) {
-               printk(KERN_ERR "atmel_nand: No parititions defined, or unsupported device.\n");
+               printk(KERN_ERR "atmel_nand: No partitions defined, or unsupported device.\n");
                res = ENXIO;
                goto err_no_partitions;
        }
index 0cd76f89f4b0a43349ff030296a1cd1252169f6c..ebd07e95b8140354ae8c51061ef7cb9b7945d153 100644 (file)
@@ -11,6 +11,8 @@
 #include <linux/platform_device.h>
 #include <linux/dma-mapping.h>
 #include <linux/delay.h>
+#include <linux/jiffies.h>
+#include <linux/sched.h>
 #include <linux/mtd/mtd.h>
 #include <linux/mtd/nand.h>
 #include <linux/mtd/partitions.h>
@@ -541,7 +543,7 @@ static int omap_wait(struct mtd_info *mtd, struct nand_chip *chip)
        struct omap_nand_info *info = container_of(mtd, struct omap_nand_info,
                                                        mtd);
        unsigned long timeo = jiffies;
-       int status, state = this->state;
+       int status = NAND_STATUS_FAIL, state = this->state;
 
        if (state == FL_ERASING)
                timeo += (HZ * 400) / 1000;
@@ -556,8 +558,9 @@ static int omap_wait(struct mtd_info *mtd, struct nand_chip *chip)
 
        while (time_before(jiffies, timeo)) {
                status = __raw_readb(this->IO_ADDR_R);
-               if (!(status & 0x40))
+               if (status & NAND_STATUS_READY)
                        break;
+               cond_resched();
        }
        return status;
 }
index e3f8495a94c27492ccaaca85e0a96a1d478a98cd..fb86cacd5bdb66adf754c8ce6ed940ff89e266a8 100644 (file)
@@ -208,7 +208,7 @@ static u16 NFTL_findfreeblock(struct NFTLrecord *nftl, int desperate )
        /* Normally, we force a fold to happen before we run out of free blocks completely */
        if (!desperate && nftl->numfreeEUNs < 2) {
                DEBUG(MTD_DEBUG_LEVEL1, "NFTL_findfreeblock: there are too few free EUNs\n");
-               return 0xffff;
+               return BLOCK_NIL;
        }
 
        /* Scan for a free block */
@@ -230,11 +230,11 @@ static u16 NFTL_findfreeblock(struct NFTLrecord *nftl, int desperate )
                        printk("Argh! No free blocks found! LastFreeEUN = %d, "
                               "FirstEUN = %d\n", nftl->LastFreeEUN,
                               le16_to_cpu(nftl->MediaHdr.FirstPhysicalEUN));
-                       return 0xffff;
+                       return BLOCK_NIL;
                }
        } while (pot != nftl->LastFreeEUN);
 
-       return 0xffff;
+       return BLOCK_NIL;
 }
 
 static u16 NFTL_foldchain (struct NFTLrecord *nftl, unsigned thisVUC, unsigned pendingblock )
@@ -431,7 +431,7 @@ static u16 NFTL_foldchain (struct NFTLrecord *nftl, unsigned thisVUC, unsigned p
 
        /* add the header so that it is now a valid chain */
        oob.u.a.VirtUnitNum = oob.u.a.SpareVirtUnitNum = cpu_to_le16(thisVUC);
-       oob.u.a.ReplUnitNum = oob.u.a.SpareReplUnitNum = 0xffff;
+       oob.u.a.ReplUnitNum = oob.u.a.SpareReplUnitNum = BLOCK_NIL;
 
        nftl_write_oob(mtd, (nftl->EraseSize * targetEUN) + 8,
                       8, &retlen, (char *)&oob.u);
@@ -515,7 +515,7 @@ static u16 NFTL_makefreeblock( struct NFTLrecord *nftl , unsigned pendingblock)
        if (ChainLength < 2) {
                printk(KERN_WARNING "No Virtual Unit Chains available for folding. "
                       "Failing request\n");
-               return 0xffff;
+               return BLOCK_NIL;
        }
 
        return NFTL_foldchain (nftl, LongestChain, pendingblock);
@@ -578,7 +578,7 @@ static inline u16 NFTL_findwriteunit(struct NFTLrecord *nftl, unsigned block)
                                printk(KERN_WARNING
                                       "Infinite loop in Virtual Unit Chain 0x%x\n",
                                       thisVUC);
-                               return 0xffff;
+                               return BLOCK_NIL;
                        }
 
                        /* Skip to next block in chain */
@@ -601,7 +601,7 @@ static inline u16 NFTL_findwriteunit(struct NFTLrecord *nftl, unsigned block)
                        //u16 startEUN = nftl->EUNtable[thisVUC];
 
                        //printk("Write to VirtualUnitChain %d, calling makefreeblock()\n", thisVUC);
-                       writeEUN = NFTL_makefreeblock(nftl, 0xffff);
+                       writeEUN = NFTL_makefreeblock(nftl, BLOCK_NIL);
 
                        if (writeEUN == BLOCK_NIL) {
                                /* OK, we accept that the above comment is
@@ -673,7 +673,7 @@ static inline u16 NFTL_findwriteunit(struct NFTLrecord *nftl, unsigned block)
 
        printk(KERN_WARNING "Error folding to make room for Virtual Unit Chain 0x%x\n",
               thisVUC);
-       return 0xffff;
+       return BLOCK_NIL;
 }
 
 static int nftl_writeblock(struct mtd_blktrans_dev *mbd, unsigned long block,
index 286ed594e5a0ec01d87810c004e0511b78385477..e1f7d0a78b9d58e28a2b6c1fdad43423cddd3956 100644 (file)
@@ -657,6 +657,11 @@ static int io_init(struct ubi_device *ubi)
        if (ubi->mtd->block_isbad && ubi->mtd->block_markbad)
                ubi->bad_allowed = 1;
 
+       if (ubi->mtd->type == MTD_NORFLASH) {
+               ubi_assert(ubi->mtd->writesize == 1);
+               ubi->nor_flash = 1;
+       }
+
        ubi->min_io_size = ubi->mtd->writesize;
        ubi->hdrs_min_io_size = ubi->mtd->writesize >> ubi->mtd->subpage_sft;
 
@@ -996,6 +1001,7 @@ int ubi_attach_mtd_dev(struct mtd_info *mtd, int ubi_num, int vid_hdr_offset)
        ubi_msg("number of PEBs reserved for bad PEB handling: %d",
                ubi->beb_rsvd_pebs);
        ubi_msg("max/mean erase counter: %d/%d", ubi->max_ec, ubi->mean_ec);
+       ubi_msg("image sequence number: %d", ubi->image_seq);
 
        /*
         * The below lock makes sure we do not race with 'ubi_thread()' which
index c0ed60e8ade978ca74091aed6a8e5b14f1a47e63..54b0186915fbf6ab6be8f845a4d942f7f2f277aa 100644 (file)
@@ -44,6 +44,8 @@ void ubi_dbg_dump_ec_hdr(const struct ubi_ec_hdr *ec_hdr)
               be32_to_cpu(ec_hdr->vid_hdr_offset));
        printk(KERN_DEBUG "\tdata_offset    %d\n",
               be32_to_cpu(ec_hdr->data_offset));
+       printk(KERN_DEBUG "\timage_seq      %d\n",
+              be32_to_cpu(ec_hdr->image_seq));
        printk(KERN_DEBUG "\thdr_crc        %#08x\n",
               be32_to_cpu(ec_hdr->hdr_crc));
        printk(KERN_DEBUG "erase counter header hexdump:\n");
index 13777e5beac93344ae759aa2ea0176c796e97d1d..a4da7a09b949b75f5e259837da31190b31874bbc 100644 (file)
@@ -93,6 +93,12 @@ void ubi_dbg_dump_mkvol_req(const struct ubi_mkvol_req *req);
 #define UBI_IO_DEBUG 0
 #endif
 
+#ifdef CONFIG_MTD_UBI_DEBUG_PARANOID
+int ubi_dbg_check_all_ff(struct ubi_device *ubi, int pnum, int offset, int len);
+#else
+#define ubi_dbg_check_all_ff(ubi, pnum, offset, len) 0
+#endif
+
 #ifdef CONFIG_MTD_UBI_DEBUG_DISABLE_BGT
 #define DBG_DISABLE_BGT 1
 #else
@@ -167,6 +173,7 @@ static inline int ubi_dbg_is_erase_failure(void)
 #define ubi_dbg_is_bitflip()       0
 #define ubi_dbg_is_write_failure() 0
 #define ubi_dbg_is_erase_failure() 0
+#define ubi_dbg_check_all_ff(ubi, pnum, offset, len) 0
 
 #endif /* !CONFIG_MTD_UBI_DEBUG */
 #endif /* !__UBI_DEBUG_H__ */
index effaff28bab18ef4936c69cf354a4b8a11db17dd..4cb69925d8d968f9021626a6dd38933af94842ee 100644 (file)
@@ -98,17 +98,12 @@ static int paranoid_check_ec_hdr(const struct ubi_device *ubi, int pnum,
 static int paranoid_check_peb_vid_hdr(const struct ubi_device *ubi, int pnum);
 static int paranoid_check_vid_hdr(const struct ubi_device *ubi, int pnum,
                                  const struct ubi_vid_hdr *vid_hdr);
-static int paranoid_check_all_ff(struct ubi_device *ubi, int pnum, int offset,
-                                int len);
-static int paranoid_check_empty(struct ubi_device *ubi, int pnum);
 #else
 #define paranoid_check_not_bad(ubi, pnum) 0
 #define paranoid_check_peb_ec_hdr(ubi, pnum)  0
 #define paranoid_check_ec_hdr(ubi, pnum, ec_hdr)  0
 #define paranoid_check_peb_vid_hdr(ubi, pnum) 0
 #define paranoid_check_vid_hdr(ubi, pnum, vid_hdr) 0
-#define paranoid_check_all_ff(ubi, pnum, offset, len) 0
-#define paranoid_check_empty(ubi, pnum) 0
 #endif
 
 /**
@@ -244,7 +239,7 @@ int ubi_io_write(struct ubi_device *ubi, const void *buf, int pnum, int offset,
                return err > 0 ? -EINVAL : err;
 
        /* The area we are writing to has to contain all 0xFF bytes */
-       err = paranoid_check_all_ff(ubi, pnum, offset, len);
+       err = ubi_dbg_check_all_ff(ubi, pnum, offset, len);
        if (err)
                return err > 0 ? -EINVAL : err;
 
@@ -271,8 +266,8 @@ int ubi_io_write(struct ubi_device *ubi, const void *buf, int pnum, int offset,
        addr = (loff_t)pnum * ubi->peb_size + offset;
        err = ubi->mtd->write(ubi->mtd, addr, len, &written, buf);
        if (err) {
-               ubi_err("error %d while writing %d bytes to PEB %d:%d, written"
-                       " %zd bytes", err, len, pnum, offset, written);
+               ubi_err("error %d while writing %d bytes to PEB %d:%d, written "
+                       "%zd bytes", err, len, pnum, offset, written);
                ubi_dbg_dump_stack();
        } else
                ubi_assert(written == len);
@@ -350,7 +345,7 @@ retry:
                return -EIO;
        }
 
-       err = paranoid_check_all_ff(ubi, pnum, 0, ubi->peb_size);
+       err = ubi_dbg_check_all_ff(ubi, pnum, 0, ubi->peb_size);
        if (err)
                return err > 0 ? -EINVAL : err;
 
@@ -458,6 +453,54 @@ out:
        return err;
 }
 
+/**
+ * nor_erase_prepare - prepare a NOR flash PEB for erasure.
+ * @ubi: UBI device description object
+ * @pnum: physical eraseblock number to prepare
+ *
+ * NOR flash, or at least some of them, have peculiar embedded PEB erasure
+ * algorithm: the PEB is first filled with zeroes, then it is erased. And
+ * filling with zeroes starts from the end of the PEB. This was observed with
+ * Spansion S29GL512N NOR flash.
+ *
+ * This means that in case of a power cut we may end up with intact data at the
+ * beginning of the PEB, and all zeroes at the end of PEB. In other words, the
+ * EC and VID headers are OK, but a large chunk of data at the end of PEB is
+ * zeroed. This makes UBI mistakenly treat this PEB as used and associate it
+ * with an LEB, which leads to subsequent failures (e.g., UBIFS fails).
+ *
+ * This function is called before erasing NOR PEBs and it zeroes out EC and VID
+ * magic numbers in order to invalidate them and prevent the failures. Returns
+ * zero in case of success and a negative error code in case of failure.
+ */
+static int nor_erase_prepare(struct ubi_device *ubi, int pnum)
+{
+       int err;
+       size_t written;
+       loff_t addr;
+       uint32_t data = 0;
+
+       addr = (loff_t)pnum * ubi->peb_size;
+       err = ubi->mtd->write(ubi->mtd, addr, 4, &written, (void *)&data);
+       if (err) {
+               ubi_err("error %d while writing 4 bytes to PEB %d:%d, written "
+                       "%zd bytes", err, pnum, 0, written);
+               ubi_dbg_dump_stack();
+               return err;
+       }
+
+       addr += ubi->vid_hdr_aloffset;
+       err = ubi->mtd->write(ubi->mtd, addr, 4, &written, (void *)&data);
+       if (err) {
+               ubi_err("error %d while writing 4 bytes to PEB %d:%d, written "
+                       "%zd bytes", err, pnum, ubi->vid_hdr_aloffset, written);
+               ubi_dbg_dump_stack();
+               return err;
+       }
+
+       return 0;
+}
+
 /**
  * ubi_io_sync_erase - synchronously erase a physical eraseblock.
  * @ubi: UBI device description object
@@ -489,6 +532,12 @@ int ubi_io_sync_erase(struct ubi_device *ubi, int pnum, int torture)
                return -EROFS;
        }
 
+       if (ubi->nor_flash) {
+               err = nor_erase_prepare(ubi, pnum);
+               if (err)
+                       return err;
+       }
+
        if (torture) {
                ret = torture_peb(ubi, pnum);
                if (ret < 0)
@@ -672,11 +721,6 @@ int ubi_io_read_ec_hdr(struct ubi_device *ubi, int pnum,
                if (read_err != -EBADMSG &&
                    check_pattern(ec_hdr, 0xFF, UBI_EC_HDR_SIZE)) {
                        /* The physical eraseblock is supposedly empty */
-                       err = paranoid_check_all_ff(ubi, pnum, 0,
-                                                   ubi->peb_size);
-                       if (err)
-                               return err > 0 ? UBI_IO_BAD_EC_HDR : err;
-
                        if (verbose)
                                ubi_warn("no EC header found at PEB %d, "
                                         "only 0xFF bytes", pnum);
@@ -752,6 +796,7 @@ int ubi_io_write_ec_hdr(struct ubi_device *ubi, int pnum,
        ec_hdr->version = UBI_VERSION;
        ec_hdr->vid_hdr_offset = cpu_to_be32(ubi->vid_hdr_offset);
        ec_hdr->data_offset = cpu_to_be32(ubi->leb_start);
+       ec_hdr->image_seq = cpu_to_be32(ubi->image_seq);
        crc = crc32(UBI_CRC32_INIT, ec_hdr, UBI_EC_HDR_SIZE_CRC);
        ec_hdr->hdr_crc = cpu_to_be32(crc);
 
@@ -947,15 +992,6 @@ int ubi_io_read_vid_hdr(struct ubi_device *ubi, int pnum,
                if (read_err != -EBADMSG &&
                    check_pattern(vid_hdr, 0xFF, UBI_VID_HDR_SIZE)) {
                        /* The physical eraseblock is supposedly free */
-
-                       /*
-                        * The below is just a paranoid check, it has to be
-                        * compiled out if paranoid checks are disabled.
-                        */
-                       err = paranoid_check_empty(ubi, pnum);
-                       if (err)
-                               return err > 0 ? UBI_IO_BAD_VID_HDR : err;
-
                        if (verbose)
                                ubi_warn("no VID header found at PEB %d, "
                                         "only 0xFF bytes", pnum);
@@ -1229,7 +1265,7 @@ exit:
 }
 
 /**
- * paranoid_check_all_ff - check that a region of flash is empty.
+ * ubi_dbg_check_all_ff - check that a region of flash is empty.
  * @ubi: UBI device description object
  * @pnum: the physical eraseblock number to check
  * @offset: the starting offset within the physical eraseblock to check
@@ -1239,8 +1275,7 @@ exit:
  * @offset of the physical eraseblock @pnum, %1 if not, and a negative error
  * code if an error occurred.
  */
-static int paranoid_check_all_ff(struct ubi_device *ubi, int pnum, int offset,
-                                int len)
+int ubi_dbg_check_all_ff(struct ubi_device *ubi, int pnum, int offset, int len)
 {
        size_t read;
        int err;
@@ -1276,74 +1311,4 @@ error:
        return err;
 }
 
-/**
- * paranoid_check_empty - whether a PEB is empty.
- * @ubi: UBI device description object
- * @pnum: the physical eraseblock number to check
- *
- * This function makes sure PEB @pnum is empty, which means it contains only
- * %0xFF data bytes. Returns zero if the PEB is empty, %1 if not, and a
- * negative error code in case of failure.
- *
- * Empty PEBs have the EC header, and do not have the VID header. The caller of
- * this function should have already made sure the PEB does not have the VID
- * header. However, this function re-checks that, because it is possible that
- * the header and data has already been written to the PEB.
- *
- * Let's consider a possible scenario. Suppose there are 2 tasks - A and B.
- * Task A is in 'wear_leveling_worker()'. It is reading VID header of PEB X to
- * find which LEB it corresponds to. PEB X is currently unmapped, and has no
- * VID header. Task B is trying to write to PEB X.
- *
- * Task A: in 'ubi_io_read_vid_hdr()': reads the VID header from PEB X. The
- *         read data contain all 0xFF bytes;
- * Task B: writes VID header and some data to PEB X;
- * Task A: assumes PEB X is empty, calls 'paranoid_check_empty()'. And if we
- *         do not re-read the VID header, and do not cancel the checking if it
- *         is there, we fail.
- */
-static int paranoid_check_empty(struct ubi_device *ubi, int pnum)
-{
-       int err, offs = ubi->vid_hdr_aloffset, len = ubi->vid_hdr_alsize;
-       size_t read;
-       uint32_t magic;
-       const struct ubi_vid_hdr *vid_hdr;
-
-       mutex_lock(&ubi->dbg_buf_mutex);
-       err = ubi->mtd->read(ubi->mtd, offs, len, &read, ubi->dbg_peb_buf);
-       if (err && err != -EUCLEAN) {
-               ubi_err("error %d while reading %d bytes from PEB %d:%d, "
-                       "read %zd bytes", err, len, pnum, offs, read);
-               goto error;
-       }
-
-       vid_hdr = ubi->dbg_peb_buf;
-       magic = be32_to_cpu(vid_hdr->magic);
-       if (magic == UBI_VID_HDR_MAGIC)
-               /* The PEB contains VID header, so it is not empty */
-               goto out;
-
-       err = check_pattern(ubi->dbg_peb_buf, 0xFF, len);
-       if (err == 0) {
-               ubi_err("flash region at PEB %d:%d, length %d does not "
-                       "contain all 0xFF bytes", pnum, offs, len);
-               goto fail;
-       }
-
-out:
-       mutex_unlock(&ubi->dbg_buf_mutex);
-       return 0;
-
-fail:
-       ubi_err("paranoid check failed for PEB %d", pnum);
-       ubi_msg("hex dump of the %d-%d region", offs, offs + len);
-       print_hex_dump(KERN_DEBUG, "", DUMP_PREFIX_OFFSET, 32, 1,
-                      ubi->dbg_peb_buf, len, 1);
-       err = 1;
-error:
-       ubi_dbg_dump_stack();
-       mutex_unlock(&ubi->dbg_buf_mutex);
-       return err;
-}
-
 #endif /* CONFIG_MTD_UBI_DEBUG_PARANOID */
index c3d653ba5ca0153c45ccbfd21a6d106bfa1b6220..f60895ee0aebde9098e1f5251be0a38ecd6cf02f 100644 (file)
@@ -757,6 +757,8 @@ static int process_eb(struct ubi_device *ubi, struct ubi_scan_info *si,
        si->is_empty = 0;
 
        if (!ec_corr) {
+               int image_seq;
+
                /* Make sure UBI version is OK */
                if (ech->version != UBI_VERSION) {
                        ubi_err("this UBI version is %d, image version is %d",
@@ -778,6 +780,18 @@ static int process_eb(struct ubi_device *ubi, struct ubi_scan_info *si,
                        ubi_dbg_dump_ec_hdr(ech);
                        return -EINVAL;
                }
+
+               image_seq = be32_to_cpu(ech->ec);
+               if (!si->image_seq_set) {
+                       ubi->image_seq = image_seq;
+                       si->image_seq_set = 1;
+               } else if (ubi->image_seq != image_seq) {
+                       ubi_err("bad image sequence number %d in PEB %d, "
+                               "expected %d", image_seq, pnum, ubi->image_seq);
+                       ubi_dbg_dump_ec_hdr(ech);
+                       return -EINVAL;
+               }
+
        }
 
        /* OK, we've done with the EC header, let's look at the VID header */
index 61df208e2f2077de860db28494e8639349368111..1017cf12def56253606168e3c2ad18af674b8eae 100644 (file)
@@ -102,6 +102,7 @@ struct ubi_scan_volume {
  * @mean_ec: mean erase counter value
  * @ec_sum: a temporary variable used when calculating @mean_ec
  * @ec_count: a temporary variable used when calculating @mean_ec
+ * @image_seq_set: indicates @ubi->image_seq is known
  *
  * This data structure contains the result of scanning and may be used by other
  * UBI sub-systems to build final UBI data structures, further error-recovery
@@ -124,6 +125,7 @@ struct ubi_scan_info {
        int mean_ec;
        uint64_t ec_sum;
        int ec_count;
+       int image_seq_set;
 };
 
 struct ubi_device;
index 8419fdccc79cbcbdadb639b8188c65eab18bd468..503ea9b273094670d0933baafbfbfb04ae6d88cd 100644 (file)
@@ -129,6 +129,7 @@ enum {
  * @ec: the erase counter
  * @vid_hdr_offset: where the VID header starts
  * @data_offset: where the user data start
+ * @image_seq: image sequence number
  * @padding2: reserved for future, zeroes
  * @hdr_crc: erase counter header CRC checksum
  *
@@ -144,6 +145,14 @@ enum {
  * volume identifier header and user data, relative to the beginning of the
  * physical eraseblock. These values have to be the same for all physical
  * eraseblocks.
+ *
+ * The @image_seq field is used to validate a UBI image that has been prepared
+ * for a UBI device. The @image_seq value can be any value, but it must be the
+ * same on all eraseblocks. UBI will ensure that all new erase counter headers
+ * also contain this value, and will check the value when scanning at start-up.
+ * One way to make use of @image_seq is to increase its value by one every time
+ * an image is flashed over an existing image, then, if the flashing does not
+ * complete, UBI will detect the error when scanning.
  */
 struct ubi_ec_hdr {
        __be32  magic;
@@ -152,7 +161,8 @@ struct ubi_ec_hdr {
        __be64  ec; /* Warning: the current limit is 31-bit anyway! */
        __be32  vid_hdr_offset;
        __be32  data_offset;
-       __u8    padding2[36];
+       __be32  image_seq;
+       __u8    padding2[32];
        __be32  hdr_crc;
 } __attribute__ ((packed));
 
index 28acd133c997987eedefe9c926313a4dd207ffb9..6a5fe963378367ab48f871cbd6893d56d4ed454e 100644 (file)
@@ -301,6 +301,7 @@ struct ubi_wl_entry;
  *                @vol->readers, @vol->writers, @vol->exclusive,
  *                @vol->ref_count, @vol->mapping and @vol->eba_tbl.
  * @ref_count: count of references on the UBI device
+ * @image_seq: image sequence number recorded on EC headers
  *
  * @rsvd_pebs: count of reserved physical eraseblocks
  * @avail_pebs: count of available physical eraseblocks
@@ -372,6 +373,7 @@ struct ubi_wl_entry;
  * @vid_hdr_shift: contains @vid_hdr_offset - @vid_hdr_aloffset
  * @bad_allowed: whether the MTD device admits of bad physical eraseblocks or
  *               not
+ * @nor_flash: non-zero if working on top of NOR flash
  * @mtd: MTD device descriptor
  *
  * @peb_buf1: a buffer of PEB size used for different purposes
@@ -390,6 +392,7 @@ struct ubi_device {
        struct ubi_volume *volumes[UBI_MAX_VOLUMES+UBI_INT_VOL_COUNT];
        spinlock_t volumes_lock;
        int ref_count;
+       int image_seq;
 
        int rsvd_pebs;
        int avail_pebs;
@@ -452,7 +455,8 @@ struct ubi_device {
        int vid_hdr_offset;
        int vid_hdr_aloffset;
        int vid_hdr_shift;
-       int bad_allowed;
+       unsigned int bad_allowed:1;
+       unsigned int nor_flash:1;
        struct mtd_info *mtd;
 
        void *peb_buf1;
index 2b2472300610f166eb897a53647436f4307c9456..600c7229d5cf21b0d959ca2d7c1a86ccc676e4af 100644 (file)
@@ -459,6 +459,14 @@ retry:
        dbg_wl("PEB %d EC %d", e->pnum, e->ec);
        prot_queue_add(ubi, e);
        spin_unlock(&ubi->wl_lock);
+
+       err = ubi_dbg_check_all_ff(ubi, e->pnum, ubi->vid_hdr_aloffset,
+                                  ubi->peb_size - ubi->vid_hdr_aloffset);
+       if (err) {
+               ubi_err("new PEB %d does not contain all 0xFF bytes", e->pnum);
+               return err > 0 ? -EINVAL : err;
+       }
+
        return e->pnum;
 }
 
index 8ae72ec14456d4dc2e31141777a1bf35776fc78a..0e2ba21d4441810a279432229d7d078ef3e65bdd 100644 (file)
@@ -908,6 +908,7 @@ static const struct net_device_ops rtl8139_netdev_ops = {
        .ndo_open               = rtl8139_open,
        .ndo_stop               = rtl8139_close,
        .ndo_get_stats          = rtl8139_get_stats,
+       .ndo_change_mtu         = eth_change_mtu,
        .ndo_validate_addr      = eth_validate_addr,
        .ndo_set_mac_address    = rtl8139_set_mac_address,
        .ndo_start_xmit         = rtl8139_start_xmit,
index 1dc721517e4cdf30db36ed726230d74b83e55501..c155bd3ec9f1a47640d4706626f544afe2e335bb 100644 (file)
@@ -1725,6 +1725,7 @@ config TLAN
 
 config KS8842
        tristate "Micrel KSZ8842"
+       depends on HAS_IOMEM
        help
          This platform driver is for Micrel KSZ8842 chip.
 
index 85a18175730ba249ab36c5985a654e34df1eb05c..08787f5a22a3dee8f9b10799332333cd3a398089 100644 (file)
@@ -569,16 +569,8 @@ static int lance_start_xmit (struct sk_buff *skb, struct net_device *dev)
 
 #ifdef DEBUG_DRIVER
        /* dump the packet */
-       {
-               int i;
-
-               for (i = 0; i < 64; i++) {
-                       if ((i % 16) == 0)
-                               printk("\n" KERN_DEBUG);
-                       printk ("%2.2x ", skb->data [i]);
-               }
-               printk("\n");
-       }
+       print_hex_dump(KERN_DEBUG, "skb->data: ", DUMP_PREFIX_NONE,
+                      16, 1, skb->data, 64, true);
 #endif
        entry = lp->tx_new & lp->tx_ring_mod_mask;
        ib->btx_ring [entry].length = (-skblen) | 0xf000;
index d6d4ab3b430ccf77a25fe865384f3daaa8b6b7b4..7d227cdab9f8c5617ca2855303f4118ca0fc6fcb 100644 (file)
@@ -158,15 +158,12 @@ module_exit(arcnet_exit);
 void arcnet_dump_skb(struct net_device *dev,
                     struct sk_buff *skb, char *desc)
 {
-       int i;
+       char hdr[32];
 
-       printk(KERN_DEBUG "%6s: skb dump (%s) follows:", dev->name, desc);
-       for (i = 0; i < skb->len; i++) {
-               if (i % 16 == 0)
-                       printk("\n" KERN_DEBUG "[%04X] ", i);
-               printk("%02X ", ((u_char *) skb->data)[i]);
-       }
-       printk("\n");
+       /* dump the packet */
+       snprintf(hdr, sizeof(hdr), "%6s:%s skb->data:", dev->name, desc);
+       print_hex_dump(KERN_DEBUG, hdr, DUMP_PREFIX_OFFSET,
+                      16, 1, skb->data, skb->len, true);
 }
 
 EXPORT_SYMBOL(arcnet_dump_skb);
@@ -184,6 +181,7 @@ static void arcnet_dump_packet(struct net_device *dev, int bufnum,
        int i, length;
        unsigned long flags = 0;
        static uint8_t buf[512];
+       char hdr[32];
 
        /* hw.copy_from_card expects IRQ context so take the IRQ lock
           to keep it single threaded */
@@ -197,14 +195,10 @@ static void arcnet_dump_packet(struct net_device *dev, int bufnum,
        /* if the offset[0] byte is nonzero, this is a 256-byte packet */
        length = (buf[2] ? 256 : 512);
 
-       printk(KERN_DEBUG "%6s: packet dump (%s) follows:", dev->name, desc);
-       for (i = 0; i < length; i++) {
-               if (i % 16 == 0)
-                       printk("\n" KERN_DEBUG "[%04X] ", i);
-               printk("%02X ", buf[i]);
-       }
-       printk("\n");
-
+       /* dump the packet */
+       snprintf(hdr, sizeof(hdr), "%6s:%s packet dump:", dev->name, desc);
+       print_hex_dump(KERN_DEBUG, hdr, DUMP_PREFIX_OFFSET,
+                      16, 1, buf, length, true);
 }
 
 #else
index 6f42ad728915b2683ee9ee66a9e11562c890453e..3fe09876e76d3f5c62e0878adf7545317760a2c3 100644 (file)
@@ -1142,7 +1142,9 @@ static const struct net_device_ops ixp4xx_netdev_ops = {
        .ndo_start_xmit = eth_xmit,
        .ndo_set_multicast_list = eth_set_mcast_list,
        .ndo_do_ioctl = eth_ioctl,
-
+       .ndo_change_mtu = eth_change_mtu,
+       .ndo_set_mac_address = eth_mac_addr,
+       .ndo_validate_addr = eth_validate_addr,
 };
 
 static int __devinit eth_init_one(struct platform_device *pdev)
index e4afbd628c23e8f8b4594e44988d37e6842592cb..607007d75b6fa82f5e2cd6e8328985ef10102c49 100644 (file)
@@ -281,6 +281,8 @@ static int atl1c_set_wol(struct net_device *netdev, struct ethtool_wolinfo *wol)
        if (wol->wolopts & WAKE_PHY)
                adapter->wol |= AT_WUFC_LNKC;
 
+       device_set_wakeup_enable(&adapter->pdev->dev, adapter->wol);
+
        return 0;
 }
 
index 619c6583e1aac7ca5e8dd1ff263fab6325b6193c..4003955d7a9650b3ed095ee516b3f671f666e37d 100644 (file)
@@ -365,6 +365,8 @@ static int atl1e_set_wol(struct net_device *netdev, struct ethtool_wolinfo *wol)
        if (wol->wolopts & WAKE_PHY)
                adapter->wol |= AT_WUFC_LNKC;
 
+       device_set_wakeup_enable(&adapter->pdev->dev, adapter->wol);
+
        return 0;
 }
 
index c734b1983ec14667bc2debd4d5eec05b4f66369d..204db961029e798e74a8dc990d7b086207c0771c 100644 (file)
@@ -2071,7 +2071,7 @@ static int atl2_set_wol(struct net_device *netdev, struct ethtool_wolinfo *wol)
        if (wol->wolopts & (WAKE_ARP | WAKE_MAGICSECURE))
                return -EOPNOTSUPP;
 
-       if (wol->wolopts & (WAKE_MCAST|WAKE_BCAST|WAKE_MCAST))
+       if (wol->wolopts & (WAKE_UCAST | WAKE_BCAST | WAKE_MCAST))
                return -EOPNOTSUPP;
 
        /* these settings will always override what we currently have */
index f703758f0a6e4f7fdaa730dbe53fec400b86d5f7..5b4bf3d2cdc2ecb9b6c85544d96a7d7f48ef156a 100644 (file)
@@ -73,7 +73,7 @@ static inline char *nic_name(struct pci_dev *pdev)
 #define RX_FRAGS_REFILL_WM     (RX_Q_LEN - MAX_RX_POST)
 
 #define BE_MAX_LRO_DESCRIPTORS  16
-#define BE_MAX_FRAGS_PER_FRAME  16
+#define BE_MAX_FRAGS_PER_FRAME  (min((u32) 16, (u32) MAX_SKB_FRAGS))
 
 struct be_dma_mem {
        void *va;
index 9592f22e4c8c29a139dd5fb523b300aacc63b9d6..cccc5419ad72a5f02b1e5109ed66315995eb3668 100644 (file)
@@ -162,8 +162,8 @@ be_set_coalesce(struct net_device *netdev, struct ethtool_coalesce *coalesce)
                return -EINVAL;
 
        adapter->max_rx_coal = coalesce->rx_max_coalesced_frames;
-       if (adapter->max_rx_coal > MAX_SKB_FRAGS)
-               adapter->max_rx_coal = MAX_SKB_FRAGS - 1;
+       if (adapter->max_rx_coal > BE_MAX_FRAGS_PER_FRAME)
+               adapter->max_rx_coal = BE_MAX_FRAGS_PER_FRAME;
 
        /* if AIC is being turned on now, start with an EQD of 0 */
        if (rx_eq->enable_aic == 0 &&
index b02e805c1db37c8e645510b6b479905b74d19e56..29c33c709c6d11262024d46768870ffc53921c6e 100644 (file)
 #define MEMBAR_CTRL_INT_CTRL_PFUNC_MASK        0x7     /* bits 26 - 28 */
 #define MEMBAR_CTRL_INT_CTRL_PFUNC_SHIFT       26
 
+/********* ISR0 Register offset **********/
+#define CEV_ISR0_OFFSET                        0xC18
+#define CEV_ISR_SIZE                           4
+
 /********* Event Q door bell *************/
 #define DB_EQ_OFFSET                   DB_CQ_OFFSET
 #define DB_EQ_RING_ID_MASK             0x1FF   /* bits 0 - 8 */
index 66c10c87f5175151d54cff2fedb9a1f96d551201..c43f6a119295097ac2c44d1040b38ae39502e1b8 100644 (file)
@@ -666,7 +666,7 @@ static void skb_fill_rx_data(struct be_adapter *adapter,
 {
        struct be_queue_info *rxq = &adapter->rx_obj.q;
        struct be_rx_page_info *page_info;
-       u16 rxq_idx, i, num_rcvd;
+       u16 rxq_idx, i, num_rcvd, j;
        u32 pktsize, hdr_len, curr_frag_len;
        u8 *start;
 
@@ -709,22 +709,33 @@ static void skb_fill_rx_data(struct be_adapter *adapter,
 
        /* More frags present for this completion */
        pktsize -= curr_frag_len; /* account for above copied frag */
-       for (i = 1; i < num_rcvd; i++) {
+       for (i = 1, j = 0; i < num_rcvd; i++) {
                index_inc(&rxq_idx, rxq->len);
                page_info = get_rx_page_info(adapter, rxq_idx);
 
                curr_frag_len = min(pktsize, rx_frag_size);
 
-               skb_shinfo(skb)->frags[i].page = page_info->page;
-               skb_shinfo(skb)->frags[i].page_offset = page_info->page_offset;
-               skb_shinfo(skb)->frags[i].size = curr_frag_len;
+               /* Coalesce all frags from the same physical page in one slot */
+               if (page_info->page_offset == 0) {
+                       /* Fresh page */
+                       j++;
+                       skb_shinfo(skb)->frags[j].page = page_info->page;
+                       skb_shinfo(skb)->frags[j].page_offset =
+                                                       page_info->page_offset;
+                       skb_shinfo(skb)->frags[j].size = 0;
+                       skb_shinfo(skb)->nr_frags++;
+               } else {
+                       put_page(page_info->page);
+               }
+
+               skb_shinfo(skb)->frags[j].size += curr_frag_len;
                skb->len += curr_frag_len;
                skb->data_len += curr_frag_len;
-               skb_shinfo(skb)->nr_frags++;
                pktsize -= curr_frag_len;
 
                memset(page_info, 0, sizeof(*page_info));
        }
+       BUG_ON(j > MAX_SKB_FRAGS);
 
 done:
        be_rx_stats_update(adapter, pktsize, num_rcvd);
@@ -786,7 +797,7 @@ static void be_rx_compl_process_lro(struct be_adapter *adapter,
        struct skb_frag_struct rx_frags[BE_MAX_FRAGS_PER_FRAME];
        struct be_queue_info *rxq = &adapter->rx_obj.q;
        u32 num_rcvd, pkt_size, remaining, vlanf, curr_frag_len;
-       u16 i, rxq_idx = 0, vid;
+       u16 i, rxq_idx = 0, vid, j;
 
        num_rcvd = AMAP_GET_BITS(struct amap_eth_rx_compl, numfrags, rxcp);
        pkt_size = AMAP_GET_BITS(struct amap_eth_rx_compl, pktsize, rxcp);
@@ -794,20 +805,28 @@ static void be_rx_compl_process_lro(struct be_adapter *adapter,
        rxq_idx = AMAP_GET_BITS(struct amap_eth_rx_compl, fragndx, rxcp);
 
        remaining = pkt_size;
-       for (i = 0; i < num_rcvd; i++) {
+       for (i = 0, j = -1; i < num_rcvd; i++) {
                page_info = get_rx_page_info(adapter, rxq_idx);
 
                curr_frag_len = min(remaining, rx_frag_size);
 
-               rx_frags[i].page = page_info->page;
-               rx_frags[i].page_offset = page_info->page_offset;
-               rx_frags[i].size = curr_frag_len;
-               remaining -= curr_frag_len;
+               /* Coalesce all frags from the same physical page in one slot */
+               if (i == 0 || page_info->page_offset == 0) {
+                       /* First frag or Fresh page */
+                       j++;
+                       rx_frags[j].page = page_info->page;
+                       rx_frags[j].page_offset = page_info->page_offset;
+                       rx_frags[j].size = 0;
+               } else {
+                       put_page(page_info->page);
+               }
+               rx_frags[j].size += curr_frag_len;
 
+               remaining -= curr_frag_len;
                index_inc(&rxq_idx, rxq->len);
-
                memset(page_info, 0, sizeof(*page_info));
        }
+       BUG_ON(j > MAX_SKB_FRAGS);
 
        if (likely(!vlanf)) {
                lro_receive_frags(&adapter->rx_obj.lro_mgr, rx_frags, pkt_size,
@@ -1255,15 +1274,17 @@ static irqreturn_t be_intx(int irq, void *dev)
 {
        struct be_adapter *adapter = dev;
        struct be_ctrl_info *ctrl = &adapter->ctrl;
-       int rx, tx;
+        int isr;
 
-       tx = event_handle(ctrl, &adapter->tx_eq);
-       rx = event_handle(ctrl, &adapter->rx_eq);
+       isr = ioread32(ctrl->csr + CEV_ISR0_OFFSET +
+                      ctrl->pci_func * CEV_ISR_SIZE);
+       if (!isr)
+                return IRQ_NONE;
 
-       if (rx || tx)
-               return IRQ_HANDLED;
-       else
-               return IRQ_NONE;
+        event_handle(ctrl, &adapter->tx_eq);
+        event_handle(ctrl, &adapter->rx_eq);
+
+        return IRQ_HANDLED;
 }
 
 static irqreturn_t be_msix_rx(int irq, void *dev)
index 9578a3dfac01333a696050e0f95abc0aa8c6da46..206144f2470f388588e40cc1638f2fa3027608b5 100644 (file)
@@ -428,10 +428,11 @@ bmac_init_phy(struct net_device *dev)
        printk(KERN_DEBUG "phy registers:");
        for (addr = 0; addr < 32; ++addr) {
                if ((addr & 7) == 0)
-                       printk("\n" KERN_DEBUG);
-               printk(" %.4x", bmac_mif_read(dev, addr));
+                       printk(KERN_DEBUG);
+               printk(KERN_CONT " %.4x", bmac_mif_read(dev, addr));
        }
-       printk("\n");
+       printk(KERN_CONT "\n");
+
        if (bp->is_bmac_plus) {
                unsigned int capable, ctrl;
 
index 38f1c3375d7f64eb7a0e50e59feef331b72cf16c..b70cc99962fcfcf6ccb655213ccf0f1f0225fa89 100644 (file)
@@ -6825,6 +6825,14 @@ bnx2_nway_reset(struct net_device *dev)
        return 0;
 }
 
+static u32
+bnx2_get_link(struct net_device *dev)
+{
+       struct bnx2 *bp = netdev_priv(dev);
+
+       return bp->link_up;
+}
+
 static int
 bnx2_get_eeprom_len(struct net_device *dev)
 {
@@ -7392,7 +7400,7 @@ static const struct ethtool_ops bnx2_ethtool_ops = {
        .get_wol                = bnx2_get_wol,
        .set_wol                = bnx2_set_wol,
        .nway_reset             = bnx2_nway_reset,
-       .get_link               = ethtool_op_get_link,
+       .get_link               = bnx2_get_link,
        .get_eeprom_len         = bnx2_get_eeprom_len,
        .get_eeprom             = bnx2_get_eeprom,
        .set_eeprom             = bnx2_set_eeprom,
index 8678457849f9ff32e5bb7b71c1af55fc43c7824f..85a737c5c23f2647577127b1e045edbaafc058a0 100644 (file)
@@ -902,6 +902,8 @@ struct bnx2x {
        u16                     rx_quick_cons_trip;
        u16                     rx_ticks_int;
        u16                     rx_ticks;
+/* Maximal coalescing timeout in us */
+#define BNX2X_MAX_COALESCE_TOUT                (0xf0*12)
 
        u32                     lin_cnt;
 
index fbf1352e9c1cbd5701202a65ed95f962c6e6d486..c36a5f33739f5f30eafa70162dd59a689571a8d6 100644 (file)
@@ -484,8 +484,9 @@ static void bnx2x_fw_dump(struct bnx2x *bp)
 
        mark = REG_RD(bp, MCP_REG_MCPR_SCRATCH + 0xf104);
        mark = ((mark + 0x3) & ~0x3);
-       printk(KERN_ERR PFX "begin fw dump (mark 0x%x)\n" KERN_ERR, mark);
+       printk(KERN_ERR PFX "begin fw dump (mark 0x%x)\n", mark);
 
+       printk(KERN_ERR PFX);
        for (offset = mark - 0x08000000; offset <= 0xF900; offset += 0x8*4) {
                for (word = 0; word < 8; word++)
                        data[word] = htonl(REG_RD(bp, MCP_REG_MCPR_SCRATCH +
@@ -500,7 +501,7 @@ static void bnx2x_fw_dump(struct bnx2x *bp)
                data[8] = 0x0;
                printk(KERN_CONT "%s", (char *)data);
        }
-       printk("\n" KERN_ERR PFX "end of fw dump\n");
+       printk(KERN_ERR PFX "end of fw dump\n");
 }
 
 static void bnx2x_panic_dump(struct bnx2x *bp)
@@ -4434,7 +4435,7 @@ static void bnx2x_update_coalesce(struct bnx2x *bp)
                REG_WR16(bp, BAR_USTRORM_INTMEM +
                         USTORM_SB_HC_DISABLE_OFFSET(port, sb_id,
                                                     U_SB_ETH_RX_CQ_INDEX),
-                        bp->rx_ticks ? 0 : 1);
+                        (bp->rx_ticks/12) ? 0 : 1);
 
                /* HC_INDEX_C_ETH_TX_CQ_CONS */
                REG_WR8(bp, BAR_CSTRORM_INTMEM +
@@ -4444,7 +4445,7 @@ static void bnx2x_update_coalesce(struct bnx2x *bp)
                REG_WR16(bp, BAR_CSTRORM_INTMEM +
                         CSTORM_SB_HC_DISABLE_OFFSET(port, sb_id,
                                                     C_SB_ETH_TX_CQ_INDEX),
-                        bp->tx_ticks ? 0 : 1);
+                        (bp->tx_ticks/12) ? 0 : 1);
        }
 }
 
@@ -7354,7 +7355,7 @@ static void bnx2x_reset_task(struct work_struct *work)
 #ifdef BNX2X_STOP_ON_ERROR
        BNX2X_ERR("reset task called but STOP_ON_ERROR defined"
                  " so reset not done to allow debug dump,\n"
-        KERN_ERR " you will need to reboot when done\n");
+                 " you will need to reboot when done\n");
        return;
 #endif
 
@@ -8637,6 +8638,14 @@ static int bnx2x_nway_reset(struct net_device *dev)
        return 0;
 }
 
+static u32
+bnx2x_get_link(struct net_device *dev)
+{
+       struct bnx2x *bp = netdev_priv(dev);
+
+       return bp->link_vars.link_up;
+}
+
 static int bnx2x_get_eeprom_len(struct net_device *dev)
 {
        struct bnx2x *bp = netdev_priv(dev);
@@ -9061,12 +9070,12 @@ static int bnx2x_set_coalesce(struct net_device *dev,
        struct bnx2x *bp = netdev_priv(dev);
 
        bp->rx_ticks = (u16) coal->rx_coalesce_usecs;
-       if (bp->rx_ticks > 3000)
-               bp->rx_ticks = 3000;
+       if (bp->rx_ticks > BNX2X_MAX_COALESCE_TOUT)
+               bp->rx_ticks = BNX2X_MAX_COALESCE_TOUT;
 
        bp->tx_ticks = (u16) coal->tx_coalesce_usecs;
-       if (bp->tx_ticks > 0x3000)
-               bp->tx_ticks = 0x3000;
+       if (bp->tx_ticks > BNX2X_MAX_COALESCE_TOUT)
+               bp->tx_ticks = BNX2X_MAX_COALESCE_TOUT;
 
        if (netif_running(dev))
                bnx2x_update_coalesce(bp);
@@ -10034,7 +10043,7 @@ static struct ethtool_ops bnx2x_ethtool_ops = {
        .get_msglevel           = bnx2x_get_msglevel,
        .set_msglevel           = bnx2x_set_msglevel,
        .nway_reset             = bnx2x_nway_reset,
-       .get_link               = ethtool_op_get_link,
+       .get_link               = bnx2x_get_link,
        .get_eeprom_len         = bnx2x_get_eeprom_len,
        .get_eeprom             = bnx2x_get_eeprom,
        .set_eeprom             = bnx2x_set_eeprom,
index d5e18812bf497f615465a6f1a5c9f7708976fefe..33821a81cbf85113336ab1b2ec37015291efcc4b 100644 (file)
@@ -36,7 +36,7 @@ config CAN_CALC_BITTIMING
          If unsure, say Y.
 
 config CAN_SJA1000
-       depends on CAN_DEV
+       depends on CAN_DEV && HAS_IOMEM
        tristate "Philips SJA1000"
        ---help---
          Driver for the SJA1000 CAN controllers from Philips or NXP
index 58afafbd3b9cb9695bcf6fe570c07b493a30d881..fd5e32cbcb8778bb7ed02fdd0d7bf6ec6d1e9163 100644 (file)
@@ -1097,7 +1097,7 @@ static const struct net_device_ops cpmac_netdev_ops = {
        .ndo_start_xmit         = cpmac_start_xmit,
        .ndo_tx_timeout         = cpmac_tx_timeout,
        .ndo_set_multicast_list = cpmac_set_multicast_list,
-       .ndo_so_ioctl           = cpmac_ioctl,
+       .ndo_do_ioctl           = cpmac_ioctl,
        .ndo_set_config         = cpmac_config,
        .ndo_change_mtu         = eth_change_mtu,
        .ndo_validate_addr      = eth_validate_addr,
index 3eee666a9cd26773fa4712704cf7066ec7f0cbc5..55445f980f9c975596d41b3a9e9a0887155f061b 100644 (file)
@@ -1524,6 +1524,7 @@ static void net_timeout(struct net_device *dev)
 static int net_send_packet(struct sk_buff *skb, struct net_device *dev)
 {
        struct net_local *lp = netdev_priv(dev);
+       unsigned long flags;
 
        if (net_debug > 3) {
                printk("%s: sent %d byte packet of type %x\n",
@@ -1535,7 +1536,7 @@ static int net_send_packet(struct sk_buff *skb, struct net_device *dev)
                   ask the chip to start transmitting before the
                   whole packet has been completely uploaded. */
 
-       spin_lock_irq(&lp->lock);
+       spin_lock_irqsave(&lp->lock, flags);
        netif_stop_queue(dev);
 
        /* initiate a transmit sequence */
@@ -1549,13 +1550,13 @@ static int net_send_packet(struct sk_buff *skb, struct net_device *dev)
                 * we're waiting for TxOk, so return 1 and requeue this packet.
                 */
 
-               spin_unlock_irq(&lp->lock);
+               spin_unlock_irqrestore(&lp->lock, flags);
                if (net_debug) printk("cs89x0: Tx buffer not free!\n");
                return NETDEV_TX_BUSY;
        }
        /* Write the contents of the packet */
        writewords(dev->base_addr, TX_FRAME_PORT,skb->data,(skb->len+1) >>1);
-       spin_unlock_irq(&lp->lock);
+       spin_unlock_irqrestore(&lp->lock, flags);
        lp->stats.tx_bytes += skb->len;
        dev->trans_start = jiffies;
        dev_kfree_skb (skb);
index 538dda4422dca039b01715e8ca10892af4954ea1..fb5df5c6203e9541849fce56a52abfaedfbe7391 100644 (file)
@@ -642,8 +642,7 @@ static int setup_sge_qsets(struct adapter *adap)
                struct port_info *pi = netdev_priv(dev);
 
                pi->qs = &adap->sge.qs[pi->first_qset];
-               for (j = pi->first_qset; j < pi->first_qset + pi->nqsets;
-                    ++j, ++qset_idx) {
+               for (j = 0; j < pi->nqsets; ++j, ++qset_idx) {
                        set_qset_lro(dev, qset_idx, pi->rx_offload & T3_LRO);
                        err = t3_sge_alloc_qset(adap, qset_idx, 1,
                                (adap->flags & USING_MSIX) ? qset_idx + 1 :
index 2df8fb0af701a0e081d8fee4820bb4047e2d6a6c..12fd446f9895036c6e7f099e0abc7517d9678f59 100644 (file)
@@ -1820,11 +1820,19 @@ static int emac_dev_setmac_addr(struct net_device *ndev, void *addr)
        struct device *emac_dev = &priv->ndev->dev;
        struct sockaddr *sa = addr;
 
+       if (!is_valid_ether_addr(sa->sa_data))
+               return -EINVAL;
+
        /* Store mac addr in priv and rx channel and set it in EMAC hw */
        memcpy(priv->mac_addr, sa->sa_data, ndev->addr_len);
-       memcpy(rxch->mac_addr, sa->sa_data, ndev->addr_len);
        memcpy(ndev->dev_addr, sa->sa_data, ndev->addr_len);
-       emac_setmac(priv, EMAC_DEF_RX_CH, rxch->mac_addr);
+
+       /* If the interface is down - rxch is NULL. */
+       /* MAC address is configured only after the interface is enabled. */
+       if (netif_running(ndev)) {
+               memcpy(rxch->mac_addr, sa->sa_data, ndev->addr_len);
+               emac_setmac(priv, EMAC_DEF_RX_CH, rxch->mac_addr);
+       }
 
        if (netif_msg_drv(priv))
                dev_notice(emac_dev, "DaVinci EMAC: emac_dev_setmac_addr %pM\n",
index 895d72143ee049757c3750ae096cad3c8387c02a..4b6a219fecea8b44be1f192db3b1352b28bc5702 100644 (file)
@@ -268,8 +268,9 @@ rio_probe1 (struct pci_dev *pdev, const struct pci_device_id *ent)
                printk(KERN_INFO "tx_coalesce:\t%d packets\n",
                                tx_coalesce);
        if (np->coalesce)
-               printk(KERN_INFO "rx_coalesce:\t%d packets\n"
-                      KERN_INFO "rx_timeout: \t%d ns\n",
+               printk(KERN_INFO
+                      "rx_coalesce:\t%d packets\n"
+                      "rx_timeout: \t%d ns\n",
                                np->rx_coalesce, np->rx_timeout*640);
        if (np->vlan)
                printk(KERN_INFO "vlan(id):\t%d\n", np->vlan);
@@ -1522,9 +1523,9 @@ mii_get_media (struct net_device *dev)
                        printk (KERN_INFO "Operating at 10 Mbps, ");
                }
                if (bmcr & MII_BMCR_DUPLEX_MODE) {
-                       printk ("Full duplex\n");
+                       printk (KERN_CONT "Full duplex\n");
                } else {
-                       printk ("Half duplex\n");
+                       printk (KERN_CONT "Half duplex\n");
                }
        }
        if (np->tx_flow)
@@ -1614,9 +1615,9 @@ mii_set_media (struct net_device *dev)
                }
                if (np->full_duplex) {
                        bmcr |= MII_BMCR_DUPLEX_MODE;
-                       printk ("Full duplex\n");
+                       printk (KERN_CONT "Full duplex\n");
                } else {
-                       printk ("Half duplex\n");
+                       printk (KERN_CONT "Half duplex\n");
                }
 #if 0
                /* Set 1000BaseT Master/Slave setting */
@@ -1669,9 +1670,9 @@ mii_get_media_pcs (struct net_device *dev)
                __u16 bmcr = mii_read (dev, phy_addr, PCS_BMCR);
                printk (KERN_INFO "Operating at 1000 Mbps, ");
                if (bmcr & MII_BMCR_DUPLEX_MODE) {
-                       printk ("Full duplex\n");
+                       printk (KERN_CONT "Full duplex\n");
                } else {
-                       printk ("Half duplex\n");
+                       printk (KERN_CONT "Half duplex\n");
                }
        }
        if (np->tx_flow)
index 5e3356f8eb5af5ae1611af238f40fcdaff6c0f94..5b8cbdb4b5201fa71223bd409b5d2ddf5e8f6287 100644 (file)
@@ -2185,12 +2185,16 @@ static void e1000_clean_rx_ring(struct e1000_adapter *adapter,
        /* Free all the Rx ring sk_buffs */
        for (i = 0; i < rx_ring->count; i++) {
                buffer_info = &rx_ring->buffer_info[i];
-               if (buffer_info->skb) {
+               if (buffer_info->dma) {
                        pci_unmap_single(pdev,
                                         buffer_info->dma,
                                         buffer_info->length,
                                         PCI_DMA_FROMDEVICE);
+               }
+
+               buffer_info->dma = 0;
 
+               if (buffer_info->skb) {
                        dev_kfree_skb(buffer_info->skb);
                        buffer_info->skb = NULL;
                }
@@ -4033,6 +4037,7 @@ static bool e1000_clean_rx_irq(struct e1000_adapter *adapter,
                                 buffer_info->dma,
                                 buffer_info->length,
                                 PCI_DMA_FROMDEVICE);
+               buffer_info->dma = 0;
 
                length = le16_to_cpu(rx_desc->length);
                /* !EOP means multiple descriptors were used to store a single
@@ -4222,6 +4227,7 @@ map_skb:
                        pci_unmap_single(pdev, buffer_info->dma,
                                         adapter->rx_buffer_len,
                                         PCI_DMA_FROMDEVICE);
+                       buffer_info->dma = 0;
 
                        break; /* while !buffer_info->skb */
                }
@@ -4817,6 +4823,9 @@ static pci_ers_result_t e1000_io_error_detected(struct pci_dev *pdev,
 
        netif_device_detach(netdev);
 
+       if (state == pci_channel_io_perm_failure)
+               return PCI_ERS_RESULT_DISCONNECT;
+
        if (netif_running(netdev))
                e1000_down(adapter);
        pci_disable_device(pdev);
index 8890c97e1120436cc68c3b930a8bf78e9cb24369..c0f185beb8bc1a7cdd1dd04393f5635470b7473c 100644 (file)
 #define E1000_STATUS_SPEED_100  0x00000040      /* Speed 100Mb/s */
 #define E1000_STATUS_SPEED_1000 0x00000080      /* Speed 1000Mb/s */
 #define E1000_STATUS_LAN_INIT_DONE 0x00000200   /* Lan Init Completion by NVM */
+#define E1000_STATUS_PHYRA      0x00000400      /* PHY Reset Asserted */
 #define E1000_STATUS_GIO_MASTER_ENABLE 0x00080000 /* Status of Master requests. */
 
 /* Constants used to interpret the masked PCI-X bus speed. */
 #define PHY_1000T_STATUS 0x0A /* 1000Base-T Status Reg */
 #define PHY_EXT_STATUS   0x0F /* Extended Status Reg */
 
+#define PHY_CONTROL_LB   0x4000 /* PHY Loopback bit */
+
 /* NVM Control */
 #define E1000_EECD_SK        0x00000001 /* NVM Clock */
 #define E1000_EECD_CS        0x00000002 /* NVM Chip Select */
index 163c1c0cfee7004b7fdcf7935300aacb3431b049..fd44d9f907696aff5ee2fdb6558d79feaf0b27e7 100644 (file)
@@ -215,6 +215,7 @@ enum e1e_registers {
        E1000_SWSM      = 0x05B50, /* SW Semaphore */
        E1000_FWSM      = 0x05B54, /* FW Semaphore */
        E1000_SWSM2     = 0x05B58, /* Driver-only SW semaphore */
+       E1000_CRC_OFFSET = 0x05F50, /* CRC Offset register */
        E1000_HICR      = 0x08F00, /* Host Interface Control */
 };
 
@@ -302,6 +303,9 @@ enum e1e_registers {
 #define E1000_KMRNCTRLSTA_REN          0x00200000
 #define E1000_KMRNCTRLSTA_DIAG_OFFSET  0x3    /* Kumeran Diagnostic */
 #define E1000_KMRNCTRLSTA_DIAG_NELPBK  0x1000 /* Nearend Loopback mode */
+#define E1000_KMRNCTRLSTA_K1_CONFIG    0x7
+#define E1000_KMRNCTRLSTA_K1_ENABLE    0x140E
+#define E1000_KMRNCTRLSTA_K1_DISABLE   0x1400
 
 #define IFE_PHY_EXTENDED_STATUS_CONTROL        0x10
 #define IFE_PHY_SPECIAL_CONTROL                0x11 /* 100BaseTx PHY Special Control */
index 9e23f50fb9cdfa32be3428fbc540e3312d16018e..d56c7473144a6cd974a253b16033ad447081b3f9 100644 (file)
@@ -338,6 +338,7 @@ static s32 e1000_init_nvm_params_ich8lan(struct e1000_hw *hw)
 {
        struct e1000_nvm_info *nvm = &hw->nvm;
        struct e1000_dev_spec_ich8lan *dev_spec = &hw->dev_spec.ich8lan;
+       union ich8_hws_flash_status hsfsts;
        u32 gfpreg;
        u32 sector_base_addr;
        u32 sector_end_addr;
@@ -374,6 +375,20 @@ static s32 e1000_init_nvm_params_ich8lan(struct e1000_hw *hw)
        /* Adjust to word count */
        nvm->flash_bank_size /= sizeof(u16);
 
+       /*
+        * Make sure the flash bank size does not overwrite the 4k
+        * sector ranges. We may have 64k allotted to us but we only care
+        * about the first 2 4k sectors. Therefore, if we have anything less
+        * than 64k set in the HSFSTS register, we will reduce the bank size
+        * down to 4k and let the rest remain unused. If berasesz == 3, then
+        * we are working in 64k mode. Otherwise we are not.
+        */
+       if (nvm->flash_bank_size > E1000_ICH8_SHADOW_RAM_WORDS) {
+               hsfsts.regval = er16flash(ICH_FLASH_HSFSTS);
+               if (hsfsts.hsf_status.berasesz != 3)
+                       nvm->flash_bank_size = E1000_ICH8_SHADOW_RAM_WORDS;
+       }
+
        nvm->word_size = E1000_ICH8_SHADOW_RAM_WORDS;
 
        /* Clear shadow ram */
@@ -446,6 +461,95 @@ static s32 e1000_init_mac_params_ich8lan(struct e1000_adapter *adapter)
        return 0;
 }
 
+/**
+ *  e1000_check_for_copper_link_ich8lan - Check for link (Copper)
+ *  @hw: pointer to the HW structure
+ *
+ *  Checks to see of the link status of the hardware has changed.  If a
+ *  change in link status has been detected, then we read the PHY registers
+ *  to get the current speed/duplex if link exists.
+ **/
+static s32 e1000_check_for_copper_link_ich8lan(struct e1000_hw *hw)
+{
+       struct e1000_mac_info *mac = &hw->mac;
+       s32 ret_val;
+       bool link;
+
+       /*
+        * We only want to go out to the PHY registers to see if Auto-Neg
+        * has completed and/or if our link status has changed.  The
+        * get_link_status flag is set upon receiving a Link Status
+        * Change or Rx Sequence Error interrupt.
+        */
+       if (!mac->get_link_status) {
+               ret_val = 0;
+               goto out;
+       }
+
+       if (hw->mac.type == e1000_pchlan) {
+               ret_val = e1000e_write_kmrn_reg(hw,
+                                                  E1000_KMRNCTRLSTA_K1_CONFIG,
+                                                  E1000_KMRNCTRLSTA_K1_ENABLE);
+               if (ret_val)
+                       goto out;
+       }
+
+       /*
+        * First we want to see if the MII Status Register reports
+        * link.  If so, then we want to get the current speed/duplex
+        * of the PHY.
+        */
+       ret_val = e1000e_phy_has_link_generic(hw, 1, 0, &link);
+       if (ret_val)
+               goto out;
+
+       if (!link)
+               goto out; /* No link detected */
+
+       mac->get_link_status = false;
+
+       if (hw->phy.type == e1000_phy_82578) {
+               ret_val = e1000_link_stall_workaround_hv(hw);
+               if (ret_val)
+                       goto out;
+       }
+
+       /*
+        * Check if there was DownShift, must be checked
+        * immediately after link-up
+        */
+       e1000e_check_downshift(hw);
+
+       /*
+        * If we are forcing speed/duplex, then we simply return since
+        * we have already determined whether we have link or not.
+        */
+       if (!mac->autoneg) {
+               ret_val = -E1000_ERR_CONFIG;
+               goto out;
+       }
+
+       /*
+        * Auto-Neg is enabled.  Auto Speed Detection takes care
+        * of MAC speed/duplex configuration.  So we only need to
+        * configure Collision Distance in the MAC.
+        */
+       e1000e_config_collision_dist(hw);
+
+       /*
+        * Configure Flow Control now that Auto-Neg has completed.
+        * First, we need to restore the desired flow control
+        * settings because we may have had to re-autoneg with a
+        * different link partner.
+        */
+       ret_val = e1000e_config_fc_after_link_up(hw);
+       if (ret_val)
+               hw_dbg(hw, "Error configuring flow control\n");
+
+out:
+       return ret_val;
+}
+
 static s32 e1000_get_variants_ich8lan(struct e1000_adapter *adapter)
 {
        struct e1000_hw *hw = &adapter->hw;
@@ -693,6 +797,38 @@ static s32 e1000_hv_phy_workarounds_ich8lan(struct e1000_hw *hw)
        return ret_val;
 }
 
+/**
+ *  e1000_lan_init_done_ich8lan - Check for PHY config completion
+ *  @hw: pointer to the HW structure
+ *
+ *  Check the appropriate indication the MAC has finished configuring the
+ *  PHY after a software reset.
+ **/
+static void e1000_lan_init_done_ich8lan(struct e1000_hw *hw)
+{
+       u32 data, loop = E1000_ICH8_LAN_INIT_TIMEOUT;
+
+       /* Wait for basic configuration completes before proceeding */
+       do {
+               data = er32(STATUS);
+               data &= E1000_STATUS_LAN_INIT_DONE;
+               udelay(100);
+       } while ((!data) && --loop);
+
+       /*
+        * If basic configuration is incomplete before the above loop
+        * count reaches 0, loading the configuration from NVM will
+        * leave the PHY in a bad state possibly resulting in no link.
+        */
+       if (loop == 0)
+               hw_dbg(hw, "LAN_INIT_DONE not set, increase timeout\n");
+
+       /* Clear the Init Done bit for the next init event */
+       data = er32(STATUS);
+       data &= ~E1000_STATUS_LAN_INIT_DONE;
+       ew32(STATUS, data);
+}
+
 /**
  *  e1000_phy_hw_reset_ich8lan - Performs a PHY reset
  *  @hw: pointer to the HW structure
@@ -707,13 +843,15 @@ static s32 e1000_phy_hw_reset_ich8lan(struct e1000_hw *hw)
        u32 i;
        u32 data, cnf_size, cnf_base_addr, sw_cfg_mask;
        s32 ret_val;
-       u16 loop = E1000_ICH8_LAN_INIT_TIMEOUT;
        u16 word_addr, reg_data, reg_addr, phy_page = 0;
 
        ret_val = e1000e_phy_hw_reset_generic(hw);
        if (ret_val)
                return ret_val;
 
+       /* Allow time for h/w to get to a quiescent state after reset */
+       mdelay(10);
+
        if (hw->mac.type == e1000_pchlan) {
                ret_val = e1000_hv_phy_workarounds_ich8lan(hw);
                if (ret_val)
@@ -741,26 +879,8 @@ static s32 e1000_phy_hw_reset_ich8lan(struct e1000_hw *hw)
                if (!(data & sw_cfg_mask))
                        return 0;
 
-               /* Wait for basic configuration completes before proceeding*/
-               do {
-                       data = er32(STATUS);
-                       data &= E1000_STATUS_LAN_INIT_DONE;
-                       udelay(100);
-               } while ((!data) && --loop);
-
-               /*
-                * If basic configuration is incomplete before the above loop
-                * count reaches 0, loading the configuration from NVM will
-                * leave the PHY in a bad state possibly resulting in no link.
-                */
-               if (loop == 0) {
-                       hw_dbg(hw, "LAN_INIT_DONE not set, increase timeout\n");
-               }
-
-               /* Clear the Init Done bit for the next init event */
-               data = er32(STATUS);
-               data &= ~E1000_STATUS_LAN_INIT_DONE;
-               ew32(STATUS, data);
+               /* Wait for basic configuration completes before proceeding */
+               e1000_lan_init_done_ich8lan(hw);
 
                /*
                 * Make sure HW does not configure LCD from PHY
@@ -961,12 +1081,14 @@ static s32 e1000_set_d0_lplu_state_ich8lan(struct e1000_hw *hw, bool active)
                phy_ctrl |= E1000_PHY_CTRL_D0A_LPLU;
                ew32(PHY_CTRL, phy_ctrl);
 
+               if (phy->type != e1000_phy_igp_3)
+                       return 0;
+
                /*
                 * Call gig speed drop workaround on LPLU before accessing
                 * any PHY registers
                 */
-               if ((hw->mac.type == e1000_ich8lan) &&
-                   (hw->phy.type == e1000_phy_igp_3))
+               if (hw->mac.type == e1000_ich8lan)
                        e1000e_gig_downshift_workaround_ich8lan(hw);
 
                /* When LPLU is enabled, we should disable SmartSpeed */
@@ -979,6 +1101,9 @@ static s32 e1000_set_d0_lplu_state_ich8lan(struct e1000_hw *hw, bool active)
                phy_ctrl &= ~E1000_PHY_CTRL_D0A_LPLU;
                ew32(PHY_CTRL, phy_ctrl);
 
+               if (phy->type != e1000_phy_igp_3)
+                       return 0;
+
                /*
                 * LPLU and SmartSpeed are mutually exclusive.  LPLU is used
                 * during Dx states where the power conservation is most
@@ -1038,6 +1163,10 @@ static s32 e1000_set_d3_lplu_state_ich8lan(struct e1000_hw *hw, bool active)
        if (!active) {
                phy_ctrl &= ~E1000_PHY_CTRL_NOND0A_LPLU;
                ew32(PHY_CTRL, phy_ctrl);
+
+               if (phy->type != e1000_phy_igp_3)
+                       return 0;
+
                /*
                 * LPLU and SmartSpeed are mutually exclusive.  LPLU is used
                 * during Dx states where the power conservation is most
@@ -1073,12 +1202,14 @@ static s32 e1000_set_d3_lplu_state_ich8lan(struct e1000_hw *hw, bool active)
                phy_ctrl |= E1000_PHY_CTRL_NOND0A_LPLU;
                ew32(PHY_CTRL, phy_ctrl);
 
+               if (phy->type != e1000_phy_igp_3)
+                       return 0;
+
                /*
                 * Call gig speed drop workaround on LPLU before accessing
                 * any PHY registers
                 */
-               if ((hw->mac.type == e1000_ich8lan) &&
-                   (hw->phy.type == e1000_phy_igp_3))
+               if (hw->mac.type == e1000_ich8lan)
                        e1000e_gig_downshift_workaround_ich8lan(hw);
 
                /* When LPLU is enabled, we should disable SmartSpeed */
@@ -1905,7 +2036,7 @@ static s32 e1000_erase_flash_bank_ich8lan(struct e1000_hw *hw, u32 bank)
                break;
        case 1:
                sector_size = ICH_FLASH_SEG_SIZE_4K;
-               iteration = flash_bank_size / ICH_FLASH_SEG_SIZE_4K;
+               iteration = 1;
                break;
        case 2:
                if (hw->mac.type == e1000_ich9lan) {
@@ -1917,7 +2048,7 @@ static s32 e1000_erase_flash_bank_ich8lan(struct e1000_hw *hw, u32 bank)
                break;
        case 3:
                sector_size = ICH_FLASH_SEG_SIZE_64K;
-               iteration = flash_bank_size / ICH_FLASH_SEG_SIZE_64K;
+               iteration = 1;
                break;
        default:
                return -E1000_ERR_NVM;
@@ -2143,6 +2274,12 @@ static s32 e1000_reset_hw_ich8lan(struct e1000_hw *hw)
        ctrl = er32(CTRL);
 
        if (!e1000_check_reset_block(hw)) {
+               /* Clear PHY Reset Asserted bit */
+               if (hw->mac.type >= e1000_pchlan) {
+                       u32 status = er32(STATUS);
+                       ew32(STATUS, status & ~E1000_STATUS_PHYRA);
+               }
+
                /*
                 * PHY HW reset requires MAC CORE reset at the same
                 * time to make sure the interface between MAC and the
@@ -2156,23 +2293,34 @@ static s32 e1000_reset_hw_ich8lan(struct e1000_hw *hw)
        ew32(CTRL, (ctrl | E1000_CTRL_RST));
        msleep(20);
 
-       if (!ret_val) {
-               /* release the swflag because it is not reset by
-                * hardware reset
-                */
+       if (!ret_val)
                e1000_release_swflag_ich8lan(hw);
-       }
 
-       ret_val = e1000e_get_auto_rd_done(hw);
-       if (ret_val) {
-               /*
-                * When auto config read does not complete, do not
-                * return with an error. This can happen in situations
-                * where there is no eeprom and prevents getting link.
-                */
-               hw_dbg(hw, "Auto Read Done did not complete\n");
+       if (ctrl & E1000_CTRL_PHY_RST)
+               ret_val = hw->phy.ops.get_cfg_done(hw);
+
+       if (hw->mac.type >= e1000_ich10lan) {
+               e1000_lan_init_done_ich8lan(hw);
+       } else {
+               ret_val = e1000e_get_auto_rd_done(hw);
+               if (ret_val) {
+                       /*
+                        * When auto config read does not complete, do not
+                        * return with an error. This can happen in situations
+                        * where there is no eeprom and prevents getting link.
+                        */
+                       hw_dbg(hw, "Auto Read Done did not complete\n");
+               }
        }
 
+       /*
+        * For PCH, this write will make sure that any noise
+        * will be detected as a CRC error and be dropped rather than show up
+        * as a bad packet to the DMA engine.
+        */
+       if (hw->mac.type == e1000_pchlan)
+               ew32(CRC_OFFSET, 0x65656565);
+
        ew32(IMC, 0xffffffff);
        icr = er32(ICR);
 
@@ -2222,6 +2370,18 @@ static s32 e1000_init_hw_ich8lan(struct e1000_hw *hw)
        for (i = 0; i < mac->mta_reg_count; i++)
                E1000_WRITE_REG_ARRAY(hw, E1000_MTA, i, 0);
 
+       /*
+        * The 82578 Rx buffer will stall if wakeup is enabled in host and
+        * the ME.  Reading the BM_WUC register will clear the host wakeup bit.
+        * Reset the phy after disabling host wakeup to reset the Rx buffer.
+        */
+       if (hw->phy.type == e1000_phy_82578) {
+               hw->phy.ops.read_phy_reg(hw, BM_WUC, &i);
+               ret_val = e1000_phy_hw_reset_ich8lan(hw);
+               if (ret_val)
+                       return ret_val;
+       }
+
        /* Setup link and flow control */
        ret_val = e1000_setup_link_ich8lan(hw);
 
@@ -2253,16 +2413,6 @@ static s32 e1000_init_hw_ich8lan(struct e1000_hw *hw)
        ctrl_ext |= E1000_CTRL_EXT_RO_DIS;
        ew32(CTRL_EXT, ctrl_ext);
 
-       /*
-        * The 82578 Rx buffer will stall if wakeup is enabled in host and
-        * the ME.  Reading the BM_WUC register will clear the host wakeup bit.
-        * Reset the phy after disabling host wakeup to reset the Rx buffer.
-        */
-       if (hw->phy.type == e1000_phy_82578) {
-               e1e_rphy(hw, BM_WUC, &i);
-               e1000e_phy_hw_reset_generic(hw);
-       }
-
        /*
         * Clear all of the statistics registers (clear on read).  It is
         * important that we do this after we have tried to establish link
@@ -2485,6 +2635,14 @@ static s32 e1000_get_link_up_info_ich8lan(struct e1000_hw *hw, u16 *speed,
        if (ret_val)
                return ret_val;
 
+       if ((hw->mac.type == e1000_pchlan) && (*speed == SPEED_1000)) {
+               ret_val = e1000e_write_kmrn_reg(hw,
+                                                 E1000_KMRNCTRLSTA_K1_CONFIG,
+                                                 E1000_KMRNCTRLSTA_K1_DISABLE);
+               if (ret_val)
+                       return ret_val;
+       }
+
        if ((hw->mac.type == e1000_ich8lan) &&
            (hw->phy.type == e1000_phy_igp_3) &&
            (*speed == SPEED_1000)) {
@@ -2850,6 +3008,16 @@ static s32 e1000_get_cfg_done_ich8lan(struct e1000_hw *hw)
 {
        u32 bank = 0;
 
+       if (hw->mac.type >= e1000_pchlan) {
+               u32 status = er32(STATUS);
+
+               if (status & E1000_STATUS_PHYRA)
+                       ew32(STATUS, status & ~E1000_STATUS_PHYRA);
+               else
+                       hw_dbg(hw,
+                              "PHY Reset Asserted not set - needs delay\n");
+       }
+
        e1000e_get_cfg_done(hw);
 
        /* If EEPROM is not marked present, init the IGP 3 PHY manually */
@@ -2921,7 +3089,7 @@ static void e1000_clear_hw_cntrs_ich8lan(struct e1000_hw *hw)
 static struct e1000_mac_operations ich8_mac_ops = {
        .id_led_init            = e1000e_id_led_init,
        .check_mng_mode         = e1000_check_mng_mode_ich8lan,
-       .check_for_link         = e1000e_check_for_copper_link,
+       .check_for_link         = e1000_check_for_copper_link_ich8lan,
        /* cleanup_led dependent on mac type */
        .clear_hw_cntrs         = e1000_clear_hw_cntrs_ich8lan,
        .get_bus_info           = e1000_get_bus_info_ich8lan,
index be6d9e9903741650ff5fe83ff1797d112a4c53ce..99ba2b8a2a054b5b7cc2a2200ab3520bff113d06 100644 (file)
@@ -378,12 +378,6 @@ s32 e1000e_check_for_copper_link(struct e1000_hw *hw)
 
        mac->get_link_status = 0;
 
-       if (hw->phy.type == e1000_phy_82578) {
-               ret_val = e1000_link_stall_workaround_hv(hw);
-               if (ret_val)
-                       return ret_val;
-       }
-
        /*
         * Check if there was DownShift, must be checked
         * immediately after link-up
index 679885a122b4da068878a4bcd471c45ecd4e905a..63415bb6f48ff02f3e2e67ec45fef854fc1b9f39 100644 (file)
@@ -4785,6 +4785,9 @@ static pci_ers_result_t e1000_io_error_detected(struct pci_dev *pdev,
 
        netif_device_detach(netdev);
 
+       if (state == pci_channel_io_perm_failure)
+               return PCI_ERS_RESULT_DISCONNECT;
+
        if (netif_running(netdev))
                e1000e_down(adapter);
        pci_disable_device(pdev);
index e23459cf3d0eecbc64329d40db9de98aa19c7634..994401fd0664fbc188980ea188e33bdf95fdb0ec 100644 (file)
@@ -1531,7 +1531,12 @@ s32 e1000e_phy_has_link_generic(struct e1000_hw *hw, u32 iterations,
                 */
                ret_val = e1e_rphy(hw, PHY_STATUS, &phy_status);
                if (ret_val)
-                       break;
+                       /*
+                        * If the first read fails, another entity may have
+                        * ownership of the resources, wait and try again to
+                        * see if they have relinquished the resources yet.
+                        */
+                       udelay(usec_interval);
                ret_val = e1e_rphy(hw, PHY_STATUS, &phy_status);
                if (ret_val)
                        break;
@@ -2737,6 +2742,11 @@ s32 e1000_link_stall_workaround_hv(struct e1000_hw *hw)
        if (hw->phy.type != e1000_phy_82578)
                goto out;
 
+       /* Do not apply workaround if in PHY loopback bit 14 set */
+       hw->phy.ops.read_phy_reg(hw, PHY_CONTROL, &data);
+       if (data & PHY_CONTROL_LB)
+               goto out;
+
        /* check if link is up and at 1Gbps */
        ret_val = hw->phy.ops.read_phy_reg(hw, BM_CS_STATUS, &data);
        if (ret_val)
index 147c4b088fb3c3467fa3b9027aa887067ccf8114..e8d46cc1bec2525ac014a727f7743dd77c108848 100644 (file)
@@ -3080,7 +3080,9 @@ static const struct net_device_ops ehea_netdev_ops = {
        .ndo_poll_controller    = ehea_netpoll,
 #endif
        .ndo_get_stats          = ehea_get_stats,
+       .ndo_change_mtu         = eth_change_mtu,
        .ndo_set_mac_address    = ehea_set_mac_addr,
+       .ndo_validate_addr      = eth_validate_addr,
        .ndo_set_multicast_list = ehea_set_multicast_list,
        .ndo_change_mtu         = ehea_change_mtu,
        .ndo_vlan_rx_register   = ehea_vlan_rx_register,
index b60e27dfcfa7c24a3c576ca1f5713e30befb4d60..88d7ebf31220c701f7f8e09ca551fbdc0f121e79 100644 (file)
@@ -338,8 +338,7 @@ static int __devinit epic_init_one (struct pci_dev *pdev,
 #ifndef MODULE
        static int printed_version;
        if (!printed_version++)
-               printk (KERN_INFO "%s" KERN_INFO "%s",
-                       version, version2);
+               printk(KERN_INFO "%s%s", version, version2);
 #endif
 
        card_idx++;
@@ -1600,7 +1599,7 @@ static int __init epic_init (void)
 {
 /* when a module, this is printed whether or not devices are found in probe */
 #ifdef MODULE
-       printk (KERN_INFO "%s" KERN_INFO "%s",
+       printk (KERN_INFO "%s%s",
                version, version2);
 #endif
 
index 891be28a7d4f43625ad5072c77b372e854564a01..48385c42ab5742bf982190cefa980a5870d7da4f 100644 (file)
@@ -1209,17 +1209,20 @@ static void fealnx_tx_timeout(struct net_device *dev)
        unsigned long flags;
        int i;
 
-       printk(KERN_WARNING "%s: Transmit timed out, status %8.8x,"
-              " resetting...\n", dev->name, ioread32(ioaddr + ISR));
+       printk(KERN_WARNING
+              "%s: Transmit timed out, status %8.8x, resetting...\n",
+              dev->name, ioread32(ioaddr + ISR));
 
        {
                printk(KERN_DEBUG "  Rx ring %p: ", np->rx_ring);
                for (i = 0; i < RX_RING_SIZE; i++)
-                       printk(" %8.8x", (unsigned int) np->rx_ring[i].status);
-               printk("\n" KERN_DEBUG "  Tx ring %p: ", np->tx_ring);
+                       printk(KERN_CONT " %8.8x",
+                              (unsigned int) np->rx_ring[i].status);
+               printk(KERN_CONT "\n");
+               printk(KERN_DEBUG "  Tx ring %p: ", np->tx_ring);
                for (i = 0; i < TX_RING_SIZE; i++)
-                       printk(" %4.4x", np->tx_ring[i].status);
-               printk("\n");
+                       printk(KERN_CONT " %4.4x", np->tx_ring[i].status);
+               printk(KERN_CONT "\n");
        }
 
        spin_lock_irqsave(&np->lock, flags);
index 0f19b743749bdf8b52783793276c36a247f3f928..d4b98074b1b787e481c3d13f6dd351494245ac11 100644 (file)
@@ -1642,6 +1642,7 @@ static const struct net_device_ops fec_netdev_ops = {
        .ndo_stop               = fec_enet_close,
        .ndo_start_xmit         = fec_enet_start_xmit,
        .ndo_set_multicast_list = set_multicast_list,
+       .ndo_change_mtu         = eth_change_mtu,
        .ndo_validate_addr      = eth_validate_addr,
        .ndo_tx_timeout         = fec_timeout,
        .ndo_set_mac_address    = fec_set_mac_address,
index 30b7dd671336b45434bdefff08c137da3ee8bf9a..cc47f3f057c7464b2f5096e7810bad46c9362cf7 100644 (file)
 
 #else
 
-#define FEC_ECNTRL;            0x000 /* Ethernet control reg */
-#define FEC_IEVENT;            0x004 /* Interrupt even reg */
-#define FEC_IMASK;             0x008 /* Interrupt mask reg */
-#define FEC_IVEC;              0x00c /* Interrupt vec status reg */
-#define FEC_R_DES_ACTIVE;      0x010 /* Receive descriptor reg */
-#define FEC_X_DES_ACTIVE;      0x01c /* Transmit descriptor reg */
+#define FEC_ECNTRL             0x000 /* Ethernet control reg */
+#define FEC_IEVENT             0x004 /* Interrupt even reg */
+#define FEC_IMASK              0x008 /* Interrupt mask reg */
+#define FEC_IVEC               0x00c /* Interrupt vec status reg */
+#define FEC_R_DES_ACTIVE       0x010 /* Receive descriptor reg */
+#define FEC_X_DES_ACTIVE       0x014 /* Transmit descriptor reg */
 #define FEC_MII_DATA           0x040 /* MII manage frame reg */
 #define FEC_MII_SPEED          0x044 /* MII speed control reg */
 #define FEC_R_BOUND            0x08c /* FIFO receive bound reg */
index 1094d292630f758039802b2b23387a320250a5f1..3b4e0766c7b2a614be5c0451bb925e789c980bf3 100644 (file)
@@ -3514,11 +3514,13 @@ static irqreturn_t nv_nic_irq(int foo, void *data)
        nv_msi_workaround(np);
 
 #ifdef CONFIG_FORCEDETH_NAPI
-       napi_schedule(&np->napi);
-
-       /* Disable furthur irq's
-          (msix not enabled with napi) */
-       writel(0, base + NvRegIrqMask);
+       if (napi_schedule_prep(&np->napi)) {
+               /*
+                * Disable further irq's (msix not enabled with napi)
+                */
+               writel(0, base + NvRegIrqMask);
+               __napi_schedule(&np->napi);
+       }
 
 #else
        do
@@ -3615,12 +3617,13 @@ static irqreturn_t nv_nic_irq_optimized(int foo, void *data)
        nv_msi_workaround(np);
 
 #ifdef CONFIG_FORCEDETH_NAPI
-       napi_schedule(&np->napi);
-
-       /* Disable furthur irq's
-          (msix not enabled with napi) */
-       writel(0, base + NvRegIrqMask);
-
+       if (napi_schedule_prep(&np->napi)) {
+               /*
+                * Disable further irq's (msix not enabled with napi)
+                */
+               writel(0, base + NvRegIrqMask);
+               __napi_schedule(&np->napi);
+       }
 #else
        do
        {
index 3af581303ca2b79577d18d0df4d6c64b6d341152..d167090248e2f31d6ba7211e447e3bd68dc43da6 100644 (file)
@@ -188,7 +188,7 @@ static int fsl_pq_mdio_find_free(struct mii_bus *new_bus)
 }
 
 
-#ifdef CONFIG_GIANFAR
+#if defined(CONFIG_GIANFAR) || defined(CONFIG_GIANFAR_MODULE)
 static u32 __iomem *get_gfar_tbipa(struct fsl_pq_mdio __iomem *regs)
 {
        struct gfar __iomem *enet_regs;
@@ -206,7 +206,7 @@ static u32 __iomem *get_gfar_tbipa(struct fsl_pq_mdio __iomem *regs)
 #endif
 
 
-#ifdef CONFIG_UCC_GETH
+#if defined(CONFIG_UCC_GETH) || defined(CONFIG_UCC_GETH_MODULE)
 static int get_ucc_id_for_range(u64 start, u64 end, u32 *ucc_id)
 {
        struct device_node *np = NULL;
@@ -291,7 +291,7 @@ static int fsl_pq_mdio_probe(struct of_device *ofdev,
        if (of_device_is_compatible(np, "fsl,gianfar-mdio") ||
                        of_device_is_compatible(np, "fsl,gianfar-tbi") ||
                        of_device_is_compatible(np, "gianfar")) {
-#ifdef CONFIG_GIANFAR
+#if defined(CONFIG_GIANFAR) || defined(CONFIG_GIANFAR_MODULE)
                tbipa = get_gfar_tbipa(regs);
 #else
                err = -ENODEV;
@@ -299,7 +299,7 @@ static int fsl_pq_mdio_probe(struct of_device *ofdev,
 #endif
        } else if (of_device_is_compatible(np, "fsl,ucc-mdio") ||
                        of_device_is_compatible(np, "ucc_geth_phy")) {
-#ifdef CONFIG_UCC_GETH
+#if defined(CONFIG_UCC_GETH) || defined(CONFIG_UCC_GETH_MODULE)
                u32 id;
                static u32 mii_mng_master;
 
index 4ae1d259fced7d6525a6818a1c641db5d1cf3850..43d813ed9f45f17af2ed57cf2d61c6d2fafddd6a 100644 (file)
@@ -156,6 +156,8 @@ static const struct net_device_ops gfar_netdev_ops = {
        .ndo_tx_timeout = gfar_timeout,
        .ndo_do_ioctl = gfar_ioctl,
        .ndo_vlan_rx_register = gfar_vlan_rx_register,
+       .ndo_set_mac_address = eth_mac_addr,
+       .ndo_validate_addr = eth_validate_addr,
 #ifdef CONFIG_NET_POLL_CONTROLLER
        .ndo_poll_controller = gfar_netpoll,
 #endif
index 9d5b62cb30f790de7f198b4d67e7e619b82d7878..d62378cbc149ee6bb502953da22515689d737f6b 100644 (file)
@@ -173,8 +173,8 @@ static int tx_params[MAX_UNITS] = {-1, -1, -1, -1, -1, -1, -1, -1};
 
 static const char version[] __devinitconst =
 KERN_INFO DRV_NAME ".c:v" DRV_VERSION " " DRV_RELDATE "  Written by Donald Becker\n"
-KERN_INFO "   Some modifications by Eric kasten <kasten@nscl.msu.edu>\n"
-KERN_INFO "   Further modifications by Keith Underwood <keithu@parl.clemson.edu>\n";
+"   Some modifications by Eric kasten <kasten@nscl.msu.edu>\n"
+"   Further modifications by Keith Underwood <keithu@parl.clemson.edu>\n";
 
 
 /* IP_MF appears to be only defined in <netinet/ip.h>, however,
@@ -1080,11 +1080,14 @@ static void hamachi_tx_timeout(struct net_device *dev)
        {
                printk(KERN_DEBUG "  Rx ring %p: ", hmp->rx_ring);
                for (i = 0; i < RX_RING_SIZE; i++)
-                       printk(" %8.8x", le32_to_cpu(hmp->rx_ring[i].status_n_length));
-               printk("\n"KERN_DEBUG"  Tx ring %p: ", hmp->tx_ring);
+                       printk(KERN_CONT " %8.8x",
+                              le32_to_cpu(hmp->rx_ring[i].status_n_length));
+               printk(KERN_CONT "\n");
+               printk(KERN_DEBUG"  Tx ring %p: ", hmp->tx_ring);
                for (i = 0; i < TX_RING_SIZE; i++)
-                       printk(" %4.4x", le32_to_cpu(hmp->tx_ring[i].status_n_length));
-               printk("\n");
+                       printk(KERN_CONT " %4.4x",
+                              le32_to_cpu(hmp->tx_ring[i].status_n_length));
+               printk(KERN_CONT "\n");
        }
 
        /* Reinit the hardware and make sure the Rx and Tx processes
@@ -1753,13 +1756,13 @@ static int hamachi_close(struct net_device *dev)
 
 #ifdef __i386__
        if (hamachi_debug > 2) {
-               printk("\n"KERN_DEBUG"  Tx ring at %8.8x:\n",
+               printk(KERN_DEBUG "  Tx ring at %8.8x:\n",
                           (int)hmp->tx_ring_dma);
                for (i = 0; i < TX_RING_SIZE; i++)
-                       printk(" %c #%d desc. %8.8x %8.8x.\n",
+                       printk(KERN_DEBUG " %c #%d desc. %8.8x %8.8x.\n",
                                   readl(ioaddr + TxCurPtr) == (long)&hmp->tx_ring[i] ? '>' : ' ',
                                   i, hmp->tx_ring[i].status_n_length, hmp->tx_ring[i].addr);
-               printk("\n"KERN_DEBUG "  Rx ring %8.8x:\n",
+               printk(KERN_DEBUG "  Rx ring %8.8x:\n",
                           (int)hmp->rx_ring_dma);
                for (i = 0; i < RX_RING_SIZE; i++) {
                        printk(KERN_DEBUG " %c #%d desc. %4.4x %8.8x\n",
@@ -1770,7 +1773,7 @@ static int hamachi_close(struct net_device *dev)
                                        u16 *addr = (u16 *)
                                                hmp->rx_skbuff[i]->data;
                                        int j;
-
+                                       printk(KERN_DEBUG "Addr: ");
                                        for (j = 0; j < 0x50; j++)
                                                printk(" %4.4x", addr[j]);
                                        printk("\n");
index 5e4b7afd068395b343f5ad267673eed7090e197a..352703255bba8a8c4efc9dec9454487078686713 100644 (file)
@@ -68,7 +68,7 @@ static const char paranoia_str[] = KERN_ERR
 
 static const char bc_drvname[] = "baycom_epp";
 static const char bc_drvinfo[] = KERN_INFO "baycom_epp: (C) 1998-2000 Thomas Sailer, HB9JNX/AE4WA\n"
-KERN_INFO "baycom_epp: version 0.7 compiled " __TIME__ " " __DATE__ "\n";
+"baycom_epp: version 0.7 compiled " __TIME__ " " __DATE__ "\n";
 
 /* --------------------------------------------------------------------- */
 
index 2e6fc4dc74b12c9ccbb66a5469752b65109484e4..5f5af9a606f8aaddbb4b8724a651db14e5ecee05 100644 (file)
 
 static const char bc_drvname[] = "baycom_par";
 static const char bc_drvinfo[] = KERN_INFO "baycom_par: (C) 1996-2000 Thomas Sailer, HB9JNX/AE4WA\n"
-KERN_INFO "baycom_par: version 0.9 compiled " __TIME__ " " __DATE__ "\n";
+"baycom_par: version 0.9 compiled " __TIME__ " " __DATE__ "\n";
 
 /* --------------------------------------------------------------------- */
 
index b6a816e60c0f74593b5e24d4cdded1115a6cc38b..aa4488e871b24d0497d3fcb92bf1954e01eab29d 100644 (file)
@@ -91,7 +91,7 @@
 
 static const char bc_drvname[] = "baycom_ser_fdx";
 static const char bc_drvinfo[] = KERN_INFO "baycom_ser_fdx: (C) 1996-2000 Thomas Sailer, HB9JNX/AE4WA\n"
-KERN_INFO "baycom_ser_fdx: version 0.10 compiled " __TIME__ " " __DATE__ "\n";
+"baycom_ser_fdx: version 0.10 compiled " __TIME__ " " __DATE__ "\n";
 
 /* --------------------------------------------------------------------- */
 
index 3bcc57acbe6d9515ec49922fd2a529f27a8b2418..88c59359602029440c00c947cb77f3351e23ef54 100644 (file)
@@ -79,7 +79,7 @@
 
 static const char bc_drvname[] = "baycom_ser_hdx";
 static const char bc_drvinfo[] = KERN_INFO "baycom_ser_hdx: (C) 1996-2000 Thomas Sailer, HB9JNX/AE4WA\n"
-KERN_INFO "baycom_ser_hdx: version 0.10 compiled " __TIME__ " " __DATE__ "\n";
+"baycom_ser_hdx: version 0.10 compiled " __TIME__ " " __DATE__ "\n";
 
 /* --------------------------------------------------------------------- */
 
index efd9be214885cbc4c5c5282df7072aee901beff9..ac28dd5a4fd137f7cd522bbcf20fb3338ecffc38 100644 (file)
@@ -190,6 +190,10 @@ static s32 igb_get_invariants_82575(struct e1000_hw *hw)
                phy->ops.write_reg          = igb_write_phy_reg_igp;
        }
 
+       /* set lan id */
+       hw->bus.func = (rd32(E1000_STATUS) & E1000_STATUS_FUNC_MASK) >>
+                      E1000_STATUS_FUNC_SHIFT;
+
        /* Set phy->phy_addr and phy->id. */
        ret_val = igb_get_phy_id_82575(hw);
        if (ret_val)
index ea17319624aa7cc3c2cc51c1ae04044f69e14dba..adb09d32625df3c2b4a565324f17927ed2db033d 100644 (file)
@@ -127,14 +127,48 @@ static void igb_restore_vlan(struct igb_adapter *);
 static void igb_ping_all_vfs(struct igb_adapter *);
 static void igb_msg_task(struct igb_adapter *);
 static int igb_rcv_msg_from_vf(struct igb_adapter *, u32);
-static inline void igb_set_rah_pool(struct e1000_hw *, int , int);
 static void igb_set_mc_list_pools(struct igb_adapter *, int, u16);
 static void igb_vmm_control(struct igb_adapter *);
-static inline void igb_set_vmolr(struct e1000_hw *, int);
-static inline int igb_set_vf_rlpml(struct igb_adapter *, int, int);
 static int igb_set_vf_mac(struct igb_adapter *adapter, int, unsigned char *);
 static void igb_restore_vf_multicasts(struct igb_adapter *adapter);
 
+static inline void igb_set_vmolr(struct e1000_hw *hw, int vfn)
+{
+       u32 reg_data;
+
+       reg_data = rd32(E1000_VMOLR(vfn));
+       reg_data |= E1000_VMOLR_BAM |    /* Accept broadcast */
+                   E1000_VMOLR_ROPE |   /* Accept packets matched in UTA */
+                   E1000_VMOLR_ROMPE |  /* Accept packets matched in MTA */
+                   E1000_VMOLR_AUPE |   /* Accept untagged packets */
+                   E1000_VMOLR_STRVLAN; /* Strip vlan tags */
+       wr32(E1000_VMOLR(vfn), reg_data);
+}
+
+static inline int igb_set_vf_rlpml(struct igb_adapter *adapter, int size,
+                                 int vfn)
+{
+       struct e1000_hw *hw = &adapter->hw;
+       u32 vmolr;
+
+       vmolr = rd32(E1000_VMOLR(vfn));
+       vmolr &= ~E1000_VMOLR_RLPML_MASK;
+       vmolr |= size | E1000_VMOLR_LPE;
+       wr32(E1000_VMOLR(vfn), vmolr);
+
+       return 0;
+}
+
+static inline void igb_set_rah_pool(struct e1000_hw *hw, int pool, int entry)
+{
+       u32 reg_data;
+
+       reg_data = rd32(E1000_RAH(entry));
+       reg_data &= ~E1000_RAH_POOL_MASK;
+       reg_data |= E1000_RAH_POOL_1 << pool;;
+       wr32(E1000_RAH(entry), reg_data);
+}
+
 #ifdef CONFIG_PM
 static int igb_suspend(struct pci_dev *, pm_message_t);
 static int igb_resume(struct pci_dev *);
@@ -4549,11 +4583,12 @@ static bool igb_clean_rx_irq_adv(struct igb_ring *rx_ring,
                cleaned = true;
                cleaned_count++;
 
+               /* this is the fast path for the non-packet split case */
                if (!adapter->rx_ps_hdr_size) {
                        pci_unmap_single(pdev, buffer_info->dma,
-                                        adapter->rx_buffer_len +
-                                          NET_IP_ALIGN,
+                                        adapter->rx_buffer_len,
                                         PCI_DMA_FROMDEVICE);
+                       buffer_info->dma = 0;
                        skb_put(skb, length);
                        goto send_up;
                }
@@ -4570,8 +4605,9 @@ static bool igb_clean_rx_irq_adv(struct igb_ring *rx_ring,
 
                if (!skb_shinfo(skb)->nr_frags) {
                        pci_unmap_single(pdev, buffer_info->dma,
-                                        adapter->rx_ps_hdr_size + NET_IP_ALIGN,
+                                        adapter->rx_ps_hdr_size,
                                         PCI_DMA_FROMDEVICE);
+                       buffer_info->dma = 0;
                        skb_put(skb, hlen);
                }
 
@@ -4713,7 +4749,6 @@ static void igb_alloc_rx_buffers_adv(struct igb_ring *rx_ring,
                bufsz = adapter->rx_ps_hdr_size;
        else
                bufsz = adapter->rx_buffer_len;
-       bufsz += NET_IP_ALIGN;
 
        while (cleaned_count--) {
                rx_desc = E1000_RX_DESC_ADV(*rx_ring, i);
@@ -4737,7 +4772,7 @@ static void igb_alloc_rx_buffers_adv(struct igb_ring *rx_ring,
                }
 
                if (!buffer_info->skb) {
-                       skb = netdev_alloc_skb(netdev, bufsz);
+                       skb = netdev_alloc_skb(netdev, bufsz + NET_IP_ALIGN);
                        if (!skb) {
                                adapter->alloc_rx_buff_failed++;
                                goto no_buffers;
@@ -5338,6 +5373,9 @@ static pci_ers_result_t igb_io_error_detected(struct pci_dev *pdev,
 
        netif_device_detach(netdev);
 
+       if (state == pci_channel_io_perm_failure)
+               return PCI_ERS_RESULT_DISCONNECT;
+
        if (netif_running(netdev))
                igb_down(adapter);
        pci_disable_device(pdev);
@@ -5414,43 +5452,6 @@ static void igb_io_resume(struct pci_dev *pdev)
        igb_get_hw_control(adapter);
 }
 
-static inline void igb_set_vmolr(struct e1000_hw *hw, int vfn)
-{
-       u32 reg_data;
-
-       reg_data = rd32(E1000_VMOLR(vfn));
-       reg_data |= E1000_VMOLR_BAM |    /* Accept broadcast */
-                   E1000_VMOLR_ROPE |   /* Accept packets matched in UTA */
-                   E1000_VMOLR_ROMPE |  /* Accept packets matched in MTA */
-                   E1000_VMOLR_AUPE |   /* Accept untagged packets */
-                   E1000_VMOLR_STRVLAN; /* Strip vlan tags */
-       wr32(E1000_VMOLR(vfn), reg_data);
-}
-
-static inline int igb_set_vf_rlpml(struct igb_adapter *adapter, int size,
-                                 int vfn)
-{
-       struct e1000_hw *hw = &adapter->hw;
-       u32 vmolr;
-
-       vmolr = rd32(E1000_VMOLR(vfn));
-       vmolr &= ~E1000_VMOLR_RLPML_MASK;
-       vmolr |= size | E1000_VMOLR_LPE;
-       wr32(E1000_VMOLR(vfn), vmolr);
-
-       return 0;
-}
-
-static inline void igb_set_rah_pool(struct e1000_hw *hw, int pool, int entry)
-{
-       u32 reg_data;
-
-       reg_data = rd32(E1000_RAH(entry));
-       reg_data &= ~E1000_RAH_POOL_MASK;
-       reg_data |= E1000_RAH_POOL_1 << pool;;
-       wr32(E1000_RAH(entry), reg_data);
-}
-
 static void igb_set_mc_list_pools(struct igb_adapter *adapter,
                                  int entry_count, u16 total_rar_filters)
 {
index f3eed6a8fba5e154df75dc1d0f901aef083a0681..911c082cee5acfa258211b117c1f018bcd9dbb49 100644 (file)
@@ -677,6 +677,14 @@ static int bfin_sir_init_iobuf(iobuff_t *io, int size)
        return 0;
 }
 
+static const struct net_device_ops bfin_sir_ndo = {
+       .ndo_open               = bfin_sir_open,
+       .ndo_stop               = bfin_sir_stop,
+       .ndo_start_xmit         = bfin_sir_hard_xmit,
+       .ndo_do_ioctl           = bfin_sir_ioctl,
+       .ndo_get_stats          = bfin_sir_stats,
+};
+
 static int __devinit bfin_sir_probe(struct platform_device *pdev)
 {
        struct net_device *dev;
@@ -718,12 +726,8 @@ static int __devinit bfin_sir_probe(struct platform_device *pdev)
        if (err)
                goto err_mem_3;
 
-       dev->hard_start_xmit = bfin_sir_hard_xmit;
-       dev->open            = bfin_sir_open;
-       dev->stop            = bfin_sir_stop;
-       dev->do_ioctl        = bfin_sir_ioctl;
-       dev->get_stats       = bfin_sir_stats;
-       dev->irq             = sir_port->irq;
+       dev->netdev_ops = &bfin_sir_ndo;
+       dev->irq = sir_port->irq;
 
        irda_init_max_qos_capabilies(&self->qos);
 
index d53aa9582137d241f0cdf22e092de488ec81efb9..20f9bc6266882eae0dae82707d9935f6bee1b8d4 100644 (file)
@@ -31,7 +31,6 @@
 #include <linux/tty.h>
 #include <linux/init.h>
 #include <asm/uaccess.h>
-#include <linux/smp_lock.h>
 #include <linux/delay.h>
 #include <linux/mutex.h>
 
index 73585fd8f29fdaee4a4647e6cdebe986c396e5ff..d12377b843581c1947fd1bdb33b9e9fe6d6ca4e4 100644 (file)
@@ -430,7 +430,8 @@ static int net_send_packet(struct sk_buff *skb, struct net_device *dev)
         * hardware interrupt handler.  Queue flow control is
         * thus managed under this lock as well.
         */
-       spin_lock_irq(&np->lock);
+       unsigned long flags;
+       spin_lock_irqsave(&np->lock, flags);
 
        add_to_tx_ring(np, skb, length);
        dev->trans_start = jiffies;
@@ -446,7 +447,7 @@ static int net_send_packet(struct sk_buff *skb, struct net_device *dev)
         * is when the transmit statistics are updated.
         */
 
-       spin_unlock_irq(&np->lock);
+       spin_unlock_irqrestore(&np->lock, flags);
 #else
        /* This is the case for older hardware which takes
         * a single transmit buffer at a time, and it is
index d56890f5c9d53f736c1ba58c5c1d73f5e2c131d2..7c5978ad929adc43424b4c1b475c2ef54c25ded9 100644 (file)
@@ -138,6 +138,10 @@ static u8 ixgbe_dcbnl_set_state(struct net_device *netdev, u8 state)
                        adapter->hw.fc.requested_mode = ixgbe_fc_none;
                }
                adapter->flags &= ~IXGBE_FLAG_RSS_ENABLED;
+               if (adapter->hw.mac.type == ixgbe_mac_82599EB) {
+                       adapter->flags &= ~IXGBE_FLAG_FDIR_HASH_CAPABLE;
+                       adapter->flags &= ~IXGBE_FLAG_FDIR_PERFECT_CAPABLE;
+               }
                adapter->flags |= IXGBE_FLAG_DCB_ENABLED;
                ixgbe_init_interrupt_scheme(adapter);
                if (netif_running(netdev))
@@ -154,6 +158,8 @@ static u8 ixgbe_dcbnl_set_state(struct net_device *netdev, u8 state)
                        adapter->dcb_cfg.pfc_mode_enable = false;
                        adapter->flags &= ~IXGBE_FLAG_DCB_ENABLED;
                        adapter->flags |= IXGBE_FLAG_RSS_ENABLED;
+                       if (adapter->hw.mac.type == ixgbe_mac_82599EB)
+                               adapter->flags |= IXGBE_FLAG_FDIR_HASH_CAPABLE;
                        ixgbe_init_interrupt_scheme(adapter);
                        if (netif_running(netdev))
                                netdev->netdev_ops->ndo_open(netdev);
index 86f4f3e36f27fc8d3ff0cccd734d8d691694bbd3..2a978008fd6efb780e05a64cbad4ef8f877bb19f 100644 (file)
@@ -139,7 +139,7 @@ static int ixgbe_get_settings(struct net_device *netdev,
        ecmd->autoneg = AUTONEG_ENABLE;
        ecmd->transceiver = XCVR_EXTERNAL;
        if ((hw->phy.media_type == ixgbe_media_type_copper) ||
-           (hw->mac.type == ixgbe_mac_82599EB)) {
+           (hw->phy.multispeed_fiber)) {
                ecmd->supported |= (SUPPORTED_1000baseT_Full |
                                    SUPPORTED_Autoneg);
 
@@ -217,7 +217,7 @@ static int ixgbe_set_settings(struct net_device *netdev,
        s32 err = 0;
 
        if ((hw->phy.media_type == ixgbe_media_type_copper) ||
-           (hw->mac.type == ixgbe_mac_82599EB)) {
+           (hw->phy.multispeed_fiber)) {
                /* 10000/copper and 1000/copper must autoneg
                 * this function does not support any duplex forcing, but can
                 * limit the advertising of the adapter to only 10000 or 1000 */
@@ -245,6 +245,7 @@ static int ixgbe_set_settings(struct net_device *netdev,
        } else {
                /* in this case we currently only support 10Gb/FULL */
                if ((ecmd->autoneg == AUTONEG_ENABLE) ||
+                   (ecmd->advertising != ADVERTISED_10000baseT_Full) ||
                    (ecmd->speed + ecmd->duplex != SPEED_10000 + DUPLEX_FULL))
                        return -EINVAL;
        }
@@ -1829,7 +1830,6 @@ static int ixgbe_wol_exclusion(struct ixgbe_adapter *adapter,
                break;
        default:
                wol->supported = 0;
-               retval = 0;
        }
 
        return retval;
index e756e220db326a98dc4b7d44d5b5b139ab33a807..e3442f47f932a6ceb7d3f70cf84f51907be8bb8e 100644 (file)
@@ -563,7 +563,6 @@ static void ixgbe_alloc_rx_buffers(struct ixgbe_adapter *adapter,
        union ixgbe_adv_rx_desc *rx_desc;
        struct ixgbe_rx_buffer *bi;
        unsigned int i;
-       unsigned int bufsz = rx_ring->rx_buf_len + NET_IP_ALIGN;
 
        i = rx_ring->next_to_use;
        bi = &rx_ring->rx_buffer_info[i];
@@ -593,7 +592,9 @@ static void ixgbe_alloc_rx_buffers(struct ixgbe_adapter *adapter,
 
                if (!bi->skb) {
                        struct sk_buff *skb;
-                       skb = netdev_alloc_skb(adapter->netdev, bufsz);
+                       skb = netdev_alloc_skb(adapter->netdev,
+                                              (rx_ring->rx_buf_len +
+                                               NET_IP_ALIGN));
 
                        if (!skb) {
                                adapter->alloc_rx_buff_failed++;
@@ -608,7 +609,8 @@ static void ixgbe_alloc_rx_buffers(struct ixgbe_adapter *adapter,
                        skb_reserve(skb, NET_IP_ALIGN);
 
                        bi->skb = skb;
-                       bi->dma = pci_map_single(pdev, skb->data, bufsz,
+                       bi->dma = pci_map_single(pdev, skb->data,
+                                                rx_ring->rx_buf_len,
                                                 PCI_DMA_FROMDEVICE);
                }
                /* Refresh the desc even if buffer_addrs didn't change because
@@ -732,6 +734,7 @@ static bool ixgbe_clean_rx_irq(struct ixgbe_q_vector *q_vector,
                        pci_unmap_single(pdev, rx_buffer_info->dma,
                                         rx_ring->rx_buf_len,
                                         PCI_DMA_FROMDEVICE);
+                       rx_buffer_info->dma = 0;
                        skb_put(skb, len);
                }
 
@@ -2694,16 +2697,23 @@ static int ixgbe_up_complete(struct ixgbe_adapter *adapter)
 
        /*
         * For hot-pluggable SFP+ devices, a new SFP+ module may have
-        * arrived before interrupts were enabled.  We need to kick off
-        * the SFP+ module setup first, then try to bring up link.
+        * arrived before interrupts were enabled but after probe.  Such
+        * devices wouldn't have their type identified yet. We need to
+        * kick off the SFP+ module setup first, then try to bring up link.
         * If we're not hot-pluggable SFP+, we just need to configure link
         * and bring it up.
         */
-       err = hw->phy.ops.identify(hw);
-       if (err == IXGBE_ERR_SFP_NOT_SUPPORTED) {
-               DPRINTK(PROBE, ERR, "PHY not supported on this NIC %d\n", err);
-               ixgbe_down(adapter);
-               return err;
+       if (hw->phy.type == ixgbe_phy_unknown) {
+               err = hw->phy.ops.identify(hw);
+               if (err == IXGBE_ERR_SFP_NOT_SUPPORTED) {
+                       /*
+                        * Take the device down and schedule the sfp tasklet
+                        * which will unregister_netdev and log it.
+                        */
+                       ixgbe_down(adapter);
+                       schedule_work(&adapter->sfp_config_module_task);
+                       return err;
+               }
        }
 
        if (ixgbe_is_sfp(hw)) {
@@ -2812,9 +2822,11 @@ static void ixgbe_clean_rx_ring(struct ixgbe_adapter *adapter,
                }
                if (!rx_buffer_info->page)
                        continue;
-               pci_unmap_page(pdev, rx_buffer_info->page_dma, PAGE_SIZE / 2,
-                              PCI_DMA_FROMDEVICE);
-               rx_buffer_info->page_dma = 0;
+               if (rx_buffer_info->page_dma) {
+                       pci_unmap_page(pdev, rx_buffer_info->page_dma,
+                                      PAGE_SIZE / 2, PCI_DMA_FROMDEVICE);
+                       rx_buffer_info->page_dma = 0;
+               }
                put_page(rx_buffer_info->page);
                rx_buffer_info->page = NULL;
                rx_buffer_info->page_offset = 0;
@@ -3118,7 +3130,11 @@ static inline bool ixgbe_set_fcoe_queues(struct ixgbe_adapter *adapter)
 #endif
                if (adapter->flags & IXGBE_FLAG_RSS_ENABLED) {
                        DPRINTK(PROBE, INFO, "FCOE enabled with RSS \n");
-                       ixgbe_set_rss_queues(adapter);
+                       if ((adapter->flags & IXGBE_FLAG_FDIR_HASH_CAPABLE) ||
+                           (adapter->flags & IXGBE_FLAG_FDIR_PERFECT_CAPABLE))
+                               ixgbe_set_fdir_queues(adapter);
+                       else
+                               ixgbe_set_rss_queues(adapter);
                }
                /* adding FCoE rx rings to the end */
                f->mask = adapter->num_rx_queues;
@@ -3376,7 +3392,12 @@ static inline bool ixgbe_cache_ring_fcoe(struct ixgbe_adapter *adapter)
                }
 #endif /* CONFIG_IXGBE_DCB */
                if (adapter->flags & IXGBE_FLAG_RSS_ENABLED) {
-                       ixgbe_cache_ring_rss(adapter);
+                       if ((adapter->flags & IXGBE_FLAG_FDIR_HASH_CAPABLE) ||
+                           (adapter->flags & IXGBE_FLAG_FDIR_PERFECT_CAPABLE))
+                               ixgbe_cache_ring_fdir(adapter);
+                       else
+                               ixgbe_cache_ring_rss(adapter);
+
                        fcoe_i = f->mask;
                }
                for (i = 0; i < f->indices; i++, fcoe_i++)
@@ -3716,14 +3737,15 @@ static void ixgbe_sfp_task(struct work_struct *work)
        if ((hw->phy.type == ixgbe_phy_nl) &&
            (hw->phy.sfp_type == ixgbe_sfp_type_not_present)) {
                s32 ret = hw->phy.ops.identify_sfp(hw);
-               if (ret)
+               if (ret == IXGBE_ERR_SFP_NOT_PRESENT)
                        goto reschedule;
                ret = hw->phy.ops.reset(hw);
                if (ret == IXGBE_ERR_SFP_NOT_SUPPORTED) {
-                       DPRINTK(PROBE, ERR, "failed to initialize because an "
-                               "unsupported SFP+ module type was detected.\n"
-                               "Reload the driver after installing a "
-                               "supported module.\n");
+                       dev_err(&adapter->pdev->dev, "failed to initialize "
+                               "because an unsupported SFP+ module type "
+                               "was detected.\n"
+                               "Reload the driver after installing a "
+                               "supported module.\n");
                        unregister_netdev(adapter->netdev);
                } else {
                        DPRINTK(PROBE, INFO, "detected SFP+: %d\n",
@@ -4502,7 +4524,8 @@ static void ixgbe_multispeed_fiber_task(struct work_struct *work)
        u32 autoneg;
 
        adapter->flags |= IXGBE_FLAG_IN_SFP_LINK_TASK;
-       if (hw->mac.ops.get_link_capabilities)
+       autoneg = hw->phy.autoneg_advertised;
+       if ((!autoneg) && (hw->mac.ops.get_link_capabilities))
                hw->mac.ops.get_link_capabilities(hw, &autoneg,
                                                  &hw->mac.autoneg);
        if (hw->mac.ops.setup_link_speed)
@@ -4524,10 +4547,17 @@ static void ixgbe_sfp_config_module_task(struct work_struct *work)
        u32 err;
 
        adapter->flags |= IXGBE_FLAG_IN_SFP_MOD_TASK;
+
+       /* Time for electrical oscillations to settle down */
+       msleep(100);
        err = hw->phy.ops.identify_sfp(hw);
+
        if (err == IXGBE_ERR_SFP_NOT_SUPPORTED) {
-               DPRINTK(PROBE, ERR, "PHY not supported on this NIC %d\n", err);
-               ixgbe_down(adapter);
+               dev_err(&adapter->pdev->dev, "failed to initialize because "
+                       "an unsupported SFP+ module type was detected.\n"
+                       "Reload the driver after installing a supported "
+                       "module.\n");
+               unregister_netdev(adapter->netdev);
                return;
        }
        hw->mac.ops.setup_sfp(hw);
@@ -5513,8 +5543,10 @@ static int __devinit ixgbe_probe(struct pci_dev *pdev,
                          round_jiffies(jiffies + (2 * HZ)));
                err = 0;
        } else if (err == IXGBE_ERR_SFP_NOT_SUPPORTED) {
-               dev_err(&adapter->pdev->dev, "failed to load because an "
-                       "unsupported SFP+ module type was detected.\n");
+               dev_err(&adapter->pdev->dev, "failed to initialize because "
+                       "an unsupported SFP+ module type was detected.\n"
+                       "Reload the driver after installing a supported "
+                       "module.\n");
                goto err_sw_init;
        } else if (err) {
                dev_err(&adapter->pdev->dev, "HW Init failed: %d\n", err);
@@ -5555,12 +5587,6 @@ static int __devinit ixgbe_probe(struct pci_dev *pdev,
                                netdev->features |= NETIF_F_FCOE_CRC;
                                netdev->features |= NETIF_F_FSO;
                                netdev->fcoe_ddp_xid = IXGBE_FCOE_DDP_MAX - 1;
-                               DPRINTK(DRV, INFO, "FCoE enabled, "
-                                       "disabling Flow Director\n");
-                               adapter->flags &= ~IXGBE_FLAG_FDIR_HASH_CAPABLE;
-                               adapter->flags &=
-                                       ~IXGBE_FLAG_FDIR_PERFECT_CAPABLE;
-                               adapter->atr_sample_rate = 0;
                        } else {
                                adapter->flags &= ~IXGBE_FLAG_FCOE_ENABLED;
                        }
index 453e966762f0e3a6f8f14c603ccbb031849ab5de..9ecad17522c33285fd7b8755cd1eaa3d4d6015bc 100644 (file)
@@ -60,6 +60,7 @@ s32 ixgbe_identify_phy_generic(struct ixgbe_hw *hw)
 
        if (hw->phy.type == ixgbe_phy_unknown) {
                for (phy_addr = 0; phy_addr < IXGBE_MAX_PHY_ADDR; phy_addr++) {
+                       hw->phy.mdio.prtad = phy_addr;
                        if (mdio45_probe(&hw->phy.mdio, phy_addr) == 0) {
                                ixgbe_get_phy_id(hw);
                                hw->phy.type =
@@ -68,6 +69,8 @@ s32 ixgbe_identify_phy_generic(struct ixgbe_hw *hw)
                                break;
                        }
                }
+               /* clear value if nothing found */
+               hw->phy.mdio.prtad = 0;
        } else {
                status = 0;
        }
index dc45e9856c35bcd810ad9ab4363d2174a3e2e3ee..6851bdb2ce29957b2293e4bb59e7bb1b37e6ae4c 100644 (file)
 #include <linux/mdio.h>
 #include <linux/module.h>
 
+MODULE_DESCRIPTION("Generic support for MDIO-compatible transceivers");
+MODULE_AUTHOR("Copyright 2006-2009 Solarflare Communications Inc.");
+MODULE_LICENSE("GPL");
+
 /**
  * mdio45_probe - probe for an MDIO (clause 45) device
  * @mdio: MDIO interface
index 2845a0560b84e18fcd28c64e9caa145b59c9a034..65ec77dc31f5b5c4a542a22a2f7d11c464a9d664 100644 (file)
@@ -80,7 +80,9 @@ enum {
        /* Bad management packet (silently discarded): */
        CMD_STAT_BAD_PKT        = 0x30,
        /* More outstanding CQEs in CQ than new CQ size: */
-       CMD_STAT_BAD_SIZE       = 0x40
+       CMD_STAT_BAD_SIZE       = 0x40,
+       /* Multi Function device support required: */
+       CMD_STAT_MULTI_FUNC_REQ = 0x50,
 };
 
 enum {
@@ -128,6 +130,7 @@ static int mlx4_status_to_errno(u8 status)
                [CMD_STAT_LAM_NOT_PRE]    = -EAGAIN,
                [CMD_STAT_BAD_PKT]        = -EINVAL,
                [CMD_STAT_BAD_SIZE]       = -ENOMEM,
+               [CMD_STAT_MULTI_FUNC_REQ] = -EACCES,
        };
 
        if (status >= ARRAY_SIZE(trans_table) ||
index 018348c011933b1240153f24ee95ba836c83c22c..dac621b1e9fc9a287fb8b4f7fdfa4f538ecc2a77 100644 (file)
@@ -729,7 +729,10 @@ static int mlx4_init_hca(struct mlx4_dev *dev)
 
        err = mlx4_QUERY_FW(dev);
        if (err) {
-               mlx4_err(dev, "QUERY_FW command failed, aborting.\n");
+               if (err == -EACCES)
+                       mlx4_info(dev, "non-primary physical function, skipping.\n");
+               else
+                       mlx4_err(dev, "QUERY_FW command failed, aborting.\n");
                return err;
        }
 
@@ -1285,6 +1288,7 @@ static struct pci_device_id mlx4_pci_table[] = {
        { PCI_VDEVICE(MELLANOX, 0x6750) }, /* MT25408 "Hermon" EN 10GigE PCIe gen2 */
        { PCI_VDEVICE(MELLANOX, 0x6372) }, /* MT25458 ConnectX EN 10GBASE-T 10GigE */
        { PCI_VDEVICE(MELLANOX, 0x675a) }, /* MT25458 ConnectX EN 10GBASE-T+Gen2 10GigE */
+       { PCI_VDEVICE(MELLANOX, 0x6764) }, /* MT26468 ConnectX EN 10GigE PCIe gen2*/
        { 0, }
 };
 
index c9bfe4eea189d9d113feac1a99174b73eb0f4eeb..78c088331f57031e4eb152a66037759f8dee8796 100644 (file)
@@ -130,8 +130,8 @@ static int full_duplex[MAX_UNITS];
 static const char version[] __devinitconst =
   KERN_INFO DRV_NAME " dp8381x driver, version "
       DRV_VERSION ", " DRV_RELDATE "\n"
-  KERN_INFO "  originally by Donald Becker <becker@scyld.com>\n"
-  KERN_INFO "  2.4.x kernel port by Jeff Garzik, Tjeerd Mulder\n";
+  "  originally by Donald Becker <becker@scyld.com>\n"
+  "  2.4.x kernel port by Jeff Garzik, Tjeerd Mulder\n";
 
 MODULE_AUTHOR("Donald Becker <becker@scyld.com>");
 MODULE_DESCRIPTION("National Semiconductor DP8381x series PCI Ethernet driver");
index 5c3e242428f11a1b5ff2e98a782614031d00a9cf..992dbfffdb05ece983205f5ffe71d5e6073af208 100644 (file)
@@ -321,7 +321,7 @@ static int __init ne_probe1(struct net_device *dev, unsigned long ioaddr)
        }
 
        if (ei_debug  &&  version_printed++ == 0)
-               printk(KERN_INFO "%s" KERN_INFO "%s", version1, version2);
+               printk(KERN_INFO "%s%s", version1, version2);
 
        printk(KERN_INFO "NE*000 ethercard probe at %#3lx:", ioaddr);
 
index 970cedeb5f37ba6923454aea9a2fc41ef63519cc..e1cdba752e09daa397c331b9c5708da267d8a7d9 100644 (file)
 #define _NETXEN_NIC_LINUX_SUBVERSION 30
 #define NETXEN_NIC_LINUX_VERSIONID  "4.0.30"
 
-#define NETXEN_VERSION_CODE(a, b, c)   (((a) << 16) + ((b) << 8) + (c))
+#define NETXEN_VERSION_CODE(a, b, c)   (((a) << 24) + ((b) << 16) + (c))
+#define _major(v)      (((v) >> 24) & 0xff)
+#define _minor(v)      (((v) >> 16) & 0xff)
+#define _build(v)      ((v) & 0xffff)
+
+/* version in image has weird encoding:
+ *  7:0  - major
+ * 15:8  - minor
+ * 31:16 - build (little endian)
+ */
+#define NETXEN_DECODE_VERSION(v) \
+       NETXEN_VERSION_CODE(((v) & 0xff), (((v) >> 8) & 0xff), ((v) >> 16))
 
 #define NETXEN_NUM_FLASH_SECTORS (64)
 #define NETXEN_FLASH_SECTOR_SIZE (64 * 1024)
@@ -614,6 +625,7 @@ struct netxen_new_user_info {
 #define NX_P2_MN_ROMIMAGE      0
 #define NX_P3_CT_ROMIMAGE      1
 #define NX_P3_MN_ROMIMAGE      2
+#define NX_FLASH_ROMIMAGE      3
 
 #define NETXEN_USER_START_OLD NETXEN_PXE_START /* for backward compatibility */
 
@@ -1243,7 +1255,7 @@ struct netxen_adapter {
        u32 resv3;
 
        u8 has_link_events;
-       u8 resv1;
+       u8 fw_type;
        u16 tx_context_id;
        u16 mtu;
        u16 is_up;
@@ -1387,6 +1399,7 @@ void netxen_free_adapter_offload(struct netxen_adapter *adapter);
 int netxen_initialize_adapter_offload(struct netxen_adapter *adapter);
 int netxen_phantom_init(struct netxen_adapter *adapter, int pegtune_val);
 int netxen_load_firmware(struct netxen_adapter *adapter);
+int netxen_need_fw_reset(struct netxen_adapter *adapter);
 void netxen_request_firmware(struct netxen_adapter *adapter);
 void netxen_release_firmware(struct netxen_adapter *adapter);
 int netxen_pinit_from_rom(struct netxen_adapter *adapter, int verbose);
index 3cc047844af30d42b555efe35e2aca774c14d4eb..82410367564838aff7f2b5872c3c436a377a183c 100644 (file)
@@ -853,6 +853,7 @@ enum {
 #define NX_PEG_TUNE_CAPABILITY         (NETXEN_CAM_RAM(0x02c))
 
 #define NETXEN_CAM_RAM_DMA_WATCHDOG_CTRL               (0x14)
+#define NETXEN_PEG_ALIVE_COUNTER       (NETXEN_CAM_RAM(0xb0))
 
 #define        ISR_MSI_INT_TRIGGER(FUNC) (NETXEN_PCIX_PS_REG(PCIX_MSI_F(FUNC)))
 #define ISR_LEGACY_INT_TRIGGERED(VAL)  (((VAL) & 0x300) == 0x200)
index bdb143d2b5c7a4f2032d19d746875dc3dfef01db..b899bd51fcd87e2563fa4fd495b8c760fe5c0e6d 100644 (file)
@@ -683,12 +683,85 @@ int netxen_pinit_from_rom(struct netxen_adapter *adapter, int verbose)
        return 0;
 }
 
+int
+netxen_need_fw_reset(struct netxen_adapter *adapter)
+{
+       u32 count, old_count;
+       u32 val, version, major, minor, build;
+       int i, timeout;
+       u8 fw_type;
+
+       /* NX2031 firmware doesn't support heartbit */
+       if (NX_IS_REVISION_P2(adapter->ahw.revision_id))
+               return 1;
+
+       /* last attempt had failed */
+       if (NXRD32(adapter, CRB_CMDPEG_STATE) == PHAN_INITIALIZE_FAILED)
+               return 1;
+
+       old_count = count = NXRD32(adapter, NETXEN_PEG_ALIVE_COUNTER);
+
+       for (i = 0; i < 10; i++) {
+
+               timeout = msleep_interruptible(200);
+               if (timeout) {
+                       NXWR32(adapter, CRB_CMDPEG_STATE,
+                                       PHAN_INITIALIZE_FAILED);
+                       return -EINTR;
+               }
+
+               count = NXRD32(adapter, NETXEN_PEG_ALIVE_COUNTER);
+               if (count != old_count)
+                       break;
+       }
+
+       /* firmware is dead */
+       if (count == old_count)
+               return 1;
+
+       /* check if we have got newer or different file firmware */
+       if (adapter->fw) {
+
+               const struct firmware *fw = adapter->fw;
+
+               val = cpu_to_le32(*(u32 *)&fw->data[NX_FW_VERSION_OFFSET]);
+               version = NETXEN_DECODE_VERSION(val);
+
+               major = NXRD32(adapter, NETXEN_FW_VERSION_MAJOR);
+               minor = NXRD32(adapter, NETXEN_FW_VERSION_MINOR);
+               build = NXRD32(adapter, NETXEN_FW_VERSION_SUB);
+
+               if (version > NETXEN_VERSION_CODE(major, minor, build))
+                       return 1;
+
+               if (version == NETXEN_VERSION_CODE(major, minor, build)) {
+
+                       val = NXRD32(adapter, NETXEN_MIU_MN_CONTROL);
+                       fw_type = (val & 0x4) ?
+                               NX_P3_CT_ROMIMAGE : NX_P3_MN_ROMIMAGE;
+
+                       if (adapter->fw_type != fw_type)
+                               return 1;
+               }
+       }
+
+       return 0;
+}
+
+static char *fw_name[] = {
+       "nxromimg.bin", "nx3fwct.bin", "nx3fwmn.bin", "flash",
+};
+
 int
 netxen_load_firmware(struct netxen_adapter *adapter)
 {
        u64 *ptr64;
        u32 i, flashaddr, size;
        const struct firmware *fw = adapter->fw;
+       struct pci_dev *pdev = adapter->pdev;
+
+       dev_info(&pdev->dev, "loading firmware from %s\n",
+                       fw_name[adapter->fw_type]);
 
        if (NX_IS_REVISION_P2(adapter->ahw.revision_id))
                NXWR32(adapter, NETXEN_ROMUSB_GLB_CAS_RST, 1);
@@ -756,7 +829,7 @@ static int
 netxen_validate_firmware(struct netxen_adapter *adapter, const char *fwname)
 {
        __le32 val;
-       u32 major, minor, build, ver, min_ver, bios;
+       u32 ver, min_ver, bios;
        struct pci_dev *pdev = adapter->pdev;
        const struct firmware *fw = adapter->fw;
 
@@ -768,21 +841,18 @@ netxen_validate_firmware(struct netxen_adapter *adapter, const char *fwname)
                return -EINVAL;
 
        val = cpu_to_le32(*(u32 *)&fw->data[NX_FW_VERSION_OFFSET]);
-       major = (__force u32)val & 0xff;
-       minor = ((__force u32)val >> 8) & 0xff;
-       build = (__force u32)val >> 16;
 
        if (NX_IS_REVISION_P3(adapter->ahw.revision_id))
                min_ver = NETXEN_VERSION_CODE(4, 0, 216);
        else
                min_ver = NETXEN_VERSION_CODE(3, 4, 216);
 
-       ver = NETXEN_VERSION_CODE(major, minor, build);
+       ver = NETXEN_DECODE_VERSION(val);
 
-       if ((major > _NETXEN_NIC_LINUX_MAJOR) || (ver < min_ver)) {
+       if ((_major(ver) > _NETXEN_NIC_LINUX_MAJOR) || (ver < min_ver)) {
                dev_err(&pdev->dev,
                                "%s: firmware version %d.%d.%d unsupported\n",
-                               fwname, major, minor, build);
+                               fwname, _major(ver), _minor(ver), _build(ver));
                return -EINVAL;
        }
 
@@ -798,22 +868,21 @@ netxen_validate_firmware(struct netxen_adapter *adapter, const char *fwname)
        if (netxen_rom_fast_read(adapter,
                        NX_FW_VERSION_OFFSET, (int *)&val))
                return -EIO;
-       major = (__force u32)val & 0xff;
-       minor = ((__force u32)val >> 8) & 0xff;
-       build = (__force u32)val >> 16;
-       if (NETXEN_VERSION_CODE(major, minor, build) > ver)
+       val = NETXEN_DECODE_VERSION(val);
+       if (val > ver) {
+               dev_info(&pdev->dev, "%s: firmware is older than flash\n",
+                               fwname);
                return -EINVAL;
+       }
 
        NXWR32(adapter, NETXEN_CAM_RAM(0x1fc), NETXEN_BDINFO_MAGIC);
        return 0;
 }
 
-static char *fw_name[] = { "nxromimg.bin", "nx3fwct.bin", "nx3fwmn.bin" };
-
 void netxen_request_firmware(struct netxen_adapter *adapter)
 {
        u32 capability, flashed_ver;
-       int fw_type;
+       u8 fw_type;
        struct pci_dev *pdev = adapter->pdev;
        int rc = 0;
 
@@ -830,6 +899,8 @@ request_mn:
 
        netxen_rom_fast_read(adapter,
                        NX_FW_VERSION_OFFSET, (int *)&flashed_ver);
+       flashed_ver = NETXEN_DECODE_VERSION(flashed_ver);
+
        if (flashed_ver >= NETXEN_VERSION_CODE(4, 0, 220)) {
                capability = NXRD32(adapter, NX_PEG_TUNE_CAPABILITY);
                if (capability & NX_PEG_TUNE_MN_PRESENT) {
@@ -838,6 +909,10 @@ request_mn:
                }
        }
 
+       fw_type = NX_FLASH_ROMIMAGE;
+       adapter->fw = NULL;
+       goto done;
+
 request_fw:
        rc = request_firmware(&adapter->fw, fw_name[fw_type], &pdev->dev);
        if (rc != 0) {
@@ -846,6 +921,7 @@ request_fw:
                        goto request_mn;
                }
 
+               fw_type = NX_FLASH_ROMIMAGE;
                adapter->fw = NULL;
                goto done;
        }
@@ -859,16 +935,13 @@ request_fw:
                        goto request_mn;
                }
 
+               fw_type = NX_FLASH_ROMIMAGE;
                adapter->fw = NULL;
                goto done;
        }
 
 done:
-       if (adapter->fw)
-               dev_info(&pdev->dev, "loading firmware from file %s\n",
-                               fw_name[fw_type]);
-       else
-               dev_info(&pdev->dev, "loading firmware from flash\n");
+       adapter->fw_type = fw_type;
 }
 
 
@@ -944,28 +1017,31 @@ int netxen_phantom_init(struct netxen_adapter *adapter, int pegtune_val)
        u32 val = 0;
        int retries = 60;
 
-       if (!pegtune_val) {
-               do {
-                       val = NXRD32(adapter, CRB_CMDPEG_STATE);
+       if (pegtune_val)
+               return 0;
 
-                       if (val == PHAN_INITIALIZE_COMPLETE ||
-                               val == PHAN_INITIALIZE_ACK)
-                               return 0;
+       do {
+               val = NXRD32(adapter, CRB_CMDPEG_STATE);
 
-                       msleep(500);
+               switch (val) {
+               case PHAN_INITIALIZE_COMPLETE:
+               case PHAN_INITIALIZE_ACK:
+                       return 0;
+               case PHAN_INITIALIZE_FAILED:
+                       goto out_err;
+               default:
+                       break;
+               }
 
-               } while (--retries);
+               msleep(500);
 
-               if (!retries) {
-                       pegtune_val = NXRD32(adapter,
-                                       NETXEN_ROMUSB_GLB_PEGTUNE_DONE);
-                       printk(KERN_WARNING "netxen_phantom_init: init failed, "
-                                       "pegtune_val=%x\n", pegtune_val);
-                       return -1;
-               }
-       }
+       } while (--retries);
 
-       return 0;
+       NXWR32(adapter, CRB_CMDPEG_STATE, PHAN_INITIALIZE_FAILED);
+
+out_err:
+       dev_warn(&adapter->pdev->dev, "firmware init failed\n");
+       return -EIO;
 }
 
 static int
index 71daa3d5f114174f7ec13015b49fa8d45cb9d2a6..27539ddf94c4f9304c8310e652c1ee7f120f78af 100644 (file)
@@ -705,7 +705,7 @@ netxen_start_firmware(struct netxen_adapter *adapter, int request_fw)
                first_driver = (adapter->ahw.pci_func == 0);
 
        if (!first_driver)
-               return 0;
+               goto wait_init;
 
        first_boot = NXRD32(adapter, NETXEN_CAM_RAM(0x1fc));
 
@@ -718,6 +718,10 @@ netxen_start_firmware(struct netxen_adapter *adapter, int request_fw)
        if (request_fw)
                netxen_request_firmware(adapter);
 
+       err = netxen_need_fw_reset(adapter);
+       if (err <= 0)
+               return err;
+
        if (first_boot != 0x55555555) {
                NXWR32(adapter, CRB_CMDPEG_STATE, 0);
                netxen_pinit_from_rom(adapter, 0);
@@ -752,6 +756,7 @@ netxen_start_firmware(struct netxen_adapter *adapter, int request_fw)
                | (_NETXEN_NIC_LINUX_SUBVERSION);
        NXWR32(adapter, CRB_DRIVER_VERSION, val);
 
+wait_init:
        /* Handshake with the card before we register the devices. */
        err = netxen_phantom_init(adapter, NETXEN_NIC_PEG_TUNE);
        if (err) {
@@ -1178,6 +1183,7 @@ static void __devexit netxen_nic_remove(struct pci_dev *pdev)
        free_netdev(netdev);
 }
 
+#ifdef CONFIG_PM
 static int
 netxen_nic_suspend(struct pci_dev *pdev, pm_message_t state)
 {
@@ -1242,6 +1248,7 @@ netxen_nic_resume(struct pci_dev *pdev)
 
        return 0;
 }
+#endif
 
 static int netxen_nic_open(struct net_device *netdev)
 {
@@ -1771,8 +1778,10 @@ static struct pci_driver netxen_driver = {
        .id_table = netxen_pci_tbl,
        .probe = netxen_nic_probe,
        .remove = __devexit_p(netxen_nic_remove),
+#ifdef CONFIG_PM
        .suspend = netxen_nic_suspend,
        .resume = netxen_nic_resume
+#endif
 };
 
 /* Driver Registration on NetXen card    */
index 8c1f6988f398bdbc42305fb1aed09fffb9db97ed..89f7b2ad523116c51ea7d612d43e32205c8515d6 100644 (file)
@@ -105,7 +105,7 @@ IVc. Errata
 
 static char version[] __devinitdata =
 KERN_INFO NETDRV_DRIVER_LOAD_MSG "\n"
-KERN_INFO "  Support available from http://foo.com/bar/baz.html\n";
+"  Support available from http://foo.com/bar/baz.html\n";
 
 /* define to 1 to enable PIO instead of MMIO */
 #undef USE_IO_OPS
index f51944b28cfa7008bd05f282844013e5459c6fc2..06618af1a4680d6c208536c903aa5de8638e8d2f 100644 (file)
@@ -298,14 +298,11 @@ static int __devinit ibmtr_config(struct pcmcia_device *link)
 
     strcpy(info->node.dev_name, dev->name);
 
-    printk(KERN_INFO "%s: port %#3lx, irq %d,",
-           dev->name, dev->base_addr, dev->irq);
-    printk (" mmio %#5lx,", (u_long)ti->mmio);
-    printk (" sram %#5lx,", (u_long)ti->sram_base << 12);
-    printk ("\n" KERN_INFO "  hwaddr=");
-    for (i = 0; i < TR_ALEN; i++)
-        printk("%02X", dev->dev_addr[i]);
-    printk("\n");
+    printk(KERN_INFO
+          "%s: port %#3lx, irq %d,  mmio %#5lx, sram %#5lx, hwaddr=%pM\n",
+           dev->name, dev->base_addr, dev->irq,
+          (u_long)ti->mmio, (u_long)(ti->sram_base << 12),
+          dev->dev_addr);
     return 0;
 
 cs_failed:
index 02ef63ed1f99ba6b6d630822baa6b5ddf897e2d2..36de91baf2387dbe5eaf88270f7aeacd4992c75d 100644 (file)
@@ -1425,15 +1425,12 @@ static void BuildLAF(int *ladrf, int *adr)
   ladrf[byte] |= (1 << (hashcode & 7));
 
 #ifdef PCMCIA_DEBUG
-  if (pc_debug > 2) {
-    printk(KERN_DEBUG "    adr =");
-    for (i = 0; i < 6; i++)
-      printk(" %02X", adr[i]);
-    printk("\n" KERN_DEBUG "    hashcode = %d(decimal), ladrf[0:63]"
-          " =", hashcode);
-    for (i = 0; i < 8; i++)
-      printk(" %02X", ladrf[i]);
-    printk("\n");
+  if (pc_debug > 2)
+    printk(KERN_DEBUG "    adr =%pM\n", adr);
+  printk(KERN_DEBUG "    hashcode = %d(decimal), ladrf[0:63] =", hashcode);
+  for (i = 0; i < 8; i++)
+    printk(KERN_CONT " %02X", ladrf[i]);
+  printk(KERN_CONT "\n");
   }
 #endif
 } /* BuildLAF */
index 652a368883612f6c837e2e5b1c1123f29187c2ae..9ef1c1bfa83d3062b6c2d903faceee333eb47141 100644 (file)
@@ -1727,6 +1727,7 @@ static struct pcmcia_device_id pcnet_ids[] = {
        PCMCIA_DEVICE_PROD_ID12("PRETEC", "Ethernet CompactLAN 10BaseT 3.3V", 0xebf91155, 0x7f5a4f50),
        PCMCIA_DEVICE_PROD_ID12("Psion Dacom", "Gold Card Ethernet", 0xf5f025c2, 0x3a30e110),
        PCMCIA_DEVICE_PROD_ID12("=RELIA==", "Ethernet", 0xcdd0644a, 0x00b2e941),
+       PCMCIA_DEVICE_PROD_ID12("RIOS Systems Co.", "PC CARD3 ETHERNET", 0x7dd33481, 0x10b41826),
        PCMCIA_DEVICE_PROD_ID12("RP", "1625B Ethernet NE2000 Compatible", 0xe3e66e22, 0xb96150df),
        PCMCIA_DEVICE_PROD_ID12("RPTI", "EP400 Ethernet NE2000 Compatible", 0xdc6f88fd, 0x4a7e2ae0),
        PCMCIA_DEVICE_PROD_ID12("RPTI", "EP401 Ethernet NE2000 Compatible", 0xdc6f88fd, 0x4bcbd7fd),
index 1c35e1d637a0e30aecd6f3369a0f89cdbf34b972..28368157dac4eabd53c71be7acf64afaa2df7d2b 100644 (file)
@@ -485,7 +485,7 @@ static void pcnet32_realloc_tx_ring(struct net_device *dev,
                                           &new_ring_dma_addr);
        if (new_tx_ring == NULL) {
                if (netif_msg_drv(lp))
-                       printk("\n" KERN_ERR
+                       printk(KERN_ERR
                               "%s: Consistent memory allocation failed.\n",
                               dev->name);
                return;
@@ -496,7 +496,7 @@ static void pcnet32_realloc_tx_ring(struct net_device *dev,
                                GFP_ATOMIC);
        if (!new_dma_addr_list) {
                if (netif_msg_drv(lp))
-                       printk("\n" KERN_ERR
+                       printk(KERN_ERR
                               "%s: Memory allocation failed.\n", dev->name);
                goto free_new_tx_ring;
        }
@@ -505,7 +505,7 @@ static void pcnet32_realloc_tx_ring(struct net_device *dev,
                                GFP_ATOMIC);
        if (!new_skb_list) {
                if (netif_msg_drv(lp))
-                       printk("\n" KERN_ERR
+                       printk(KERN_ERR
                               "%s: Memory allocation failed.\n", dev->name);
                goto free_new_lists;
        }
@@ -563,7 +563,7 @@ static void pcnet32_realloc_rx_ring(struct net_device *dev,
                                           &new_ring_dma_addr);
        if (new_rx_ring == NULL) {
                if (netif_msg_drv(lp))
-                       printk("\n" KERN_ERR
+                       printk(KERN_ERR
                               "%s: Consistent memory allocation failed.\n",
                               dev->name);
                return;
@@ -574,7 +574,7 @@ static void pcnet32_realloc_rx_ring(struct net_device *dev,
                                GFP_ATOMIC);
        if (!new_dma_addr_list) {
                if (netif_msg_drv(lp))
-                       printk("\n" KERN_ERR
+                       printk(KERN_ERR
                               "%s: Memory allocation failed.\n", dev->name);
                goto free_new_rx_ring;
        }
@@ -583,7 +583,7 @@ static void pcnet32_realloc_rx_ring(struct net_device *dev,
                                GFP_ATOMIC);
        if (!new_skb_list) {
                if (netif_msg_drv(lp))
-                       printk("\n" KERN_ERR
+                       printk(KERN_ERR
                               "%s: Memory allocation failed.\n", dev->name);
                goto free_new_lists;
        }
@@ -1766,38 +1766,38 @@ pcnet32_probe1(unsigned long ioaddr, int shared, struct pci_dev *pdev)
                /* Version 0x2623 and 0x2624 */
                if (((chip_version + 1) & 0xfffe) == 0x2624) {
                        i = a->read_csr(ioaddr, 80) & 0x0C00;   /* Check tx_start_pt */
-                       printk("\n" KERN_INFO "    tx_start_pt(0x%04x):", i);
+                       printk(KERN_INFO "    tx_start_pt(0x%04x):", i);
                        switch (i >> 10) {
                        case 0:
-                               printk("  20 bytes,");
+                               printk(KERN_CONT "  20 bytes,");
                                break;
                        case 1:
-                               printk("  64 bytes,");
+                               printk(KERN_CONT "  64 bytes,");
                                break;
                        case 2:
-                               printk(" 128 bytes,");
+                               printk(KERN_CONT " 128 bytes,");
                                break;
                        case 3:
-                               printk("~220 bytes,");
+                               printk(KERN_CONT "~220 bytes,");
                                break;
                        }
                        i = a->read_bcr(ioaddr, 18);    /* Check Burst/Bus control */
-                       printk(" BCR18(%x):", i & 0xffff);
+                       printk(KERN_CONT " BCR18(%x):", i & 0xffff);
                        if (i & (1 << 5))
-                               printk("BurstWrEn ");
+                               printk(KERN_CONT "BurstWrEn ");
                        if (i & (1 << 6))
-                               printk("BurstRdEn ");
+                               printk(KERN_CONT "BurstRdEn ");
                        if (i & (1 << 7))
-                               printk("DWordIO ");
+                               printk(KERN_CONT "DWordIO ");
                        if (i & (1 << 11))
-                               printk("NoUFlow ");
+                               printk(KERN_CONT "NoUFlow ");
                        i = a->read_bcr(ioaddr, 25);
-                       printk("\n" KERN_INFO "    SRAMSIZE=0x%04x,", i << 8);
+                       printk(KERN_INFO "    SRAMSIZE=0x%04x,", i << 8);
                        i = a->read_bcr(ioaddr, 26);
-                       printk(" SRAM_BND=0x%04x,", i << 8);
+                       printk(KERN_CONT " SRAM_BND=0x%04x,", i << 8);
                        i = a->read_bcr(ioaddr, 27);
                        if (i & (1 << 14))
-                               printk("LowLatRx");
+                               printk(KERN_CONT "LowLatRx");
                }
        }
 
@@ -1996,7 +1996,7 @@ static int pcnet32_alloc_ring(struct net_device *dev, const char *name)
                                           &lp->tx_ring_dma_addr);
        if (lp->tx_ring == NULL) {
                if (netif_msg_drv(lp))
-                       printk("\n" KERN_ERR PFX
+                       printk(KERN_ERR PFX
                               "%s: Consistent memory allocation failed.\n",
                               name);
                return -ENOMEM;
@@ -2008,7 +2008,7 @@ static int pcnet32_alloc_ring(struct net_device *dev, const char *name)
                                           &lp->rx_ring_dma_addr);
        if (lp->rx_ring == NULL) {
                if (netif_msg_drv(lp))
-                       printk("\n" KERN_ERR PFX
+                       printk(KERN_ERR PFX
                               "%s: Consistent memory allocation failed.\n",
                               name);
                return -ENOMEM;
@@ -2018,7 +2018,7 @@ static int pcnet32_alloc_ring(struct net_device *dev, const char *name)
                                  GFP_ATOMIC);
        if (!lp->tx_dma_addr) {
                if (netif_msg_drv(lp))
-                       printk("\n" KERN_ERR PFX
+                       printk(KERN_ERR PFX
                               "%s: Memory allocation failed.\n", name);
                return -ENOMEM;
        }
@@ -2027,7 +2027,7 @@ static int pcnet32_alloc_ring(struct net_device *dev, const char *name)
                                  GFP_ATOMIC);
        if (!lp->rx_dma_addr) {
                if (netif_msg_drv(lp))
-                       printk("\n" KERN_ERR PFX
+                       printk(KERN_ERR PFX
                               "%s: Memory allocation failed.\n", name);
                return -ENOMEM;
        }
@@ -2036,7 +2036,7 @@ static int pcnet32_alloc_ring(struct net_device *dev, const char *name)
                                GFP_ATOMIC);
        if (!lp->tx_skbuff) {
                if (netif_msg_drv(lp))
-                       printk("\n" KERN_ERR PFX
+                       printk(KERN_ERR PFX
                               "%s: Memory allocation failed.\n", name);
                return -ENOMEM;
        }
@@ -2045,7 +2045,7 @@ static int pcnet32_alloc_ring(struct net_device *dev, const char *name)
                                GFP_ATOMIC);
        if (!lp->rx_skbuff) {
                if (netif_msg_drv(lp))
-                       printk("\n" KERN_ERR PFX
+                       printk(KERN_ERR PFX
                               "%s: Memory allocation failed.\n", name);
                return -ENOMEM;
        }
index 61755cbd978e4aee3cfae9306395d80763abceef..eda94fcd4065a9391150c4ce27ff8c01553af2bf 100644 (file)
@@ -928,13 +928,32 @@ static void phy_state_machine(struct work_struct *work)
                                 * Otherwise, it's 0, and we're
                                 * still waiting for AN */
                                if (err > 0) {
-                                       phydev->state = PHY_RUNNING;
+                                       err = phy_read_status(phydev);
+                                       if (err)
+                                               break;
+
+                                       if (phydev->link) {
+                                               phydev->state = PHY_RUNNING;
+                                               netif_carrier_on(phydev->attached_dev);
+                                       } else
+                                               phydev->state = PHY_NOLINK;
+                                       phydev->adjust_link(phydev->attached_dev);
                                } else {
                                        phydev->state = PHY_AN;
                                        phydev->link_timeout = PHY_AN_TIMEOUT;
                                }
-                       } else
-                               phydev->state = PHY_RUNNING;
+                       } else {
+                               err = phy_read_status(phydev);
+                               if (err)
+                                       break;
+
+                               if (phydev->link) {
+                                       phydev->state = PHY_RUNNING;
+                                       netif_carrier_on(phydev->attached_dev);
+                               } else
+                                       phydev->state = PHY_NOLINK;
+                               phydev->adjust_link(phydev->attached_dev);
+                       }
                        break;
        }
 
index eba937c463767fd1e07ea2425db0a17165e263ab..b10fedd8214394b591bfb81bd102c8d38fce9fb1 100644 (file)
@@ -134,8 +134,10 @@ int phy_scan_fixups(struct phy_device *phydev)
 
                        err = fixup->run(phydev);
 
-                       if (err < 0)
+                       if (err < 0) {
+                               mutex_unlock(&phy_fixup_lock);
                                return err;
+                       }
                }
        }
        mutex_unlock(&phy_fixup_lock);
index 7a62f781fef2b83fdfe55dc0cad944cb5a2d7c8b..2ca8b0d84ee2d7f2647e3064e6f1615f116c1294 100644 (file)
@@ -270,6 +270,9 @@ static const struct net_device_ops plip_netdev_ops = {
        .ndo_stop                = plip_close,
        .ndo_start_xmit          = plip_tx_packet,
        .ndo_do_ioctl            = plip_ioctl,
+       .ndo_change_mtu          = eth_change_mtu,
+       .ndo_set_mac_address     = eth_mac_addr,
+       .ndo_validate_addr       = eth_validate_addr,
 };
 
 /* Entry point of PLIP driver.
index 17c116bb332c7e0c41da3f97aeb3ac3755097e87..6de8399d6dd92d26875cca679ec332c19082d736 100644 (file)
@@ -356,6 +356,7 @@ ppp_asynctty_receive(struct tty_struct *tty, const unsigned char *buf,
        if (!skb_queue_empty(&ap->rqueue))
                tasklet_schedule(&ap->tsk);
        ap_put(ap);
+       tty_unthrottle(tty);
 }
 
 static void
index aa3d39f38e2257deee5e72e9df06453be96e3046..d2fa2db1358633771439013546758654444c6a00 100644 (file)
@@ -397,6 +397,7 @@ ppp_sync_receive(struct tty_struct *tty, const unsigned char *buf,
        if (!skb_queue_empty(&ap->rqueue))
                tasklet_schedule(&ap->tsk);
        sp_put(ap);
+       tty_unthrottle(tty);
 }
 
 static void
index d1a5fb4d6acb1e63e479abea8db9a1e1f4a3e5f7..a3932c9f3406c9d4e75967fc392d759cffb78330 100644 (file)
@@ -1411,6 +1411,7 @@ static const struct net_device_ops gelic_netdevice_ops = {
        .ndo_set_multicast_list = gelic_net_set_multi,
        .ndo_change_mtu = gelic_net_change_mtu,
        .ndo_tx_timeout = gelic_net_tx_timeout,
+       .ndo_set_mac_address = eth_mac_addr,
        .ndo_validate_addr = eth_validate_addr,
 #ifdef CONFIG_NET_POLL_CONTROLLER
        .ndo_poll_controller = gelic_net_poll_controller,
index b6b3ca9bdb213a9fa995b35cda8cc72f0cf480d2..6932b08d746b38b1c830d3ea3f720496562e9129 100644 (file)
@@ -2707,6 +2707,7 @@ static const struct net_device_ops gelic_wl_netdevice_ops = {
        .ndo_set_multicast_list = gelic_net_set_multi,
        .ndo_change_mtu = gelic_net_change_mtu,
        .ndo_tx_timeout = gelic_net_tx_timeout,
+       .ndo_set_mac_address = eth_mac_addr,
        .ndo_validate_addr = eth_validate_addr,
 #ifdef CONFIG_NET_POLL_CONTROLLER
        .ndo_poll_controller = gelic_net_poll_controller,
index bbc6d4d3cc945b1cdf9f42f1872d7cef231012a6..3e4b67aaa6ea5bddeee06f372d5925bf394466ce 100644 (file)
@@ -3142,6 +3142,7 @@ static int ql_adapter_initialize(struct ql3_adapter *qdev)
                                                (void __iomem *)port_regs;
        u32 delay = 10;
        int status = 0;
+       unsigned long hw_flags = 0;
 
        if(ql_mii_setup(qdev))
                return -1;
@@ -3150,7 +3151,8 @@ static int ql_adapter_initialize(struct ql3_adapter *qdev)
        ql_write_common_reg(qdev, &port_regs->CommonRegs.serialPortInterfaceReg,
                            (ISP_SERIAL_PORT_IF_WE |
                             (ISP_SERIAL_PORT_IF_WE << 16)));
-
+       /* Give the PHY time to come out of reset. */
+       mdelay(100);
        qdev->port_link_state = LS_DOWN;
        netif_carrier_off(qdev->ndev);
 
@@ -3350,7 +3352,9 @@ static int ql_adapter_initialize(struct ql3_adapter *qdev)
                value = ql_read_page0_reg(qdev, &port_regs->portStatus);
                if (value & PORT_STATUS_IC)
                        break;
+               spin_unlock_irqrestore(&qdev->hw_lock, hw_flags);
                msleep(500);
+               spin_lock_irqsave(&qdev->hw_lock, hw_flags);
        } while (--delay);
 
        if (delay == 0) {
index 156e02e8905ddc0b3ddc00bbdef4110bdb6ad165..6ed5317ab1c09a11d6d71eb05c7046f19cfe9bad 100644 (file)
@@ -1607,6 +1607,8 @@ int ql_mb_get_fw_state(struct ql_adapter *qdev);
 int ql_cam_route_initialize(struct ql_adapter *qdev);
 int ql_read_mpi_reg(struct ql_adapter *qdev, u32 reg, u32 *data);
 int ql_mb_about_fw(struct ql_adapter *qdev);
+void ql_link_on(struct ql_adapter *qdev);
+void ql_link_off(struct ql_adapter *qdev);
 
 #if 1
 #define QL_ALL_DUMP
index 37c99fe79770fc78de8c6a9cec9c15a743f50bef..eb6a9ee640ed9fdb2711d4244732ba17fca136e3 100644 (file)
@@ -59,7 +59,7 @@ static int ql_update_ring_coalescing(struct ql_adapter *qdev)
                        cqicb->pkt_delay =
                            cpu_to_le16(qdev->tx_max_coalesced_frames);
                        cqicb->flags = FLAGS_LI;
-                       status = ql_write_cfg(qdev, cqicb, sizeof(cqicb),
+                       status = ql_write_cfg(qdev, cqicb, sizeof(*cqicb),
                                                CFG_LCQ, rx_ring->cq_id);
                        if (status) {
                                QPRINTK(qdev, IFUP, ERR,
@@ -82,7 +82,7 @@ static int ql_update_ring_coalescing(struct ql_adapter *qdev)
                        cqicb->pkt_delay =
                            cpu_to_le16(qdev->rx_max_coalesced_frames);
                        cqicb->flags = FLAGS_LI;
-                       status = ql_write_cfg(qdev, cqicb, sizeof(cqicb),
+                       status = ql_write_cfg(qdev, cqicb, sizeof(*cqicb),
                                                CFG_LCQ, rx_ring->cq_id);
                        if (status) {
                                QPRINTK(qdev, IFUP, ERR,
index 90d1f76c0e8b074729047d5d7aed9440b8d8315f..5768af17f168b668a28e55bc65460a82cd87ef03 100644 (file)
@@ -214,6 +214,10 @@ int ql_write_cfg(struct ql_adapter *qdev, void *ptr, int size, u32 bit,
                return -ENOMEM;
        }
 
+       status = ql_sem_spinlock(qdev, SEM_ICB_MASK);
+       if (status)
+               return status;
+
        status = ql_wait_cfg(qdev, bit);
        if (status) {
                QPRINTK(qdev, IFUP, ERR,
@@ -221,12 +225,8 @@ int ql_write_cfg(struct ql_adapter *qdev, void *ptr, int size, u32 bit,
                goto exit;
        }
 
-       status = ql_sem_spinlock(qdev, SEM_ICB_MASK);
-       if (status)
-               goto exit;
        ql_write32(qdev, ICB_L, (u32) map);
        ql_write32(qdev, ICB_H, (u32) (map >> 32));
-       ql_sem_unlock(qdev, SEM_ICB_MASK);      /* does flush too */
 
        mask = CFG_Q_MASK | (bit << 16);
        value = bit | (q_id << CFG_Q_SHIFT);
@@ -237,6 +237,7 @@ int ql_write_cfg(struct ql_adapter *qdev, void *ptr, int size, u32 bit,
         */
        status = ql_wait_cfg(qdev, bit);
 exit:
+       ql_sem_unlock(qdev, SEM_ICB_MASK);      /* does flush too */
        pci_unmap_single(qdev->pdev, map, size, direction);
        return status;
 }
@@ -412,6 +413,57 @@ exit:
        return status;
 }
 
+/* Set or clear MAC address in hardware. We sometimes
+ * have to clear it to prevent wrong frame routing
+ * especially in a bonding environment.
+ */
+static int ql_set_mac_addr(struct ql_adapter *qdev, int set)
+{
+       int status;
+       char zero_mac_addr[ETH_ALEN];
+       char *addr;
+
+       if (set) {
+               addr = &qdev->ndev->dev_addr[0];
+               QPRINTK(qdev, IFUP, DEBUG,
+                       "Set Mac addr %02x:%02x:%02x:%02x:%02x:%02x\n",
+                       addr[0], addr[1], addr[2], addr[3],
+                       addr[4], addr[5]);
+       } else {
+               memset(zero_mac_addr, 0, ETH_ALEN);
+               addr = &zero_mac_addr[0];
+               QPRINTK(qdev, IFUP, DEBUG,
+                               "Clearing MAC address on %s\n",
+                               qdev->ndev->name);
+       }
+       status = ql_sem_spinlock(qdev, SEM_MAC_ADDR_MASK);
+       if (status)
+               return status;
+       status = ql_set_mac_addr_reg(qdev, (u8 *) addr,
+                       MAC_ADDR_TYPE_CAM_MAC, qdev->func * MAX_CQ);
+       ql_sem_unlock(qdev, SEM_MAC_ADDR_MASK);
+       if (status)
+               QPRINTK(qdev, IFUP, ERR, "Failed to init mac "
+                       "address.\n");
+       return status;
+}
+
+void ql_link_on(struct ql_adapter *qdev)
+{
+       QPRINTK(qdev, LINK, ERR, "%s: Link is up.\n",
+                                qdev->ndev->name);
+       netif_carrier_on(qdev->ndev);
+       ql_set_mac_addr(qdev, 1);
+}
+
+void ql_link_off(struct ql_adapter *qdev)
+{
+       QPRINTK(qdev, LINK, ERR, "%s: Link is down.\n",
+                                qdev->ndev->name);
+       netif_carrier_off(qdev->ndev);
+       ql_set_mac_addr(qdev, 0);
+}
+
 /* Get a specific frame routing value from the CAM.
  * Used for debug and reg dump.
  */
@@ -1628,7 +1680,7 @@ static void ql_process_mac_tx_intr(struct ql_adapter *qdev,
        tx_ring = &qdev->tx_ring[mac_rsp->txq_idx];
        tx_ring_desc = &tx_ring->q[mac_rsp->tid];
        ql_unmap_send(qdev, tx_ring_desc, tx_ring_desc->map_cnt);
-       qdev->stats.tx_bytes += tx_ring_desc->map_cnt;
+       qdev->stats.tx_bytes += (tx_ring_desc->skb)->len;
        qdev->stats.tx_packets++;
        dev_kfree_skb(tx_ring_desc->skb);
        tx_ring_desc->skb = NULL;
@@ -1660,13 +1712,13 @@ static void ql_process_mac_tx_intr(struct ql_adapter *qdev,
 /* Fire up a handler to reset the MPI processor. */
 void ql_queue_fw_error(struct ql_adapter *qdev)
 {
-       netif_carrier_off(qdev->ndev);
+       ql_link_off(qdev);
        queue_delayed_work(qdev->workqueue, &qdev->mpi_reset_work, 0);
 }
 
 void ql_queue_asic_error(struct ql_adapter *qdev)
 {
-       netif_carrier_off(qdev->ndev);
+       ql_link_off(qdev);
        ql_disable_interrupts(qdev);
        /* Clear adapter up bit to signal the recovery
         * process that it shouldn't kill the reset worker
@@ -2104,7 +2156,7 @@ static int qlge_send(struct sk_buff *skb, struct net_device *ndev)
        }
        tx_ring_desc = &tx_ring->q[tx_ring->prod_idx];
        mac_iocb_ptr = tx_ring_desc->queue_entry;
-       memset((void *)mac_iocb_ptr, 0, sizeof(mac_iocb_ptr));
+       memset((void *)mac_iocb_ptr, 0, sizeof(*mac_iocb_ptr));
 
        mac_iocb_ptr->opcode = OPCODE_OB_MAC_IOCB;
        mac_iocb_ptr->tid = tx_ring_desc->index;
@@ -2743,7 +2795,7 @@ static int ql_start_tx_ring(struct ql_adapter *qdev, struct tx_ring *tx_ring)
 
        ql_init_tx_ring(qdev, tx_ring);
 
-       err = ql_write_cfg(qdev, wqicb, sizeof(wqicb), CFG_LRQ,
+       err = ql_write_cfg(qdev, wqicb, sizeof(*wqicb), CFG_LRQ,
                           (u16) tx_ring->wq_id);
        if (err) {
                QPRINTK(qdev, IFUP, ERR, "Failed to load tx_ring.\n");
@@ -3008,7 +3060,7 @@ static int ql_start_rss(struct ql_adapter *qdev)
        int i;
        u8 *hash_id = (u8 *) ricb->hash_cq_id;
 
-       memset((void *)ricb, 0, sizeof(ricb));
+       memset((void *)ricb, 0, sizeof(*ricb));
 
        ricb->base_cq = qdev->rss_ring_first_cq_id | RSS_L4K;
        ricb->flags =
@@ -3030,7 +3082,7 @@ static int ql_start_rss(struct ql_adapter *qdev)
 
        QPRINTK(qdev, IFUP, DEBUG, "Initializing RSS.\n");
 
-       status = ql_write_cfg(qdev, ricb, sizeof(ricb), CFG_LR, 0);
+       status = ql_write_cfg(qdev, ricb, sizeof(*ricb), CFG_LR, 0);
        if (status) {
                QPRINTK(qdev, IFUP, ERR, "Failed to load RICB.\n");
                return status;
@@ -3039,25 +3091,40 @@ static int ql_start_rss(struct ql_adapter *qdev)
        return status;
 }
 
-/* Initialize the frame-to-queue routing. */
-static int ql_route_initialize(struct ql_adapter *qdev)
+static int ql_clear_routing_entries(struct ql_adapter *qdev)
 {
-       int status = 0;
-       int i;
+       int i, status = 0;
 
        status = ql_sem_spinlock(qdev, SEM_RT_IDX_MASK);
        if (status)
                return status;
-
        /* Clear all the entries in the routing table. */
        for (i = 0; i < 16; i++) {
                status = ql_set_routing_reg(qdev, i, 0, 0);
                if (status) {
                        QPRINTK(qdev, IFUP, ERR,
-                               "Failed to init routing register for CAM packets.\n");
-                       goto exit;
+                               "Failed to init routing register for CAM "
+                               "packets.\n");
+                       break;
                }
        }
+       ql_sem_unlock(qdev, SEM_RT_IDX_MASK);
+       return status;
+}
+
+/* Initialize the frame-to-queue routing. */
+static int ql_route_initialize(struct ql_adapter *qdev)
+{
+       int status = 0;
+
+       status = ql_sem_spinlock(qdev, SEM_RT_IDX_MASK);
+       if (status)
+               return status;
+
+       /* Clear all the entries in the routing table. */
+       status = ql_clear_routing_entries(qdev);
+       if (status)
+               goto exit;
 
        status = ql_set_routing_reg(qdev, RT_IDX_ALL_ERR_SLOT, RT_IDX_ERR, 1);
        if (status) {
@@ -3096,14 +3163,15 @@ exit:
 
 int ql_cam_route_initialize(struct ql_adapter *qdev)
 {
-       int status;
+       int status, set;
 
-       status = ql_sem_spinlock(qdev, SEM_MAC_ADDR_MASK);
-       if (status)
-               return status;
-       status = ql_set_mac_addr_reg(qdev, (u8 *) qdev->ndev->perm_addr,
-                            MAC_ADDR_TYPE_CAM_MAC, qdev->func * MAX_CQ);
-       ql_sem_unlock(qdev, SEM_MAC_ADDR_MASK);
+       /* If check if the link is up and use to
+        * determine if we are setting or clearing
+        * the MAC address in the CAM.
+        */
+       set = ql_read32(qdev, STS);
+       set &= qdev->port_link_up;
+       status = ql_set_mac_addr(qdev, set);
        if (status) {
                QPRINTK(qdev, IFUP, ERR, "Failed to init mac address.\n");
                return status;
@@ -3210,9 +3278,17 @@ static int ql_adapter_reset(struct ql_adapter *qdev)
 {
        u32 value;
        int status = 0;
-       unsigned long end_jiffies = jiffies +
-               max((unsigned long)1, usecs_to_jiffies(30));
+       unsigned long end_jiffies;
 
+       /* Clear all the entries in the routing table. */
+       status = ql_clear_routing_entries(qdev);
+       if (status) {
+               QPRINTK(qdev, IFUP, ERR, "Failed to clear routing bits.\n");
+               return status;
+       }
+
+       end_jiffies = jiffies +
+               max((unsigned long)1, usecs_to_jiffies(30));
        ql_write32(qdev, RST_FO, (RST_FO_FR << 16) | RST_FO_FR);
 
        do {
@@ -3252,7 +3328,7 @@ static int ql_adapter_down(struct ql_adapter *qdev)
        int i, status = 0;
        struct rx_ring *rx_ring;
 
-       netif_carrier_off(qdev->ndev);
+       ql_link_off(qdev);
 
        /* Don't kill the reset worker thread if we
         * are in the process of recovery.
@@ -3319,8 +3395,12 @@ static int ql_adapter_up(struct ql_adapter *qdev)
        }
        set_bit(QL_ADAPTER_UP, &qdev->flags);
        ql_alloc_rx_buffers(qdev);
-       if ((ql_read32(qdev, STS) & qdev->port_init))
-               netif_carrier_on(qdev->ndev);
+       /* If the port is initialized and the
+        * link is up the turn on the carrier.
+        */
+       if ((ql_read32(qdev, STS) & qdev->port_init) &&
+                       (ql_read32(qdev, STS) & qdev->port_link_up))
+               ql_link_on(qdev);
        ql_enable_interrupts(qdev);
        ql_enable_all_completion_interrupts(qdev);
        netif_tx_start_all_queues(qdev->ndev);
@@ -3346,11 +3426,6 @@ static int ql_get_adapter_resources(struct ql_adapter *qdev)
                return -ENOMEM;
        }
        status = ql_request_irq(qdev);
-       if (status)
-               goto err_irq;
-       return status;
-err_irq:
-       ql_free_mem_resources(qdev);
        return status;
 }
 
@@ -3414,7 +3489,7 @@ static int ql_configure_rings(struct ql_adapter *qdev)
 
        for (i = 0; i < qdev->tx_ring_count; i++) {
                tx_ring = &qdev->tx_ring[i];
-               memset((void *)tx_ring, 0, sizeof(tx_ring));
+               memset((void *)tx_ring, 0, sizeof(*tx_ring));
                tx_ring->qdev = qdev;
                tx_ring->wq_id = i;
                tx_ring->wq_len = qdev->tx_ring_size;
@@ -3430,7 +3505,7 @@ static int ql_configure_rings(struct ql_adapter *qdev)
 
        for (i = 0; i < qdev->rx_ring_count; i++) {
                rx_ring = &qdev->rx_ring[i];
-               memset((void *)rx_ring, 0, sizeof(rx_ring));
+               memset((void *)rx_ring, 0, sizeof(*rx_ring));
                rx_ring->qdev = qdev;
                rx_ring->cq_id = i;
                rx_ring->cpu = i % cpu_cnt;     /* CPU to run handler on. */
@@ -3789,7 +3864,7 @@ static int __devinit ql_init_device(struct pci_dev *pdev,
        int pos, err = 0;
        u16 val16;
 
-       memset((void *)qdev, 0, sizeof(qdev));
+       memset((void *)qdev, 0, sizeof(*qdev));
        err = pci_enable_device(pdev);
        if (err) {
                dev_err(&pdev->dev, "PCI device enable failed.\n");
@@ -3976,7 +4051,7 @@ static int __devinit qlge_probe(struct pci_dev *pdev,
                pci_disable_device(pdev);
                return err;
        }
-       netif_carrier_off(ndev);
+       ql_link_off(qdev);
        ql_display_dev_info(ndev);
        cards_found++;
        return 0;
index 71afbf8b9c50c23d9c36acbc788dcda20d7e5336..6685bd97da91f211452743dd7cfd9c5ae77996a3 100644 (file)
@@ -238,7 +238,7 @@ static void ql_link_up(struct ql_adapter *qdev, struct mbox_params *mbcp)
                                &qdev->mpi_port_cfg_work, 0);
        }
 
-       netif_carrier_on(qdev->ndev);
+       ql_link_on(qdev);
 }
 
 static void ql_link_down(struct ql_adapter *qdev, struct mbox_params *mbcp)
@@ -251,7 +251,7 @@ static void ql_link_down(struct ql_adapter *qdev, struct mbox_params *mbcp)
        if (status)
                QPRINTK(qdev, DRV, ERR, "Link down AEN broken!\n");
 
-       netif_carrier_off(qdev->ndev);
+       ql_link_off(qdev);
 }
 
 static int ql_sfp_in(struct ql_adapter *qdev, struct mbox_params *mbcp)
@@ -849,7 +849,7 @@ void ql_mpi_idc_work(struct work_struct *work)
        case MB_CMD_PORT_RESET:
        case MB_CMD_SET_PORT_CFG:
        case MB_CMD_STOP_FW:
-               netif_carrier_off(qdev->ndev);
+               ql_link_off(qdev);
                /* Signal the resulting link up AEN
                 * that the frame routing and mac addr
                 * needs to be set.
index ed63d23a645233f9da9a6e88abb51632fdf5f98d..961b5397a531ea3800ccf43ac4f9b12a7e6849c2 100644 (file)
@@ -49,8 +49,8 @@
 #include <asm/processor.h>
 
 #define DRV_NAME       "r6040"
-#define DRV_VERSION    "0.23"
-#define DRV_RELDATE    "05May2009"
+#define DRV_VERSION    "0.24"
+#define DRV_RELDATE    "08Jul2009"
 
 /* PHY CHIP Address */
 #define PHY1_ADDR      1       /* For MAC1 */
@@ -704,8 +704,11 @@ static irqreturn_t r6040_interrupt(int irq, void *dev_id)
        /* Read MISR status and clear */
        status = ioread16(ioaddr + MISR);
 
-       if (status == 0x0000 || status == 0xffff)
+       if (status == 0x0000 || status == 0xffff) {
+               /* Restore RDC MAC interrupt */
+               iowrite16(misr, ioaddr + MIER);
                return IRQ_NONE;
+       }
 
        /* RX interrupt request */
        if (status & RX_INTS) {
index 341882f959f3c9eb12de2cb5afa4b422062c5636..a2d82ddb3b4d790bc70c1ec4a87ed873eef3d8b1 100644 (file)
@@ -865,8 +865,7 @@ static irqreturn_t sh_eth_interrupt(int irq, void *netdev)
        struct sh_eth_private *mdp = netdev_priv(ndev);
        struct sh_eth_cpu_data *cd = mdp->cd;
        irqreturn_t ret = IRQ_NONE;
-       u32 ioaddr, boguscnt = RX_RING_SIZE;
-       u32 intr_status = 0;
+       u32 ioaddr, intr_status = 0;
 
        ioaddr = ndev->base_addr;
        spin_lock(&mdp->lock);
@@ -901,12 +900,6 @@ static irqreturn_t sh_eth_interrupt(int irq, void *netdev)
        if (intr_status & cd->eesr_err_check)
                sh_eth_error(ndev, intr_status);
 
-       if (--boguscnt < 0) {
-               printk(KERN_WARNING
-                      "%s: Too much work at interrupt, status=0x%4.4x.\n",
-                      ndev->name, intr_status);
-       }
-
 other_irq:
        spin_unlock(&mdp->lock);
 
index 7681d28c53d7778a15c1795e786aaf72d875b79a..daf961ab68bc27e3fa16ddea89784aa0091b42e2 100644 (file)
@@ -2495,7 +2495,7 @@ static int sky2_status_intr(struct sky2_hw *hw, int to_do, u16 idx)
                        if (likely(status >> 16 == (status & 0xffff))) {
                                skb = sky2->rx_ring[sky2->rx_next].skb;
                                skb->ip_summed = CHECKSUM_COMPLETE;
-                               skb->csum = status & 0xffff;
+                               skb->csum = le16_to_cpu(status);
                        } else {
                                printk(KERN_NOTICE PFX "%s: hardware receive "
                                       "checksum problem (status = %#x)\n",
index fdcbaf8dfa739618a5a8f25bc27f6c24222e8004..1c70e999cc50d866ab5ebdba0956b25bba83659d 100644 (file)
@@ -1774,6 +1774,7 @@ static const struct net_device_ops smc_netdev_ops = {
        .ndo_start_xmit         = smc_hard_start_xmit,
        .ndo_tx_timeout         = smc_timeout,
        .ndo_set_multicast_list = smc_set_multicast_list,
+       .ndo_change_mtu         = eth_change_mtu,
        .ndo_validate_addr      = eth_validate_addr,
        .ndo_set_mac_address    = eth_mac_addr,
 #ifdef CONFIG_NET_POLL_CONTROLLER
index b60639bd181b998738185a5d6ceaa1f6059339ad..94b6d2658ddc016cea883126e276bbf4c0c936bf 100644 (file)
@@ -1779,6 +1779,7 @@ static const struct net_device_ops smsc911x_netdev_ops = {
        .ndo_get_stats          = smsc911x_get_stats,
        .ndo_set_multicast_list = smsc911x_set_multicast_list,
        .ndo_do_ioctl           = smsc911x_do_ioctl,
+       .ndo_change_mtu         = eth_change_mtu,
        .ndo_validate_addr      = eth_validate_addr,
        .ndo_set_mac_address    = smsc911x_set_mac_address,
 #ifdef CONFIG_NET_POLL_CONTROLLER
@@ -1938,7 +1939,7 @@ static int __devexit smsc911x_drv_remove(struct platform_device *pdev)
        if (!res)
                res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 
-       release_mem_region(res->start, res->end - res->start);
+       release_mem_region(res->start, resource_size(res));
 
        iounmap(pdata->ioaddr);
 
@@ -1976,7 +1977,7 @@ static int __devinit smsc911x_drv_probe(struct platform_device *pdev)
                retval = -ENODEV;
                goto out_0;
        }
-       res_size = res->end - res->start + 1;
+       res_size = resource_size(res);
 
        irq_res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
        if (!irq_res) {
@@ -2104,7 +2105,7 @@ out_unmap_io_3:
 out_free_netdev_2:
        free_netdev(dev);
 out_release_io_1:
-       release_mem_region(res->start, res->end - res->start);
+       release_mem_region(res->start, resource_size(res));
 out_0:
        return retval;
 }
index 838cce8b8fff3969286408536ad92b06f36e6063..669253c7bd41f871800f4a50c1886cbf9efae007 100644 (file)
@@ -180,7 +180,7 @@ static int full_duplex[MAX_UNITS] = {0, };
 /* These identify the driver base version and may not be removed. */
 static const char version[] __devinitconst =
 KERN_INFO "starfire.c:v1.03 7/26/2000  Written by Donald Becker <becker@scyld.com>\n"
-KERN_INFO " (unofficial 2.2/2.4 kernel port, version " DRV_VERSION ", " DRV_RELDATE ")\n";
+" (unofficial 2.2/2.4 kernel port, version " DRV_VERSION ", " DRV_RELDATE ")\n";
 
 MODULE_AUTHOR("Donald Becker <becker@scyld.com>");
 MODULE_DESCRIPTION("Adaptec Starfire Ethernet driver");
index 545f81b34ad7ee7ba8e055e90135437e98bdc87b..d1521c3875b2d6dd41ca81fc152cdfc841762368 100644 (file)
@@ -1698,13 +1698,13 @@ static int netdev_close(struct net_device *dev)
 
 #ifdef __i386__
        if (netif_msg_hw(np)) {
-               printk("\n"KERN_DEBUG"  Tx ring at %8.8x:\n",
+               printk(KERN_DEBUG "  Tx ring at %8.8x:\n",
                           (int)(np->tx_ring_dma));
                for (i = 0; i < TX_RING_SIZE; i++)
-                       printk(" #%d desc. %4.4x %8.8x %8.8x.\n",
+                       printk(KERN_DEBUG " #%d desc. %4.4x %8.8x %8.8x.\n",
                                   i, np->tx_ring[i].status, np->tx_ring[i].frag[0].addr,
                                   np->tx_ring[i].frag[0].length);
-               printk("\n"KERN_DEBUG "  Rx ring %8.8x:\n",
+               printk(KERN_DEBUG "  Rx ring %8.8x:\n",
                           (int)(np->rx_ring_dma));
                for (i = 0; i < /*RX_RING_SIZE*/4 ; i++) {
                        printk(KERN_DEBUG " #%d desc. %4.4x %4.4x %8.8x\n",
index a82fb2aca4cb7d89fe52e8bb31dfe4b6eacac505..f1e5e4542c2a04084b419c990e67760e05253f82 100644 (file)
@@ -1016,7 +1016,9 @@ static const struct net_device_ops vnet_ops = {
        .ndo_open               = vnet_open,
        .ndo_stop               = vnet_close,
        .ndo_set_multicast_list = vnet_set_rx_mode,
+       .ndo_change_mtu         = eth_change_mtu,
        .ndo_set_mac_address    = vnet_set_mac_addr,
+       .ndo_validate_addr      = eth_validate_addr,
        .ndo_tx_timeout         = vnet_tx_timeout,
        .ndo_change_mtu         = vnet_change_mtu,
        .ndo_start_xmit         = vnet_start_xmit,
index 0f78f99f9b20ca247573e46d7b78dd8c7566abb9..7030bd5e9848e1582160b4414365086bc22972ca 100644 (file)
@@ -1132,7 +1132,9 @@ static int tsi108_get_mac(struct net_device *dev)
        }
 
        if (!is_valid_ether_addr(dev->dev_addr)) {
-               printk("KERN_ERR: word1: %08x, word2: %08x\n", word1, word2);
+               printk(KERN_ERR
+                      "%s: Invalid MAC address. word1: %08x, word2: %08x\n",
+                      dev->name, word1, word2);
                return -EINVAL;
        }
 
@@ -1201,8 +1203,8 @@ static void tsi108_set_rx_mode(struct net_device *dev)
                                __set_bit(hash, &data->mc_hash[0]);
                        } else {
                                printk(KERN_ERR
-                                      "%s: got multicast address of length %d "
-                                      "instead of 6.\n", dev->name,
+               "%s: got multicast address of length %d instead of 6.\n",
+                                      dev->name,
                                       mc->dmi_addrlen);
                        }
 
index 81f054dbb88ddb2712bc6d60921f857c3920a05e..ef49744a508520124e2970538e880df4b48b8cae 100644 (file)
@@ -944,9 +944,10 @@ static void de_set_media (struct de_private *de)
                macmode &= ~FullDuplex;
 
        if (netif_msg_link(de)) {
-               printk(KERN_INFO "%s: set link %s\n"
-                      KERN_INFO "%s:    mode 0x%x, sia 0x%x,0x%x,0x%x,0x%x\n"
-                      KERN_INFO "%s:    set mode 0x%x, set sia 0x%x,0x%x,0x%x\n",
+               printk(KERN_INFO
+                      "%s: set link %s\n"
+                      "%s:    mode 0x%x, sia 0x%x,0x%x,0x%x,0x%x\n"
+                      "%s:    set mode 0x%x, set sia 0x%x,0x%x,0x%x\n",
                       de->dev->name, media_name[media],
                       de->dev->name, dr32(MacMode), dr32(SIAStatus),
                       dr32(CSR13), dr32(CSR14), dr32(CSR15),
index 2abb5d3becc6d2d98ec7613b42c0f05b8b439352..99a63649f4fcd1b75c807398fe9a872fb38c3bd1 100644 (file)
@@ -570,16 +570,18 @@ static void tulip_tx_timeout(struct net_device *dev)
                                   (unsigned int)tp->rx_ring[i].buffer2,
                                   buf[0], buf[1], buf[2]);
                        for (j = 0; buf[j] != 0xee && j < 1600; j++)
-                               if (j < 100) printk(" %2.2x", buf[j]);
-                       printk(" j=%d.\n", j);
+                               if (j < 100)
+                                       printk(KERN_CONT " %2.2x", buf[j]);
+                       printk(KERN_CONT " j=%d.\n", j);
                }
                printk(KERN_DEBUG "  Rx ring %8.8x: ", (int)tp->rx_ring);
                for (i = 0; i < RX_RING_SIZE; i++)
-                       printk(" %8.8x", (unsigned int)tp->rx_ring[i].status);
-               printk("\n" KERN_DEBUG "  Tx ring %8.8x: ", (int)tp->tx_ring);
+                       printk(KERN_CONT " %8.8x",
+                              (unsigned int)tp->rx_ring[i].status);
+               printk(KERN_DEBUG "  Tx ring %8.8x: ", (int)tp->tx_ring);
                for (i = 0; i < TX_RING_SIZE; i++)
-                       printk(" %8.8x", (unsigned int)tp->tx_ring[i].status);
-               printk("\n");
+                       printk(KERN_CONT " %8.8x", (unsigned int)tp->tx_ring[i].status);
+               printk(KERN_CONT "\n");
        }
 #endif
 
index 842b1a2c40d4abed18d9d241c8759f1daaaae8be..0f15773dae528374dd94a36ebb4f73025af51eb2 100644 (file)
@@ -142,7 +142,7 @@ static int full_duplex[MAX_UNITS] = {-1, -1, -1, -1, -1, -1, -1, -1};
 static const char version[] __initconst =
        KERN_INFO DRV_NAME ".c:v" DRV_VERSION " (2.4 port) "
        DRV_RELDATE "  Donald Becker <becker@scyld.com>\n"
-       KERN_INFO "  http://www.scyld.com/network/drivers.html\n";
+       "  http://www.scyld.com/network/drivers.html\n";
 
 MODULE_AUTHOR("Donald Becker <becker@scyld.com>");
 MODULE_DESCRIPTION("Winbond W89c840 Ethernet driver");
@@ -939,7 +939,7 @@ static void tx_timeout(struct net_device *dev)
                printk(KERN_DEBUG "  Rx ring %p: ", np->rx_ring);
                for (i = 0; i < RX_RING_SIZE; i++)
                        printk(" %8.8x", (unsigned int)np->rx_ring[i].status);
-               printk("\n"KERN_DEBUG"  Tx ring %p: ", np->tx_ring);
+               printk(KERN_DEBUG"  Tx ring %p: ", np->tx_ring);
                for (i = 0; i < TX_RING_SIZE; i++)
                        printk(" %8.8x", np->tx_ring[i].status);
                printk("\n");
@@ -1520,7 +1520,7 @@ static int netdev_close(struct net_device *dev)
                        printk(KERN_DEBUG " #%d desc. %4.4x %4.4x %8.8x.\n",
                                   i, np->tx_ring[i].length,
                                   np->tx_ring[i].status, np->tx_ring[i].buffer1);
-               printk("\n"KERN_DEBUG "  Rx ring %8.8x:\n",
+               printk(KERN_DEBUG "  Rx ring %8.8x:\n",
                           (int)np->rx_ring);
                for (i = 0; i < RX_RING_SIZE; i++) {
                        printk(KERN_DEBUG " #%d desc. %4.4x %4.4x %8.8x\n",
index 11a0ba47b67782d920f3bf5cb36d3e24d4874b63..027f7aba26af1d339dad5081a1ae8167b34c3d8c 100644 (file)
@@ -486,12 +486,14 @@ static unsigned int tun_chr_poll(struct file *file, poll_table * wait)
 {
        struct tun_file *tfile = file->private_data;
        struct tun_struct *tun = __tun_get(tfile);
-       struct sock *sk = tun->sk;
+       struct sock *sk;
        unsigned int mask = 0;
 
        if (!tun)
                return POLLERR;
 
+       sk = tun->sk;
+
        DBG(KERN_INFO "%s: tun_chr_poll\n", tun->dev->name);
 
        poll_wait(file, &tun->socket.wait, wait);
@@ -1324,20 +1326,22 @@ static int tun_chr_close(struct inode *inode, struct file *file)
        struct tun_file *tfile = file->private_data;
        struct tun_struct *tun;
 
-
-       rtnl_lock();
        tun = __tun_get(tfile);
        if (tun) {
-               DBG(KERN_INFO "%s: tun_chr_close\n", tun->dev->name);
+               struct net_device *dev = tun->dev;
+
+               DBG(KERN_INFO "%s: tun_chr_close\n", dev->name);
 
                __tun_detach(tun);
 
                /* If desireable, unregister the netdevice. */
-               if (!(tun->flags & TUN_PERSIST))
-                       unregister_netdevice(tun->dev);
-
+               if (!(tun->flags & TUN_PERSIST)) {
+                       rtnl_lock();
+                       if (dev->reg_state == NETREG_REGISTERED)
+                               unregister_netdevice(dev);
+                       rtnl_unlock();
+               }
        }
-       rtnl_unlock();
 
        tun = tfile->tun;
        if (tun)
index 80e01778dd3bae3bd4c8c52456188520d620870d..cd35d50e46d4686982f9b285c7967cfb00a381de 100644 (file)
@@ -319,7 +319,7 @@ static int eem_rx_fixup(struct usbnet *dev, struct sk_buff *skb)
                                return crc == crc2;
 
                        if (unlikely(crc != crc2)) {
-                               dev->stats.rx_errors++;
+                               dev->net->stats.rx_errors++;
                                dev_kfree_skb_any(skb2);
                        } else
                                usbnet_skb_return(dev, skb2);
index 7ae82446b93aed59f3dd646f5df5767ab3feb74f..1d3730d6690fc90c640ac87bc655f04b19ad5eff 100644 (file)
@@ -513,11 +513,11 @@ static int dm9601_rx_fixup(struct usbnet *dev, struct sk_buff *skb)
        len = (skb->data[1] | (skb->data[2] << 8)) - 4;
 
        if (unlikely(status & 0xbf)) {
-               if (status & 0x01) dev->stats.rx_fifo_errors++;
-               if (status & 0x02) dev->stats.rx_crc_errors++;
-               if (status & 0x04) dev->stats.rx_frame_errors++;
-               if (status & 0x20) dev->stats.rx_missed_errors++;
-               if (status & 0x90) dev->stats.rx_length_errors++;
+               if (status & 0x01) dev->net->stats.rx_fifo_errors++;
+               if (status & 0x02) dev->net->stats.rx_crc_errors++;
+               if (status & 0x04) dev->net->stats.rx_frame_errors++;
+               if (status & 0x20) dev->net->stats.rx_missed_errors++;
+               if (status & 0x90) dev->net->stats.rx_length_errors++;
                return 0;
        }
 
index e0131478971829902dd2f8e836f7b17d0d74aeda..1f9ec29fce5042fc3a17f16f4a1c0708b9e6e50c 100644 (file)
@@ -999,6 +999,9 @@ static const struct net_device_ops kaweth_netdev_ops = {
        .ndo_tx_timeout =               kaweth_tx_timeout,
        .ndo_set_multicast_list =       kaweth_set_rx_mode,
        .ndo_get_stats =                kaweth_netdev_stats,
+       .ndo_change_mtu =               eth_change_mtu,
+       .ndo_set_mac_address =          eth_mac_addr,
+       .ndo_validate_addr =            eth_validate_addr,
 };
 
 static int kaweth_probe(
index 034e8a73ca6b487dc7ab32e02ba11d77d71ab72e..aeb1ab03a9ee650e8aa7c732eac56b7e2585b86d 100644 (file)
@@ -433,7 +433,7 @@ static int net1080_rx_fixup(struct usbnet *dev, struct sk_buff *skb)
                dbg("rx framesize %d range %d..%d mtu %d", skb->len,
                        net->hard_header_len, dev->hard_mtu, net->mtu);
 #endif
-               dev->stats.rx_frame_errors++;
+               dev->net->stats.rx_frame_errors++;
                nc_ensure_sync(dev);
                return 0;
        }
@@ -442,12 +442,12 @@ static int net1080_rx_fixup(struct usbnet *dev, struct sk_buff *skb)
        hdr_len = le16_to_cpup(&header->hdr_len);
        packet_len = le16_to_cpup(&header->packet_len);
        if (FRAMED_SIZE(packet_len) > NC_MAX_PACKET) {
-               dev->stats.rx_frame_errors++;
+               dev->net->stats.rx_frame_errors++;
                dbg("packet too big, %d", packet_len);
                nc_ensure_sync(dev);
                return 0;
        } else if (hdr_len < MIN_HEADER) {
-               dev->stats.rx_frame_errors++;
+               dev->net->stats.rx_frame_errors++;
                dbg("header too short, %d", hdr_len);
                nc_ensure_sync(dev);
                return 0;
@@ -465,21 +465,21 @@ static int net1080_rx_fixup(struct usbnet *dev, struct sk_buff *skb)
 
        if ((packet_len & 0x01) == 0) {
                if (skb->data [packet_len] != PAD_BYTE) {
-                       dev->stats.rx_frame_errors++;
+                       dev->net->stats.rx_frame_errors++;
                        dbg("bad pad");
                        return 0;
                }
                skb_trim(skb, skb->len - 1);
        }
        if (skb->len != packet_len) {
-               dev->stats.rx_frame_errors++;
+               dev->net->stats.rx_frame_errors++;
                dbg("bad packet len %d (expected %d)",
                        skb->len, packet_len);
                nc_ensure_sync(dev);
                return 0;
        }
        if (header->packet_id != get_unaligned(&trailer->packet_id)) {
-               dev->stats.rx_fifo_errors++;
+               dev->net->stats.rx_fifo_errors++;
                dbg("(2+ dropped) rx packet_id mismatch 0x%x 0x%x",
                        le16_to_cpu(header->packet_id),
                        le16_to_cpu(trailer->packet_id));
index 73acbd244aa106493cbdf7c3474937ee44e370f1..631d269ac980a8bb75647875dd1770241a48f5ba 100644 (file)
@@ -1493,6 +1493,9 @@ static const struct net_device_ops pegasus_netdev_ops = {
        .ndo_set_multicast_list =       pegasus_set_multicast,
        .ndo_get_stats =                pegasus_netdev_stats,
        .ndo_tx_timeout =               pegasus_tx_timeout,
+       .ndo_change_mtu =               eth_change_mtu,
+       .ndo_set_mac_address =          eth_mac_addr,
+       .ndo_validate_addr =            eth_validate_addr,
 };
 
 static struct usb_driver pegasus_driver = {
index 1bf243ef950e264e4a11ec86c900812db31e6a99..2232232b79899dab8b6ce2f621742961fb26f647 100644 (file)
@@ -487,7 +487,7 @@ int rndis_rx_fixup(struct usbnet *dev, struct sk_buff *skb)
                if (unlikely(hdr->msg_type != RNDIS_MSG_PACKET
                                || skb->len < msg_len
                                || (data_offset + data_len + 8) > msg_len)) {
-                       dev->stats.rx_frame_errors++;
+                       dev->net->stats.rx_frame_errors++;
                        devdbg(dev, "bad rndis message %d/%d/%d/%d, len %d",
                                le32_to_cpu(hdr->msg_type),
                                msg_len, data_offset, data_len, skb->len);
index 89a91f8c22dea051009a1a2c513f28fa9a9b600f..fe045896406bdbf3bffa7525621b31b535a265d5 100644 (file)
@@ -1108,18 +1108,18 @@ static int smsc95xx_rx_fixup(struct usbnet *dev, struct sk_buff *skb)
                if (unlikely(header & RX_STS_ES_)) {
                        if (netif_msg_rx_err(dev))
                                devdbg(dev, "Error header=0x%08x", header);
-                       dev->stats.rx_errors++;
-                       dev->stats.rx_dropped++;
+                       dev->net->stats.rx_errors++;
+                       dev->net->stats.rx_dropped++;
 
                        if (header & RX_STS_CRC_) {
-                               dev->stats.rx_crc_errors++;
+                               dev->net->stats.rx_crc_errors++;
                        } else {
                                if (header & (RX_STS_TL_ | RX_STS_RF_))
-                                       dev->stats.rx_frame_errors++;
+                                       dev->net->stats.rx_frame_errors++;
 
                                if ((header & RX_STS_LE_) &&
                                        (!(header & RX_STS_FT_)))
-                                       dev->stats.rx_length_errors++;
+                                       dev->net->stats.rx_length_errors++;
                        }
                } else {
                        /* ETH_FRAME_LEN + 4(CRC) + 2(COE) + 4(Vlan) */
index 22c0585a03198f75ea73b3974d394fc984a4ecc1..edfd9e10ceba28fcdc6454dd9c7f386a6ac9f6ac 100644 (file)
@@ -234,8 +234,8 @@ void usbnet_skb_return (struct usbnet *dev, struct sk_buff *skb)
        int     status;
 
        skb->protocol = eth_type_trans (skb, dev->net);
-       dev->stats.rx_packets++;
-       dev->stats.rx_bytes += skb->len;
+       dev->net->stats.rx_packets++;
+       dev->net->stats.rx_bytes += skb->len;
 
        if (netif_msg_rx_status (dev))
                devdbg (dev, "< rx, len %zu, type 0x%x",
@@ -397,7 +397,7 @@ static inline void rx_process (struct usbnet *dev, struct sk_buff *skb)
                if (netif_msg_rx_err (dev))
                        devdbg (dev, "drop");
 error:
-               dev->stats.rx_errors++;
+               dev->net->stats.rx_errors++;
                skb_queue_tail (&dev->done, skb);
        }
 }
@@ -420,8 +420,8 @@ static void rx_complete (struct urb *urb)
        case 0:
                if (skb->len < dev->net->hard_header_len) {
                        entry->state = rx_cleanup;
-                       dev->stats.rx_errors++;
-                       dev->stats.rx_length_errors++;
+                       dev->net->stats.rx_errors++;
+                       dev->net->stats.rx_length_errors++;
                        if (netif_msg_rx_err (dev))
                                devdbg (dev, "rx length %d", skb->len);
                }
@@ -433,7 +433,7 @@ static void rx_complete (struct urb *urb)
         * storm, recovering as needed.
         */
        case -EPIPE:
-               dev->stats.rx_errors++;
+               dev->net->stats.rx_errors++;
                usbnet_defer_kevent (dev, EVENT_RX_HALT);
                // FALLTHROUGH
 
@@ -451,7 +451,7 @@ static void rx_complete (struct urb *urb)
        case -EPROTO:
        case -ETIME:
        case -EILSEQ:
-               dev->stats.rx_errors++;
+               dev->net->stats.rx_errors++;
                if (!timer_pending (&dev->delay)) {
                        mod_timer (&dev->delay, jiffies + THROTTLE_JIFFIES);
                        if (netif_msg_link (dev))
@@ -465,12 +465,12 @@ block:
 
        /* data overrun ... flush fifo? */
        case -EOVERFLOW:
-               dev->stats.rx_over_errors++;
+               dev->net->stats.rx_over_errors++;
                // FALLTHROUGH
 
        default:
                entry->state = rx_cleanup;
-               dev->stats.rx_errors++;
+               dev->net->stats.rx_errors++;
                if (netif_msg_rx_err (dev))
                        devdbg (dev, "rx status %d", urb_status);
                break;
@@ -583,8 +583,8 @@ int usbnet_stop (struct net_device *net)
 
        if (netif_msg_ifdown (dev))
                devinfo (dev, "stop stats: rx/tx %ld/%ld, errs %ld/%ld",
-                       dev->stats.rx_packets, dev->stats.tx_packets,
-                       dev->stats.rx_errors, dev->stats.tx_errors
+                       net->stats.rx_packets, net->stats.tx_packets,
+                       net->stats.rx_errors, net->stats.tx_errors
                        );
 
        // ensure there are no more active urbs
@@ -891,10 +891,10 @@ static void tx_complete (struct urb *urb)
        struct usbnet           *dev = entry->dev;
 
        if (urb->status == 0) {
-               dev->stats.tx_packets++;
-               dev->stats.tx_bytes += entry->length;
+               dev->net->stats.tx_packets++;
+               dev->net->stats.tx_bytes += entry->length;
        } else {
-               dev->stats.tx_errors++;
+               dev->net->stats.tx_errors++;
 
                switch (urb->status) {
                case -EPIPE:
@@ -1020,7 +1020,7 @@ int usbnet_start_xmit (struct sk_buff *skb, struct net_device *net)
                        devdbg (dev, "drop, code %d", retval);
 drop:
                retval = NET_XMIT_SUCCESS;
-               dev->stats.tx_dropped++;
+               dev->net->stats.tx_dropped++;
                if (skb)
                        dev_kfree_skb_any (skb);
                usb_free_urb (urb);
index 87197dd9c78847b1eec6497ea331df660841bf83..1097c72e44d5ba3fbfa8c3930e0ee5872ea2b452 100644 (file)
@@ -208,11 +208,14 @@ rx_drop:
 
 static struct net_device_stats *veth_get_stats(struct net_device *dev)
 {
-       struct veth_priv *priv = netdev_priv(dev);
-       struct net_device_stats *dev_stats = &dev->stats;
-       unsigned int cpu;
+       struct veth_priv *priv;
+       struct net_device_stats *dev_stats;
+       int cpu;
        struct veth_net_stats *stats;
 
+       priv = netdev_priv(dev);
+       dev_stats = &dev->stats;
+
        dev_stats->rx_packets = 0;
        dev_stats->tx_packets = 0;
        dev_stats->rx_bytes = 0;
@@ -220,17 +223,16 @@ static struct net_device_stats *veth_get_stats(struct net_device *dev)
        dev_stats->tx_dropped = 0;
        dev_stats->rx_dropped = 0;
 
-       if (priv->stats)
-               for_each_online_cpu(cpu) {
-                       stats = per_cpu_ptr(priv->stats, cpu);
+       for_each_online_cpu(cpu) {
+               stats = per_cpu_ptr(priv->stats, cpu);
 
-                       dev_stats->rx_packets += stats->rx_packets;
-                       dev_stats->tx_packets += stats->tx_packets;
-                       dev_stats->rx_bytes += stats->rx_bytes;
-                       dev_stats->tx_bytes += stats->tx_bytes;
-                       dev_stats->tx_dropped += stats->tx_dropped;
-                       dev_stats->rx_dropped += stats->rx_dropped;
-               }
+               dev_stats->rx_packets += stats->rx_packets;
+               dev_stats->tx_packets += stats->tx_packets;
+               dev_stats->rx_bytes += stats->rx_bytes;
+               dev_stats->tx_bytes += stats->tx_bytes;
+               dev_stats->tx_dropped += stats->tx_dropped;
+               dev_stats->rx_dropped += stats->rx_dropped;
+       }
 
        return dev_stats;
 }
@@ -257,8 +259,6 @@ static int veth_close(struct net_device *dev)
        netif_carrier_off(dev);
        netif_carrier_off(priv->peer);
 
-       free_percpu(priv->stats);
-       priv->stats = NULL;
        return 0;
 }
 
@@ -289,6 +289,15 @@ static int veth_dev_init(struct net_device *dev)
        return 0;
 }
 
+static void veth_dev_free(struct net_device *dev)
+{
+       struct veth_priv *priv;
+
+       priv = netdev_priv(dev);
+       free_percpu(priv->stats);
+       free_netdev(dev);
+}
+
 static const struct net_device_ops veth_netdev_ops = {
        .ndo_init            = veth_dev_init,
        .ndo_open            = veth_open,
@@ -306,7 +315,7 @@ static void veth_setup(struct net_device *dev)
        dev->netdev_ops = &veth_netdev_ops;
        dev->ethtool_ops = &veth_ethtool_ops;
        dev->features |= NETIF_F_LLTX;
-       dev->destructor = free_netdev;
+       dev->destructor = veth_dev_free;
 }
 
 /*
index d3489a3c4c03b28907035181134c20ccb44b9233..88c30a58b4bda50d0b5fb610916365076cbdf1c5 100644 (file)
@@ -621,6 +621,7 @@ static const struct net_device_ops rhine_netdev_ops = {
        .ndo_start_xmit          = rhine_start_tx,
        .ndo_get_stats           = rhine_get_stats,
        .ndo_set_multicast_list  = rhine_set_rx_mode,
+       .ndo_change_mtu          = eth_change_mtu,
        .ndo_validate_addr       = eth_validate_addr,
        .ndo_set_mac_address     = eth_mac_addr,
        .ndo_do_ioctl            = netdev_ioctl,
index 223238de475cdf2ed8802334dfa8addca693f90f..1ea1ef6c3b96205ed787361d884ad786d4cdd404 100644 (file)
@@ -584,8 +584,9 @@ static void sca_dump_rings(struct net_device *dev)
               sca_in(DSR_RX(phy_node(port)), card) & DSR_DE ? "" : "in");
        for (cnt = 0; cnt < port_to_card(port)->rx_ring_buffers; cnt++)
                printk(" %02X", readb(&(desc_address(port, cnt, 0)->stat)));
+       printk(KERN_CONT "\n");
 
-       printk("\n" KERN_DEBUG "TX ring: CDA=%u EDA=%u DSR=%02X in=%u "
+       printk(KERN_DEBUG "TX ring: CDA=%u EDA=%u DSR=%02X in=%u "
               "last=%u %sactive",
               sca_inw(get_dmac_tx(port) + CDAL, card),
               sca_inw(get_dmac_tx(port) + EDAL, card),
index 497b003d72392a1ba87968ba3ea8fc47b077f610..f099c34a3ae24ddec276db15ecfa976ae895f40e 100644 (file)
@@ -529,8 +529,9 @@ static void sca_dump_rings(struct net_device *dev)
               sca_in(DSR_RX(port->chan), card) & DSR_DE ? "" : "in");
        for (cnt = 0; cnt < port->card->rx_ring_buffers; cnt++)
                printk(" %02X", readb(&(desc_address(port, cnt, 0)->stat)));
+       printk(KERN_CONT "\n");
 
-       printk("\n" KERN_DEBUG "TX ring: CDA=%u EDA=%u DSR=%02X in=%u "
+       printk(KERN_DEBUG "TX ring: CDA=%u EDA=%u DSR=%02X in=%u "
               "last=%u %sactive",
               sca_inl(get_dmac_tx(port) + CDAL, card),
               sca_inl(get_dmac_tx(port) + EDAL, card),
index 3fb9dbc88a1aaa277ba631f4c09a19026cdce11d..d14e95a08d66825347721951c480fda1c2967a79 100644 (file)
@@ -326,11 +326,9 @@ sbni_pci_probe( struct net_device  *dev )
                }
 
                if (pci_irq_line <= 0 || pci_irq_line >= nr_irqs)
-                       printk( KERN_WARNING "  WARNING: The PCI BIOS assigned "
-                               "this PCI card to IRQ %d, which is unlikely "
-                               "to work!.\n"
-                               KERN_WARNING " You should use the PCI BIOS "
-                               "setup to assign a valid IRQ line.\n",
+                       printk( KERN_WARNING
+       "  WARNING: The PCI BIOS assigned this PCI card to IRQ %d, which is unlikely to work!.\n"
+       " You should use the PCI BIOS setup to assign a valid IRQ line.\n",
                                pci_irq_line );
 
                /* avoiding re-enable dual adapters */
index d26e7b4853156dda0cfcaa597ddbb4eb580817df..eb0337c49546b6e976589a8719d996d8acd17a5c 100644 (file)
@@ -1,5 +1,6 @@
 config ATH_COMMON
        tristate "Atheros Wireless Cards"
+       depends on WLAN_80211
        depends on ATH5K || ATH9K || AR9170_USB
 
 source "drivers/net/wireless/ath/ath5k/Kconfig"
index b61a071788a50f98347ddaa7f74b778791372c4c..4ccf48e396dfd1529f4114fec7ae9c2d8829efbf 100644 (file)
@@ -355,7 +355,14 @@ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq,
                }
 
                if (bf_next == NULL) {
-                       INIT_LIST_HEAD(&bf_head);
+                       /*
+                        * Make sure the last desc is reclaimed if it
+                        * not a holding desc.
+                        */
+                       if (!bf_last->bf_stale)
+                               list_move_tail(&bf->list, &bf_head);
+                       else
+                               INIT_LIST_HEAD(&bf_head);
                } else {
                        ASSERT(!list_empty(bf_q));
                        list_move_tail(&bf->list, &bf_head);
index f580c2812d91846d611c552295e9722fe09aa06f..40448067e4ccaff3276420d462ca4a8b232dca13 100644 (file)
@@ -648,6 +648,7 @@ struct b43_wl {
        u8 nr_devs;
 
        bool radiotap_enabled;
+       bool radio_enabled;
 
        /* The beacon we are currently using (AP or IBSS mode).
         * This beacon stuff is protected by the irq_lock. */
index 6456afebdba10d3268d6184a76695f253bce135b..e71c8d9cd706ee6b8340d295b86a20817f577d07 100644 (file)
@@ -3497,8 +3497,8 @@ static int b43_op_config(struct ieee80211_hw *hw, u32 changed)
        if (phy->ops->set_rx_antenna)
                phy->ops->set_rx_antenna(dev, antenna);
 
-       if (!!conf->radio_enabled != phy->radio_on) {
-               if (conf->radio_enabled) {
+       if (wl->radio_enabled != phy->radio_on) {
+               if (wl->radio_enabled) {
                        b43_software_rfkill(dev, false);
                        b43info(dev->wl, "Radio turned on by software\n");
                        if (!dev->radio_hw_enable) {
@@ -4339,6 +4339,7 @@ static int b43_op_start(struct ieee80211_hw *hw)
        wl->beacon0_uploaded = 0;
        wl->beacon1_uploaded = 0;
        wl->beacon_templates_virgin = 1;
+       wl->radio_enabled = 1;
 
        mutex_lock(&wl->mutex);
 
@@ -4378,6 +4379,7 @@ static void b43_op_stop(struct ieee80211_hw *hw)
        if (b43_status(dev) >= B43_STAT_STARTED)
                b43_wireless_core_stop(dev);
        b43_wireless_core_exit(dev);
+       wl->radio_enabled = 0;
        mutex_unlock(&wl->mutex);
 
        cancel_work_sync(&(wl->txpower_adjust_work));
@@ -4560,6 +4562,7 @@ static int b43_wireless_core_attach(struct b43_wldev *dev)
                B43_WARN_ON(1);
 
        dev->phy.gmode = have_2ghz_phy;
+       dev->phy.radio_on = 1;
        tmp = dev->phy.gmode ? B43_TMSLOW_GMODE : 0;
        b43_wireless_core_reset(dev, tmp);
 
index 3cfc30307a27d33f48ed8bbffc3e2da13a2cc686..6c3a74964ab888585e0466424290415fcdf653e0 100644 (file)
@@ -35,6 +35,7 @@
 
 static /*const */ struct pcmcia_device_id b43_pcmcia_tbl[] = {
        PCMCIA_DEVICE_MANF_CARD(0x2D0, 0x448),
+       PCMCIA_DEVICE_MANF_CARD(0x2D0, 0x476),
        PCMCIA_DEVICE_NULL,
 };
 
index 77fda148ac4684b904e996095b1e7c68d3fa9469..038baa8869e233e038ca97b2919d0954f485d5ec 100644 (file)
@@ -607,6 +607,7 @@ struct b43legacy_wl {
        u8 nr_devs;
 
        bool radiotap_enabled;
+       bool radio_enabled;
 
        /* The beacon we are currently using (AP or IBSS mode).
         * This beacon stuff is protected by the irq_lock. */
index e5136fb65dddb066f3d6ab65b0671bf8386c3b97..c4973c1942bfdda4b5878b46e5120cc12d8c71bc 100644 (file)
@@ -2689,8 +2689,8 @@ static int b43legacy_op_dev_config(struct ieee80211_hw *hw,
        /* Antennas for RX and management frame TX. */
        b43legacy_mgmtframe_txantenna(dev, antenna_tx);
 
-       if (!!conf->radio_enabled != phy->radio_on) {
-               if (conf->radio_enabled) {
+       if (wl->radio_enabled != phy->radio_on) {
+               if (wl->radio_enabled) {
                        b43legacy_radio_turn_on(dev);
                        b43legacyinfo(dev->wl, "Radio turned on by software\n");
                        if (!dev->radio_hw_enable)
@@ -3441,6 +3441,7 @@ static int b43legacy_op_start(struct ieee80211_hw *hw)
        wl->beacon0_uploaded = 0;
        wl->beacon1_uploaded = 0;
        wl->beacon_templates_virgin = 1;
+       wl->radio_enabled = 1;
 
        mutex_lock(&wl->mutex);
 
@@ -3479,6 +3480,7 @@ static void b43legacy_op_stop(struct ieee80211_hw *hw)
        if (b43legacy_status(dev) >= B43legacy_STAT_STARTED)
                b43legacy_wireless_core_stop(dev);
        b43legacy_wireless_core_exit(dev);
+       wl->radio_enabled = 0;
        mutex_unlock(&wl->mutex);
 }
 
@@ -3620,6 +3622,7 @@ static int b43legacy_wireless_core_attach(struct b43legacy_wldev *dev)
                have_bphy = 1;
 
        dev->phy.gmode = (have_gphy || have_bphy);
+       dev->phy.radio_on = 1;
        tmp = dev->phy.gmode ? B43legacy_TMSLOW_GMODE : 0;
        b43legacy_wireless_core_reset(dev, tmp);
 
index 1eccb6df46dd948664d75470172532b60211e6d4..030401d367d30aa7b82a894464fc2d973556fcef 100644 (file)
@@ -4,6 +4,15 @@ config IWM
        depends on CFG80211
        select WIRELESS_EXT
        select FW_LOADER
+       help
+         The Intel Wireless Multicomm 3200 hardware is a combo
+         card with GPS, Bluetooth, WiMax and 802.11 radios. It
+         runs over SDIO and is typically found on Moorestown
+         based platform. This driver takes care of the 802.11
+         part, which is a fullmac one.
+
+         If you choose to build it as a module, it'll be called
+         iwmc3200wifi.ko.
 
 config IWM_DEBUG
        bool "Enable full debugging output in iwmc3200wifi"
index e789c6e9938cb60e62a918b2f5e2083af7251591..a111bda392e2084115c4738296e1873bf385ab21 100644 (file)
@@ -418,6 +418,7 @@ static bool mac80211_hwsim_tx_frame(struct ieee80211_hw *hw,
                        continue;
 
                if (!data2->started || !hwsim_ps_rx_ok(data2, skb) ||
+                   !data->channel || !data2->channel ||
                    data->channel->center_freq != data2->channel->center_freq ||
                    !(data->group & data2->group))
                        continue;
index 345593c4accbe3c2f007acd9836e66a9ff8375e0..a370e510f19f8e3800f8f30d55eda1587032bbf6 100644 (file)
@@ -2521,6 +2521,8 @@ static const struct net_device_ops orinoco_netdev_ops = {
        .ndo_start_xmit         = orinoco_xmit,
        .ndo_set_multicast_list = orinoco_set_multicast_list,
        .ndo_change_mtu         = orinoco_change_mtu,
+       .ndo_set_mac_address    = eth_mac_addr,
+       .ndo_validate_addr      = eth_validate_addr,
        .ndo_tx_timeout         = orinoco_tx_timeout,
        .ndo_get_stats          = orinoco_get_stats,
 };
@@ -2555,7 +2557,6 @@ struct net_device
        priv->wireless_data.spy_data = &priv->spy_data;
        dev->wireless_data = &priv->wireless_data;
 #endif
-       /* we use the default eth_mac_addr for setting the MAC addr */
 
        /* Reserve space in skb for the SNAP header */
        dev->hard_header_len += ENCAPS_OVERHEAD;
index b618bd14583f9489143de1e1654dad3a290c2598..22ca122bd798c7d37ae3a7da4476b64dbacde233 100644 (file)
@@ -823,30 +823,30 @@ void p54_free_skb(struct ieee80211_hw *dev, struct sk_buff *skb)
        struct p54_tx_info *range;
        unsigned long flags;
 
-       if (unlikely(!skb || !dev || skb_queue_empty(&priv->tx_queue)))
+       if (unlikely(!skb || !dev || !skb_queue_len(&priv->tx_queue)))
                return;
 
-       /* There used to be a check here to see if the SKB was on the
-        * TX queue or not.  This can never happen because all SKBs we
-        * see here successfully went through p54_assign_address()
-        * which means the SKB is on the ->tx_queue.
+       /*
+        * don't try to free an already unlinked skb
         */
+       if (unlikely((!skb->next) || (!skb->prev)))
+               return;
 
        spin_lock_irqsave(&priv->tx_queue.lock, flags);
        info = IEEE80211_SKB_CB(skb);
        range = (void *)info->rate_driver_data;
-       if (!skb_queue_is_first(&priv->tx_queue, skb)) {
+       if (skb->prev != (struct sk_buff *)&priv->tx_queue) {
                struct ieee80211_tx_info *ni;
                struct p54_tx_info *mr;
 
-               ni = IEEE80211_SKB_CB(skb_queue_prev(&priv->tx_queue, skb));
+               ni = IEEE80211_SKB_CB(skb->prev);
                mr = (struct p54_tx_info *)ni->rate_driver_data;
        }
-       if (!skb_queue_is_last(&priv->tx_queue, skb)) {
+       if (skb->next != (struct sk_buff *)&priv->tx_queue) {
                struct ieee80211_tx_info *ni;
                struct p54_tx_info *mr;
 
-               ni = IEEE80211_SKB_CB(skb_queue_next(&priv->tx_queue, skb));
+               ni = IEEE80211_SKB_CB(skb->next);
                mr = (struct p54_tx_info *)ni->rate_driver_data;
        }
        __skb_unlink(skb, &priv->tx_queue);
@@ -864,13 +864,15 @@ static struct sk_buff *p54_find_tx_entry(struct ieee80211_hw *dev,
        unsigned long flags;
 
        spin_lock_irqsave(&priv->tx_queue.lock, flags);
-       skb_queue_walk(&priv->tx_queue, entry) {
+       entry = priv->tx_queue.next;
+       while (entry != (struct sk_buff *)&priv->tx_queue) {
                struct p54_hdr *hdr = (struct p54_hdr *) entry->data;
 
                if (hdr->req_id == req_id) {
                        spin_unlock_irqrestore(&priv->tx_queue.lock, flags);
                        return entry;
                }
+               entry = entry->next;
        }
        spin_unlock_irqrestore(&priv->tx_queue.lock, flags);
        return NULL;
@@ -888,33 +890,36 @@ static void p54_rx_frame_sent(struct ieee80211_hw *dev, struct sk_buff *skb)
        int count, idx;
 
        spin_lock_irqsave(&priv->tx_queue.lock, flags);
-       skb_queue_walk(&priv->tx_queue, entry) {
+       entry = (struct sk_buff *) priv->tx_queue.next;
+       while (entry != (struct sk_buff *)&priv->tx_queue) {
                struct ieee80211_tx_info *info = IEEE80211_SKB_CB(entry);
                struct p54_hdr *entry_hdr;
                struct p54_tx_data *entry_data;
                unsigned int pad = 0, frame_len;
 
                range = (void *)info->rate_driver_data;
-               if (range->start_addr != addr)
+               if (range->start_addr != addr) {
+                       entry = entry->next;
                        continue;
+               }
 
-               if (!skb_queue_is_last(&priv->tx_queue, entry)) {
+               if (entry->next != (struct sk_buff *)&priv->tx_queue) {
                        struct ieee80211_tx_info *ni;
                        struct p54_tx_info *mr;
 
-                       ni = IEEE80211_SKB_CB(skb_queue_next(&priv->tx_queue,
-                                                            entry));
+                       ni = IEEE80211_SKB_CB(entry->next);
                        mr = (struct p54_tx_info *)ni->rate_driver_data;
                }
 
                __skb_unlink(entry, &priv->tx_queue);
-               spin_unlock_irqrestore(&priv->tx_queue.lock, flags);
 
                frame_len = entry->len;
                entry_hdr = (struct p54_hdr *) entry->data;
                entry_data = (struct p54_tx_data *) entry_hdr->data;
-               priv->tx_stats[entry_data->hw_queue].len--;
+               if (priv->tx_stats[entry_data->hw_queue].len)
+                       priv->tx_stats[entry_data->hw_queue].len--;
                priv->stats.dot11ACKFailureCount += payload->tries - 1;
+               spin_unlock_irqrestore(&priv->tx_queue.lock, flags);
 
                /*
                 * Frames in P54_QUEUE_FWSCAN and P54_QUEUE_BEACON are
@@ -1164,21 +1169,23 @@ static int p54_assign_address(struct ieee80211_hw *dev, struct sk_buff *skb,
                }
        }
 
-       skb_queue_walk(&priv->tx_queue, entry) {
+       entry = priv->tx_queue.next;
+       while (left--) {
                u32 hole_size;
                info = IEEE80211_SKB_CB(entry);
                range = (void *)info->rate_driver_data;
                hole_size = range->start_addr - last_addr;
                if (!target_skb && hole_size >= len) {
-                       target_skb = skb_queue_prev(&priv->tx_queue, entry);
+                       target_skb = entry->prev;
                        hole_size -= len;
                        target_addr = last_addr;
                }
                largest_hole = max(largest_hole, hole_size);
                last_addr = range->end_addr;
+               entry = entry->next;
        }
        if (!target_skb && priv->rx_end - last_addr >= len) {
-               target_skb = skb_peek_tail(&priv->tx_queue);
+               target_skb = priv->tx_queue.prev;
                largest_hole = max(largest_hole, priv->rx_end - last_addr - len);
                if (!skb_queue_empty(&priv->tx_queue)) {
                        info = IEEE80211_SKB_CB(target_skb);
@@ -2084,6 +2091,7 @@ out:
 static void p54_stop(struct ieee80211_hw *dev)
 {
        struct p54_common *priv = dev->priv;
+       struct sk_buff *skb;
 
        mutex_lock(&priv->conf_mutex);
        priv->mode = NL80211_IFTYPE_UNSPECIFIED;
@@ -2098,7 +2106,8 @@ static void p54_stop(struct ieee80211_hw *dev)
                p54_tx_cancel(dev, priv->cached_beacon);
 
        priv->stop(dev);
-       skb_queue_purge(&priv->tx_queue);
+       while ((skb = skb_dequeue(&priv->tx_queue)))
+               kfree_skb(skb);
        priv->cached_beacon = NULL;
        priv->tsf_high32 = priv->tsf_low32 = 0;
        mutex_unlock(&priv->conf_mutex);
index b10b0383dfa5ecaa9b6970fc51f36e80bb0a57be..698b11b1cadbb28fd09155f767063d30dc9c3e71 100644 (file)
@@ -2427,11 +2427,10 @@ static void untranslate(ray_dev_t *local, struct sk_buff *skb, int len)
 
 #ifdef PCMCIA_DEBUG
        if (pc_debug > 3) {
-               int i;
-               printk(KERN_DEBUG "skb->data before untranslate");
-               for (i = 0; i < 64; i++)
-                       printk("%02x ", skb->data[i]);
-               printk("\n" KERN_DEBUG
+               print_hex_dump(KERN_DEBUG, "skb->data before untranslate: ",
+                              DUMP_PREFIX_NONE, 16, 1,
+                              skb->data, 64, true);
+               printk(KERN_DEBUG
                       "type = %08x, xsap = %02x%02x%02x, org = %02x02x02x\n",
                       ntohs(type), psnap->dsap, psnap->ssap, psnap->ctrl,
                       psnap->org[0], psnap->org[1], psnap->org[2]);
index 6af706408ac08bf252a4a97105af0379734db621..c6d300666ad8b2126d629fe9aa7b4ce413afe718 100644 (file)
@@ -3556,17 +3556,8 @@ wv_82593_config(struct net_device *      dev)
   cfblk.rcvstop = TRUE;        /* Enable Receive Stop Register */
 
 #ifdef DEBUG_I82593_SHOW
-  {
-    u_char *c = (u_char *) &cfblk;
-    int i;
-    printk(KERN_DEBUG "wavelan_cs: config block:");
-    for(i = 0; i < sizeof(struct i82593_conf_block); i++,c++)
-      {
-       if((i % 16) == 0) printk("\n" KERN_DEBUG);
-       printk("%02x ", *c);
-      }
-    printk("\n");
-  }
+  print_hex_dump(KERN_DEBUG, "wavelan_cs: config block: ", DUMP_PREFIX_NONE,
+                16, 1, &cfblk, sizeof(struct i82593_conf_block), false);
 #endif
 
   /* Copy the config block to the i82593 */
index 14a19baff2144c512a9e28bb34c94584af9c1b06..0e6e44689cc61f863b9a25f936ab19d4ec943e6d 100644 (file)
@@ -38,7 +38,6 @@ static struct usb_device_id usb_ids[] = {
        /* ZD1211 */
        { USB_DEVICE(0x0ace, 0x1211), .driver_info = DEVICE_ZD1211 },
        { USB_DEVICE(0x0ace, 0xa211), .driver_info = DEVICE_ZD1211 },
-       { USB_DEVICE(0x07b8, 0x6001), .driver_info = DEVICE_ZD1211 },
        { USB_DEVICE(0x126f, 0xa006), .driver_info = DEVICE_ZD1211 },
        { USB_DEVICE(0x6891, 0xa727), .driver_info = DEVICE_ZD1211 },
        { USB_DEVICE(0x0df6, 0x9071), .driver_info = DEVICE_ZD1211 },
@@ -61,6 +60,7 @@ static struct usb_device_id usb_ids[] = {
        { USB_DEVICE(0x157e, 0x300a), .driver_info = DEVICE_ZD1211 },
        { USB_DEVICE(0x0105, 0x145f), .driver_info = DEVICE_ZD1211 },
        /* ZD1211B */
+       { USB_DEVICE(0x054c, 0x0257), .driver_info = DEVICE_ZD1211B },
        { USB_DEVICE(0x0ace, 0x1215), .driver_info = DEVICE_ZD1211B },
        { USB_DEVICE(0x0ace, 0xb215), .driver_info = DEVICE_ZD1211B },
        { USB_DEVICE(0x157e, 0x300d), .driver_info = DEVICE_ZD1211B },
@@ -87,6 +87,7 @@ static struct usb_device_id usb_ids[] = {
        { USB_DEVICE(0x0471, 0x1237), .driver_info = DEVICE_ZD1211B },
        { USB_DEVICE(0x07fa, 0x1196), .driver_info = DEVICE_ZD1211B },
        { USB_DEVICE(0x0df6, 0x0036), .driver_info = DEVICE_ZD1211B },
+       { USB_DEVICE(0x07b8, 0x6001), .driver_info = DEVICE_ZD1211B },
        /* "Driverless" devices that need ejecting */
        { USB_DEVICE(0x0ace, 0x2011), .driver_info = DEVICE_INSTALLER },
        { USB_DEVICE(0x0ace, 0x20ff), .driver_info = DEVICE_INSTALLER },
index 3c7a5053f1da7ec054c81b9169ceb8109b7a19a1..a07580138e8109c10b958498dad13ca1f200ad1c 100644 (file)
@@ -109,7 +109,7 @@ static int gx_fix;
 /* These identify the driver base version and may not be removed. */
 static const char version[] __devinitconst =
   KERN_INFO DRV_NAME ".c:v1.05  1/09/2001  Written by Donald Becker <becker@scyld.com>\n"
-  KERN_INFO "  (unofficial 2.4.x port, " DRV_VERSION ", " DRV_RELDATE ")\n";
+  "  (unofficial 2.4.x port, " DRV_VERSION ", " DRV_RELDATE ")\n";
 
 MODULE_AUTHOR("Donald Becker <becker@scyld.com>");
 MODULE_DESCRIPTION("Packet Engines Yellowfin G-NIC Gigabit Ethernet driver");
@@ -700,12 +700,15 @@ static void yellowfin_tx_timeout(struct net_device *dev)
                int i;
                printk(KERN_WARNING "  Rx ring %p: ", yp->rx_ring);
                for (i = 0; i < RX_RING_SIZE; i++)
-                       printk(" %8.8x", yp->rx_ring[i].result_status);
-               printk("\n"KERN_WARNING"  Tx ring %p: ", yp->tx_ring);
+                       printk(KERN_CONT " %8.8x",
+                              yp->rx_ring[i].result_status);
+               printk(KERN_CONT "\n");
+               printk(KERN_WARNING"  Tx ring %p: ", yp->tx_ring);
                for (i = 0; i < TX_RING_SIZE; i++)
-                       printk(" %4.4x /%8.8x", yp->tx_status[i].tx_errs,
-                                  yp->tx_ring[i].result_status);
-               printk("\n");
+                       printk(KERN_CONT " %4.4x /%8.8x",
+                              yp->tx_status[i].tx_errs,
+                              yp->tx_ring[i].result_status);
+               printk(KERN_CONT "\n");
        }
 
        /* If the hardware is found to hang regularly, we will update the code
@@ -1216,20 +1219,20 @@ static int yellowfin_close(struct net_device *dev)
 
 #if defined(__i386__)
        if (yellowfin_debug > 2) {
-               printk("\n"KERN_DEBUG"  Tx ring at %8.8llx:\n",
+               printk(KERN_DEBUG"  Tx ring at %8.8llx:\n",
                                (unsigned long long)yp->tx_ring_dma);
                for (i = 0; i < TX_RING_SIZE*2; i++)
-                       printk(" %c #%d desc. %8.8x %8.8x %8.8x %8.8x.\n",
+                       printk(KERN_DEBUG " %c #%d desc. %8.8x %8.8x %8.8x %8.8x.\n",
                                   ioread32(ioaddr + TxPtr) == (long)&yp->tx_ring[i] ? '>' : ' ',
                                   i, yp->tx_ring[i].dbdma_cmd, yp->tx_ring[i].addr,
                                   yp->tx_ring[i].branch_addr, yp->tx_ring[i].result_status);
                printk(KERN_DEBUG "  Tx status %p:\n", yp->tx_status);
                for (i = 0; i < TX_RING_SIZE; i++)
-                       printk("   #%d status %4.4x %4.4x %4.4x %4.4x.\n",
+                       printk(KERN_DEBUG "   #%d status %4.4x %4.4x %4.4x %4.4x.\n",
                                   i, yp->tx_status[i].tx_cnt, yp->tx_status[i].tx_errs,
                                   yp->tx_status[i].total_tx_cnt, yp->tx_status[i].paused);
 
-               printk("\n"KERN_DEBUG "  Rx ring %8.8llx:\n",
+               printk(KERN_DEBUG "  Rx ring %8.8llx:\n",
                                (unsigned long long)yp->rx_ring_dma);
                for (i = 0; i < RX_RING_SIZE; i++) {
                        printk(KERN_DEBUG " %c #%d desc. %8.8x %8.8x %8.8x\n",
index e1f6ce03705ed915d94b77f1dde0a687e07e08f8..3c2270a8300c40833bcf0900968635e2b166abc6 100644 (file)
@@ -33,6 +33,7 @@ void oprofile_reset_stats(void)
        atomic_set(&oprofile_stats.sample_lost_no_mm, 0);
        atomic_set(&oprofile_stats.sample_lost_no_mapping, 0);
        atomic_set(&oprofile_stats.event_lost_overflow, 0);
+       atomic_set(&oprofile_stats.bt_lost_no_mapping, 0);
 }
 
 
index 5d610cbcfe80cf294a676c38a18bce5dbdd9af4b..0f0e0b919ef43f285bdb72d728681dcd1f71947a 100644 (file)
@@ -1134,7 +1134,7 @@ static const struct file_operations ccio_proc_bitmap_fops = {
        .llseek = seq_lseek,
        .release = single_release,
 };
-#endif
+#endif /* CONFIG_PROC_FS */
 
 /**
  * ccio_find_ioc - Find the ioc in the ioc_list
@@ -1568,14 +1568,15 @@ static int __init ccio_probe(struct parisc_device *dev)
        /* if this fails, no I/O cards will work, so may as well bug */
        BUG_ON(dev->dev.platform_data == NULL);
        HBA_DATA(dev->dev.platform_data)->iommu = ioc;
-       
+
+#ifdef CONFIG_PROC_FS
        if (ioc_count == 0) {
                proc_create(MODULE_NAME, 0, proc_runway_root,
                            &ccio_proc_info_fops);
                proc_create(MODULE_NAME"-bitmap", 0, proc_runway_root,
                            &ccio_proc_bitmap_fops);
        }
-
+#endif
        ioc_count++;
 
        parisc_has_iommu();
index 52ae0b1d470ccd24ee39a32fd04d29ac86722d44..c590974e9815cc78651f1dd9f3cab6b3f71b3730 100644 (file)
@@ -353,7 +353,7 @@ static unsigned int dino_startup_irq(unsigned int irq)
        return 0;
 }
 
-static struct hw_interrupt_type dino_interrupt_type = {
+static struct irq_chip dino_interrupt_type = {
        .typename       = "GSC-PCI",
        .startup        = dino_startup_irq,
        .shutdown       = dino_disable_irq,
@@ -1019,22 +1019,22 @@ static int __init dino_probe(struct parisc_device *dev)
        ** It's not used to avoid chicken/egg problems
        ** with configuration accessor functions.
        */
-       bus = pci_scan_bus_parented(&dev->dev, dino_current_bus,
-                                   &dino_cfg_ops, NULL);
+       dino_dev->hba.hba_bus = bus = pci_scan_bus_parented(&dev->dev,
+                        dino_current_bus, &dino_cfg_ops, NULL);
+
        if(bus) {
-               pci_bus_add_devices(bus);
                /* This code *depends* on scanning being single threaded
                 * if it isn't, this global bus number count will fail
                 */
                dino_current_bus = bus->subordinate + 1;
                pci_bus_assign_resources(bus);
+               pci_bus_add_devices(bus);
        } else {
-               printk(KERN_ERR "ERROR: failed to scan PCI bus on %s (probably duplicate bus number %d)\n",
+               printk(KERN_ERR "ERROR: failed to scan PCI bus on %s (duplicate bus number %d?)\n",
                       dev_name(&dev->dev), dino_current_bus);
                /* increment the bus number in case of duplicates */
                dino_current_bus++;
        }
-       dino_dev->hba.hba_bus = bus;
        return 0;
 }
 
index 5b89f404e668876f53da1f0278523763e3512e16..51220749cb656805fa98a52117e799eeedee8944 100644 (file)
@@ -188,7 +188,7 @@ static unsigned int eisa_startup_irq(unsigned int irq)
        return 0;
 }
 
-static struct hw_interrupt_type eisa_interrupt_type = {
+static struct irq_chip eisa_interrupt_type = {
        .typename =     "EISA",
        .startup =      eisa_startup_irq,
        .shutdown =     eisa_disable_irq,
index c709ecc2b7f71626622f9c6f834b4c2160e374b0..0be1d50645ab0f3fde6f47b2c65b72e81ecfc316 100644 (file)
@@ -101,7 +101,7 @@ static int configure_memory(const unsigned char *buf,
                        printk("memory %lx-%lx ", (unsigned long)res->start, (unsigned long)res->end);
                        result = request_resource(mem_parent, res);
                        if (result < 0) {
-                               printk("\n" KERN_ERR "EISA Enumerator: failed to claim EISA Bus address space!\n");
+                               printk(KERN_ERR "EISA Enumerator: failed to claim EISA Bus address space!\n");
                                return result;
                        }
                }
@@ -191,7 +191,7 @@ static int configure_port(const unsigned char *buf, struct resource *io_parent,
                        printk("ioports %lx-%lx ", (unsigned long)res->start, (unsigned long)res->end);
                        result = request_resource(io_parent, res);
                        if (result < 0) {
-                               printk("\n" KERN_ERR "EISA Enumerator: failed to claim EISA Bus address space!\n");
+                               printk(KERN_ERR "EISA Enumerator: failed to claim EISA Bus address space!\n");
                                return result;
                        }
                }
@@ -224,7 +224,7 @@ static int configure_port_init(const unsigned char *buf)
                 case HPEE_PORT_INIT_WIDTH_BYTE:
                        s=1;
                        if (c & HPEE_PORT_INIT_MASK) {
-                               printk("\n" KERN_WARNING "port_init: unverified mask attribute\n");
+                               printk(KERN_WARNING "port_init: unverified mask attribute\n");
                                outb((inb(get_16(buf+len+1) & 
                                          get_8(buf+len+3)) | 
                                      get_8(buf+len+4)), get_16(buf+len+1));
@@ -249,7 +249,7 @@ static int configure_port_init(const unsigned char *buf)
                 case HPEE_PORT_INIT_WIDTH_DWORD:
                        s=4;
                        if (c & HPEE_PORT_INIT_MASK) {
-                               printk("\n" KERN_WARNING "port_init: unverified mask attribute\n");
+                               printk(KERN_WARNING "port_init: unverified mask attribute\n");
                                outl((inl(get_16(buf+len+1) &
                                          get_32(buf+len+3)) |
                                      get_32(buf+len+7)), get_16(buf+len+1));
@@ -259,7 +259,7 @@ static int configure_port_init(const unsigned char *buf)
 
                        break;
                 default:
-                       printk("\n" KERN_ERR "Invalid port init word %02x\n", c);
+                       printk(KERN_ERR "Invalid port init word %02x\n", c);
                        return 0;
                }
                
@@ -297,7 +297,7 @@ static int configure_type_string(const unsigned char *buf)
        /* just skip past the type field */
        len = get_8(buf);
        if (len > 80) {
-               printk("\n" KERN_ERR "eisa_enumerator: type info field too long (%d, max is 80)\n", len);
+               printk(KERN_ERR "eisa_enumerator: type info field too long (%d, max is 80)\n", len);
        }
        
        return 1+len;
@@ -398,7 +398,7 @@ static int parse_slot_config(int slot,
                }
                
                if (p0 + function_len < pos) {
-                       printk("\n" KERN_ERR "eisa_enumerator: function %d length mis-match "
+                       printk(KERN_ERR "eisa_enumerator: function %d length mis-match "
                               "got %d, expected %d\n",
                               num_func, pos-p0, function_len);
                        res=-1;
index d336329176962461cb160016ad7aba736d3e232e..647adc9f85adf1118f7b294a89cac45200344b6c 100644 (file)
@@ -148,7 +148,7 @@ static unsigned int gsc_asic_startup_irq(unsigned int irq)
        return 0;
 }
 
-static struct hw_interrupt_type gsc_asic_interrupt_type = {
+static struct irq_chip gsc_asic_interrupt_type = {
        .typename =     "GSC-ASIC",
        .startup =      gsc_asic_startup_irq,
        .shutdown =     gsc_asic_disable_irq,
@@ -158,7 +158,7 @@ static struct hw_interrupt_type gsc_asic_interrupt_type = {
        .end =          no_end_irq,
 };
 
-int gsc_assign_irq(struct hw_interrupt_type *type, void *data)
+int gsc_assign_irq(struct irq_chip *type, void *data)
 {
        static int irq = GSC_IRQ_BASE;
        struct irq_desc *desc;
index 762a1babad604a318a9f5a22bfb7d467bc760e93..b9d7bfb68e24d057e89e726ce0852250e90d4a85 100644 (file)
@@ -38,7 +38,7 @@ struct gsc_asic {
 int gsc_common_setup(struct parisc_device *parent, struct gsc_asic *gsc_asic);
 int gsc_alloc_irq(struct gsc_irq *dev);                        /* dev needs an irq */
 int gsc_claim_irq(struct gsc_irq *dev, int irq);       /* dev needs this irq */
-int gsc_assign_irq(struct hw_interrupt_type *type, void *data);
+int gsc_assign_irq(struct irq_chip *type, void *data);
 int gsc_find_local_irq(unsigned int irq, int *global_irq, int limit);
 void gsc_fixup_irqs(struct parisc_device *parent, void *ctrl,
                void (*choose)(struct parisc_device *child, void *ctrl));
index 4a9cc92d4d1867469dcae3efed4c468b251ff7f8..88e333553212c33d4c38985040c95f4fb23249b1 100644 (file)
@@ -729,7 +729,7 @@ static int iosapic_set_affinity_irq(unsigned int irq,
 }
 #endif
 
-static struct hw_interrupt_type iosapic_interrupt_type = {
+static struct irq_chip iosapic_interrupt_type = {
        .typename =     "IO-SAPIC-level",
        .startup =      iosapic_startup_irq,
        .shutdown =     iosapic_disable_irq,
index 59fbbf12836579a9d4d729993186af88b79701d8..ede614616f8efbb4b3ca20149ed73c0b877c37ba 100644 (file)
@@ -980,28 +980,38 @@ static void
 lba_pat_resources(struct parisc_device *pa_dev, struct lba_device *lba_dev)
 {
        unsigned long bytecnt;
-       pdc_pat_cell_mod_maddr_block_t pa_pdc_cell;     /* PA_VIEW */
-       pdc_pat_cell_mod_maddr_block_t io_pdc_cell;     /* IO_VIEW */
        long io_count;
        long status;    /* PDC return status */
        long pa_count;
+       pdc_pat_cell_mod_maddr_block_t *pa_pdc_cell;    /* PA_VIEW */
+       pdc_pat_cell_mod_maddr_block_t *io_pdc_cell;    /* IO_VIEW */
        int i;
 
+       pa_pdc_cell = kzalloc(sizeof(pdc_pat_cell_mod_maddr_block_t), GFP_KERNEL);
+       if (!pa_pdc_cell)
+               return;
+
+       io_pdc_cell = kzalloc(sizeof(pdc_pat_cell_mod_maddr_block_t), GFP_KERNEL);
+       if (!pa_pdc_cell) {
+               kfree(pa_pdc_cell);
+               return;
+       }
+
        /* return cell module (IO view) */
        status = pdc_pat_cell_module(&bytecnt, pa_dev->pcell_loc, pa_dev->mod_index,
-                               PA_VIEW, pa_pdc_cell);
-       pa_count = pa_pdc_cell.mod[1];
+                               PA_VIEW, pa_pdc_cell);
+       pa_count = pa_pdc_cell->mod[1];
 
        status |= pdc_pat_cell_module(&bytecnt, pa_dev->pcell_loc, pa_dev->mod_index,
-                               IO_VIEW, &io_pdc_cell);
-       io_count = io_pdc_cell.mod[1];
+                               IO_VIEW, io_pdc_cell);
+       io_count = io_pdc_cell->mod[1];
 
        /* We've already done this once for device discovery...*/
        if (status != PDC_OK) {
                panic("pdc_pat_cell_module() call failed for LBA!\n");
        }
 
-       if (PAT_GET_ENTITY(pa_pdc_cell.mod_info) != PAT_ENTITY_LBA) {
+       if (PAT_GET_ENTITY(pa_pdc_cell->mod_info) != PAT_ENTITY_LBA) {
                panic("pdc_pat_cell_module() entity returned != PAT_ENTITY_LBA!\n");
        }
 
@@ -1016,8 +1026,8 @@ lba_pat_resources(struct parisc_device *pa_dev, struct lba_device *lba_dev)
                } *p, *io;
                struct resource *r;
 
-               p = (void *) &(pa_pdc_cell.mod[2+i*3]);
-               io = (void *) &(io_pdc_cell.mod[2+i*3]);
+               p = (void *) &(pa_pdc_cell->mod[2+i*3]);
+               io = (void *) &(io_pdc_cell->mod[2+i*3]);
 
                /* Convert the PAT range data to PCI "struct resource" */
                switch(p->type & 0xff) {
@@ -1096,6 +1106,9 @@ lba_pat_resources(struct parisc_device *pa_dev, struct lba_device *lba_dev)
                        break;
                }
        }
+
+       kfree(pa_pdc_cell);
+       kfree(io_pdc_cell);
 }
 #else
 /* keep compiler from complaining about missing declarations */
@@ -1509,10 +1522,6 @@ lba_driver_probe(struct parisc_device *dev)
        lba_bus = lba_dev->hba.hba_bus =
                pci_scan_bus_parented(&dev->dev, lba_dev->hba.bus_num.start,
                                cfg_ops, NULL);
-       if (lba_bus) {
-               lba_next_bus = lba_bus->subordinate + 1;
-               pci_bus_add_devices(lba_bus);
-       }
 
        /* This is in lieu of calling pci_assign_unassigned_resources() */
        if (is_pdc_pat()) {
@@ -1533,7 +1542,6 @@ lba_driver_probe(struct parisc_device *dev)
        }
        pci_enable_bridges(lba_bus);
 
-
        /*
        ** Once PCI register ops has walked the bus, access to config
        ** space is restricted. Avoids master aborts on config cycles.
@@ -1543,6 +1551,11 @@ lba_driver_probe(struct parisc_device *dev)
                lba_dev->flags |= LBA_FLAG_SKIP_PROBE;
        }
 
+       if (lba_bus) {
+               lba_next_bus = lba_bus->subordinate + 1;
+               pci_bus_add_devices(lba_bus);
+       }
+
        /* Whew! Finally done! Tell services we got this one covered. */
        return 0;
 }
index d46dd57450acd151d4d97a7d7016e54cedab1f54..123d8fe3427d0a1286f8ebd5d1cf684d13969993 100644 (file)
@@ -2057,6 +2057,7 @@ void sba_directed_lmmio(struct parisc_device *pci_hba, struct resource *r)
                r->start = (base & ~1UL) | PCI_F_EXTEND;
                size = ~ READ_REG32(reg + LMMIO_DIRECT0_MASK);
                r->end = r->start + size;
+               r->flags = IORESOURCE_MEM;
        }
 }
 
@@ -2093,4 +2094,5 @@ void sba_distributed_lmmio(struct parisc_device *pci_hba, struct resource *r )
        size = (~READ_REG32(sba->sba_hpa + LMMIO_DIST_MASK)) / ROPES_PER_IOC;
        r->start += rope * (size + 1);  /* adjust base for this rope */
        r->end = r->start + size;
+       r->flags = IORESOURCE_MEM;
 }
index 33e5ade774ca01c98004bcafdfd1820f939a4b34..675f04e6597a5d664f6f535f670be1f5c9855c9e 100644 (file)
@@ -325,7 +325,7 @@ static unsigned int superio_startup_irq(unsigned int irq)
        return 0;
 }
 
-static struct hw_interrupt_type superio_interrupt_type = {
+static struct irq_chip superio_interrupt_type = {
        .typename =     SUPERIO,
        .startup =      superio_startup_irq,
        .shutdown =     superio_disable_irq,
@@ -434,8 +434,8 @@ static void __init superio_parport_init(void)
                        0 /*base_hi*/,
                        PAR_IRQ, 
                        PARPORT_DMA_NONE /* dma */,
-                       NULL /*struct pci_dev* */),
-                       0 /* shared irq flags */ )
+                       NULL /*struct pci_dev* */,
+                       0 /* shared irq flags */))
 
                printk(KERN_WARNING PFX "Probing parallel port failed.\n");
 #endif /* CONFIG_PARPORT_PC */
index 1032d5fdbd423ce8736d72e85f8f6d3edbcd6eed..2597145a066e391fa988ecbbf44921f2f249ef1d 100644 (file)
@@ -2907,6 +2907,7 @@ enum parport_pc_pci_cards {
        netmos_9755,
        netmos_9805,
        netmos_9815,
+       netmos_9901,
        quatech_sppxp100,
 };
 
@@ -2987,7 +2988,7 @@ static struct parport_pc_pci {
        /* netmos_9755 */               { 2, { { 0, 1 }, { 2, 3 },} },
        /* netmos_9805 */               { 1, { { 0, -1 }, } },
        /* netmos_9815 */               { 2, { { 0, -1 }, { 2, -1 }, } },
-
+       /* netmos_9901 */               { 1, { { 0, -1 }, } },
        /* quatech_sppxp100 */          { 1, { { 0, 1 }, } },
 };
 
@@ -3089,6 +3090,8 @@ static const struct pci_device_id parport_pc_pci_tbl[] = {
          PCI_ANY_ID, PCI_ANY_ID, 0, 0, netmos_9805 },
        { PCI_VENDOR_ID_NETMOS, PCI_DEVICE_ID_NETMOS_9815,
          PCI_ANY_ID, PCI_ANY_ID, 0, 0, netmos_9815 },
+       { PCI_VENDOR_ID_NETMOS, PCI_DEVICE_ID_NETMOS_9901,
+         0xA000, 0x2000, 0, 0, netmos_9901 },
        /* Quatech SPPXP-100 Parallel port PCI ExpressCard */
        { PCI_VENDOR_ID_QUATECH, PCI_DEVICE_ID_QUATECH_SPPXP_100,
          PCI_ANY_ID, PCI_ANY_ID, 0, 0, quatech_sppxp100 },
index fbc63d5e459fd4182f35f5beffc9bee1a875c8d8..eb159587d0bfa5701c2d9476c8b606625d761af9 100644 (file)
@@ -354,7 +354,7 @@ acpi_status acpi_get_hp_params_from_firmware(struct pci_bus *bus,
                status = acpi_run_hpp(handle, hpp);
                if (ACPI_SUCCESS(status))
                        break;
-               if (acpi_root_bridge(handle))
+               if (acpi_is_root_bridge(handle))
                        break;
                status = acpi_get_parent(handle, &phandle);
                if (ACPI_FAILURE(status))
@@ -428,7 +428,7 @@ int acpi_get_hp_hw_control_from_firmware(struct pci_dev *pdev, u32 flags)
                status = acpi_run_oshp(handle);
                if (ACPI_SUCCESS(status))
                        goto got_one;
-               if (acpi_root_bridge(handle))
+               if (acpi_is_root_bridge(handle))
                        break;
                chandle = handle;
                status = acpi_get_parent(chandle, &handle);
@@ -449,42 +449,6 @@ got_one:
 }
 EXPORT_SYMBOL(acpi_get_hp_hw_control_from_firmware);
 
-/* acpi_root_bridge - check to see if this acpi object is a root bridge
- *
- * @handle - the acpi object in question.
- */
-int acpi_root_bridge(acpi_handle handle)
-{
-       acpi_status status;
-       struct acpi_device_info *info;
-       struct acpi_buffer buffer = {ACPI_ALLOCATE_BUFFER, NULL};
-       int i;
-
-       status = acpi_get_object_info(handle, &buffer);
-       if (ACPI_SUCCESS(status)) {
-               info = buffer.pointer;
-               if ((info->valid & ACPI_VALID_HID) &&
-                       !strcmp(PCI_ROOT_HID_STRING,
-                                       info->hardware_id.value)) {
-                       kfree(buffer.pointer);
-                       return 1;
-               }
-               if (info->valid & ACPI_VALID_CID) {
-                       for (i=0; i < info->compatibility_id.count; i++) {
-                               if (!strcmp(PCI_ROOT_HID_STRING,
-                                       info->compatibility_id.id[i].value)) {
-                                       kfree(buffer.pointer);
-                                       return 1;
-                               }
-                       }
-               }
-               kfree(buffer.pointer);
-       }
-       return 0;
-}
-EXPORT_SYMBOL_GPL(acpi_root_bridge);
-
-
 static int is_ejectable(acpi_handle handle)
 {
        acpi_status status;
index 3a6064bce5614a84ba16e1411a50bcfc7afddce3..0cb0f830a99307539d780e25e54ead35ed43cf02 100644 (file)
@@ -678,18 +678,9 @@ static void remove_bridge(acpi_handle handle)
 
 static struct pci_dev * get_apic_pci_info(acpi_handle handle)
 {
-       struct acpi_pci_id id;
-       struct pci_bus *bus;
        struct pci_dev *dev;
 
-       if (ACPI_FAILURE(acpi_get_pci_id(handle, &id)))
-               return NULL;
-
-       bus = pci_find_bus(id.segment, id.bus);
-       if (!bus)
-               return NULL;
-
-       dev = pci_get_slot(bus, PCI_DEVFN(id.device, id.function));
+       dev = acpi_get_pci_dev(handle);
        if (!dev)
                return NULL;
 
@@ -1396,19 +1387,16 @@ static void acpiphp_sanitize_bus(struct pci_bus *bus)
 /* Program resources in newly inserted bridge */
 static int acpiphp_configure_bridge (acpi_handle handle)
 {
-       struct acpi_pci_id pci_id;
+       struct pci_dev *dev;
        struct pci_bus *bus;
 
-       if (ACPI_FAILURE(acpi_get_pci_id(handle, &pci_id))) {
+       dev = acpi_get_pci_dev(handle);
+       if (!dev) {
                err("cannot get PCI domain and bus number for bridge\n");
                return -EINVAL;
        }
-       bus = pci_find_bus(pci_id.segment, pci_id.bus);
-       if (!bus) {
-               err("cannot find bus %d:%d\n",
-                               pci_id.segment, pci_id.bus);
-               return -EINVAL;
-       }
+
+       bus = dev->bus;
 
        pci_bus_size_bridges(bus);
        pci_bus_assign_resources(bus);
@@ -1416,6 +1404,7 @@ static int acpiphp_configure_bridge (acpi_handle handle)
        acpiphp_set_hpp_values(handle, bus);
        pci_enable_bridges(bus);
        acpiphp_configure_ioapics(handle);
+       pci_dev_put(dev);
        return 0;
 }
 
@@ -1631,7 +1620,7 @@ find_root_bridges(acpi_handle handle, u32 lvl, void *context, void **rv)
 {
        int *count = (int *)context;
 
-       if (acpi_root_bridge(handle)) {
+       if (acpi_is_root_bridge(handle)) {
                acpi_install_notify_handler(handle, ACPI_SYSTEM_NOTIFY,
                                handle_hotplug_event_bridge, NULL);
                        (*count)++;
index a5b9f6ae507bb5cf23ab4cf614e97c1fa7e2c6d3..d703e73fffa7cc5cf334dbd003c7334a9bec42b1 100644 (file)
@@ -32,7 +32,6 @@
 #include <linux/pci_hotplug.h>
 #include <linux/init.h>
 #include <linux/interrupt.h>
-#include <linux/smp_lock.h>
 #include <asm/atomic.h>
 #include <linux/delay.h>
 #include <linux/kthread.h>
index 2fa47af992a8281ff1bfb43d5fd0e7c0c7bf2111..0ff689afa757bb1aa21df038623c4a63c41364f7 100644 (file)
@@ -34,7 +34,6 @@
 #include <linux/interrupt.h>
 #include <linux/delay.h>
 #include <linux/wait.h>
-#include <linux/smp_lock.h>
 #include <linux/pci.h>
 #include <linux/pci_hotplug.h>
 #include <linux/kthread.h>
index 8450f4a6568a852a288b75a62436e913b71e7ef8..e6089bdb6e5bddbc2b08e09c9419d26056e543e7 100644 (file)
@@ -33,6 +33,7 @@
 #include <linux/workqueue.h>
 #include <linux/pci.h>
 #include <linux/pci_hotplug.h>
+#include <linux/smp_lock.h>
 #include <linux/debugfs.h>
 #include "cpqphp.h"
 
index 844580489d4da56d63dc7015b2320206661a63d4..5c5043f239cf560fb33fad276f47972f7ffd65f4 100644 (file)
@@ -555,6 +555,8 @@ static struct hotplug_slot *get_slot_from_name (const char *name)
  * @slot: pointer to the &struct hotplug_slot to register
  * @devnr: device number
  * @name: name registered with kobject core
+ * @owner: caller module owner
+ * @mod_name: caller module name
  *
  * Registers a hotplug slot with the pci hotplug subsystem, which will allow
  * userspace interaction to the slot.
index ff4034502d240355b9e5dfd4c02b226606ba2f52..8aab8edf123eeecfc5d0bc5d79ae63a1685e6c0e 100644 (file)
@@ -30,7 +30,6 @@
 #include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/types.h>
-#include <linux/smp_lock.h>
 #include <linux/pci.h>
 #include <linux/workqueue.h>
 #include "../pci.h"
index 178853a074405d746d6c0932030aa22daf2b17ca..ebc9b8dca881f588e974fbcb60faabf9642902f8 100644 (file)
 #define MAX_AGAW_WIDTH 64
 
 #define DOMAIN_MAX_ADDR(gaw) ((((u64)1) << gaw) - 1)
+#define DOMAIN_MAX_PFN(gaw)  ((((u64)1) << (gaw-VTD_PAGE_SHIFT)) - 1)
 
 #define IOVA_PFN(addr)         ((addr) >> PAGE_SHIFT)
 #define DMA_32BIT_PFN          IOVA_PFN(DMA_BIT_MASK(32))
 #define DMA_64BIT_PFN          IOVA_PFN(DMA_BIT_MASK(64))
 
-#ifndef PHYSICAL_PAGE_MASK
-#define PHYSICAL_PAGE_MASK PAGE_MASK
-#endif
+
+/* VT-d pages must always be _smaller_ than MM pages. Otherwise things
+   are never going to work. */
+static inline unsigned long dma_to_mm_pfn(unsigned long dma_pfn)
+{
+       return dma_pfn >> (PAGE_SHIFT - VTD_PAGE_SHIFT);
+}
+
+static inline unsigned long mm_to_dma_pfn(unsigned long mm_pfn)
+{
+       return mm_pfn << (PAGE_SHIFT - VTD_PAGE_SHIFT);
+}
+static inline unsigned long page_to_dma_pfn(struct page *pg)
+{
+       return mm_to_dma_pfn(page_to_pfn(pg));
+}
+static inline unsigned long virt_to_dma_pfn(void *p)
+{
+       return page_to_dma_pfn(virt_to_page(p));
+}
 
 /* global iommu list, set NULL for ignored DMAR units */
 static struct intel_iommu **g_iommus;
@@ -204,12 +222,17 @@ static inline void dma_set_pte_prot(struct dma_pte *pte, unsigned long prot)
 
 static inline u64 dma_pte_addr(struct dma_pte *pte)
 {
-       return (pte->val & VTD_PAGE_MASK);
+#ifdef CONFIG_64BIT
+       return pte->val & VTD_PAGE_MASK;
+#else
+       /* Must have a full atomic 64-bit read */
+       return  __cmpxchg64(pte, 0ULL, 0ULL) & VTD_PAGE_MASK;
+#endif
 }
 
-static inline void dma_set_pte_addr(struct dma_pte *pte, u64 addr)
+static inline void dma_set_pte_pfn(struct dma_pte *pte, unsigned long pfn)
 {
-       pte->val |= (addr & VTD_PAGE_MASK);
+       pte->val |= (uint64_t)pfn << VTD_PAGE_SHIFT;
 }
 
 static inline bool dma_pte_present(struct dma_pte *pte)
@@ -217,6 +240,19 @@ static inline bool dma_pte_present(struct dma_pte *pte)
        return (pte->val & 3) != 0;
 }
 
+static inline int first_pte_in_page(struct dma_pte *pte)
+{
+       return !((unsigned long)pte & ~VTD_PAGE_MASK);
+}
+
+/*
+ * This domain is a statically identity mapping domain.
+ *     1. This domain creats a static 1:1 mapping to all usable memory.
+ *     2. It maps to each iommu if successful.
+ *     3. Each iommu mapps to this domain if successful.
+ */
+struct dmar_domain *si_domain;
+
 /* devices under the same p2p bridge are owned in one domain */
 #define DOMAIN_FLAG_P2P_MULTIPLE_DEVICES (1 << 0)
 
@@ -225,6 +261,9 @@ static inline bool dma_pte_present(struct dma_pte *pte)
  */
 #define DOMAIN_FLAG_VIRTUAL_MACHINE    (1 << 1)
 
+/* si_domain contains mulitple devices */
+#define DOMAIN_FLAG_STATIC_IDENTITY    (1 << 2)
+
 struct dmar_domain {
        int     id;                     /* domain id */
        unsigned long iommu_bmp;        /* bitmap of iommus this domain uses*/
@@ -233,7 +272,6 @@ struct dmar_domain {
        struct iova_domain iovad;       /* iova's that belong to this domain */
 
        struct dma_pte  *pgd;           /* virtual address */
-       spinlock_t      mapping_lock;   /* page table lock */
        int             gaw;            /* max guest address width */
 
        /* adjusted guest address width, 0 is level 2 30-bit */
@@ -435,12 +473,14 @@ int iommu_calculate_agaw(struct intel_iommu *iommu)
        return __iommu_calculate_agaw(iommu, DEFAULT_DOMAIN_ADDRESS_WIDTH);
 }
 
-/* in native case, each domain is related to only one iommu */
+/* This functionin only returns single iommu in a domain */
 static struct intel_iommu *domain_get_iommu(struct dmar_domain *domain)
 {
        int iommu_id;
 
+       /* si_domain and vm domain should not get here. */
        BUG_ON(domain->flags & DOMAIN_FLAG_VIRTUAL_MACHINE);
+       BUG_ON(domain->flags & DOMAIN_FLAG_STATIC_IDENTITY);
 
        iommu_id = find_first_bit(&domain->iommu_bmp, g_num_of_iommus);
        if (iommu_id < 0 || iommu_id >= g_num_of_iommus)
@@ -635,80 +675,78 @@ static inline int width_to_agaw(int width)
 
 static inline unsigned int level_to_offset_bits(int level)
 {
-       return (12 + (level - 1) * LEVEL_STRIDE);
+       return (level - 1) * LEVEL_STRIDE;
 }
 
-static inline int address_level_offset(u64 addr, int level)
+static inline int pfn_level_offset(unsigned long pfn, int level)
 {
-       return ((addr >> level_to_offset_bits(level)) & LEVEL_MASK);
+       return (pfn >> level_to_offset_bits(level)) & LEVEL_MASK;
 }
 
-static inline u64 level_mask(int level)
+static inline unsigned long level_mask(int level)
 {
-       return ((u64)-1 << level_to_offset_bits(level));
+       return -1UL << level_to_offset_bits(level);
 }
 
-static inline u64 level_size(int level)
+static inline unsigned long level_size(int level)
 {
-       return ((u64)1 << level_to_offset_bits(level));
+       return 1UL << level_to_offset_bits(level);
 }
 
-static inline u64 align_to_level(u64 addr, int level)
+static inline unsigned long align_to_level(unsigned long pfn, int level)
 {
-       return ((addr + level_size(level) - 1) & level_mask(level));
+       return (pfn + level_size(level) - 1) & level_mask(level);
 }
 
-static struct dma_pte * addr_to_dma_pte(struct dmar_domain *domain, u64 addr)
+static struct dma_pte *pfn_to_dma_pte(struct dmar_domain *domain,
+                                     unsigned long pfn)
 {
-       int addr_width = agaw_to_width(domain->agaw);
+       int addr_width = agaw_to_width(domain->agaw) - VTD_PAGE_SHIFT;
        struct dma_pte *parent, *pte = NULL;
        int level = agaw_to_level(domain->agaw);
        int offset;
-       unsigned long flags;
 
        BUG_ON(!domain->pgd);
-
-       addr &= (((u64)1) << addr_width) - 1;
+       BUG_ON(addr_width < BITS_PER_LONG && pfn >> addr_width);
        parent = domain->pgd;
 
-       spin_lock_irqsave(&domain->mapping_lock, flags);
        while (level > 0) {
                void *tmp_page;
 
-               offset = address_level_offset(addr, level);
+               offset = pfn_level_offset(pfn, level);
                pte = &parent[offset];
                if (level == 1)
                        break;
 
                if (!dma_pte_present(pte)) {
+                       uint64_t pteval;
+
                        tmp_page = alloc_pgtable_page();
 
-                       if (!tmp_page) {
-                               spin_unlock_irqrestore(&domain->mapping_lock,
-                                       flags);
+                       if (!tmp_page)
                                return NULL;
+
+                       domain_flush_cache(domain, tmp_page, VTD_PAGE_SIZE);
+                       pteval = (virt_to_dma_pfn(tmp_page) << VTD_PAGE_SHIFT) | DMA_PTE_READ | DMA_PTE_WRITE;
+                       if (cmpxchg64(&pte->val, 0ULL, pteval)) {
+                               /* Someone else set it while we were thinking; use theirs. */
+                               free_pgtable_page(tmp_page);
+                       } else {
+                               dma_pte_addr(pte);
+                               domain_flush_cache(domain, pte, sizeof(*pte));
                        }
-                       domain_flush_cache(domain, tmp_page, PAGE_SIZE);
-                       dma_set_pte_addr(pte, virt_to_phys(tmp_page));
-                       /*
-                        * high level table always sets r/w, last level page
-                        * table control read/write
-                        */
-                       dma_set_pte_readable(pte);
-                       dma_set_pte_writable(pte);
-                       domain_flush_cache(domain, pte, sizeof(*pte));
                }
                parent = phys_to_virt(dma_pte_addr(pte));
                level--;
        }
 
-       spin_unlock_irqrestore(&domain->mapping_lock, flags);
        return pte;
 }
 
 /* return address's pte at specific level */
-static struct dma_pte *dma_addr_level_pte(struct dmar_domain *domain, u64 addr,
-               int level)
+static struct dma_pte *dma_pfn_level_pte(struct dmar_domain *domain,
+                                        unsigned long pfn,
+                                        int level)
 {
        struct dma_pte *parent, *pte = NULL;
        int total = agaw_to_level(domain->agaw);
@@ -716,7 +754,7 @@ static struct dma_pte *dma_addr_level_pte(struct dmar_domain *domain, u64 addr,
 
        parent = domain->pgd;
        while (level <= total) {
-               offset = address_level_offset(addr, total);
+               offset = pfn_level_offset(pfn, total);
                pte = &parent[offset];
                if (level == total)
                        return pte;
@@ -729,74 +767,82 @@ static struct dma_pte *dma_addr_level_pte(struct dmar_domain *domain, u64 addr,
        return NULL;
 }
 
-/* clear one page's page table */
-static void dma_pte_clear_one(struct dmar_domain *domain, u64 addr)
-{
-       struct dma_pte *pte = NULL;
-
-       /* get last level pte */
-       pte = dma_addr_level_pte(domain, addr, 1);
-
-       if (pte) {
-               dma_clear_pte(pte);
-               domain_flush_cache(domain, pte, sizeof(*pte));
-       }
-}
-
 /* clear last level pte, a tlb flush should be followed */
-static void dma_pte_clear_range(struct dmar_domain *domain, u64 start, u64 end)
+static void dma_pte_clear_range(struct dmar_domain *domain,
+                               unsigned long start_pfn,
+                               unsigned long last_pfn)
 {
-       int addr_width = agaw_to_width(domain->agaw);
-       int npages;
+       int addr_width = agaw_to_width(domain->agaw) - VTD_PAGE_SHIFT;
+       struct dma_pte *first_pte, *pte;
 
-       start &= (((u64)1) << addr_width) - 1;
-       end &= (((u64)1) << addr_width) - 1;
-       /* in case it's partial page */
-       start &= PAGE_MASK;
-       end = PAGE_ALIGN(end);
-       npages = (end - start) / VTD_PAGE_SIZE;
+       BUG_ON(addr_width < BITS_PER_LONG && start_pfn >> addr_width);
+       BUG_ON(addr_width < BITS_PER_LONG && last_pfn >> addr_width);
 
-       /* we don't need lock here, nobody else touches the iova range */
-       while (npages--) {
-               dma_pte_clear_one(domain, start);
-               start += VTD_PAGE_SIZE;
+       /* we don't need lock here; nobody else touches the iova range */
+       while (start_pfn <= last_pfn) {
+               first_pte = pte = dma_pfn_level_pte(domain, start_pfn, 1);
+               if (!pte) {
+                       start_pfn = align_to_level(start_pfn + 1, 2);
+                       continue;
+               }
+               do { 
+                       dma_clear_pte(pte);
+                       start_pfn++;
+                       pte++;
+               } while (start_pfn <= last_pfn && !first_pte_in_page(pte));
+
+               domain_flush_cache(domain, first_pte,
+                                  (void *)pte - (void *)first_pte);
        }
 }
 
 /* free page table pages. last level pte should already be cleared */
 static void dma_pte_free_pagetable(struct dmar_domain *domain,
-       u64 start, u64 end)
+                                  unsigned long start_pfn,
+                                  unsigned long last_pfn)
 {
-       int addr_width = agaw_to_width(domain->agaw);
-       struct dma_pte *pte;
+       int addr_width = agaw_to_width(domain->agaw) - VTD_PAGE_SHIFT;
+       struct dma_pte *first_pte, *pte;
        int total = agaw_to_level(domain->agaw);
        int level;
-       u64 tmp;
+       unsigned long tmp;
 
-       start &= (((u64)1) << addr_width) - 1;
-       end &= (((u64)1) << addr_width) - 1;
+       BUG_ON(addr_width < BITS_PER_LONG && start_pfn >> addr_width);
+       BUG_ON(addr_width < BITS_PER_LONG && last_pfn >> addr_width);
 
-       /* we don't need lock here, nobody else touches the iova range */
+       /* We don't need lock here; nobody else touches the iova range */
        level = 2;
        while (level <= total) {
-               tmp = align_to_level(start, level);
-               if (tmp >= end || (tmp + level_size(level) > end))
+               tmp = align_to_level(start_pfn, level);
+
+               /* If we can't even clear one PTE at this level, we're done */
+               if (tmp + level_size(level) - 1 > last_pfn)
                        return;
 
-               while (tmp < end) {
-                       pte = dma_addr_level_pte(domain, tmp, level);
-                       if (pte) {
-                               free_pgtable_page(
-                                       phys_to_virt(dma_pte_addr(pte)));
-                               dma_clear_pte(pte);
-                               domain_flush_cache(domain, pte, sizeof(*pte));
+               while (tmp + level_size(level) - 1 <= last_pfn) {
+                       first_pte = pte = dma_pfn_level_pte(domain, tmp, level);
+                       if (!pte) {
+                               tmp = align_to_level(tmp + 1, level + 1);
+                               continue;
                        }
-                       tmp += level_size(level);
+                       do {
+                               if (dma_pte_present(pte)) {
+                                       free_pgtable_page(phys_to_virt(dma_pte_addr(pte)));
+                                       dma_clear_pte(pte);
+                               }
+                               pte++;
+                               tmp += level_size(level);
+                       } while (!first_pte_in_page(pte) &&
+                                tmp + level_size(level) - 1 <= last_pfn);
+
+                       domain_flush_cache(domain, first_pte,
+                                          (void *)pte - (void *)first_pte);
+                       
                }
                level++;
        }
        /* free pgd */
-       if (start == 0 && end >= ((((u64)1) << addr_width) - 1)) {
+       if (start_pfn == 0 && last_pfn == DOMAIN_MAX_PFN(domain->gaw)) {
                free_pgtable_page(domain->pgd);
                domain->pgd = NULL;
        }
@@ -1022,11 +1068,11 @@ static void iommu_flush_dev_iotlb(struct dmar_domain *domain,
 }
 
 static void iommu_flush_iotlb_psi(struct intel_iommu *iommu, u16 did,
-                                 u64 addr, unsigned int pages)
+                                 unsigned long pfn, unsigned int pages)
 {
        unsigned int mask = ilog2(__roundup_pow_of_two(pages));
+       uint64_t addr = (uint64_t)pfn << VTD_PAGE_SHIFT;
 
-       BUG_ON(addr & (~VTD_PAGE_MASK));
        BUG_ON(pages == 0);
 
        /*
@@ -1041,7 +1087,12 @@ static void iommu_flush_iotlb_psi(struct intel_iommu *iommu, u16 did,
        else
                iommu->flush.flush_iotlb(iommu, did, addr, mask,
                                                DMA_TLB_PSI_FLUSH);
-       if (did)
+
+       /*
+        * In caching mode, domain ID 0 is reserved for non-present to present
+        * mapping flush. Device IOTLB doesn't need to be flushed in this case.
+        */
+       if (!cap_caching_mode(iommu->cap) || did)
                iommu_flush_dev_iotlb(iommu->domains[did], addr, mask);
 }
 
@@ -1189,48 +1240,71 @@ void free_dmar_iommu(struct intel_iommu *iommu)
        free_context_table(iommu);
 }
 
-static struct dmar_domain * iommu_alloc_domain(struct intel_iommu *iommu)
+static struct dmar_domain *alloc_domain(void)
 {
-       unsigned long num;
-       unsigned long ndomains;
        struct dmar_domain *domain;
-       unsigned long flags;
 
        domain = alloc_domain_mem();
        if (!domain)
                return NULL;
 
+       memset(&domain->iommu_bmp, 0, sizeof(unsigned long));
+       domain->flags = 0;
+
+       return domain;
+}
+
+static int iommu_attach_domain(struct dmar_domain *domain,
+                              struct intel_iommu *iommu)
+{
+       int num;
+       unsigned long ndomains;
+       unsigned long flags;
+
        ndomains = cap_ndoms(iommu->cap);
 
        spin_lock_irqsave(&iommu->lock, flags);
+
        num = find_first_zero_bit(iommu->domain_ids, ndomains);
        if (num >= ndomains) {
                spin_unlock_irqrestore(&iommu->lock, flags);
-               free_domain_mem(domain);
                printk(KERN_ERR "IOMMU: no free domain ids\n");
-               return NULL;
+               return -ENOMEM;
        }
 
-       set_bit(num, iommu->domain_ids);
        domain->id = num;
-       memset(&domain->iommu_bmp, 0, sizeof(unsigned long));
+       set_bit(num, iommu->domain_ids);
        set_bit(iommu->seq_id, &domain->iommu_bmp);
-       domain->flags = 0;
        iommu->domains[num] = domain;
        spin_unlock_irqrestore(&iommu->lock, flags);
 
-       return domain;
+       return 0;
 }
 
-static void iommu_free_domain(struct dmar_domain *domain)
+static void iommu_detach_domain(struct dmar_domain *domain,
+                               struct intel_iommu *iommu)
 {
        unsigned long flags;
-       struct intel_iommu *iommu;
-
-       iommu = domain_get_iommu(domain);
+       int num, ndomains;
+       int found = 0;
 
        spin_lock_irqsave(&iommu->lock, flags);
-       clear_bit(domain->id, iommu->domain_ids);
+       ndomains = cap_ndoms(iommu->cap);
+       num = find_first_bit(iommu->domain_ids, ndomains);
+       for (; num < ndomains; ) {
+               if (iommu->domains[num] == domain) {
+                       found = 1;
+                       break;
+               }
+               num = find_next_bit(iommu->domain_ids,
+                                   cap_ndoms(iommu->cap), num+1);
+       }
+
+       if (found) {
+               clear_bit(num, iommu->domain_ids);
+               clear_bit(iommu->seq_id, &domain->iommu_bmp);
+               iommu->domains[num] = NULL;
+       }
        spin_unlock_irqrestore(&iommu->lock, flags);
 }
 
@@ -1243,7 +1317,6 @@ static void dmar_init_reserved_ranges(void)
        struct pci_dev *pdev = NULL;
        struct iova *iova;
        int i;
-       u64 addr, size;
 
        init_iova_domain(&reserved_iova_list, DMA_32BIT_PFN);
 
@@ -1266,12 +1339,9 @@ static void dmar_init_reserved_ranges(void)
                        r = &pdev->resource[i];
                        if (!r->flags || !(r->flags & IORESOURCE_MEM))
                                continue;
-                       addr = r->start;
-                       addr &= PHYSICAL_PAGE_MASK;
-                       size = r->end - addr;
-                       size = PAGE_ALIGN(size);
-                       iova = reserve_iova(&reserved_iova_list, IOVA_PFN(addr),
-                               IOVA_PFN(size + addr) - 1);
+                       iova = reserve_iova(&reserved_iova_list,
+                                           IOVA_PFN(r->start),
+                                           IOVA_PFN(r->end));
                        if (!iova)
                                printk(KERN_ERR "Reserve iova failed\n");
                }
@@ -1305,7 +1375,6 @@ static int domain_init(struct dmar_domain *domain, int guest_width)
        unsigned long sagaw;
 
        init_iova_domain(&domain->iovad, DMA_32BIT_PFN);
-       spin_lock_init(&domain->mapping_lock);
        spin_lock_init(&domain->iommu_lock);
 
        domain_reserve_special_ranges(domain);
@@ -1350,7 +1419,8 @@ static int domain_init(struct dmar_domain *domain, int guest_width)
 
 static void domain_exit(struct dmar_domain *domain)
 {
-       u64 end;
+       struct dmar_drhd_unit *drhd;
+       struct intel_iommu *iommu;
 
        /* Domain 0 is reserved, so dont process it */
        if (!domain)
@@ -1359,16 +1429,17 @@ static void domain_exit(struct dmar_domain *domain)
        domain_remove_dev_info(domain);
        /* destroy iovas */
        put_iova_domain(&domain->iovad);
-       end = DOMAIN_MAX_ADDR(domain->gaw);
-       end = end & (~PAGE_MASK);
 
        /* clear ptes */
-       dma_pte_clear_range(domain, 0, end);
+       dma_pte_clear_range(domain, 0, DOMAIN_MAX_PFN(domain->gaw));
 
        /* free page tables */
-       dma_pte_free_pagetable(domain, 0, end);
+       dma_pte_free_pagetable(domain, 0, DOMAIN_MAX_PFN(domain->gaw));
+
+       for_each_active_iommu(iommu, drhd)
+               if (test_bit(iommu->seq_id, &domain->iommu_bmp))
+                       iommu_detach_domain(domain, iommu);
 
-       iommu_free_domain(domain);
        free_domain_mem(domain);
 }
 
@@ -1408,7 +1479,8 @@ static int domain_context_mapping_one(struct dmar_domain *domain, int segment,
        id = domain->id;
        pgd = domain->pgd;
 
-       if (domain->flags & DOMAIN_FLAG_VIRTUAL_MACHINE) {
+       if (domain->flags & DOMAIN_FLAG_VIRTUAL_MACHINE ||
+           domain->flags & DOMAIN_FLAG_STATIC_IDENTITY) {
                int found = 0;
 
                /* find an available domain id for this device in iommu */
@@ -1433,6 +1505,7 @@ static int domain_context_mapping_one(struct dmar_domain *domain, int segment,
                        }
 
                        set_bit(num, iommu->domain_ids);
+                       set_bit(iommu->seq_id, &domain->iommu_bmp);
                        iommu->domains[num] = domain;
                        id = num;
                }
@@ -1575,42 +1648,86 @@ static int domain_context_mapped(struct pci_dev *pdev)
                                             tmp->devfn);
 }
 
-static int
-domain_page_mapping(struct dmar_domain *domain, dma_addr_t iova,
-                       u64 hpa, size_t size, int prot)
+static int __domain_mapping(struct dmar_domain *domain, unsigned long iov_pfn,
+                           struct scatterlist *sg, unsigned long phys_pfn,
+                           unsigned long nr_pages, int prot)
 {
-       u64 start_pfn, end_pfn;
-       struct dma_pte *pte;
-       int index;
-       int addr_width = agaw_to_width(domain->agaw);
+       struct dma_pte *first_pte = NULL, *pte = NULL;
+       phys_addr_t uninitialized_var(pteval);
+       int addr_width = agaw_to_width(domain->agaw) - VTD_PAGE_SHIFT;
+       unsigned long sg_res;
 
-       hpa &= (((u64)1) << addr_width) - 1;
+       BUG_ON(addr_width < BITS_PER_LONG && (iov_pfn + nr_pages - 1) >> addr_width);
 
        if ((prot & (DMA_PTE_READ|DMA_PTE_WRITE)) == 0)
                return -EINVAL;
-       iova &= PAGE_MASK;
-       start_pfn = ((u64)hpa) >> VTD_PAGE_SHIFT;
-       end_pfn = (VTD_PAGE_ALIGN(((u64)hpa) + size)) >> VTD_PAGE_SHIFT;
-       index = 0;
-       while (start_pfn < end_pfn) {
-               pte = addr_to_dma_pte(domain, iova + VTD_PAGE_SIZE * index);
-               if (!pte)
-                       return -ENOMEM;
+
+       prot &= DMA_PTE_READ | DMA_PTE_WRITE | DMA_PTE_SNP;
+
+       if (sg)
+               sg_res = 0;
+       else {
+               sg_res = nr_pages + 1;
+               pteval = ((phys_addr_t)phys_pfn << VTD_PAGE_SHIFT) | prot;
+       }
+
+       while (nr_pages--) {
+               uint64_t tmp;
+
+               if (!sg_res) {
+                       sg_res = (sg->offset + sg->length + VTD_PAGE_SIZE - 1) >> VTD_PAGE_SHIFT;
+                       sg->dma_address = ((dma_addr_t)iov_pfn << VTD_PAGE_SHIFT) + sg->offset;
+                       sg->dma_length = sg->length;
+                       pteval = page_to_phys(sg_page(sg)) | prot;
+               }
+               if (!pte) {
+                       first_pte = pte = pfn_to_dma_pte(domain, iov_pfn);
+                       if (!pte)
+                               return -ENOMEM;
+               }
                /* We don't need lock here, nobody else
                 * touches the iova range
                 */
-               BUG_ON(dma_pte_addr(pte));
-               dma_set_pte_addr(pte, start_pfn << VTD_PAGE_SHIFT);
-               dma_set_pte_prot(pte, prot);
-               if (prot & DMA_PTE_SNP)
-                       dma_set_pte_snp(pte);
-               domain_flush_cache(domain, pte, sizeof(*pte));
-               start_pfn++;
-               index++;
+               tmp = cmpxchg64_local(&pte->val, 0ULL, pteval);
+               if (tmp) {
+                       static int dumps = 5;
+                       printk(KERN_CRIT "ERROR: DMA PTE for vPFN 0x%lx already set (to %llx not %llx)\n",
+                              iov_pfn, tmp, (unsigned long long)pteval);
+                       if (dumps) {
+                               dumps--;
+                               debug_dma_dump_mappings(NULL);
+                       }
+                       WARN_ON(1);
+               }
+               pte++;
+               if (!nr_pages || first_pte_in_page(pte)) {
+                       domain_flush_cache(domain, first_pte,
+                                          (void *)pte - (void *)first_pte);
+                       pte = NULL;
+               }
+               iov_pfn++;
+               pteval += VTD_PAGE_SIZE;
+               sg_res--;
+               if (!sg_res)
+                       sg = sg_next(sg);
        }
        return 0;
 }
 
+static inline int domain_sg_mapping(struct dmar_domain *domain, unsigned long iov_pfn,
+                                   struct scatterlist *sg, unsigned long nr_pages,
+                                   int prot)
+{
+       return __domain_mapping(domain, iov_pfn, sg, 0, nr_pages, prot);
+}
+
+static inline int domain_pfn_mapping(struct dmar_domain *domain, unsigned long iov_pfn,
+                                    unsigned long phys_pfn, unsigned long nr_pages,
+                                    int prot)
+{
+       return __domain_mapping(domain, iov_pfn, NULL, phys_pfn, nr_pages, prot);
+}
+
 static void iommu_detach_dev(struct intel_iommu *iommu, u8 bus, u8 devfn)
 {
        if (!iommu)
@@ -1675,6 +1792,7 @@ static struct dmar_domain *get_domain_for_dev(struct pci_dev *pdev, int gaw)
        unsigned long flags;
        int bus = 0, devfn = 0;
        int segment;
+       int ret;
 
        domain = find_domain(pdev);
        if (domain)
@@ -1707,6 +1825,10 @@ static struct dmar_domain *get_domain_for_dev(struct pci_dev *pdev, int gaw)
                }
        }
 
+       domain = alloc_domain();
+       if (!domain)
+               goto error;
+
        /* Allocate new domain for the device */
        drhd = dmar_find_matched_drhd_unit(pdev);
        if (!drhd) {
@@ -1716,9 +1838,11 @@ static struct dmar_domain *get_domain_for_dev(struct pci_dev *pdev, int gaw)
        }
        iommu = drhd->iommu;
 
-       domain = iommu_alloc_domain(iommu);
-       if (!domain)
+       ret = iommu_attach_domain(domain, iommu);
+       if (ret) {
+               domain_exit(domain);
                goto error;
+       }
 
        if (domain_init(domain, gaw)) {
                domain_exit(domain);
@@ -1792,55 +1916,63 @@ error:
        return find_domain(pdev);
 }
 
+static int iommu_identity_mapping;
+
+static int iommu_domain_identity_map(struct dmar_domain *domain,
+                                    unsigned long long start,
+                                    unsigned long long end)
+{
+       unsigned long first_vpfn = start >> VTD_PAGE_SHIFT;
+       unsigned long last_vpfn = end >> VTD_PAGE_SHIFT;
+
+       if (!reserve_iova(&domain->iovad, dma_to_mm_pfn(first_vpfn),
+                         dma_to_mm_pfn(last_vpfn))) {
+               printk(KERN_ERR "IOMMU: reserve iova failed\n");
+               return -ENOMEM;
+       }
+
+       pr_debug("Mapping reserved region %llx-%llx for domain %d\n",
+                start, end, domain->id);
+       /*
+        * RMRR range might have overlap with physical memory range,
+        * clear it first
+        */
+       dma_pte_clear_range(domain, first_vpfn, last_vpfn);
+
+       return domain_pfn_mapping(domain, first_vpfn, first_vpfn,
+                                 last_vpfn - first_vpfn + 1,
+                                 DMA_PTE_READ|DMA_PTE_WRITE);
+}
+
 static int iommu_prepare_identity_map(struct pci_dev *pdev,
                                      unsigned long long start,
                                      unsigned long long end)
 {
        struct dmar_domain *domain;
-       unsigned long size;
-       unsigned long long base;
        int ret;
 
        printk(KERN_INFO
-               "IOMMU: Setting identity map for device %s [0x%Lx - 0x%Lx]\n",
-               pci_name(pdev), start, end);
-       /* page table init */
+              "IOMMU: Setting identity map for device %s [0x%Lx - 0x%Lx]\n",
+              pci_name(pdev), start, end);
+
        domain = get_domain_for_dev(pdev, DEFAULT_DOMAIN_ADDRESS_WIDTH);
        if (!domain)
                return -ENOMEM;
 
-       /* The address might not be aligned */
-       base = start & PAGE_MASK;
-       size = end - base;
-       size = PAGE_ALIGN(size);
-       if (!reserve_iova(&domain->iovad, IOVA_PFN(base),
-                       IOVA_PFN(base + size) - 1)) {
-               printk(KERN_ERR "IOMMU: reserve iova failed\n");
-               ret = -ENOMEM;
-               goto error;
-       }
-
-       pr_debug("Mapping reserved region %lx@%llx for %s\n",
-               size, base, pci_name(pdev));
-       /*
-        * RMRR range might have overlap with physical memory range,
-        * clear it first
-        */
-       dma_pte_clear_range(domain, base, base + size);
-
-       ret = domain_page_mapping(domain, base, base, size,
-               DMA_PTE_READ|DMA_PTE_WRITE);
+       ret = iommu_domain_identity_map(domain, start, end);
        if (ret)
                goto error;
 
        /* context entry init */
        ret = domain_context_mapping(domain, pdev, CONTEXT_TT_MULTI_LEVEL);
-       if (!ret)
-               return 0;
-error:
+       if (ret)
+               goto error;
+
+       return 0;
+
+ error:
        domain_exit(domain);
        return ret;
-
 }
 
 static inline int iommu_prepare_rmrr_dev(struct dmar_rmrr_unit *rmrr,
@@ -1852,64 +1984,6 @@ static inline int iommu_prepare_rmrr_dev(struct dmar_rmrr_unit *rmrr,
                rmrr->end_address + 1);
 }
 
-#ifdef CONFIG_DMAR_GFX_WA
-struct iommu_prepare_data {
-       struct pci_dev *pdev;
-       int ret;
-};
-
-static int __init iommu_prepare_work_fn(unsigned long start_pfn,
-                                        unsigned long end_pfn, void *datax)
-{
-       struct iommu_prepare_data *data;
-
-       data = (struct iommu_prepare_data *)datax;
-
-       data->ret = iommu_prepare_identity_map(data->pdev,
-                               start_pfn<<PAGE_SHIFT, end_pfn<<PAGE_SHIFT);
-       return data->ret;
-
-}
-
-static int __init iommu_prepare_with_active_regions(struct pci_dev *pdev)
-{
-       int nid;
-       struct iommu_prepare_data data;
-
-       data.pdev = pdev;
-       data.ret = 0;
-
-       for_each_online_node(nid) {
-               work_with_active_regions(nid, iommu_prepare_work_fn, &data);
-               if (data.ret)
-                       return data.ret;
-       }
-       return data.ret;
-}
-
-static void __init iommu_prepare_gfx_mapping(void)
-{
-       struct pci_dev *pdev = NULL;
-       int ret;
-
-       for_each_pci_dev(pdev) {
-               if (pdev->dev.archdata.iommu == DUMMY_DEVICE_DOMAIN_INFO ||
-                               !IS_GFX_DEVICE(pdev))
-                       continue;
-               printk(KERN_INFO "IOMMU: gfx device %s 1-1 mapping\n",
-                       pci_name(pdev));
-               ret = iommu_prepare_with_active_regions(pdev);
-               if (ret)
-                       printk(KERN_ERR "IOMMU: mapping reserved region failed\n");
-       }
-}
-#else /* !CONFIG_DMAR_GFX_WA */
-static inline void iommu_prepare_gfx_mapping(void)
-{
-       return;
-}
-#endif
-
 #ifdef CONFIG_DMAR_FLOPPY_WA
 static inline void iommu_prepare_isa(void)
 {
@@ -1920,12 +1994,12 @@ static inline void iommu_prepare_isa(void)
        if (!pdev)
                return;
 
-       printk(KERN_INFO "IOMMU: Prepare 0-16M unity mapping for LPC\n");
+       printk(KERN_INFO "IOMMU: Prepare 0-16MiB unity mapping for LPC\n");
        ret = iommu_prepare_identity_map(pdev, 0, 16*1024*1024);
 
        if (ret)
-               printk(KERN_ERR "IOMMU: Failed to create 0-64M identity map, "
-                       "floppy might not work\n");
+               printk(KERN_ERR "IOMMU: Failed to create 0-16MiB identity map; "
+                      "floppy might not work\n");
 
 }
 #else
@@ -1952,7 +2026,166 @@ static int __init init_context_pass_through(void)
        return 0;
 }
 
-static int __init init_dmars(void)
+static int md_domain_init(struct dmar_domain *domain, int guest_width);
+
+static int __init si_domain_work_fn(unsigned long start_pfn,
+                                   unsigned long end_pfn, void *datax)
+{
+       int *ret = datax;
+
+       *ret = iommu_domain_identity_map(si_domain,
+                                        (uint64_t)start_pfn << PAGE_SHIFT,
+                                        (uint64_t)end_pfn << PAGE_SHIFT);
+       return *ret;
+
+}
+
+static int si_domain_init(void)
+{
+       struct dmar_drhd_unit *drhd;
+       struct intel_iommu *iommu;
+       int nid, ret = 0;
+
+       si_domain = alloc_domain();
+       if (!si_domain)
+               return -EFAULT;
+
+       pr_debug("Identity mapping domain is domain %d\n", si_domain->id);
+
+       for_each_active_iommu(iommu, drhd) {
+               ret = iommu_attach_domain(si_domain, iommu);
+               if (ret) {
+                       domain_exit(si_domain);
+                       return -EFAULT;
+               }
+       }
+
+       if (md_domain_init(si_domain, DEFAULT_DOMAIN_ADDRESS_WIDTH)) {
+               domain_exit(si_domain);
+               return -EFAULT;
+       }
+
+       si_domain->flags = DOMAIN_FLAG_STATIC_IDENTITY;
+
+       for_each_online_node(nid) {
+               work_with_active_regions(nid, si_domain_work_fn, &ret);
+               if (ret)
+                       return ret;
+       }
+
+       return 0;
+}
+
+static void domain_remove_one_dev_info(struct dmar_domain *domain,
+                                         struct pci_dev *pdev);
+static int identity_mapping(struct pci_dev *pdev)
+{
+       struct device_domain_info *info;
+
+       if (likely(!iommu_identity_mapping))
+               return 0;
+
+
+       list_for_each_entry(info, &si_domain->devices, link)
+               if (info->dev == pdev)
+                       return 1;
+       return 0;
+}
+
+static int domain_add_dev_info(struct dmar_domain *domain,
+                                 struct pci_dev *pdev)
+{
+       struct device_domain_info *info;
+       unsigned long flags;
+
+       info = alloc_devinfo_mem();
+       if (!info)
+               return -ENOMEM;
+
+       info->segment = pci_domain_nr(pdev->bus);
+       info->bus = pdev->bus->number;
+       info->devfn = pdev->devfn;
+       info->dev = pdev;
+       info->domain = domain;
+
+       spin_lock_irqsave(&device_domain_lock, flags);
+       list_add(&info->link, &domain->devices);
+       list_add(&info->global, &device_domain_list);
+       pdev->dev.archdata.iommu = info;
+       spin_unlock_irqrestore(&device_domain_lock, flags);
+
+       return 0;
+}
+
+static int iommu_should_identity_map(struct pci_dev *pdev, int startup)
+{
+       if (iommu_identity_mapping == 2)
+               return IS_GFX_DEVICE(pdev);
+
+       /*
+        * We want to start off with all devices in the 1:1 domain, and
+        * take them out later if we find they can't access all of memory.
+        *
+        * However, we can't do this for PCI devices behind bridges,
+        * because all PCI devices behind the same bridge will end up
+        * with the same source-id on their transactions.
+        *
+        * Practically speaking, we can't change things around for these
+        * devices at run-time, because we can't be sure there'll be no
+        * DMA transactions in flight for any of their siblings.
+        * 
+        * So PCI devices (unless they're on the root bus) as well as
+        * their parent PCI-PCI or PCIe-PCI bridges must be left _out_ of
+        * the 1:1 domain, just in _case_ one of their siblings turns out
+        * not to be able to map all of memory.
+        */
+       if (!pdev->is_pcie) {
+               if (!pci_is_root_bus(pdev->bus))
+                       return 0;
+               if (pdev->class >> 8 == PCI_CLASS_BRIDGE_PCI)
+                       return 0;
+       } else if (pdev->pcie_type == PCI_EXP_TYPE_PCI_BRIDGE)
+               return 0;
+
+       /* 
+        * At boot time, we don't yet know if devices will be 64-bit capable.
+        * Assume that they will -- if they turn out not to be, then we can 
+        * take them out of the 1:1 domain later.
+        */
+       if (!startup)
+               return pdev->dma_mask > DMA_BIT_MASK(32);
+
+       return 1;
+}
+
+static int iommu_prepare_static_identity_mapping(void)
+{
+       struct pci_dev *pdev = NULL;
+       int ret;
+
+       ret = si_domain_init();
+       if (ret)
+               return -EFAULT;
+
+       for_each_pci_dev(pdev) {
+               if (iommu_should_identity_map(pdev, 1)) {
+                       printk(KERN_INFO "IOMMU: identity mapping for device %s\n",
+                              pci_name(pdev));
+
+                       ret = domain_context_mapping(si_domain, pdev,
+                                                    CONTEXT_TT_MULTI_LEVEL);
+                       if (ret)
+                               return ret;
+                       ret = domain_add_dev_info(si_domain, pdev);
+                       if (ret)
+                               return ret;
+               }
+       }
+
+       return 0;
+}
+
+int __init init_dmars(void)
 {
        struct dmar_drhd_unit *drhd;
        struct dmar_rmrr_unit *rmrr;
@@ -1961,6 +2194,13 @@ static int __init init_dmars(void)
        int i, ret;
        int pass_through = 1;
 
+       /*
+        * In case pass through can not be enabled, iommu tries to use identity
+        * mapping.
+        */
+       if (iommu_pass_through)
+               iommu_identity_mapping = 1;
+
        /*
         * for each drhd
         *    allocate root
@@ -2090,9 +2330,16 @@ static int __init init_dmars(void)
 
        /*
         * If pass through is not set or not enabled, setup context entries for
-        * identity mappings for rmrr, gfx, and isa.
+        * identity mappings for rmrr, gfx, and isa and may fall back to static
+        * identity mapping if iommu_identity_mapping is set.
         */
        if (!iommu_pass_through) {
+#ifdef CONFIG_DMAR_BROKEN_GFX_WA
+               if (!iommu_identity_mapping)
+                       iommu_identity_mapping = 2;
+#endif
+               if (iommu_identity_mapping)
+                       iommu_prepare_static_identity_mapping();
                /*
                 * For each rmrr
                 *   for each dev attached to rmrr
@@ -2107,6 +2354,7 @@ static int __init init_dmars(void)
                 *    endfor
                 * endfor
                 */
+               printk(KERN_INFO "IOMMU: Setting RMRR:\n");
                for_each_rmrr_units(rmrr) {
                        for (i = 0; i < rmrr->devices_cnt; i++) {
                                pdev = rmrr->devices[i];
@@ -2123,8 +2371,6 @@ static int __init init_dmars(void)
                        }
                }
 
-               iommu_prepare_gfx_mapping();
-
                iommu_prepare_isa();
        }
 
@@ -2169,50 +2415,40 @@ error:
        return ret;
 }
 
-static inline u64 aligned_size(u64 host_addr, size_t size)
+/* Returns a number of VTD pages, but aligned to MM page size */
+static inline unsigned long aligned_nrpages(unsigned long host_addr,
+                                           size_t size)
 {
-       u64 addr;
-       addr = (host_addr & (~PAGE_MASK)) + size;
-       return PAGE_ALIGN(addr);
+       host_addr &= ~PAGE_MASK;
+       return PAGE_ALIGN(host_addr + size) >> VTD_PAGE_SHIFT;
 }
 
-struct iova *
-iommu_alloc_iova(struct dmar_domain *domain, size_t size, u64 end)
-{
-       struct iova *piova;
-
-       /* Make sure it's in range */
-       end = min_t(u64, DOMAIN_MAX_ADDR(domain->gaw), end);
-       if (!size || (IOVA_START_ADDR + size > end))
-               return NULL;
-
-       piova = alloc_iova(&domain->iovad,
-                       size >> PAGE_SHIFT, IOVA_PFN(end), 1);
-       return piova;
-}
-
-static struct iova *
-__intel_alloc_iova(struct device *dev, struct dmar_domain *domain,
-                  size_t size, u64 dma_mask)
+/* This takes a number of _MM_ pages, not VTD pages */
+static struct iova *intel_alloc_iova(struct device *dev,
+                                    struct dmar_domain *domain,
+                                    unsigned long nrpages, uint64_t dma_mask)
 {
        struct pci_dev *pdev = to_pci_dev(dev);
        struct iova *iova = NULL;
 
-       if (dma_mask <= DMA_BIT_MASK(32) || dmar_forcedac)
-               iova = iommu_alloc_iova(domain, size, dma_mask);
-       else {
+       /* Restrict dma_mask to the width that the iommu can handle */
+       dma_mask = min_t(uint64_t, DOMAIN_MAX_ADDR(domain->gaw), dma_mask);
+
+       if (!dmar_forcedac && dma_mask > DMA_BIT_MASK(32)) {
                /*
                 * First try to allocate an io virtual address in
                 * DMA_BIT_MASK(32) and if that fails then try allocating
                 * from higher range
                 */
-               iova = iommu_alloc_iova(domain, size, DMA_BIT_MASK(32));
-               if (!iova)
-                       iova = iommu_alloc_iova(domain, size, dma_mask);
-       }
-
-       if (!iova) {
-               printk(KERN_ERR"Allocating iova for %s failed", pci_name(pdev));
+               iova = alloc_iova(&domain->iovad, nrpages,
+                                 IOVA_PFN(DMA_BIT_MASK(32)), 1);
+               if (iova)
+                       return iova;
+       }
+       iova = alloc_iova(&domain->iovad, nrpages, IOVA_PFN(dma_mask), 1);
+       if (unlikely(!iova)) {
+               printk(KERN_ERR "Allocating %ld-page iova for %s failed",
+                      nrpages, pci_name(pdev));
                return NULL;
        }
 
@@ -2248,6 +2484,63 @@ get_valid_domain_for_dev(struct pci_dev *pdev)
        return domain;
 }
 
+static int iommu_dummy(struct pci_dev *pdev)
+{
+       return pdev->dev.archdata.iommu == DUMMY_DEVICE_DOMAIN_INFO;
+}
+
+/* Check if the pdev needs to go through non-identity map and unmap process.*/
+static int iommu_no_mapping(struct device *dev)
+{
+       struct pci_dev *pdev;
+       int found;
+
+       if (unlikely(dev->bus != &pci_bus_type))
+               return 1;
+
+       pdev = to_pci_dev(dev);
+       if (iommu_dummy(pdev))
+               return 1;
+
+       if (!iommu_identity_mapping)
+               return 0;
+
+       found = identity_mapping(pdev);
+       if (found) {
+               if (iommu_should_identity_map(pdev, 0))
+                       return 1;
+               else {
+                       /*
+                        * 32 bit DMA is removed from si_domain and fall back
+                        * to non-identity mapping.
+                        */
+                       domain_remove_one_dev_info(si_domain, pdev);
+                       printk(KERN_INFO "32bit %s uses non-identity mapping\n",
+                              pci_name(pdev));
+                       return 0;
+               }
+       } else {
+               /*
+                * In case of a detached 64 bit DMA device from vm, the device
+                * is put into si_domain for identity mapping.
+                */
+               if (iommu_should_identity_map(pdev, 0)) {
+                       int ret;
+                       ret = domain_add_dev_info(si_domain, pdev);
+                       if (ret)
+                               return 0;
+                       ret = domain_context_mapping(si_domain, pdev, CONTEXT_TT_MULTI_LEVEL);
+                       if (!ret) {
+                               printk(KERN_INFO "64bit %s uses identity mapping\n",
+                                      pci_name(pdev));
+                               return 1;
+                       }
+               }
+       }
+
+       return 0;
+}
+
 static dma_addr_t __intel_map_single(struct device *hwdev, phys_addr_t paddr,
                                     size_t size, int dir, u64 dma_mask)
 {
@@ -2260,7 +2553,8 @@ static dma_addr_t __intel_map_single(struct device *hwdev, phys_addr_t paddr,
        struct intel_iommu *iommu;
 
        BUG_ON(dir == DMA_NONE);
-       if (pdev->dev.archdata.iommu == DUMMY_DEVICE_DOMAIN_INFO)
+
+       if (iommu_no_mapping(hwdev))
                return paddr;
 
        domain = get_valid_domain_for_dev(pdev);
@@ -2268,14 +2562,13 @@ static dma_addr_t __intel_map_single(struct device *hwdev, phys_addr_t paddr,
                return 0;
 
        iommu = domain_get_iommu(domain);
-       size = aligned_size((u64)paddr, size);
+       size = aligned_nrpages(paddr, size);
 
-       iova = __intel_alloc_iova(hwdev, domain, size, pdev->dma_mask);
+       iova = intel_alloc_iova(hwdev, domain, dma_to_mm_pfn(size),
+                               pdev->dma_mask);
        if (!iova)
                goto error;
 
-       start_paddr = (phys_addr_t)iova->pfn_lo << PAGE_SHIFT;
-
        /*
         * Check if DMAR supports zero-length reads on write only
         * mappings..
@@ -2291,20 +2584,20 @@ static dma_addr_t __intel_map_single(struct device *hwdev, phys_addr_t paddr,
         * might have two guest_addr mapping to the same host paddr, but this
         * is not a big problem
         */
-       ret = domain_page_mapping(domain, start_paddr,
-                                 ((u64)paddr) & PHYSICAL_PAGE_MASK,
-                                 size, prot);
+       ret = domain_pfn_mapping(domain, mm_to_dma_pfn(iova->pfn_lo),
+                                paddr >> VTD_PAGE_SHIFT, size, prot);
        if (ret)
                goto error;
 
        /* it's a non-present to present mapping. Only flush if caching mode */
        if (cap_caching_mode(iommu->cap))
-               iommu_flush_iotlb_psi(iommu, 0, start_paddr,
-                                     size >> VTD_PAGE_SHIFT);
+               iommu_flush_iotlb_psi(iommu, 0, mm_to_dma_pfn(iova->pfn_lo), size);
        else
                iommu_flush_write_buffer(iommu);
 
-       return start_paddr + ((u64)paddr & (~PAGE_MASK));
+       start_paddr = (phys_addr_t)iova->pfn_lo << PAGE_SHIFT;
+       start_paddr += paddr & ~PAGE_MASK;
+       return start_paddr;
 
 error:
        if (iova)
@@ -2397,34 +2690,38 @@ static void intel_unmap_page(struct device *dev, dma_addr_t dev_addr,
 {
        struct pci_dev *pdev = to_pci_dev(dev);
        struct dmar_domain *domain;
-       unsigned long start_addr;
+       unsigned long start_pfn, last_pfn;
        struct iova *iova;
        struct intel_iommu *iommu;
 
-       if (pdev->dev.archdata.iommu == DUMMY_DEVICE_DOMAIN_INFO)
+       if (iommu_no_mapping(dev))
                return;
+
        domain = find_domain(pdev);
        BUG_ON(!domain);
 
        iommu = domain_get_iommu(domain);
 
        iova = find_iova(&domain->iovad, IOVA_PFN(dev_addr));
-       if (!iova)
+       if (WARN_ONCE(!iova, "Driver unmaps unmatched page at PFN %llx\n",
+                     (unsigned long long)dev_addr))
                return;
 
-       start_addr = iova->pfn_lo << PAGE_SHIFT;
-       size = aligned_size((u64)dev_addr, size);
+       start_pfn = mm_to_dma_pfn(iova->pfn_lo);
+       last_pfn = mm_to_dma_pfn(iova->pfn_hi + 1) - 1;
 
-       pr_debug("Device %s unmapping: %zx@%llx\n",
-               pci_name(pdev), size, (unsigned long long)start_addr);
+       pr_debug("Device %s unmapping: pfn %lx-%lx\n",
+                pci_name(pdev), start_pfn, last_pfn);
 
        /*  clear the whole page */
-       dma_pte_clear_range(domain, start_addr, start_addr + size);
+       dma_pte_clear_range(domain, start_pfn, last_pfn);
+
        /* free page tables */
-       dma_pte_free_pagetable(domain, start_addr, start_addr + size);
+       dma_pte_free_pagetable(domain, start_pfn, last_pfn);
+
        if (intel_iommu_strict) {
-               iommu_flush_iotlb_psi(iommu, domain->id, start_addr,
-                                     size >> VTD_PAGE_SHIFT);
+               iommu_flush_iotlb_psi(iommu, domain->id, start_pfn,
+                                     last_pfn - start_pfn + 1);
                /* free iova */
                __free_iova(&domain->iovad, iova);
        } else {
@@ -2482,17 +2779,13 @@ static void intel_unmap_sg(struct device *hwdev, struct scatterlist *sglist,
                           int nelems, enum dma_data_direction dir,
                           struct dma_attrs *attrs)
 {
-       int i;
        struct pci_dev *pdev = to_pci_dev(hwdev);
        struct dmar_domain *domain;
-       unsigned long start_addr;
+       unsigned long start_pfn, last_pfn;
        struct iova *iova;
-       size_t size = 0;
-       phys_addr_t addr;
-       struct scatterlist *sg;
        struct intel_iommu *iommu;
 
-       if (pdev->dev.archdata.iommu == DUMMY_DEVICE_DOMAIN_INFO)
+       if (iommu_no_mapping(hwdev))
                return;
 
        domain = find_domain(pdev);
@@ -2501,22 +2794,21 @@ static void intel_unmap_sg(struct device *hwdev, struct scatterlist *sglist,
        iommu = domain_get_iommu(domain);
 
        iova = find_iova(&domain->iovad, IOVA_PFN(sglist[0].dma_address));
-       if (!iova)
+       if (WARN_ONCE(!iova, "Driver unmaps unmatched sglist at PFN %llx\n",
+                     (unsigned long long)sglist[0].dma_address))
                return;
-       for_each_sg(sglist, sg, nelems, i) {
-               addr = page_to_phys(sg_page(sg)) + sg->offset;
-               size += aligned_size((u64)addr, sg->length);
-       }
 
-       start_addr = iova->pfn_lo << PAGE_SHIFT;
+       start_pfn = mm_to_dma_pfn(iova->pfn_lo);
+       last_pfn = mm_to_dma_pfn(iova->pfn_hi + 1) - 1;
 
        /*  clear the whole page */
-       dma_pte_clear_range(domain, start_addr, start_addr + size);
+       dma_pte_clear_range(domain, start_pfn, last_pfn);
+
        /* free page tables */
-       dma_pte_free_pagetable(domain, start_addr, start_addr + size);
+       dma_pte_free_pagetable(domain, start_pfn, last_pfn);
 
-       iommu_flush_iotlb_psi(iommu, domain->id, start_addr,
-                             size >> VTD_PAGE_SHIFT);
+       iommu_flush_iotlb_psi(iommu, domain->id, start_pfn,
+                             (last_pfn - start_pfn + 1));
 
        /* free iova */
        __free_iova(&domain->iovad, iova);
@@ -2539,21 +2831,20 @@ static int intel_nontranslate_map_sg(struct device *hddev,
 static int intel_map_sg(struct device *hwdev, struct scatterlist *sglist, int nelems,
                        enum dma_data_direction dir, struct dma_attrs *attrs)
 {
-       phys_addr_t addr;
        int i;
        struct pci_dev *pdev = to_pci_dev(hwdev);
        struct dmar_domain *domain;
        size_t size = 0;
        int prot = 0;
-       size_t offset = 0;
+       size_t offset_pfn = 0;
        struct iova *iova = NULL;
        int ret;
        struct scatterlist *sg;
-       unsigned long start_addr;
+       unsigned long start_vpfn;
        struct intel_iommu *iommu;
 
        BUG_ON(dir == DMA_NONE);
-       if (pdev->dev.archdata.iommu == DUMMY_DEVICE_DOMAIN_INFO)
+       if (iommu_no_mapping(hwdev))
                return intel_nontranslate_map_sg(hwdev, sglist, nelems, dir);
 
        domain = get_valid_domain_for_dev(pdev);
@@ -2562,12 +2853,11 @@ static int intel_map_sg(struct device *hwdev, struct scatterlist *sglist, int ne
 
        iommu = domain_get_iommu(domain);
 
-       for_each_sg(sglist, sg, nelems, i) {
-               addr = page_to_phys(sg_page(sg)) + sg->offset;
-               size += aligned_size((u64)addr, sg->length);
-       }
+       for_each_sg(sglist, sg, nelems, i)
+               size += aligned_nrpages(sg->offset, sg->length);
 
-       iova = __intel_alloc_iova(hwdev, domain, size, pdev->dma_mask);
+       iova = intel_alloc_iova(hwdev, domain, dma_to_mm_pfn(size),
+                               pdev->dma_mask);
        if (!iova) {
                sglist->dma_length = 0;
                return 0;
@@ -2583,35 +2873,24 @@ static int intel_map_sg(struct device *hwdev, struct scatterlist *sglist, int ne
        if (dir == DMA_FROM_DEVICE || dir == DMA_BIDIRECTIONAL)
                prot |= DMA_PTE_WRITE;
 
-       start_addr = iova->pfn_lo << PAGE_SHIFT;
-       offset = 0;
-       for_each_sg(sglist, sg, nelems, i) {
-               addr = page_to_phys(sg_page(sg)) + sg->offset;
-               size = aligned_size((u64)addr, sg->length);
-               ret = domain_page_mapping(domain, start_addr + offset,
-                                         ((u64)addr) & PHYSICAL_PAGE_MASK,
-                                         size, prot);
-               if (ret) {
-                       /*  clear the page */
-                       dma_pte_clear_range(domain, start_addr,
-                                 start_addr + offset);
-                       /* free page tables */
-                       dma_pte_free_pagetable(domain, start_addr,
-                                 start_addr + offset);
-                       /* free iova */
-                       __free_iova(&domain->iovad, iova);
-                       return 0;
-               }
-               sg->dma_address = start_addr + offset +
-                               ((u64)addr & (~PAGE_MASK));
-               sg->dma_length = sg->length;
-               offset += size;
+       start_vpfn = mm_to_dma_pfn(iova->pfn_lo);
+
+       ret = domain_sg_mapping(domain, start_vpfn, sglist, mm_to_dma_pfn(size), prot);
+       if (unlikely(ret)) {
+               /*  clear the page */
+               dma_pte_clear_range(domain, start_vpfn,
+                                   start_vpfn + size - 1);
+               /* free page tables */
+               dma_pte_free_pagetable(domain, start_vpfn,
+                                      start_vpfn + size - 1);
+               /* free iova */
+               __free_iova(&domain->iovad, iova);
+               return 0;
        }
 
        /* it's a non-present to present mapping. Only flush if caching mode */
        if (cap_caching_mode(iommu->cap))
-               iommu_flush_iotlb_psi(iommu, 0, start_addr,
-                                     offset >> VTD_PAGE_SHIFT);
+               iommu_flush_iotlb_psi(iommu, 0, start_vpfn, offset_pfn);
        else
                iommu_flush_write_buffer(iommu);
 
@@ -2951,31 +3230,6 @@ int __init intel_iommu_init(void)
        return 0;
 }
 
-static int vm_domain_add_dev_info(struct dmar_domain *domain,
-                                 struct pci_dev *pdev)
-{
-       struct device_domain_info *info;
-       unsigned long flags;
-
-       info = alloc_devinfo_mem();
-       if (!info)
-               return -ENOMEM;
-
-       info->segment = pci_domain_nr(pdev->bus);
-       info->bus = pdev->bus->number;
-       info->devfn = pdev->devfn;
-       info->dev = pdev;
-       info->domain = domain;
-
-       spin_lock_irqsave(&device_domain_lock, flags);
-       list_add(&info->link, &domain->devices);
-       list_add(&info->global, &device_domain_list);
-       pdev->dev.archdata.iommu = info;
-       spin_unlock_irqrestore(&device_domain_lock, flags);
-
-       return 0;
-}
-
 static void iommu_detach_dependent_devices(struct intel_iommu *iommu,
                                           struct pci_dev *pdev)
 {
@@ -3003,7 +3257,7 @@ static void iommu_detach_dependent_devices(struct intel_iommu *iommu,
        }
 }
 
-static void vm_domain_remove_one_dev_info(struct dmar_domain *domain,
+static void domain_remove_one_dev_info(struct dmar_domain *domain,
                                          struct pci_dev *pdev)
 {
        struct device_domain_info *info;
@@ -3136,12 +3390,11 @@ static struct dmar_domain *iommu_alloc_vm_domain(void)
        return domain;
 }
 
-static int vm_domain_init(struct dmar_domain *domain, int guest_width)
+static int md_domain_init(struct dmar_domain *domain, int guest_width)
 {
        int adjust_width;
 
        init_iova_domain(&domain->iovad, DMA_32BIT_PFN);
-       spin_lock_init(&domain->mapping_lock);
        spin_lock_init(&domain->iommu_lock);
 
        domain_reserve_special_ranges(domain);
@@ -3195,8 +3448,6 @@ static void iommu_free_vm_domain(struct dmar_domain *domain)
 
 static void vm_domain_exit(struct dmar_domain *domain)
 {
-       u64 end;
-
        /* Domain 0 is reserved, so dont process it */
        if (!domain)
                return;
@@ -3204,14 +3455,12 @@ static void vm_domain_exit(struct dmar_domain *domain)
        vm_domain_remove_all_dev_info(domain);
        /* destroy iovas */
        put_iova_domain(&domain->iovad);
-       end = DOMAIN_MAX_ADDR(domain->gaw);
-       end = end & (~VTD_PAGE_MASK);
 
        /* clear ptes */
-       dma_pte_clear_range(domain, 0, end);
+       dma_pte_clear_range(domain, 0, DOMAIN_MAX_PFN(domain->gaw));
 
        /* free page tables */
-       dma_pte_free_pagetable(domain, 0, end);
+       dma_pte_free_pagetable(domain, 0, DOMAIN_MAX_PFN(domain->gaw));
 
        iommu_free_vm_domain(domain);
        free_domain_mem(domain);
@@ -3227,7 +3476,7 @@ static int intel_iommu_domain_init(struct iommu_domain *domain)
                        "intel_iommu_domain_init: dmar_domain == NULL\n");
                return -ENOMEM;
        }
-       if (vm_domain_init(dmar_domain, DEFAULT_DOMAIN_ADDRESS_WIDTH)) {
+       if (md_domain_init(dmar_domain, DEFAULT_DOMAIN_ADDRESS_WIDTH)) {
                printk(KERN_ERR
                        "intel_iommu_domain_init() failed\n");
                vm_domain_exit(dmar_domain);
@@ -3262,8 +3511,9 @@ static int intel_iommu_attach_device(struct iommu_domain *domain,
 
                old_domain = find_domain(pdev);
                if (old_domain) {
-                       if (dmar_domain->flags & DOMAIN_FLAG_VIRTUAL_MACHINE)
-                               vm_domain_remove_one_dev_info(old_domain, pdev);
+                       if (dmar_domain->flags & DOMAIN_FLAG_VIRTUAL_MACHINE ||
+                           dmar_domain->flags & DOMAIN_FLAG_STATIC_IDENTITY)
+                               domain_remove_one_dev_info(old_domain, pdev);
                        else
                                domain_remove_dev_info(old_domain);
                }
@@ -3285,7 +3535,7 @@ static int intel_iommu_attach_device(struct iommu_domain *domain,
                return -EFAULT;
        }
 
-       ret = vm_domain_add_dev_info(dmar_domain, pdev);
+       ret = domain_add_dev_info(dmar_domain, pdev);
        if (ret)
                return ret;
 
@@ -3299,7 +3549,7 @@ static void intel_iommu_detach_device(struct iommu_domain *domain,
        struct dmar_domain *dmar_domain = domain->priv;
        struct pci_dev *pdev = to_pci_dev(dev);
 
-       vm_domain_remove_one_dev_info(dmar_domain, pdev);
+       domain_remove_one_dev_info(dmar_domain, pdev);
 }
 
 static int intel_iommu_map_range(struct iommu_domain *domain,
@@ -3319,7 +3569,7 @@ static int intel_iommu_map_range(struct iommu_domain *domain,
        if ((iommu_prot & IOMMU_CACHE) && dmar_domain->iommu_snooping)
                prot |= DMA_PTE_SNP;
 
-       max_addr = (iova & VTD_PAGE_MASK) + VTD_PAGE_ALIGN(size);
+       max_addr = iova + size;
        if (dmar_domain->max_addr < max_addr) {
                int min_agaw;
                u64 end;
@@ -3337,8 +3587,11 @@ static int intel_iommu_map_range(struct iommu_domain *domain,
                }
                dmar_domain->max_addr = max_addr;
        }
-
-       ret = domain_page_mapping(dmar_domain, iova, hpa, size, prot);
+       /* Round up size to next multiple of PAGE_SIZE, if it and
+          the low bits of hpa would take us onto the next page */
+       size = aligned_nrpages(hpa, size);
+       ret = domain_pfn_mapping(dmar_domain, iova >> VTD_PAGE_SHIFT,
+                                hpa >> VTD_PAGE_SHIFT, size, prot);
        return ret;
 }
 
@@ -3346,15 +3599,15 @@ static void intel_iommu_unmap_range(struct iommu_domain *domain,
                                    unsigned long iova, size_t size)
 {
        struct dmar_domain *dmar_domain = domain->priv;
-       dma_addr_t base;
 
-       /* The address might not be aligned */
-       base = iova & VTD_PAGE_MASK;
-       size = VTD_PAGE_ALIGN(size);
-       dma_pte_clear_range(dmar_domain, base, base + size);
+       if (!size)
+               return;
+
+       dma_pte_clear_range(dmar_domain, iova >> VTD_PAGE_SHIFT,
+                           (iova + size - 1) >> VTD_PAGE_SHIFT);
 
-       if (dmar_domain->max_addr == base + size)
-               dmar_domain->max_addr = base;
+       if (dmar_domain->max_addr == iova + size)
+               dmar_domain->max_addr = iova;
 }
 
 static phys_addr_t intel_iommu_iova_to_phys(struct iommu_domain *domain,
@@ -3364,7 +3617,7 @@ static phys_addr_t intel_iommu_iova_to_phys(struct iommu_domain *domain,
        struct dma_pte *pte;
        u64 phys = 0;
 
-       pte = addr_to_dma_pte(dmar_domain, iova);
+       pte = pfn_to_dma_pte(dmar_domain, iova >> VTD_PAGE_SHIFT);
        if (pte)
                phys = dma_pte_addr(pte);
 
index 1e83c8c5f9859d29229bec9225205eb5e39e5253..4f5b8712931f0d34c1702440a80ff0bb71f46964 100644 (file)
@@ -10,6 +10,8 @@
 #include <linux/intel-iommu.h>
 #include "intr_remapping.h"
 #include <acpi/acpi.h>
+#include <asm/pci-direct.h>
+#include "pci.h"
 
 static struct ioapic_scope ir_ioapic[MAX_IO_APICS];
 static int ir_ioapic_num;
@@ -314,7 +316,8 @@ int modify_irte(int irq, struct irte *irte_modified)
        index = irq_iommu->irte_index + irq_iommu->sub_handle;
        irte = &iommu->ir_table->base[index];
 
-       set_64bit((unsigned long *)irte, irte_modified->low);
+       set_64bit((unsigned long *)&irte->low, irte_modified->low);
+       set_64bit((unsigned long *)&irte->high, irte_modified->high);
        __iommu_flush_cache(iommu, irte, sizeof(*irte));
 
        rc = qi_flush_iec(iommu, index, 0);
@@ -369,12 +372,32 @@ struct intel_iommu *map_dev_to_ir(struct pci_dev *dev)
        return drhd->iommu;
 }
 
+static int clear_entries(struct irq_2_iommu *irq_iommu)
+{
+       struct irte *start, *entry, *end;
+       struct intel_iommu *iommu;
+       int index;
+
+       if (irq_iommu->sub_handle)
+               return 0;
+
+       iommu = irq_iommu->iommu;
+       index = irq_iommu->irte_index + irq_iommu->sub_handle;
+
+       start = iommu->ir_table->base + index;
+       end = start + (1 << irq_iommu->irte_mask);
+
+       for (entry = start; entry < end; entry++) {
+               set_64bit((unsigned long *)&entry->low, 0);
+               set_64bit((unsigned long *)&entry->high, 0);
+       }
+
+       return qi_flush_iec(iommu, index, irq_iommu->irte_mask);
+}
+
 int free_irte(int irq)
 {
        int rc = 0;
-       int index, i;
-       struct irte *irte;
-       struct intel_iommu *iommu;
        struct irq_2_iommu *irq_iommu;
        unsigned long flags;
 
@@ -385,16 +408,7 @@ int free_irte(int irq)
                return -1;
        }
 
-       iommu = irq_iommu->iommu;
-
-       index = irq_iommu->irte_index + irq_iommu->sub_handle;
-       irte = &iommu->ir_table->base[index];
-
-       if (!irq_iommu->sub_handle) {
-               for (i = 0; i < (1 << irq_iommu->irte_mask); i++)
-                       set_64bit((unsigned long *)(irte + i), 0);
-               rc = qi_flush_iec(iommu, index, irq_iommu->irte_mask);
-       }
+       rc = clear_entries(irq_iommu);
 
        irq_iommu->iommu = NULL;
        irq_iommu->irte_index = 0;
@@ -406,6 +420,91 @@ int free_irte(int irq)
        return rc;
 }
 
+/*
+ * source validation type
+ */
+#define SVT_NO_VERIFY          0x0  /* no verification is required */
+#define SVT_VERIFY_SID_SQ      0x1  /* verify using SID and SQ fiels */
+#define SVT_VERIFY_BUS         0x2  /* verify bus of request-id */
+
+/*
+ * source-id qualifier
+ */
+#define SQ_ALL_16      0x0  /* verify all 16 bits of request-id */
+#define SQ_13_IGNORE_1 0x1  /* verify most significant 13 bits, ignore
+                             * the third least significant bit
+                             */
+#define SQ_13_IGNORE_2 0x2  /* verify most significant 13 bits, ignore
+                             * the second and third least significant bits
+                             */
+#define SQ_13_IGNORE_3 0x3  /* verify most significant 13 bits, ignore
+                             * the least three significant bits
+                             */
+
+/*
+ * set SVT, SQ and SID fields of irte to verify
+ * source ids of interrupt requests
+ */
+static void set_irte_sid(struct irte *irte, unsigned int svt,
+                        unsigned int sq, unsigned int sid)
+{
+       irte->svt = svt;
+       irte->sq = sq;
+       irte->sid = sid;
+}
+
+int set_ioapic_sid(struct irte *irte, int apic)
+{
+       int i;
+       u16 sid = 0;
+
+       if (!irte)
+               return -1;
+
+       for (i = 0; i < MAX_IO_APICS; i++) {
+               if (ir_ioapic[i].id == apic) {
+                       sid = (ir_ioapic[i].bus << 8) | ir_ioapic[i].devfn;
+                       break;
+               }
+       }
+
+       if (sid == 0) {
+               pr_warning("Failed to set source-id of IOAPIC (%d)\n", apic);
+               return -1;
+       }
+
+       set_irte_sid(irte, 1, 0, sid);
+
+       return 0;
+}
+
+int set_msi_sid(struct irte *irte, struct pci_dev *dev)
+{
+       struct pci_dev *bridge;
+
+       if (!irte || !dev)
+               return -1;
+
+       /* PCIe device or Root Complex integrated PCI device */
+       if (dev->is_pcie || !dev->bus->parent) {
+               set_irte_sid(irte, SVT_VERIFY_SID_SQ, SQ_ALL_16,
+                            (dev->bus->number << 8) | dev->devfn);
+               return 0;
+       }
+
+       bridge = pci_find_upstream_pcie_bridge(dev);
+       if (bridge) {
+               if (bridge->is_pcie) /* this is a PCIE-to-PCI/PCIX bridge */
+                       set_irte_sid(irte, SVT_VERIFY_BUS, SQ_ALL_16,
+                               (bridge->bus->number << 8) | dev->bus->number);
+               else /* this is a legacy PCI bridge */
+                       set_irte_sid(irte, SVT_VERIFY_SID_SQ, SQ_ALL_16,
+                               (bridge->bus->number << 8) | bridge->devfn);
+       }
+
+       return 0;
+}
+
 static void iommu_set_intr_remapping(struct intel_iommu *iommu, int mode)
 {
        u64 addr;
@@ -612,6 +711,35 @@ error:
        return -1;
 }
 
+static void ir_parse_one_ioapic_scope(struct acpi_dmar_device_scope *scope,
+                                     struct intel_iommu *iommu)
+{
+       struct acpi_dmar_pci_path *path;
+       u8 bus;
+       int count;
+
+       bus = scope->bus;
+       path = (struct acpi_dmar_pci_path *)(scope + 1);
+       count = (scope->length - sizeof(struct acpi_dmar_device_scope))
+               / sizeof(struct acpi_dmar_pci_path);
+
+       while (--count > 0) {
+               /*
+                * Access PCI directly due to the PCI
+                * subsystem isn't initialized yet.
+                */
+               bus = read_pci_config_byte(bus, path->dev, path->fn,
+                                          PCI_SECONDARY_BUS);
+               path++;
+       }
+
+       ir_ioapic[ir_ioapic_num].bus   = bus;
+       ir_ioapic[ir_ioapic_num].devfn = PCI_DEVFN(path->dev, path->fn);
+       ir_ioapic[ir_ioapic_num].iommu = iommu;
+       ir_ioapic[ir_ioapic_num].id    = scope->enumeration_id;
+       ir_ioapic_num++;
+}
+
 static int ir_parse_ioapic_scope(struct acpi_dmar_header *header,
                                 struct intel_iommu *iommu)
 {
@@ -636,9 +764,7 @@ static int ir_parse_ioapic_scope(struct acpi_dmar_header *header,
                               " 0x%Lx\n", scope->enumeration_id,
                               drhd->address);
 
-                       ir_ioapic[ir_ioapic_num].iommu = iommu;
-                       ir_ioapic[ir_ioapic_num].id = scope->enumeration_id;
-                       ir_ioapic_num++;
+                       ir_parse_one_ioapic_scope(scope, iommu);
                }
                start += scope->length;
        }
index ca48f0df8ac989bb41889e1efd87db7d5ee5fe10..63a263c18415f8d2f61ce13c6b1918d95c65d19a 100644 (file)
@@ -3,6 +3,8 @@
 struct ioapic_scope {
        struct intel_iommu *iommu;
        unsigned int id;
+       unsigned int bus;       /* PCI bus number */
+       unsigned int devfn;     /* PCI devfn number */
 };
 
 #define IR_X2APIC_MODE(mode) (mode ? (1 << 11) : 0)
index 2287116e9822472a1ef879bd6facfbd30920b087..46dd440e2315d2ec7beaf096c00fae5c3c11df1a 100644 (file)
@@ -1,9 +1,19 @@
 /*
- * Copyright (c) 2006, Intel Corporation.
+ * Copyright Â© 2006-2009, Intel Corporation.
  *
- * This file is released under the GPLv2.
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place - Suite 330, Boston, MA 02111-1307 USA.
  *
- * Copyright (C) 2006-2008 Intel Corporation
  * Author: Anil S Keshavamurthy <anil.s.keshavamurthy@intel.com>
  */
 
@@ -123,7 +133,15 @@ move_left:
        /* Insert the new_iova into domain rbtree by holding writer lock */
        /* Add new node and rebalance tree. */
        {
-               struct rb_node **entry = &((prev)), *parent = NULL;
+               struct rb_node **entry, *parent = NULL;
+
+               /* If we have 'prev', it's a valid place to start the
+                  insertion. Otherwise, start from the root. */
+               if (prev)
+                       entry = &prev;
+               else
+                       entry = &iovad->rbroot.rb_node;
+
                /* Figure out where to put new node */
                while (*entry) {
                        struct iova *this = container_of(*entry,
index d9f06fbfa0bf8fd56051d5f1bd2252fdc52377f8..d986afb7032bbaf5ad70a32c59e67701b741e8e6 100644 (file)
@@ -127,17 +127,23 @@ static inline __attribute_const__ u32 msi_enabled_mask(u16 control)
  * reliably as devices without an INTx disable bit will then generate a
  * level IRQ which will never be cleared.
  */
-static void msi_mask_irq(struct msi_desc *desc, u32 mask, u32 flag)
+static u32 __msi_mask_irq(struct msi_desc *desc, u32 mask, u32 flag)
 {
        u32 mask_bits = desc->masked;
 
        if (!desc->msi_attrib.maskbit)
-               return;
+               return 0;
 
        mask_bits &= ~mask;
        mask_bits |= flag;
        pci_write_config_dword(desc->dev, desc->mask_pos, mask_bits);
-       desc->masked = mask_bits;
+
+       return mask_bits;
+}
+
+static void msi_mask_irq(struct msi_desc *desc, u32 mask, u32 flag)
+{
+       desc->masked = __msi_mask_irq(desc, mask, flag);
 }
 
 /*
@@ -147,15 +153,21 @@ static void msi_mask_irq(struct msi_desc *desc, u32 mask, u32 flag)
  * file.  This saves a few milliseconds when initialising devices with lots
  * of MSI-X interrupts.
  */
-static void msix_mask_irq(struct msi_desc *desc, u32 flag)
+static u32 __msix_mask_irq(struct msi_desc *desc, u32 flag)
 {
        u32 mask_bits = desc->masked;
        unsigned offset = desc->msi_attrib.entry_nr * PCI_MSIX_ENTRY_SIZE +
-                                       PCI_MSIX_ENTRY_VECTOR_CTRL_OFFSET;
+                                               PCI_MSIX_ENTRY_VECTOR_CTRL;
        mask_bits &= ~1;
        mask_bits |= flag;
        writel(mask_bits, desc->mask_base + offset);
-       desc->masked = mask_bits;
+
+       return mask_bits;
+}
+
+static void msix_mask_irq(struct msi_desc *desc, u32 flag)
+{
+       desc->masked = __msix_mask_irq(desc, flag);
 }
 
 static void msi_set_mask_bit(unsigned irq, u32 flag)
@@ -188,9 +200,9 @@ void read_msi_msg_desc(struct irq_desc *desc, struct msi_msg *msg)
                void __iomem *base = entry->mask_base +
                        entry->msi_attrib.entry_nr * PCI_MSIX_ENTRY_SIZE;
 
-               msg->address_lo = readl(base + PCI_MSIX_ENTRY_LOWER_ADDR_OFFSET);
-               msg->address_hi = readl(base + PCI_MSIX_ENTRY_UPPER_ADDR_OFFSET);
-               msg->data = readl(base + PCI_MSIX_ENTRY_DATA_OFFSET);
+               msg->address_lo = readl(base + PCI_MSIX_ENTRY_LOWER_ADDR);
+               msg->address_hi = readl(base + PCI_MSIX_ENTRY_UPPER_ADDR);
+               msg->data = readl(base + PCI_MSIX_ENTRY_DATA);
        } else {
                struct pci_dev *dev = entry->dev;
                int pos = entry->msi_attrib.pos;
@@ -225,11 +237,9 @@ void write_msi_msg_desc(struct irq_desc *desc, struct msi_msg *msg)
                base = entry->mask_base +
                        entry->msi_attrib.entry_nr * PCI_MSIX_ENTRY_SIZE;
 
-               writel(msg->address_lo,
-                       base + PCI_MSIX_ENTRY_LOWER_ADDR_OFFSET);
-               writel(msg->address_hi,
-                       base + PCI_MSIX_ENTRY_UPPER_ADDR_OFFSET);
-               writel(msg->data, base + PCI_MSIX_ENTRY_DATA_OFFSET);
+               writel(msg->address_lo, base + PCI_MSIX_ENTRY_LOWER_ADDR);
+               writel(msg->address_hi, base + PCI_MSIX_ENTRY_UPPER_ADDR);
+               writel(msg->data, base + PCI_MSIX_ENTRY_DATA);
        } else {
                struct pci_dev *dev = entry->dev;
                int pos = entry->msi_attrib.pos;
@@ -385,6 +395,7 @@ static int msi_capability_init(struct pci_dev *dev, int nvec)
        /* Configure MSI capability structure */
        ret = arch_setup_msi_irqs(dev, nvec, PCI_CAP_ID_MSI);
        if (ret) {
+               msi_mask_irq(entry, mask, ~mask);
                msi_free_irqs(dev);
                return ret;
        }
@@ -439,8 +450,14 @@ static int msix_capability_init(struct pci_dev *dev,
 
        for (i = 0; i < nvec; i++) {
                entry = alloc_msi_entry(dev);
-               if (!entry)
-                       break;
+               if (!entry) {
+                       if (!i)
+                               iounmap(base);
+                       else
+                               msi_free_irqs(dev);
+                       /* No enough memory. Don't try again */
+                       return -ENOMEM;
+               }
 
                j = entries[i].entry;
                entry->msi_attrib.is_msix = 1;
@@ -487,7 +504,7 @@ static int msix_capability_init(struct pci_dev *dev,
                set_irq_msi(entry->irq, entry);
                j = entries[i].entry;
                entry->masked = readl(base + j * PCI_MSIX_ENTRY_SIZE +
-                                       PCI_MSIX_ENTRY_VECTOR_CTRL_OFFSET);
+                                               PCI_MSIX_ENTRY_VECTOR_CTRL);
                msix_mask_irq(entry, 1);
                i++;
        }
@@ -611,9 +628,11 @@ void pci_msi_shutdown(struct pci_dev *dev)
        pci_intx_for_msi(dev, 1);
        dev->msi_enabled = 0;
 
+       /* Return the device with MSI unmasked as initial states */
        pci_read_config_word(dev, pos + PCI_MSI_FLAGS, &ctrl);
        mask = msi_capable_mask(ctrl);
-       msi_mask_irq(desc, mask, ~mask);
+       /* Keep cached state to be restored */
+       __msi_mask_irq(desc, mask, ~mask);
 
        /* Restore dev->irq to its default pin-assertion irq */
        dev->irq = desc->msi_attrib.default_irq;
@@ -653,7 +672,6 @@ static int msi_free_irqs(struct pci_dev* dev)
 
        list_for_each_entry_safe(entry, tmp, &dev->msi_list, list) {
                if (entry->msi_attrib.is_msix) {
-                       msix_mask_irq(entry, 1);
                        if (list_is_last(&entry->list, &dev->msi_list))
                                iounmap(entry->mask_base);
                }
@@ -741,9 +759,17 @@ static void msix_free_all_irqs(struct pci_dev *dev)
 
 void pci_msix_shutdown(struct pci_dev* dev)
 {
+       struct msi_desc *entry;
+
        if (!pci_msi_enable || !dev || !dev->msix_enabled)
                return;
 
+       /* Return the device with MSI-X masked as initial states */
+       list_for_each_entry(entry, &dev->msi_list, list) {
+               /* Keep cached states to be restored */
+               __msix_mask_irq(entry, 1);
+       }
+
        msix_set_enable(dev, 0);
        pci_intx_for_msi(dev, 1);
        dev->msix_enabled = 0;
index a0662842550bcb91c008272ba7194f5b97e35388..de27c1cb5a2bb8be30a3003ca47c45eac37c9d2a 100644 (file)
@@ -6,11 +6,11 @@
 #ifndef MSI_H
 #define MSI_H
 
-#define PCI_MSIX_ENTRY_SIZE                    16
-#define  PCI_MSIX_ENTRY_LOWER_ADDR_OFFSET      0
-#define  PCI_MSIX_ENTRY_UPPER_ADDR_OFFSET      4
-#define  PCI_MSIX_ENTRY_DATA_OFFSET            8
-#define  PCI_MSIX_ENTRY_VECTOR_CTRL_OFFSET     12
+#define PCI_MSIX_ENTRY_SIZE            16
+#define  PCI_MSIX_ENTRY_LOWER_ADDR     0
+#define  PCI_MSIX_ENTRY_UPPER_ADDR     4
+#define  PCI_MSIX_ENTRY_DATA           8
+#define  PCI_MSIX_ENTRY_VECTOR_CTRL    12
 
 #define msi_control_reg(base)          (base + PCI_MSI_FLAGS)
 #define msi_lower_address_reg(base)    (base + PCI_MSI_ADDRESS_LO)
index 6c93af5ced186bd9a18faaea77fb0d160d37aba8..dbd0f947f49728a3849f7e96b03a2de1f2ae180f 100644 (file)
@@ -1517,11 +1517,20 @@ void pci_enable_ari(struct pci_dev *dev)
  *
  * Perform INTx swizzling for a device behind one level of bridge.  This is
  * required by section 9.1 of the PCI-to-PCI bridge specification for devices
- * behind bridges on add-in cards.
+ * behind bridges on add-in cards.  For devices with ARI enabled, the slot
+ * number is always 0 (see the Implementation Note in section 2.2.8.1 of
+ * the PCI Express Base Specification, Revision 2.1)
  */
 u8 pci_swizzle_interrupt_pin(struct pci_dev *dev, u8 pin)
 {
-       return (((pin - 1) + PCI_SLOT(dev->devfn)) % 4) + 1;
+       int slot;
+
+       if (pci_ari_enabled(dev->bus))
+               slot = 0;
+       else
+               slot = PCI_SLOT(dev->devfn);
+
+       return (((pin - 1) + slot) % 4) + 1;
 }
 
 int
@@ -2171,7 +2180,7 @@ static int pci_parent_bus_reset(struct pci_dev *dev, int probe)
        u16 ctrl;
        struct pci_dev *pdev;
 
-       if (dev->subordinate)
+       if (pci_is_root_bus(dev->bus) || dev->subordinate || !dev->bus->self)
                return -ENOTTY;
 
        list_for_each_entry(pdev, &dev->bus->devices, bus_list)
index ece97df4df6d1e8ccfceb32ee240c1d74c4af05d..a928d8ab6bda2a95f3fce746617778c53163585d 100644 (file)
@@ -106,7 +106,7 @@ void pcie_set_ecrc_checking(struct pci_dev *dev)
                disable_ecrc_checking(dev);
                break;
        case ECRC_POLICY_ON:
-               enable_ecrc_checking(dev);;
+               enable_ecrc_checking(dev);
                break;
        default:
                return;
index 56552d74abea1506e9d40df04f7ea0c0e3b3ab5b..06b96562396230e3c52dc6f6067fdf39e66597d1 100644 (file)
@@ -1058,6 +1058,11 @@ static void __devinit quirk_no_ata_d3(struct pci_dev *pdev)
 }
 DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_SERVERWORKS, PCI_ANY_ID, quirk_no_ata_d3);
 DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_ATI, PCI_ANY_ID, quirk_no_ata_d3);
+/* ALi loses some register settings that we cannot then restore */
+DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_AL, PCI_ANY_ID, quirk_no_ata_d3);
+/* VIA comes back fine but we need to keep it alive or ACPI GTM failures
+   occur when mode detecting */
+DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_VIA, PCI_ANY_ID, quirk_no_ata_d3);
 
 /* This was originally an Alpha specific thing, but it really fits here.
  * The i82375 PCI/EISA bridge appears as non-classified. Fix that.
index eddb0748b0ea365b9acd4d5898a5547326bf5231..8c02b6c53bdbd483ce6161bc92ba83f0352bae51 100644 (file)
@@ -311,7 +311,7 @@ EXPORT_SYMBOL_GPL(pci_destroy_slot);
 #include <linux/pci_hotplug.h>
 /**
  * pci_hp_create_link - create symbolic link to the hotplug driver module.
- * @slot: struct pci_slot
+ * @pci_slot: struct pci_slot
  *
  * Helper function for pci_hotplug_core.c to create symbolic link to
  * the hotplug driver module.
@@ -334,7 +334,7 @@ EXPORT_SYMBOL_GPL(pci_hp_create_module_link);
 
 /**
  * pci_hp_remove_link - remove symbolic link to the hotplug driver module.
- * @slot: struct pci_slot
+ * @pci_slot: struct pci_slot
  *
  * Helper function for pci_hotplug_core.c to remove symbolic link to
  * the hotplug driver module.
index ec22284eed307ccf565eb83df55f960876f57cd4..e1c1ec5408934204c35025122cd5b64d6a14080e 100644 (file)
@@ -9,7 +9,6 @@
 
 #include <linux/errno.h>
 #include <linux/pci.h>
-#include <linux/smp_lock.h>
 #include <linux/syscalls.h>
 #include <asm/uaccess.h>
 #include "pci.h"
index 9ad97ea836e8a0fc6ccb4f0721f387fae44f5d68..8eb04230fec7a475c24bc012285dd86089b986ce 100644 (file)
@@ -472,7 +472,8 @@ static int __init init_tcic(void)
     init_timer(&poll_timer);
 
     /* Build interrupt mask */
-    printk(", %d sockets\n" KERN_INFO "  irq list (", sockets);
+    printk(KERN_CONT ", %d sockets\n", sockets);
+    printk(KERN_INFO "  irq list (");
     if (irq_list_count == 0)
        mask = irq_mask;
     else
index 659421d0ca46aeab37fac76aefdee41cc6a5562d..d4ad50d737b060392fdf2c82bc80a211a57f5be1 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * vrc4171_card.c, NEC VRC4171 Card Controller driver for Socket Services.
  *
- * Copyright (C) 2003-2005  Yoichi Yuasa <yoichi_yuasa@tripeaks.co.jp>
+ * Copyright (C) 2003-2005  Yoichi Yuasa <yuasa@linux-mips.org>
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
@@ -32,7 +32,7 @@
 #include "i82365.h"
 
 MODULE_DESCRIPTION("NEC VRC4171 Card Controllers driver for Socket Services");
-MODULE_AUTHOR("Yoichi Yuasa <yoichi_yuasa@tripeaks.co.jp>");
+MODULE_AUTHOR("Yoichi Yuasa <yuasa@linux-mips.org>");
 MODULE_LICENSE("GPL");
 
 #define CARD_MAX_SLOTS         2
index 812f038e9bdaeea761c66dc978b583bc571bf9b0..9b3c15827e5c763208a82b212eb7ab6cc2e9919f 100644 (file)
@@ -6,7 +6,7 @@
  *     NEC VRC4173 CARDU driver for Socket Services
  *     (This device doesn't support CardBus. it is supporting only 16bit PC Card.)
  *
- * Copyright 2002,2003 Yoichi Yuasa <yoichi_yuasa@tripeaks.co.jp>
+ * Copyright 2002,2003 Yoichi Yuasa <yuasa@linux-mips.org>
  *
  *  This program is free software; you can redistribute it and/or modify it
  *  under the terms of the GNU General Public License as published by the
@@ -41,7 +41,7 @@
 #include "vrc4173_cardu.h"
 
 MODULE_DESCRIPTION("NEC VRC4173 CARDU driver for Socket Services");
-MODULE_AUTHOR("Yoichi Yuasa <yoichi_yuasa@tripeaks.co.jp>");
+MODULE_AUTHOR("Yoichi Yuasa <yuasa@linux-mips.org>");
 MODULE_LICENSE("GPL");
 
 static int vrc4173_cardu_slots;
index 7d77c74120c1cb646fef6af93b80aa35bc964c01..a7d96018ed8d4c471a493b62dc732dd9d79e1d19 100644 (file)
@@ -5,7 +5,7 @@
  * BRIEF MODULE DESCRIPTION
  *     Include file for NEC VRC4173 CARDU.
  *
- * Copyright 2002 Yoichi Yuasa <yoichi_yuasa@tripeaks.co.jp>
+ * Copyright 2002 Yoichi Yuasa <yuasa@linux-mips.org>
  *
  *  This program is free software; you can redistribute it and/or modify it
  *  under the terms of the GNU General Public License as published by the
index c682ac53641554a82c3b47ef91a71204530d393e..46dad12f952f21b9bb874008abbf133b131aa6ad 100644 (file)
@@ -34,10 +34,27 @@ config ACER_WMI
          If you have an ACPI-WMI compatible Acer/ Wistron laptop, say Y or M
          here.
 
+config ACERHDF
+       tristate "Acer Aspire One temperature and fan driver"
+       depends on THERMAL && THERMAL_HWMON && ACPI
+       ---help---
+         This is a driver for Acer Aspire One netbooks. It allows to access
+         the temperature sensor and to control the fan.
+
+         After loading this driver the BIOS is still in control of the fan.
+         To let the kernel handle the fan, do:
+         echo -n enabled > /sys/class/thermal/thermal_zone0/mode
+
+         For more information about this driver see
+         <http://piie.net/files/acerhdf_README.txt>
+
+         If you have an Acer Aspire One netbook, say Y or M
+         here.
+
 config ASUS_LAPTOP
-       tristate "Asus Laptop Extras (EXPERIMENTAL)"
+       tristate "Asus Laptop Extras"
        depends on ACPI
-       depends on EXPERIMENTAL && !ACPI_ASUS
+       depends on !ACPI_ASUS
        select LEDS_CLASS
        select NEW_LEDS
        select BACKLIGHT_CLASS_DEVICE
@@ -45,12 +62,12 @@ config ASUS_LAPTOP
        ---help---
          This is the new Linux driver for Asus laptops. It may also support some
          MEDION, JVC or VICTOR laptops. It makes all the extra buttons generate
-         standard ACPI events that go through /proc/acpi/events. It also adds
+         standard ACPI events and input events. It also adds
          support for video output switching, LCD backlight control, Bluetooth and
          Wlan control, and most importantly, allows you to blink those fancy LEDs.
 
          For more information and a userspace daemon for handling the extra
-         buttons see <http://acpi4asus.sf.net/>.
+         buttons see <http://acpi4asus.sf.net>.
 
          If you have an ACPI-compatible ASUS laptop, say Y or M here.
 
@@ -338,11 +355,15 @@ config EEEPC_LAPTOP
        depends on INPUT
        depends on EXPERIMENTAL
        depends on RFKILL || RFKILL = n
+       depends on HOTPLUG_PCI
        select BACKLIGHT_CLASS_DEVICE
        select HWMON
        ---help---
          This driver supports the Fn-Fx keys on Eee PC laptops.
-         It also adds the ability to switch camera/wlan on/off.
+
+         It  also gives access to some extra laptop functionalities like
+         Bluetooth, backlight and allows powering on/off some other
+         devices.
 
          If you have an Eee PC laptop, say Y or M here.
 
@@ -369,7 +390,7 @@ config ACPI_WMI
          any ACPI-WMI devices.
 
 config ACPI_ASUS
-       tristate "ASUS/Medion Laptop Extras"
+       tristate "ASUS/Medion Laptop Extras (DEPRECATED)"
        depends on ACPI
        select BACKLIGHT_CLASS_DEVICE
        ---help---
@@ -390,7 +411,7 @@ config ACPI_ASUS
          parameters.
 
          More information and a userspace daemon for handling the extra buttons
-         at <http://sourceforge.net/projects/acpi4asus/>.
+         at <http://acpi4asus.sf.net>.
 
          If you have an ACPI-compatible ASUS laptop, say Y or M here. This
          driver is still under development, so if your laptop is unsupported or
index e40c7bd1b87e55358a4bb02235e5e6ca7720bfdf..641b8bfa5538a7ca3ed0ebfc62410552bbd8dfb1 100644 (file)
@@ -9,6 +9,7 @@ obj-$(CONFIG_COMPAL_LAPTOP)     += compal-laptop.o
 obj-$(CONFIG_DELL_LAPTOP)      += dell-laptop.o
 obj-$(CONFIG_DELL_WMI)         += dell-wmi.o
 obj-$(CONFIG_ACER_WMI)         += acer-wmi.o
+obj-$(CONFIG_ACERHDF)          += acerhdf.o
 obj-$(CONFIG_HP_WMI)           += hp-wmi.o
 obj-$(CONFIG_TC1100_WMI)       += tc1100-wmi.o
 obj-$(CONFIG_SONY_LAPTOP)      += sony-laptop.o
diff --git a/drivers/platform/x86/acerhdf.c b/drivers/platform/x86/acerhdf.c
new file mode 100644 (file)
index 0000000..bdfee17
--- /dev/null
@@ -0,0 +1,602 @@
+/*
+ * acerhdf - A driver which monitors the temperature
+ *           of the aspire one netbook, turns on/off the fan
+ *           as soon as the upper/lower threshold is reached.
+ *
+ * (C) 2009 - Peter Feuerer     peter (a) piie.net
+ *                              http://piie.net
+ *     2009 Borislav Petkov <petkovbb@gmail.com>
+ *
+ * Inspired by and many thanks to:
+ *  o acerfand   - Rachel Greenham
+ *  o acer_ec.pl - Michael Kurz     michi.kurz (at) googlemail.com
+ *               - Petr Tomasek     tomasek (#) etf,cuni,cz
+ *               - Carlos Corbacho  cathectic (at) gmail.com
+ *  o lkml       - Matthew Garrett
+ *               - Borislav Petkov
+ *               - Andreas Mohr
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#define pr_fmt(fmt) "acerhdf: " fmt
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/fs.h>
+#include <linux/dmi.h>
+#include <acpi/acpi_drivers.h>
+#include <linux/sched.h>
+#include <linux/thermal.h>
+#include <linux/platform_device.h>
+
+/*
+ * The driver is started with "kernel mode off" by default. That means, the BIOS
+ * is still in control of the fan. In this mode the driver allows to read the
+ * temperature of the cpu and a userspace tool may take over control of the fan.
+ * If the driver is switched to "kernel mode" (e.g. via module parameter) the
+ * driver is in full control of the fan. If you want the module to be started in
+ * kernel mode by default, define the following:
+ */
+#undef START_IN_KERNEL_MODE
+
+#define DRV_VER "0.5.13"
+
+/*
+ * According to the Atom N270 datasheet,
+ * (http://download.intel.com/design/processor/datashts/320032.pdf) the
+ * CPU's optimal operating limits denoted in junction temperature as
+ * measured by the on-die thermal monitor are within 0 <= Tj <= 90. So,
+ * assume 89°C is critical temperature.
+ */
+#define ACERHDF_TEMP_CRIT 89
+#define ACERHDF_FAN_OFF 0
+#define ACERHDF_FAN_AUTO 1
+
+/*
+ * No matter what value the user puts into the fanon variable, turn on the fan
+ * at 80 degree Celsius to prevent hardware damage
+ */
+#define ACERHDF_MAX_FANON 80
+
+/*
+ * Maximum interval between two temperature checks is 15 seconds, as the die
+ * can get hot really fast under heavy load (plus we shouldn't forget about
+ * possible impact of _external_ aggressive sources such as heaters, sun etc.)
+ */
+#define ACERHDF_MAX_INTERVAL 15
+
+#ifdef START_IN_KERNEL_MODE
+static int kernelmode = 1;
+#else
+static int kernelmode;
+#endif
+
+static unsigned int interval = 10;
+static unsigned int fanon = 63;
+static unsigned int fanoff = 58;
+static unsigned int verbose;
+static unsigned int fanstate = ACERHDF_FAN_AUTO;
+static char force_bios[16];
+static unsigned int prev_interval;
+struct thermal_zone_device *thz_dev;
+struct thermal_cooling_device *cl_dev;
+struct platform_device *acerhdf_dev;
+
+module_param(kernelmode, uint, 0);
+MODULE_PARM_DESC(kernelmode, "Kernel mode fan control on / off");
+module_param(interval, uint, 0600);
+MODULE_PARM_DESC(interval, "Polling interval of temperature check");
+module_param(fanon, uint, 0600);
+MODULE_PARM_DESC(fanon, "Turn the fan on above this temperature");
+module_param(fanoff, uint, 0600);
+MODULE_PARM_DESC(fanoff, "Turn the fan off below this temperature");
+module_param(verbose, uint, 0600);
+MODULE_PARM_DESC(verbose, "Enable verbose dmesg output");
+module_param_string(force_bios, force_bios, 16, 0);
+MODULE_PARM_DESC(force_bios, "Force BIOS version and omit BIOS check");
+
+/* BIOS settings */
+struct bios_settings_t {
+       const char *vendor;
+       const char *version;
+       unsigned char fanreg;
+       unsigned char tempreg;
+       unsigned char fancmd[2]; /* fan off and auto commands */
+};
+
+/* Register addresses and values for different BIOS versions */
+static const struct bios_settings_t bios_tbl[] = {
+       {"Acer", "v0.3109", 0x55, 0x58, {0x1f, 0x00} },
+       {"Acer", "v0.3114", 0x55, 0x58, {0x1f, 0x00} },
+       {"Acer", "v0.3301", 0x55, 0x58, {0xaf, 0x00} },
+       {"Acer", "v0.3304", 0x55, 0x58, {0xaf, 0x00} },
+       {"Acer", "v0.3305", 0x55, 0x58, {0xaf, 0x00} },
+       {"Acer", "v0.3308", 0x55, 0x58, {0x21, 0x00} },
+       {"Acer", "v0.3309", 0x55, 0x58, {0x21, 0x00} },
+       {"Acer", "v0.3310", 0x55, 0x58, {0x21, 0x00} },
+       {"Gateway", "v0.3103", 0x55, 0x58, {0x21, 0x00} },
+       {"Packard Bell", "v0.3105", 0x55, 0x58, {0x21, 0x00} },
+       {"", "", 0, 0, {0, 0} }
+};
+
+static const struct bios_settings_t *bios_cfg __read_mostly;
+
+
+static int acerhdf_get_temp(int *temp)
+{
+       u8 read_temp;
+
+       if (ec_read(bios_cfg->tempreg, &read_temp))
+               return -EINVAL;
+
+       *temp = read_temp;
+
+       return 0;
+}
+
+static int acerhdf_get_fanstate(int *state)
+{
+       u8 fan;
+       bool tmp;
+
+       if (ec_read(bios_cfg->fanreg, &fan))
+               return -EINVAL;
+
+       tmp = (fan == bios_cfg->fancmd[ACERHDF_FAN_OFF]);
+       *state = tmp ? ACERHDF_FAN_OFF : ACERHDF_FAN_AUTO;
+
+       return 0;
+}
+
+static void acerhdf_change_fanstate(int state)
+{
+       unsigned char cmd;
+
+       if (verbose)
+               pr_notice("fan %s\n", (state == ACERHDF_FAN_OFF) ?
+                               "OFF" : "ON");
+
+       if ((state != ACERHDF_FAN_OFF) && (state != ACERHDF_FAN_AUTO)) {
+               pr_err("invalid fan state %d requested, setting to auto!\n",
+                       state);
+               state = ACERHDF_FAN_AUTO;
+       }
+
+       cmd = bios_cfg->fancmd[state];
+       fanstate = state;
+
+       ec_write(bios_cfg->fanreg, cmd);
+}
+
+static void acerhdf_check_param(struct thermal_zone_device *thermal)
+{
+       if (fanon > ACERHDF_MAX_FANON) {
+               pr_err("fanon temperature too high, set to %d\n",
+                               ACERHDF_MAX_FANON);
+               fanon = ACERHDF_MAX_FANON;
+       }
+
+       if (kernelmode && prev_interval != interval) {
+               if (interval > ACERHDF_MAX_INTERVAL) {
+                       pr_err("interval too high, set to %d\n",
+                               ACERHDF_MAX_INTERVAL);
+                       interval = ACERHDF_MAX_INTERVAL;
+               }
+               if (verbose)
+                       pr_notice("interval changed to: %d\n",
+                                       interval);
+               thermal->polling_delay = interval*1000;
+               prev_interval = interval;
+       }
+}
+
+/*
+ * This is the thermal zone callback which does the delayed polling of the fan
+ * state. We do check /sysfs-originating settings here in acerhdf_check_param()
+ * as late as the polling interval is since we can't do that in the respective
+ * accessors of the module parameters.
+ */
+static int acerhdf_get_ec_temp(struct thermal_zone_device *thermal,
+                              unsigned long *t)
+{
+       int temp, err = 0;
+
+       acerhdf_check_param(thermal);
+
+       err = acerhdf_get_temp(&temp);
+       if (err)
+               return err;
+
+       if (verbose)
+               pr_notice("temp %d\n", temp);
+
+       *t = temp;
+       return 0;
+}
+
+static int acerhdf_bind(struct thermal_zone_device *thermal,
+                       struct thermal_cooling_device *cdev)
+{
+       /* if the cooling device is the one from acerhdf bind it */
+       if (cdev != cl_dev)
+               return 0;
+
+       if (thermal_zone_bind_cooling_device(thermal, 0, cdev)) {
+               pr_err("error binding cooling dev\n");
+               return -EINVAL;
+       }
+       return 0;
+}
+
+static int acerhdf_unbind(struct thermal_zone_device *thermal,
+                         struct thermal_cooling_device *cdev)
+{
+       if (cdev != cl_dev)
+               return 0;
+
+       if (thermal_zone_unbind_cooling_device(thermal, 0, cdev)) {
+               pr_err("error unbinding cooling dev\n");
+               return -EINVAL;
+       }
+       return 0;
+}
+
+static inline void acerhdf_revert_to_bios_mode(void)
+{
+       acerhdf_change_fanstate(ACERHDF_FAN_AUTO);
+       kernelmode = 0;
+       if (thz_dev)
+               thz_dev->polling_delay = 0;
+       pr_notice("kernel mode fan control OFF\n");
+}
+static inline void acerhdf_enable_kernelmode(void)
+{
+       kernelmode = 1;
+
+       thz_dev->polling_delay = interval*1000;
+       thermal_zone_device_update(thz_dev);
+       pr_notice("kernel mode fan control ON\n");
+}
+
+static int acerhdf_get_mode(struct thermal_zone_device *thermal,
+                           enum thermal_device_mode *mode)
+{
+       if (verbose)
+               pr_notice("kernel mode fan control %d\n", kernelmode);
+
+       *mode = (kernelmode) ? THERMAL_DEVICE_ENABLED
+                            : THERMAL_DEVICE_DISABLED;
+
+       return 0;
+}
+
+/*
+ * set operation mode;
+ * enabled: the thermal layer of the kernel takes care about
+ *          the temperature and the fan.
+ * disabled: the BIOS takes control of the fan.
+ */
+static int acerhdf_set_mode(struct thermal_zone_device *thermal,
+                           enum thermal_device_mode mode)
+{
+       if (mode == THERMAL_DEVICE_DISABLED && kernelmode)
+               acerhdf_revert_to_bios_mode();
+       else if (mode == THERMAL_DEVICE_ENABLED && !kernelmode)
+               acerhdf_enable_kernelmode();
+
+       return 0;
+}
+
+static int acerhdf_get_trip_type(struct thermal_zone_device *thermal, int trip,
+                                enum thermal_trip_type *type)
+{
+       if (trip == 0)
+               *type = THERMAL_TRIP_ACTIVE;
+
+       return 0;
+}
+
+static int acerhdf_get_trip_temp(struct thermal_zone_device *thermal, int trip,
+                                unsigned long *temp)
+{
+       if (trip == 0)
+               *temp = fanon;
+
+       return 0;
+}
+
+static int acerhdf_get_crit_temp(struct thermal_zone_device *thermal,
+                                unsigned long *temperature)
+{
+       *temperature = ACERHDF_TEMP_CRIT;
+       return 0;
+}
+
+/* bind callback functions to thermalzone */
+struct thermal_zone_device_ops acerhdf_dev_ops = {
+       .bind = acerhdf_bind,
+       .unbind = acerhdf_unbind,
+       .get_temp = acerhdf_get_ec_temp,
+       .get_mode = acerhdf_get_mode,
+       .set_mode = acerhdf_set_mode,
+       .get_trip_type = acerhdf_get_trip_type,
+       .get_trip_temp = acerhdf_get_trip_temp,
+       .get_crit_temp = acerhdf_get_crit_temp,
+};
+
+
+/*
+ * cooling device callback functions
+ * get maximal fan cooling state
+ */
+static int acerhdf_get_max_state(struct thermal_cooling_device *cdev,
+                                unsigned long *state)
+{
+       *state = 1;
+
+       return 0;
+}
+
+static int acerhdf_get_cur_state(struct thermal_cooling_device *cdev,
+                                unsigned long *state)
+{
+       int err = 0, tmp;
+
+       err = acerhdf_get_fanstate(&tmp);
+       if (err)
+               return err;
+
+       *state = (tmp == ACERHDF_FAN_AUTO) ? 1 : 0;
+       return 0;
+}
+
+/* change current fan state - is overwritten when running in kernel mode */
+static int acerhdf_set_cur_state(struct thermal_cooling_device *cdev,
+                                unsigned long state)
+{
+       int cur_temp, cur_state, err = 0;
+
+       if (!kernelmode)
+               return 0;
+
+       err = acerhdf_get_temp(&cur_temp);
+       if (err) {
+               pr_err("error reading temperature, hand off control to BIOS\n");
+               goto err_out;
+       }
+
+       err = acerhdf_get_fanstate(&cur_state);
+       if (err) {
+               pr_err("error reading fan state, hand off control to BIOS\n");
+               goto err_out;
+       }
+
+       if (state == 0) {
+               /* turn fan off only if below fanoff temperature */
+               if ((cur_state == ACERHDF_FAN_AUTO) &&
+                   (cur_temp < fanoff))
+                       acerhdf_change_fanstate(ACERHDF_FAN_OFF);
+       } else {
+               if (cur_state == ACERHDF_FAN_OFF)
+                       acerhdf_change_fanstate(ACERHDF_FAN_AUTO);
+       }
+       return 0;
+
+err_out:
+       acerhdf_revert_to_bios_mode();
+       return -EINVAL;
+}
+
+/* bind fan callbacks to fan device */
+struct thermal_cooling_device_ops acerhdf_cooling_ops = {
+       .get_max_state = acerhdf_get_max_state,
+       .get_cur_state = acerhdf_get_cur_state,
+       .set_cur_state = acerhdf_set_cur_state,
+};
+
+/* suspend / resume functionality */
+static int acerhdf_suspend(struct platform_device *dev, pm_message_t state)
+{
+       if (kernelmode)
+               acerhdf_change_fanstate(ACERHDF_FAN_AUTO);
+
+       if (verbose)
+               pr_notice("going suspend\n");
+
+       return 0;
+}
+
+static int acerhdf_resume(struct platform_device *device)
+{
+       if (verbose)
+               pr_notice("resuming\n");
+
+       return 0;
+}
+
+static int __devinit acerhdf_probe(struct platform_device *device)
+{
+       return 0;
+}
+
+static int acerhdf_remove(struct platform_device *device)
+{
+       return 0;
+}
+
+struct platform_driver acerhdf_drv = {
+       .driver = {
+               .name = "acerhdf",
+               .owner = THIS_MODULE,
+       },
+       .probe = acerhdf_probe,
+       .remove = acerhdf_remove,
+       .suspend = acerhdf_suspend,
+       .resume = acerhdf_resume,
+};
+
+
+/* check hardware */
+static int acerhdf_check_hardware(void)
+{
+       char const *vendor, *version, *product;
+       int i;
+
+       /* get BIOS data */
+       vendor  = dmi_get_system_info(DMI_SYS_VENDOR);
+       version = dmi_get_system_info(DMI_BIOS_VERSION);
+       product = dmi_get_system_info(DMI_PRODUCT_NAME);
+
+       pr_info("Acer Aspire One Fan driver, v.%s\n", DRV_VER);
+
+       if (!force_bios[0]) {
+               if (strncmp(product, "AO", 2)) {
+                       pr_err("no Aspire One hardware found\n");
+                       return -EINVAL;
+               }
+       } else {
+               pr_info("forcing BIOS version: %s\n", version);
+               version = force_bios;
+               kernelmode = 0;
+       }
+
+       if (verbose)
+               pr_info("BIOS info: %s %s, product: %s\n",
+                       vendor, version, product);
+
+       /* search BIOS version and vendor in BIOS settings table */
+       for (i = 0; bios_tbl[i].version[0]; i++) {
+               if (!strcmp(bios_tbl[i].vendor, vendor) &&
+                   !strcmp(bios_tbl[i].version, version)) {
+                       bios_cfg = &bios_tbl[i];
+                       break;
+               }
+       }
+
+       if (!bios_cfg) {
+               pr_err("unknown (unsupported) BIOS version %s/%s, "
+                       "please report, aborting!\n", vendor, version);
+               return -EINVAL;
+       }
+
+       /*
+        * if started with kernel mode off, prevent the kernel from switching
+        * off the fan
+        */
+       if (!kernelmode) {
+               pr_notice("Fan control off, to enable do:\n");
+               pr_notice("echo -n \"enabled\" > "
+                       "/sys/class/thermal/thermal_zone0/mode\n");
+       }
+
+       return 0;
+}
+
+static int acerhdf_register_platform(void)
+{
+       int err = 0;
+
+       err = platform_driver_register(&acerhdf_drv);
+       if (err)
+               return err;
+
+       acerhdf_dev = platform_device_alloc("acerhdf", -1);
+       platform_device_add(acerhdf_dev);
+
+       return 0;
+}
+
+static void acerhdf_unregister_platform(void)
+{
+       if (!acerhdf_dev)
+               return;
+
+       platform_device_del(acerhdf_dev);
+       platform_driver_unregister(&acerhdf_drv);
+}
+
+static int acerhdf_register_thermal(void)
+{
+       cl_dev = thermal_cooling_device_register("acerhdf-fan", NULL,
+                                                &acerhdf_cooling_ops);
+
+       if (IS_ERR(cl_dev))
+               return -EINVAL;
+
+       thz_dev = thermal_zone_device_register("acerhdf", 1, NULL,
+                                             &acerhdf_dev_ops, 0, 0, 0,
+                                             (kernelmode) ? interval*1000 : 0);
+       if (IS_ERR(thz_dev))
+               return -EINVAL;
+
+       return 0;
+}
+
+static void acerhdf_unregister_thermal(void)
+{
+       if (cl_dev) {
+               thermal_cooling_device_unregister(cl_dev);
+               cl_dev = NULL;
+       }
+
+       if (thz_dev) {
+               thermal_zone_device_unregister(thz_dev);
+               thz_dev = NULL;
+       }
+}
+
+static int __init acerhdf_init(void)
+{
+       int err = 0;
+
+       err = acerhdf_check_hardware();
+       if (err)
+               goto out_err;
+
+       err = acerhdf_register_platform();
+       if (err)
+               goto err_unreg;
+
+       err = acerhdf_register_thermal();
+       if (err)
+               goto err_unreg;
+
+       return 0;
+
+err_unreg:
+       acerhdf_unregister_thermal();
+       acerhdf_unregister_platform();
+
+out_err:
+       return -ENODEV;
+}
+
+static void __exit acerhdf_exit(void)
+{
+       acerhdf_change_fanstate(ACERHDF_FAN_AUTO);
+       acerhdf_unregister_thermal();
+       acerhdf_unregister_platform();
+}
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Peter Feuerer");
+MODULE_DESCRIPTION("Aspire One temperature and fan driver");
+MODULE_ALIAS("dmi:*:*Acer*:*:");
+MODULE_ALIAS("dmi:*:*Gateway*:*:");
+MODULE_ALIAS("dmi:*:*Packard Bell*:*:");
+
+module_init(acerhdf_init);
+module_exit(acerhdf_exit);
index bfc1a8892a32f5eb03c8c2752ffb2daff977488c..db657bbeec908e456facb8271fa8624fe0f0a515 100644 (file)
@@ -33,6 +33,8 @@
  *  Sam Lin        - GPS support
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/init.h>
 #define ASUS_HOTK_NAME          "Asus Laptop Support"
 #define ASUS_HOTK_CLASS         "hotkey"
 #define ASUS_HOTK_DEVICE_NAME   "Hotkey"
-#define ASUS_HOTK_FILE          "asus-laptop"
+#define ASUS_HOTK_FILE          KBUILD_MODNAME
 #define ASUS_HOTK_PREFIX        "\\_SB.ATKD."
 
+
 /*
  * Some events we use, same for all Asus
  */
@@ -207,13 +210,17 @@ MODULE_DEVICE_TABLE(acpi, asus_device_ids);
 
 static int asus_hotk_add(struct acpi_device *device);
 static int asus_hotk_remove(struct acpi_device *device, int type);
+static void asus_hotk_notify(struct acpi_device *device, u32 event);
+
 static struct acpi_driver asus_hotk_driver = {
        .name = ASUS_HOTK_NAME,
        .class = ASUS_HOTK_CLASS,
        .ids = asus_device_ids,
+       .flags = ACPI_DRIVER_ALL_NOTIFY_EVENTS,
        .ops = {
                .add = asus_hotk_add,
                .remove = asus_hotk_remove,
+               .notify = asus_hotk_notify,
                },
 };
 
@@ -323,7 +330,7 @@ static int read_wireless_status(int mask)
 
        rv = acpi_evaluate_integer(wireless_status_handle, NULL, NULL, &status);
        if (ACPI_FAILURE(rv))
-               printk(ASUS_WARNING "Error reading Wireless status\n");
+               pr_warning("Error reading Wireless status\n");
        else
                return (status & mask) ? 1 : 0;
 
@@ -337,7 +344,7 @@ static int read_gps_status(void)
 
        rv = acpi_evaluate_integer(gps_status_handle, NULL, NULL, &status);
        if (ACPI_FAILURE(rv))
-               printk(ASUS_WARNING "Error reading GPS status\n");
+               pr_warning("Error reading GPS status\n");
        else
                return status ? 1 : 0;
 
@@ -377,7 +384,7 @@ static void write_status(acpi_handle handle, int out, int mask)
        }
 
        if (write_acpi_int(handle, NULL, out, NULL))
-               printk(ASUS_WARNING " write failed %x\n", mask);
+               pr_warning(" write failed %x\n", mask);
 }
 
 /* /sys/class/led handlers */
@@ -420,7 +427,7 @@ static int set_lcd_state(int value)
                                              NULL, NULL, NULL);
 
                if (ACPI_FAILURE(status))
-                       printk(ASUS_WARNING "Error switching LCD\n");
+                       pr_warning("Error switching LCD\n");
        }
 
        write_status(NULL, lcd, LCD_ON);
@@ -444,7 +451,7 @@ static int read_brightness(struct backlight_device *bd)
 
        rv = acpi_evaluate_integer(brightness_get_handle, NULL, NULL, &value);
        if (ACPI_FAILURE(rv))
-               printk(ASUS_WARNING "Error reading brightness\n");
+               pr_warning("Error reading brightness\n");
 
        return value;
 }
@@ -457,7 +464,7 @@ static int set_brightness(struct backlight_device *bd, int value)
        /* 0 <= value <= 15 */
 
        if (write_acpi_int(brightness_set_handle, NULL, value, NULL)) {
-               printk(ASUS_WARNING "Error changing brightness\n");
+               pr_warning("Error changing brightness\n");
                ret = -EIO;
        }
 
@@ -587,7 +594,7 @@ static ssize_t store_ledd(struct device *dev, struct device_attribute *attr,
        rv = parse_arg(buf, count, &value);
        if (rv > 0) {
                if (write_acpi_int(ledd_set_handle, NULL, value, NULL))
-                       printk(ASUS_WARNING "LED display write failed\n");
+                       pr_warning("LED display write failed\n");
                else
                        hotk->ledd_status = (u32) value;
        }
@@ -632,7 +639,7 @@ static void set_display(int value)
 {
        /* no sanity check needed for now */
        if (write_acpi_int(display_set_handle, NULL, value, NULL))
-               printk(ASUS_WARNING "Error setting display\n");
+               pr_warning("Error setting display\n");
        return;
 }
 
@@ -647,7 +654,7 @@ static int read_display(void)
                rv = acpi_evaluate_integer(display_get_handle, NULL,
                                           NULL, &value);
                if (ACPI_FAILURE(rv))
-                       printk(ASUS_WARNING "Error reading display status\n");
+                       pr_warning("Error reading display status\n");
        }
 
        value &= 0x0F;          /* needed for some models, shouldn't hurt others */
@@ -689,7 +696,7 @@ static ssize_t store_disp(struct device *dev, struct device_attribute *attr,
 static void set_light_sens_switch(int value)
 {
        if (write_acpi_int(ls_switch_handle, NULL, value, NULL))
-               printk(ASUS_WARNING "Error setting light sensor switch\n");
+               pr_warning("Error setting light sensor switch\n");
        hotk->light_switch = value;
 }
 
@@ -714,7 +721,7 @@ static ssize_t store_lssw(struct device *dev, struct device_attribute *attr,
 static void set_light_sens_level(int value)
 {
        if (write_acpi_int(ls_level_handle, NULL, value, NULL))
-               printk(ASUS_WARNING "Error setting light sensor level\n");
+               pr_warning("Error setting light sensor level\n");
        hotk->light_level = value;
 }
 
@@ -812,7 +819,7 @@ static int asus_setkeycode(struct input_dev *dev, int scancode, int keycode)
        return -EINVAL;
 }
 
-static void asus_hotk_notify(acpi_handle handle, u32 event, void *data)
+static void asus_hotk_notify(struct acpi_device *device, u32 event)
 {
        static struct key_entry *key;
        u16 count;
@@ -975,11 +982,11 @@ static int asus_hotk_get_info(void)
         */
        status = acpi_get_table(ACPI_SIG_DSDT, 1, &asus_info);
        if (ACPI_FAILURE(status))
-               printk(ASUS_WARNING "Couldn't get the DSDT table header\n");
+               pr_warning("Couldn't get the DSDT table header\n");
 
        /* We have to write 0 on init this far for all ASUS models */
        if (write_acpi_int(hotk->handle, "INIT", 0, &buffer)) {
-               printk(ASUS_ERR "Hotkey initialization failed\n");
+               pr_err("Hotkey initialization failed\n");
                return -ENODEV;
        }
 
@@ -987,9 +994,9 @@ static int asus_hotk_get_info(void)
        status =
            acpi_evaluate_integer(hotk->handle, "BSTS", NULL, &bsts_result);
        if (ACPI_FAILURE(status))
-               printk(ASUS_WARNING "Error calling BSTS\n");
+               pr_warning("Error calling BSTS\n");
        else if (bsts_result)
-               printk(ASUS_NOTICE "BSTS called, 0x%02x returned\n",
+               pr_notice("BSTS called, 0x%02x returned\n",
                       (uint) bsts_result);
 
        /* This too ... */
@@ -1020,7 +1027,7 @@ static int asus_hotk_get_info(void)
                return -ENOMEM;
 
        if (*string)
-               printk(ASUS_NOTICE "  %s model detected\n", string);
+               pr_notice("  %s model detected\n", string);
 
        ASUS_HANDLE_INIT(mled_set);
        ASUS_HANDLE_INIT(tled_set);
@@ -1077,7 +1084,7 @@ static int asus_input_init(void)
 
        hotk->inputdev = input_allocate_device();
        if (!hotk->inputdev) {
-               printk(ASUS_INFO "Unable to allocate input device\n");
+               pr_info("Unable to allocate input device\n");
                return 0;
        }
        hotk->inputdev->name = "Asus Laptop extra buttons";
@@ -1096,7 +1103,7 @@ static int asus_input_init(void)
        }
        result = input_register_device(hotk->inputdev);
        if (result) {
-               printk(ASUS_INFO "Unable to register input device\n");
+               pr_info("Unable to register input device\n");
                input_free_device(hotk->inputdev);
        }
        return result;
@@ -1113,7 +1120,7 @@ static int asus_hotk_check(void)
        if (hotk->device->status.present) {
                result = asus_hotk_get_info();
        } else {
-               printk(ASUS_ERR "Hotkey device not present, aborting\n");
+               pr_err("Hotkey device not present, aborting\n");
                return -EINVAL;
        }
 
@@ -1124,13 +1131,12 @@ static int asus_hotk_found;
 
 static int asus_hotk_add(struct acpi_device *device)
 {
-       acpi_status status = AE_OK;
        int result;
 
        if (!device)
                return -EINVAL;
 
-       printk(ASUS_NOTICE "Asus Laptop Support version %s\n",
+       pr_notice("Asus Laptop Support version %s\n",
               ASUS_LAPTOP_VERSION);
 
        hotk = kzalloc(sizeof(struct asus_hotk), GFP_KERNEL);
@@ -1149,15 +1155,6 @@ static int asus_hotk_add(struct acpi_device *device)
 
        asus_hotk_add_fs();
 
-       /*
-        * We install the handler, it will receive the hotk in parameter, so, we
-        * could add other data to the hotk struct
-        */
-       status = acpi_install_notify_handler(hotk->handle, ACPI_ALL_NOTIFY,
-                                            asus_hotk_notify, hotk);
-       if (ACPI_FAILURE(status))
-               printk(ASUS_ERR "Error installing notify handler\n");
-
        asus_hotk_found = 1;
 
        /* WLED and BLED are on by default */
@@ -1198,16 +1195,9 @@ end:
 
 static int asus_hotk_remove(struct acpi_device *device, int type)
 {
-       acpi_status status = 0;
-
        if (!device || !acpi_driver_data(device))
                return -EINVAL;
 
-       status = acpi_remove_notify_handler(hotk->handle, ACPI_ALL_NOTIFY,
-                                           asus_hotk_notify);
-       if (ACPI_FAILURE(status))
-               printk(ASUS_ERR "Error removing notify handler\n");
-
        kfree(hotk->name);
        kfree(hotk);
 
@@ -1260,8 +1250,7 @@ static int asus_backlight_init(struct device *dev)
                bd = backlight_device_register(ASUS_HOTK_FILE, dev,
                                               NULL, &asusbl_ops);
                if (IS_ERR(bd)) {
-                       printk(ASUS_ERR
-                              "Could not register asus backlight device\n");
+                       pr_err("Could not register asus backlight device\n");
                        asus_backlight_device = NULL;
                        return PTR_ERR(bd);
                }
@@ -1334,7 +1323,6 @@ out:
 
 static int __init asus_laptop_init(void)
 {
-       struct device *dev;
        int result;
 
        if (acpi_disabled)
@@ -1356,24 +1344,10 @@ static int __init asus_laptop_init(void)
                return -ENODEV;
        }
 
-       dev = acpi_get_physical_device(hotk->device->handle);
-
-       if (!acpi_video_backlight_support()) {
-               result = asus_backlight_init(dev);
-               if (result)
-                       goto fail_backlight;
-       } else
-               printk(ASUS_INFO "Brightness ignored, must be controlled by "
-                      "ACPI video driver\n");
-
        result = asus_input_init();
        if (result)
                goto fail_input;
 
-       result = asus_led_init(dev);
-       if (result)
-               goto fail_led;
-
        /* Register platform stuff */
        result = platform_driver_register(&asuspf_driver);
        if (result)
@@ -1394,8 +1368,27 @@ static int __init asus_laptop_init(void)
        if (result)
                goto fail_sysfs;
 
+       result = asus_led_init(&asuspf_device->dev);
+       if (result)
+               goto fail_led;
+
+       if (!acpi_video_backlight_support()) {
+               result = asus_backlight_init(&asuspf_device->dev);
+               if (result)
+                       goto fail_backlight;
+       } else
+               pr_info("Brightness ignored, must be controlled by "
+                      "ACPI video driver\n");
+
        return 0;
 
+fail_backlight:
+       asus_led_exit();
+
+fail_led:
+       sysfs_remove_group(&asuspf_device->dev.kobj,
+                         &asuspf_attribute_group);
+
 fail_sysfs:
        platform_device_del(asuspf_device);
 
@@ -1406,15 +1399,9 @@ fail_platform_device1:
        platform_driver_unregister(&asuspf_driver);
 
 fail_platform_driver:
-       asus_led_exit();
-
-fail_led:
        asus_input_exit();
 
 fail_input:
-       asus_backlight_exit();
-
-fail_backlight:
 
        return result;
 }
index ba1f7497e4b9a99f5be8d9d9d406ff1f6b170dbd..ddf5240ade8cc0e10358553382ffa68716933ce0 100644 (file)
@@ -455,6 +455,8 @@ static struct asus_hotk *hotk;
  */
 static int asus_hotk_add(struct acpi_device *device);
 static int asus_hotk_remove(struct acpi_device *device, int type);
+static void asus_hotk_notify(struct acpi_device *device, u32 event);
+
 static const struct acpi_device_id asus_device_ids[] = {
        {"ATK0100", 0},
        {"", 0},
@@ -465,9 +467,11 @@ static struct acpi_driver asus_hotk_driver = {
        .name = "asus_acpi",
        .class = ACPI_HOTK_CLASS,
        .ids = asus_device_ids,
+       .flags = ACPI_DRIVER_ALL_NOTIFY_EVENTS,
        .ops = {
                .add = asus_hotk_add,
                .remove = asus_hotk_remove,
+               .notify = asus_hotk_notify,
                },
 };
 
@@ -1101,12 +1105,20 @@ static int asus_hotk_remove_fs(struct acpi_device *device)
        return 0;
 }
 
-static void asus_hotk_notify(acpi_handle handle, u32 event, void *data)
+static void asus_hotk_notify(struct acpi_device *device, u32 event)
 {
        /* TODO Find a better way to handle events count. */
        if (!hotk)
                return;
 
+       /*
+        * The BIOS *should* be sending us device events, but apparently
+        * Asus uses system events instead, so just ignore any device
+        * events we get.
+        */
+       if (event > ACPI_MAX_SYS_NOTIFY)
+               return;
+
        if ((event & ~((u32) BR_UP)) < 16)
                hotk->brightness = (event & ~((u32) BR_UP));
        else if ((event & ~((u32) BR_DOWN)) < 16)
@@ -1346,15 +1358,6 @@ static int asus_hotk_add(struct acpi_device *device)
        if (result)
                goto end;
 
-       /*
-        * We install the handler, it will receive the hotk in parameter, so, we
-        * could add other data to the hotk struct
-        */
-       status = acpi_install_notify_handler(hotk->handle, ACPI_SYSTEM_NOTIFY,
-                                            asus_hotk_notify, hotk);
-       if (ACPI_FAILURE(status))
-               printk(KERN_ERR "  Error installing notify handler\n");
-
        /* For laptops without GPLV: init the hotk->brightness value */
        if ((!hotk->methods->brightness_get)
            && (!hotk->methods->brightness_status)
@@ -1389,16 +1392,9 @@ end:
 
 static int asus_hotk_remove(struct acpi_device *device, int type)
 {
-       acpi_status status = 0;
-
        if (!device || !acpi_driver_data(device))
                return -EINVAL;
 
-       status = acpi_remove_notify_handler(hotk->handle, ACPI_SYSTEM_NOTIFY,
-                                           asus_hotk_notify);
-       if (ACPI_FAILURE(status))
-               printk(KERN_ERR "Asus ACPI: Error removing notify handler\n");
-
        asus_hotk_remove_fs(device);
 
        kfree(hotk);
index 2fab94162147e2b2bc0206bcad3e6b4b76764587..0f900cc9fa7a5131283c14b2aae8e11d7667b949 100644 (file)
@@ -46,10 +46,53 @@ struct key_entry {
        u16 keycode;
 };
 
-enum { KE_KEY, KE_SW, KE_END };
+enum { KE_KEY, KE_SW, KE_IGNORE, KE_END };
+
+/*
+ * Certain keys are flagged as KE_IGNORE. All of these are either
+ * notifications (rather than requests for change) or are also sent
+ * via the keyboard controller so should not be sent again.
+ */
 
 static struct key_entry dell_wmi_keymap[] = {
        {KE_KEY, 0xe045, KEY_PROG1},
+       {KE_KEY, 0xe009, KEY_EJECTCD},
+
+       /* These also contain the brightness level at offset 6 */
+       {KE_KEY, 0xe006, KEY_BRIGHTNESSUP},
+       {KE_KEY, 0xe005, KEY_BRIGHTNESSDOWN},
+
+       /* Battery health status button */
+       {KE_KEY, 0xe007, KEY_BATTERY},
+
+       /* This is actually for all radios. Although physically a
+        * switch, the notification does not provide an indication of
+        * state and so it should be reported as a key */
+       {KE_KEY, 0xe008, KEY_WLAN},
+
+       /* The next device is at offset 6, the active devices are at
+          offset 8 and the attached devices at offset 10 */
+       {KE_KEY, 0xe00b, KEY_DISPLAYTOGGLE},
+
+       {KE_IGNORE, 0xe00c, KEY_KBDILLUMTOGGLE},
+
+       /* BIOS error detected */
+       {KE_IGNORE, 0xe00d, KEY_RESERVED},
+
+       /* Wifi Catcher */
+       {KE_KEY, 0xe011, KEY_PROG2},
+
+       /* Ambient light sensor toggle */
+       {KE_IGNORE, 0xe013, KEY_RESERVED},
+
+       {KE_IGNORE, 0xe020, KEY_MUTE},
+       {KE_IGNORE, 0xe02e, KEY_VOLUMEDOWN},
+       {KE_IGNORE, 0xe030, KEY_VOLUMEUP},
+       {KE_IGNORE, 0xe033, KEY_KBDILLUMUP},
+       {KE_IGNORE, 0xe034, KEY_KBDILLUMDOWN},
+       {KE_IGNORE, 0xe03a, KEY_CAPSLOCK},
+       {KE_IGNORE, 0xe045, KEY_NUMLOCK},
+       {KE_IGNORE, 0xe046, KEY_SCROLLLOCK},
        {KE_END, 0}
 };
 
@@ -122,15 +165,20 @@ static void dell_wmi_notify(u32 value, void *context)
 
        if (obj && obj->type == ACPI_TYPE_BUFFER) {
                int *buffer = (int *)obj->buffer.pointer;
-               key = dell_wmi_get_entry_by_scancode(buffer[1]);
+               /*
+                *  The upper bytes of the event may contain
+                *  additional information, so mask them off for the
+                *  scancode lookup
+                */
+               key = dell_wmi_get_entry_by_scancode(buffer[1] & 0xFFFF);
                if (key) {
                        input_report_key(dell_wmi_input_dev, key->keycode, 1);
                        input_sync(dell_wmi_input_dev);
                        input_report_key(dell_wmi_input_dev, key->keycode, 0);
                        input_sync(dell_wmi_input_dev);
-               } else
+               } else if (buffer[1] & 0xFFFF)
                        printk(KERN_INFO "dell-wmi: Unknown key %x pressed\n",
-                              buffer[1]);
+                              buffer[1] & 0xFFFF);
        }
 }
 
index 8153b3e5918967bb1662c44523d1ab7eab233d69..ec560f16d7204a20c42b874d7e54902aaf2762cd 100644 (file)
@@ -16,6 +16,8 @@
  *  GNU General Public License for more details.
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/init.h>
@@ -31,6 +33,7 @@
 #include <linux/input.h>
 #include <linux/rfkill.h>
 #include <linux/pci.h>
+#include <linux/pci_hotplug.h>
 
 #define EEEPC_LAPTOP_VERSION   "0.1"
 
 #define EEEPC_HOTK_DEVICE_NAME "Hotkey"
 #define EEEPC_HOTK_HID         "ASUS010"
 
-#define EEEPC_LOG      EEEPC_HOTK_FILE ": "
-#define EEEPC_ERR      KERN_ERR        EEEPC_LOG
-#define EEEPC_WARNING  KERN_WARNING    EEEPC_LOG
-#define EEEPC_NOTICE   KERN_NOTICE     EEEPC_LOG
-#define EEEPC_INFO     KERN_INFO       EEEPC_LOG
 
 /*
  * Definitions for Asus EeePC
@@ -62,7 +60,10 @@ enum {
        DISABLE_ASL_GPS = 0x0020,
        DISABLE_ASL_DISPLAYSWITCH = 0x0040,
        DISABLE_ASL_MODEM = 0x0080,
-       DISABLE_ASL_CARDREADER = 0x0100
+       DISABLE_ASL_CARDREADER = 0x0100,
+       DISABLE_ASL_3G = 0x0200,
+       DISABLE_ASL_WIMAX = 0x0400,
+       DISABLE_ASL_HWCF = 0x0800
 };
 
 enum {
@@ -87,7 +88,13 @@ enum {
        CM_ASL_USBPORT3,
        CM_ASL_MODEM,
        CM_ASL_CARDREADER,
-       CM_ASL_LID
+       CM_ASL_3G,
+       CM_ASL_WIMAX,
+       CM_ASL_HWCF,
+       CM_ASL_LID,
+       CM_ASL_TYPE,
+       CM_ASL_PANELPOWER,      /*P901*/
+       CM_ASL_TPD
 };
 
 static const char *cm_getv[] = {
@@ -96,7 +103,8 @@ static const char *cm_getv[] = {
        NULL, "PBLG", NULL, NULL,
        "CFVG", NULL, NULL, NULL,
        "USBG", NULL, NULL, "MODG",
-       "CRDG", "LIDG"
+       "CRDG", "M3GG", "WIMG", "HWCF",
+       "LIDG", "TYPE", "PBPG", "TPDG"
 };
 
 static const char *cm_setv[] = {
@@ -105,7 +113,8 @@ static const char *cm_setv[] = {
        "SDSP", "PBLS", "HDPS", NULL,
        "CFVS", NULL, NULL, NULL,
        "USBG", NULL, NULL, "MODS",
-       "CRDS", NULL
+       "CRDS", "M3GS", "WIMS", NULL,
+       NULL, NULL, "PBPS", "TPDS"
 };
 
 #define EEEPC_EC       "\\_SB.PCI0.SBRG.EC0."
@@ -130,8 +139,10 @@ struct eeepc_hotk {
        u16 event_count[128];           /* count for each event */
        struct input_dev *inputdev;
        u16 *keycode_map;
-       struct rfkill *eeepc_wlan_rfkill;
-       struct rfkill *eeepc_bluetooth_rfkill;
+       struct rfkill *wlan_rfkill;
+       struct rfkill *bluetooth_rfkill;
+       struct rfkill *wwan3g_rfkill;
+       struct hotplug_slot *hotplug_slot;
 };
 
 /* The actual device the driver binds to */
@@ -181,6 +192,7 @@ static struct key_entry eeepc_keymap[] = {
 static int eeepc_hotk_add(struct acpi_device *device);
 static int eeepc_hotk_remove(struct acpi_device *device, int type);
 static int eeepc_hotk_resume(struct acpi_device *device);
+static void eeepc_hotk_notify(struct acpi_device *device, u32 event);
 
 static const struct acpi_device_id eeepc_device_ids[] = {
        {EEEPC_HOTK_HID, 0},
@@ -192,13 +204,24 @@ static struct acpi_driver eeepc_hotk_driver = {
        .name = EEEPC_HOTK_NAME,
        .class = EEEPC_HOTK_CLASS,
        .ids = eeepc_device_ids,
+       .flags = ACPI_DRIVER_ALL_NOTIFY_EVENTS,
        .ops = {
                .add = eeepc_hotk_add,
                .remove = eeepc_hotk_remove,
                .resume = eeepc_hotk_resume,
+               .notify = eeepc_hotk_notify,
        },
 };
 
+/* PCI hotplug ops */
+static int eeepc_get_adapter_status(struct hotplug_slot *slot, u8 *value);
+
+static struct hotplug_slot_ops eeepc_hotplug_slot_ops = {
+       .owner = THIS_MODULE,
+       .get_adapter_status = eeepc_get_adapter_status,
+       .get_power_status = eeepc_get_adapter_status,
+};
+
 /* The backlight device /sys/class/backlight */
 static struct backlight_device *eeepc_backlight_device;
 
@@ -260,20 +283,20 @@ static int set_acpi(int cm, int value)
                if (method == NULL)
                        return -ENODEV;
                if (write_acpi_int(ehotk->handle, method, value, NULL))
-                       printk(EEEPC_WARNING "Error writing %s\n", method);
+                       pr_warning("Error writing %s\n", method);
        }
        return 0;
 }
 
 static int get_acpi(int cm)
 {
-       int value = -1;
+       int value = -ENODEV;
        if ((ehotk->cm_supported & (0x1 << cm))) {
                const char *method = cm_getv[cm];
                if (method == NULL)
                        return -ENODEV;
                if (read_acpi_int(ehotk->handle, method, &value))
-                       printk(EEEPC_WARNING "Error reading %s\n", method);
+                       pr_warning("Error reading %s\n", method);
        }
        return value;
 }
@@ -318,6 +341,15 @@ static const struct rfkill_ops eeepc_rfkill_ops = {
        .set_block = eeepc_rfkill_set,
 };
 
+static void __init eeepc_enable_camera(void)
+{
+       /*
+        * If the following call to set_acpi() fails, it's because there's no
+        * camera so we can ignore the error.
+        */
+       set_acpi(CM_ASL_CAMERA, 1);
+}
+
 /*
  * Sys helpers
  */
@@ -336,13 +368,19 @@ static ssize_t store_sys_acpi(int cm, const char *buf, size_t count)
 
        rv = parse_arg(buf, count, &value);
        if (rv > 0)
-               set_acpi(cm, value);
+               value = set_acpi(cm, value);
+       if (value < 0)
+               return value;
        return rv;
 }
 
 static ssize_t show_sys_acpi(int cm, char *buf)
 {
-       return sprintf(buf, "%d\n", get_acpi(cm));
+       int value = get_acpi(cm);
+
+       if (value < 0)
+               return value;
+       return sprintf(buf, "%d\n", value);
 }
 
 #define EEEPC_CREATE_DEVICE_ATTR(_name, _cm)                           \
@@ -369,13 +407,88 @@ static ssize_t show_sys_acpi(int cm, char *buf)
 EEEPC_CREATE_DEVICE_ATTR(camera, CM_ASL_CAMERA);
 EEEPC_CREATE_DEVICE_ATTR(cardr, CM_ASL_CARDREADER);
 EEEPC_CREATE_DEVICE_ATTR(disp, CM_ASL_DISPLAYSWITCH);
-EEEPC_CREATE_DEVICE_ATTR(cpufv, CM_ASL_CPUFV);
+
+struct eeepc_cpufv {
+       int num;
+       int cur;
+};
+
+static int get_cpufv(struct eeepc_cpufv *c)
+{
+       c->cur = get_acpi(CM_ASL_CPUFV);
+       c->num = (c->cur >> 8) & 0xff;
+       c->cur &= 0xff;
+       if (c->cur < 0 || c->num <= 0 || c->num > 12)
+               return -ENODEV;
+       return 0;
+}
+
+static ssize_t show_available_cpufv(struct device *dev,
+                                   struct device_attribute *attr,
+                                   char *buf)
+{
+       struct eeepc_cpufv c;
+       int i;
+       ssize_t len = 0;
+
+       if (get_cpufv(&c))
+               return -ENODEV;
+       for (i = 0; i < c.num; i++)
+               len += sprintf(buf + len, "%d ", i);
+       len += sprintf(buf + len, "\n");
+       return len;
+}
+
+static ssize_t show_cpufv(struct device *dev,
+                         struct device_attribute *attr,
+                         char *buf)
+{
+       struct eeepc_cpufv c;
+
+       if (get_cpufv(&c))
+               return -ENODEV;
+       return sprintf(buf, "%#x\n", (c.num << 8) | c.cur);
+}
+
+static ssize_t store_cpufv(struct device *dev,
+                          struct device_attribute *attr,
+                          const char *buf, size_t count)
+{
+       struct eeepc_cpufv c;
+       int rv, value;
+
+       if (get_cpufv(&c))
+               return -ENODEV;
+       rv = parse_arg(buf, count, &value);
+       if (rv < 0)
+               return rv;
+       if (!rv || value < 0 || value >= c.num)
+               return -EINVAL;
+       set_acpi(CM_ASL_CPUFV, value);
+       return rv;
+}
+
+static struct device_attribute dev_attr_cpufv = {
+       .attr = {
+               .name = "cpufv",
+               .mode = 0644 },
+       .show   = show_cpufv,
+       .store  = store_cpufv
+};
+
+static struct device_attribute dev_attr_available_cpufv = {
+       .attr = {
+               .name = "available_cpufv",
+               .mode = 0444 },
+       .show   = show_available_cpufv
+};
 
 static struct attribute *platform_attributes[] = {
        &dev_attr_camera.attr,
        &dev_attr_cardr.attr,
        &dev_attr_disp.attr,
        &dev_attr_cpufv.attr,
+       &dev_attr_available_cpufv.attr,
        NULL
 };
 
@@ -441,6 +554,28 @@ static int eeepc_setkeycode(struct input_dev *dev, int scancode, int keycode)
        return -EINVAL;
 }
 
+static void cmsg_quirk(int cm, const char *name)
+{
+       int dummy;
+
+       /* Some BIOSes do not report cm although it is avaliable.
+          Check if cm_getv[cm] works and, if yes, assume cm should be set. */
+       if (!(ehotk->cm_supported & (1 << cm))
+           && !read_acpi_int(ehotk->handle, cm_getv[cm], &dummy)) {
+               pr_info("%s (%x) not reported by BIOS,"
+                       " enabling anyway\n", name, 1 << cm);
+               ehotk->cm_supported |= 1 << cm;
+       }
+}
+
+static void cmsg_quirks(void)
+{
+       cmsg_quirk(CM_ASL_LID, "LID");
+       cmsg_quirk(CM_ASL_TYPE, "TYPE");
+       cmsg_quirk(CM_ASL_PANELPOWER, "PANELPOWER");
+       cmsg_quirk(CM_ASL_TPD, "TPD");
+}
+
 static int eeepc_hotk_check(void)
 {
        const struct key_entry *key;
@@ -453,26 +588,24 @@ static int eeepc_hotk_check(void)
        if (ehotk->device->status.present) {
                if (write_acpi_int(ehotk->handle, "INIT", ehotk->init_flag,
                                    &buffer)) {
-                       printk(EEEPC_ERR "Hotkey initialization failed\n");
+                       pr_err("Hotkey initialization failed\n");
                        return -ENODEV;
                } else {
-                       printk(EEEPC_NOTICE "Hotkey init flags 0x%x\n",
-                              ehotk->init_flag);
+                       pr_notice("Hotkey init flags 0x%x\n", ehotk->init_flag);
                }
                /* get control methods supported */
                if (read_acpi_int(ehotk->handle, "CMSG"
                                   , &ehotk->cm_supported)) {
-                       printk(EEEPC_ERR
-                              "Get control methods supported failed\n");
+                       pr_err("Get control methods supported failed\n");
                        return -ENODEV;
                } else {
-                       printk(EEEPC_INFO
-                              "Get control methods supported: 0x%x\n",
-                              ehotk->cm_supported);
+                       cmsg_quirks();
+                       pr_info("Get control methods supported: 0x%x\n",
+                               ehotk->cm_supported);
                }
                ehotk->inputdev = input_allocate_device();
                if (!ehotk->inputdev) {
-                       printk(EEEPC_INFO "Unable to allocate input device\n");
+                       pr_info("Unable to allocate input device\n");
                        return 0;
                }
                ehotk->inputdev->name = "Asus EeePC extra buttons";
@@ -491,12 +624,12 @@ static int eeepc_hotk_check(void)
                }
                result = input_register_device(ehotk->inputdev);
                if (result) {
-                       printk(EEEPC_INFO "Unable to register input device\n");
+                       pr_info("Unable to register input device\n");
                        input_free_device(ehotk->inputdev);
                        return 0;
                }
        } else {
-               printk(EEEPC_ERR "Hotkey device not present, aborting\n");
+               pr_err("Hotkey device not present, aborting\n");
                return -EINVAL;
        }
        return 0;
@@ -514,6 +647,19 @@ static int notify_brn(void)
        return -1;
 }
 
+static int eeepc_get_adapter_status(struct hotplug_slot *hotplug_slot,
+                                   u8 *value)
+{
+       int val = get_acpi(CM_ASL_WLAN);
+
+       if (val == 1 || val == 0)
+               *value = val;
+       else
+               return -EINVAL;
+
+       return 0;
+}
+
 static void eeepc_rfkill_hotplug(void)
 {
        struct pci_dev *dev;
@@ -521,7 +667,7 @@ static void eeepc_rfkill_hotplug(void)
        bool blocked;
 
        if (!bus) {
-               printk(EEEPC_WARNING "Unable to find PCI bus 1?\n");
+               pr_warning("Unable to find PCI bus 1?\n");
                return;
        }
 
@@ -537,7 +683,7 @@ static void eeepc_rfkill_hotplug(void)
                if (dev) {
                        pci_bus_assign_resources(bus);
                        if (pci_bus_add_device(dev))
-                               printk(EEEPC_ERR "Unable to hotplug wifi\n");
+                               pr_err("Unable to hotplug wifi\n");
                }
        } else {
                dev = pci_get_slot(bus, 0);
@@ -547,7 +693,7 @@ static void eeepc_rfkill_hotplug(void)
                }
        }
 
-       rfkill_set_sw_state(ehotk->eeepc_wlan_rfkill, blocked);
+       rfkill_set_sw_state(ehotk->wlan_rfkill, blocked);
 }
 
 static void eeepc_rfkill_notify(acpi_handle handle, u32 event, void *data)
@@ -558,7 +704,7 @@ static void eeepc_rfkill_notify(acpi_handle handle, u32 event, void *data)
        eeepc_rfkill_hotplug();
 }
 
-static void eeepc_hotk_notify(acpi_handle handle, u32 event, void *data)
+static void eeepc_hotk_notify(struct acpi_device *device, u32 event)
 {
        static struct key_entry *key;
        u16 count;
@@ -566,6 +712,8 @@ static void eeepc_hotk_notify(acpi_handle handle, u32 event, void *data)
 
        if (!ehotk)
                return;
+       if (event > ACPI_MAX_SYS_NOTIFY)
+               return;
        if (event >= NOTIFY_BRN_MIN && event <= NOTIFY_BRN_MAX)
                brn = notify_brn();
        count = ehotk->event_count[event % 128]++;
@@ -618,8 +766,7 @@ static int eeepc_register_rfkill_notifier(char *node)
                                                     eeepc_rfkill_notify,
                                                     NULL);
                if (ACPI_FAILURE(status))
-                       printk(EEEPC_WARNING
-                              "Failed to register notify on %s\n", node);
+                       pr_warning("Failed to register notify on %s\n", node);
        } else
                return -ENODEV;
 
@@ -638,20 +785,66 @@ static void eeepc_unregister_rfkill_notifier(char *node)
                                                     ACPI_SYSTEM_NOTIFY,
                                                     eeepc_rfkill_notify);
                if (ACPI_FAILURE(status))
-                       printk(EEEPC_ERR
-                              "Error removing rfkill notify handler %s\n",
+                       pr_err("Error removing rfkill notify handler %s\n",
                                node);
        }
 }
 
+static void eeepc_cleanup_pci_hotplug(struct hotplug_slot *hotplug_slot)
+{
+       kfree(hotplug_slot->info);
+       kfree(hotplug_slot);
+}
+
+static int eeepc_setup_pci_hotplug(void)
+{
+       int ret = -ENOMEM;
+       struct pci_bus *bus = pci_find_bus(0, 1);
+
+       if (!bus) {
+               pr_err("Unable to find wifi PCI bus\n");
+               return -ENODEV;
+       }
+
+       ehotk->hotplug_slot = kzalloc(sizeof(struct hotplug_slot), GFP_KERNEL);
+       if (!ehotk->hotplug_slot)
+               goto error_slot;
+
+       ehotk->hotplug_slot->info = kzalloc(sizeof(struct hotplug_slot_info),
+                                           GFP_KERNEL);
+       if (!ehotk->hotplug_slot->info)
+               goto error_info;
+
+       ehotk->hotplug_slot->private = ehotk;
+       ehotk->hotplug_slot->release = &eeepc_cleanup_pci_hotplug;
+       ehotk->hotplug_slot->ops = &eeepc_hotplug_slot_ops;
+       eeepc_get_adapter_status(ehotk->hotplug_slot,
+                                &ehotk->hotplug_slot->info->adapter_status);
+
+       ret = pci_hp_register(ehotk->hotplug_slot, bus, 0, "eeepc-wifi");
+       if (ret) {
+               pr_err("Unable to register hotplug slot - %d\n", ret);
+               goto error_register;
+       }
+
+       return 0;
+
+error_register:
+       kfree(ehotk->hotplug_slot->info);
+error_info:
+       kfree(ehotk->hotplug_slot);
+       ehotk->hotplug_slot = NULL;
+error_slot:
+       return ret;
+}
+
 static int eeepc_hotk_add(struct acpi_device *device)
 {
-       acpi_status status = AE_OK;
        int result;
 
        if (!device)
                 return -EINVAL;
-       printk(EEEPC_NOTICE EEEPC_HOTK_NAME "\n");
+       pr_notice(EEEPC_HOTK_NAME "\n");
        ehotk = kzalloc(sizeof(struct eeepc_hotk), GFP_KERNEL);
        if (!ehotk)
                return -ENOMEM;
@@ -664,58 +857,9 @@ static int eeepc_hotk_add(struct acpi_device *device)
        result = eeepc_hotk_check();
        if (result)
                goto ehotk_fail;
-       status = acpi_install_notify_handler(ehotk->handle, ACPI_SYSTEM_NOTIFY,
-                                            eeepc_hotk_notify, ehotk);
-       if (ACPI_FAILURE(status))
-               printk(EEEPC_ERR "Error installing notify handler\n");
-
-       eeepc_register_rfkill_notifier("\\_SB.PCI0.P0P6");
-       eeepc_register_rfkill_notifier("\\_SB.PCI0.P0P7");
-
-       if (get_acpi(CM_ASL_WLAN) != -1) {
-               ehotk->eeepc_wlan_rfkill = rfkill_alloc("eeepc-wlan",
-                                                       &device->dev,
-                                                       RFKILL_TYPE_WLAN,
-                                                       &eeepc_rfkill_ops,
-                                                       (void *)CM_ASL_WLAN);
-
-               if (!ehotk->eeepc_wlan_rfkill)
-                       goto wlan_fail;
-
-               rfkill_init_sw_state(ehotk->eeepc_wlan_rfkill,
-                                    get_acpi(CM_ASL_WLAN) != 1);
-               result = rfkill_register(ehotk->eeepc_wlan_rfkill);
-               if (result)
-                       goto wlan_fail;
-       }
-
-       if (get_acpi(CM_ASL_BLUETOOTH) != -1) {
-               ehotk->eeepc_bluetooth_rfkill =
-                       rfkill_alloc("eeepc-bluetooth",
-                                    &device->dev,
-                                    RFKILL_TYPE_BLUETOOTH,
-                                    &eeepc_rfkill_ops,
-                                    (void *)CM_ASL_BLUETOOTH);
-
-               if (!ehotk->eeepc_bluetooth_rfkill)
-                       goto bluetooth_fail;
-
-               rfkill_init_sw_state(ehotk->eeepc_bluetooth_rfkill,
-                                    get_acpi(CM_ASL_BLUETOOTH) != 1);
-               result = rfkill_register(ehotk->eeepc_bluetooth_rfkill);
-               if (result)
-                       goto bluetooth_fail;
-       }
 
        return 0;
 
- bluetooth_fail:
-       rfkill_destroy(ehotk->eeepc_bluetooth_rfkill);
-       rfkill_unregister(ehotk->eeepc_wlan_rfkill);
- wlan_fail:
-       rfkill_destroy(ehotk->eeepc_wlan_rfkill);
-       eeepc_unregister_rfkill_notifier("\\_SB.PCI0.P0P6");
-       eeepc_unregister_rfkill_notifier("\\_SB.PCI0.P0P7");
  ehotk_fail:
        kfree(ehotk);
        ehotk = NULL;
@@ -725,17 +869,8 @@ static int eeepc_hotk_add(struct acpi_device *device)
 
 static int eeepc_hotk_remove(struct acpi_device *device, int type)
 {
-       acpi_status status = 0;
-
        if (!device || !acpi_driver_data(device))
                 return -EINVAL;
-       status = acpi_remove_notify_handler(ehotk->handle, ACPI_SYSTEM_NOTIFY,
-                                           eeepc_hotk_notify);
-       if (ACPI_FAILURE(status))
-               printk(EEEPC_ERR "Error removing notify handler\n");
-
-       eeepc_unregister_rfkill_notifier("\\_SB.PCI0.P0P6");
-       eeepc_unregister_rfkill_notifier("\\_SB.PCI0.P0P7");
 
        kfree(ehotk);
        return 0;
@@ -743,7 +878,7 @@ static int eeepc_hotk_remove(struct acpi_device *device, int type)
 
 static int eeepc_hotk_resume(struct acpi_device *device)
 {
-       if (ehotk->eeepc_wlan_rfkill) {
+       if (ehotk->wlan_rfkill) {
                bool wlan;
 
                /* Workaround - it seems that _PTS disables the wireless
@@ -755,14 +890,13 @@ static int eeepc_hotk_resume(struct acpi_device *device)
                wlan = get_acpi(CM_ASL_WLAN);
                set_acpi(CM_ASL_WLAN, wlan);
 
-               rfkill_set_sw_state(ehotk->eeepc_wlan_rfkill,
-                                   wlan != 1);
+               rfkill_set_sw_state(ehotk->wlan_rfkill, wlan != 1);
 
                eeepc_rfkill_hotplug();
        }
 
-       if (ehotk->eeepc_bluetooth_rfkill)
-               rfkill_set_sw_state(ehotk->eeepc_bluetooth_rfkill,
+       if (ehotk->bluetooth_rfkill)
+               rfkill_set_sw_state(ehotk->bluetooth_rfkill,
                                    get_acpi(CM_ASL_BLUETOOTH) != 1);
 
        return 0;
@@ -884,10 +1018,16 @@ static void eeepc_backlight_exit(void)
 
 static void eeepc_rfkill_exit(void)
 {
-       if (ehotk->eeepc_wlan_rfkill)
-               rfkill_unregister(ehotk->eeepc_wlan_rfkill);
-       if (ehotk->eeepc_bluetooth_rfkill)
-               rfkill_unregister(ehotk->eeepc_bluetooth_rfkill);
+       eeepc_unregister_rfkill_notifier("\\_SB.PCI0.P0P6");
+       eeepc_unregister_rfkill_notifier("\\_SB.PCI0.P0P7");
+       if (ehotk->wlan_rfkill)
+               rfkill_unregister(ehotk->wlan_rfkill);
+       if (ehotk->bluetooth_rfkill)
+               rfkill_unregister(ehotk->bluetooth_rfkill);
+       if (ehotk->wwan3g_rfkill)
+               rfkill_unregister(ehotk->wwan3g_rfkill);
+       if (ehotk->hotplug_slot)
+               pci_hp_deregister(ehotk->hotplug_slot);
 }
 
 static void eeepc_input_exit(void)
@@ -922,6 +1062,75 @@ static void __exit eeepc_laptop_exit(void)
        platform_driver_unregister(&platform_driver);
 }
 
+static int eeepc_new_rfkill(struct rfkill **rfkill,
+                           const char *name, struct device *dev,
+                           enum rfkill_type type, int cm)
+{
+       int result;
+
+       result = get_acpi(cm);
+       if (result < 0)
+               return result;
+
+       *rfkill = rfkill_alloc(name, dev, type,
+                              &eeepc_rfkill_ops, (void *)(unsigned long)cm);
+
+       if (!*rfkill)
+               return -EINVAL;
+
+       rfkill_init_sw_state(*rfkill, get_acpi(cm) != 1);
+       result = rfkill_register(*rfkill);
+       if (result) {
+               rfkill_destroy(*rfkill);
+               *rfkill = NULL;
+               return result;
+       }
+       return 0;
+}
+
+
+static int eeepc_rfkill_init(struct device *dev)
+{
+       int result = 0;
+
+       eeepc_register_rfkill_notifier("\\_SB.PCI0.P0P6");
+       eeepc_register_rfkill_notifier("\\_SB.PCI0.P0P7");
+
+       result = eeepc_new_rfkill(&ehotk->wlan_rfkill,
+                                 "eeepc-wlan", dev,
+                                 RFKILL_TYPE_WLAN, CM_ASL_WLAN);
+
+       if (result && result != -ENODEV)
+               goto exit;
+
+       result = eeepc_new_rfkill(&ehotk->bluetooth_rfkill,
+                                 "eeepc-bluetooth", dev,
+                                 RFKILL_TYPE_BLUETOOTH, CM_ASL_BLUETOOTH);
+
+       if (result && result != -ENODEV)
+               goto exit;
+
+       result = eeepc_new_rfkill(&ehotk->wwan3g_rfkill,
+                                 "eeepc-wwan3g", dev,
+                                 RFKILL_TYPE_WWAN, CM_ASL_3G);
+
+       if (result && result != -ENODEV)
+               goto exit;
+
+       result = eeepc_setup_pci_hotplug();
+       /*
+        * If we get -EBUSY then something else is handling the PCI hotplug -
+        * don't fail in this case
+        */
+       if (result == -EBUSY)
+               result = 0;
+
+exit:
+       if (result && result != -ENODEV)
+               eeepc_rfkill_exit();
+       return result;
+}
+
 static int eeepc_backlight_init(struct device *dev)
 {
        struct backlight_device *bd;
@@ -929,8 +1138,7 @@ static int eeepc_backlight_init(struct device *dev)
        bd = backlight_device_register(EEEPC_HOTK_FILE, dev,
                                       NULL, &eeepcbl_ops);
        if (IS_ERR(bd)) {
-               printk(EEEPC_ERR
-                      "Could not register eeepc backlight device\n");
+               pr_err("Could not register eeepc backlight device\n");
                eeepc_backlight_device = NULL;
                return PTR_ERR(bd);
        }
@@ -949,8 +1157,7 @@ static int eeepc_hwmon_init(struct device *dev)
 
        hwmon = hwmon_device_register(dev);
        if (IS_ERR(hwmon)) {
-               printk(EEEPC_ERR
-                      "Could not register eeepc hwmon device\n");
+               pr_err("Could not register eeepc hwmon device\n");
                eeepc_hwmon_device = NULL;
                return PTR_ERR(hwmon);
        }
@@ -976,19 +1183,9 @@ static int __init eeepc_laptop_init(void)
                acpi_bus_unregister_driver(&eeepc_hotk_driver);
                return -ENODEV;
        }
-       dev = acpi_get_physical_device(ehotk->device->handle);
 
-       if (!acpi_video_backlight_support()) {
-               result = eeepc_backlight_init(dev);
-               if (result)
-                       goto fail_backlight;
-       } else
-               printk(EEEPC_INFO "Backlight controlled by ACPI video "
-                      "driver\n");
+       eeepc_enable_camera();
 
-       result = eeepc_hwmon_init(dev);
-       if (result)
-               goto fail_hwmon;
        /* Register platform stuff */
        result = platform_driver_register(&platform_driver);
        if (result)
@@ -1005,7 +1202,33 @@ static int __init eeepc_laptop_init(void)
                                    &platform_attribute_group);
        if (result)
                goto fail_sysfs;
+
+       dev = &platform_device->dev;
+
+       if (!acpi_video_backlight_support()) {
+               result = eeepc_backlight_init(dev);
+               if (result)
+                       goto fail_backlight;
+       } else
+               pr_info("Backlight controlled by ACPI video "
+                       "driver\n");
+
+       result = eeepc_hwmon_init(dev);
+       if (result)
+               goto fail_hwmon;
+
+       result = eeepc_rfkill_init(dev);
+       if (result)
+               goto fail_rfkill;
+
        return 0;
+fail_rfkill:
+       eeepc_hwmon_exit();
+fail_hwmon:
+       eeepc_backlight_exit();
+fail_backlight:
+       sysfs_remove_group(&platform_device->dev.kobj,
+                          &platform_attribute_group);
 fail_sysfs:
        platform_device_del(platform_device);
 fail_platform_device2:
@@ -1013,12 +1236,7 @@ fail_platform_device2:
 fail_platform_device1:
        platform_driver_unregister(&platform_driver);
 fail_platform_driver:
-       eeepc_hwmon_exit();
-fail_hwmon:
-       eeepc_backlight_exit();
-fail_backlight:
        eeepc_input_exit();
-       eeepc_rfkill_exit();
        return result;
 }
 
index 16fffe44e3335ee34b4053e7b309b6e4dd3a631b..ca508564a18144a519ee84c3d88c549b7b5d8ae7 100644 (file)
@@ -47,7 +47,7 @@ MODULE_ALIAS("wmi:5FB7F034-2C63-45e9-BE91-3D44E2C707E4");
 #define HPWMI_DISPLAY_QUERY 0x1
 #define HPWMI_HDDTEMP_QUERY 0x2
 #define HPWMI_ALS_QUERY 0x3
-#define HPWMI_DOCK_QUERY 0x4
+#define HPWMI_HARDWARE_QUERY 0x4
 #define HPWMI_WIRELESS_QUERY 0x5
 #define HPWMI_HOTKEY_QUERY 0xc
 
@@ -75,10 +75,9 @@ struct key_entry {
        u16 keycode;
 };
 
-enum { KE_KEY, KE_SW, KE_END };
+enum { KE_KEY, KE_END };
 
 static struct key_entry hp_wmi_keymap[] = {
-       {KE_SW, 0x01, SW_DOCK},
        {KE_KEY, 0x02, KEY_BRIGHTNESSUP},
        {KE_KEY, 0x03, KEY_BRIGHTNESSDOWN},
        {KE_KEY, 0x20e6, KEY_PROG1},
@@ -151,13 +150,28 @@ static int hp_wmi_als_state(void)
 
 static int hp_wmi_dock_state(void)
 {
-       return hp_wmi_perform_query(HPWMI_DOCK_QUERY, 0, 0);
+       int ret = hp_wmi_perform_query(HPWMI_HARDWARE_QUERY, 0, 0);
+
+       if (ret < 0)
+               return ret;
+
+       return ret & 0x1;
+}
+
+static int hp_wmi_tablet_state(void)
+{
+       int ret = hp_wmi_perform_query(HPWMI_HARDWARE_QUERY, 0, 0);
+
+       if (ret < 0)
+               return ret;
+
+       return (ret & 0x4) ? 1 : 0;
 }
 
 static int hp_wmi_set_block(void *data, bool blocked)
 {
        unsigned long b = (unsigned long) data;
-       int query = BIT(b + 8) | ((!!blocked) << b);
+       int query = BIT(b + 8) | ((!blocked) << b);
 
        return hp_wmi_perform_query(HPWMI_WIRELESS_QUERY, 1, query);
 }
@@ -232,6 +246,15 @@ static ssize_t show_dock(struct device *dev, struct device_attribute *attr,
        return sprintf(buf, "%d\n", value);
 }
 
+static ssize_t show_tablet(struct device *dev, struct device_attribute *attr,
+                        char *buf)
+{
+       int value = hp_wmi_tablet_state();
+       if (value < 0)
+               return -EINVAL;
+       return sprintf(buf, "%d\n", value);
+}
+
 static ssize_t set_als(struct device *dev, struct device_attribute *attr,
                       const char *buf, size_t count)
 {
@@ -244,6 +267,7 @@ static DEVICE_ATTR(display, S_IRUGO, show_display, NULL);
 static DEVICE_ATTR(hddtemp, S_IRUGO, show_hddtemp, NULL);
 static DEVICE_ATTR(als, S_IRUGO | S_IWUSR, show_als, set_als);
 static DEVICE_ATTR(dock, S_IRUGO, show_dock, NULL);
+static DEVICE_ATTR(tablet, S_IRUGO, show_tablet, NULL);
 
 static struct key_entry *hp_wmi_get_entry_by_scancode(int code)
 {
@@ -326,13 +350,13 @@ static void hp_wmi_notify(u32 value, void *context)
                                                 key->keycode, 0);
                                input_sync(hp_wmi_input_dev);
                                break;
-                       case KE_SW:
-                               input_report_switch(hp_wmi_input_dev,
-                                                   key->keycode,
-                                                   hp_wmi_dock_state());
-                               input_sync(hp_wmi_input_dev);
-                               break;
                        }
+               } else if (eventcode == 0x1) {
+                       input_report_switch(hp_wmi_input_dev, SW_DOCK,
+                                           hp_wmi_dock_state());
+                       input_report_switch(hp_wmi_input_dev, SW_TABLET_MODE,
+                                           hp_wmi_tablet_state());
+                       input_sync(hp_wmi_input_dev);
                } else if (eventcode == 0x5) {
                        if (wifi_rfkill)
                                rfkill_set_sw_state(wifi_rfkill,
@@ -369,18 +393,19 @@ static int __init hp_wmi_input_setup(void)
                        set_bit(EV_KEY, hp_wmi_input_dev->evbit);
                        set_bit(key->keycode, hp_wmi_input_dev->keybit);
                        break;
-               case KE_SW:
-                       set_bit(EV_SW, hp_wmi_input_dev->evbit);
-                       set_bit(key->keycode, hp_wmi_input_dev->swbit);
-
-                       /* Set initial dock state */
-                       input_report_switch(hp_wmi_input_dev, key->keycode,
-                                           hp_wmi_dock_state());
-                       input_sync(hp_wmi_input_dev);
-                       break;
                }
        }
 
+       set_bit(EV_SW, hp_wmi_input_dev->evbit);
+       set_bit(SW_DOCK, hp_wmi_input_dev->swbit);
+       set_bit(SW_TABLET_MODE, hp_wmi_input_dev->swbit);
+
+       /* Set initial hardware state */
+       input_report_switch(hp_wmi_input_dev, SW_DOCK, hp_wmi_dock_state());
+       input_report_switch(hp_wmi_input_dev, SW_TABLET_MODE,
+                           hp_wmi_tablet_state());
+       input_sync(hp_wmi_input_dev);
+
        err = input_register_device(hp_wmi_input_dev);
 
        if (err) {
@@ -397,6 +422,7 @@ static void cleanup_sysfs(struct platform_device *device)
        device_remove_file(&device->dev, &dev_attr_hddtemp);
        device_remove_file(&device->dev, &dev_attr_als);
        device_remove_file(&device->dev, &dev_attr_dock);
+       device_remove_file(&device->dev, &dev_attr_tablet);
 }
 
 static int __init hp_wmi_bios_setup(struct platform_device *device)
@@ -414,6 +440,9 @@ static int __init hp_wmi_bios_setup(struct platform_device *device)
        if (err)
                goto add_sysfs_error;
        err = device_create_file(&device->dev, &dev_attr_dock);
+       if (err)
+               goto add_sysfs_error;
+       err = device_create_file(&device->dev, &dev_attr_tablet);
        if (err)
                goto add_sysfs_error;
 
@@ -485,23 +514,17 @@ static int __exit hp_wmi_bios_remove(struct platform_device *device)
 
 static int hp_wmi_resume_handler(struct platform_device *device)
 {
-       struct key_entry *key;
-
        /*
-        * Docking state may have changed while suspended, so trigger
-        * an input event for the current state. As this is a switch,
+        * Hardware state may have changed while suspended, so trigger
+        * input events for the current state. As this is a switch,
         * the input layer will only actually pass it on if the state
         * changed.
         */
-       for (key = hp_wmi_keymap; key->type != KE_END; key++) {
-               switch (key->type) {
-               case KE_SW:
-                       input_report_switch(hp_wmi_input_dev, key->keycode,
-                                           hp_wmi_dock_state());
-                       input_sync(hp_wmi_input_dev);
-                       break;
-               }
-       }
+
+       input_report_switch(hp_wmi_input_dev, SW_DOCK, hp_wmi_dock_state());
+       input_report_switch(hp_wmi_input_dev, SW_TABLET_MODE,
+                           hp_wmi_tablet_state());
+       input_sync(hp_wmi_input_dev);
 
        return 0;
 }
index 40d64c03278ca4bd18db3cf8214e11a9412cc0e7..a463fd72c49560a7c5d7fe2f8744a614519f7f34 100644 (file)
@@ -22,7 +22,7 @@
  */
 
 #define TPACPI_VERSION "0.23"
-#define TPACPI_SYSFS_VERSION 0x020300
+#define TPACPI_SYSFS_VERSION 0x020400
 
 /*
  *  Changelog:
@@ -257,6 +257,8 @@ static struct {
        u32 wan:1;
        u32 uwb:1;
        u32 fan_ctrl_status_undef:1;
+       u32 second_fan:1;
+       u32 beep_needs_two_args:1;
        u32 input_device_registered:1;
        u32 platform_drv_registered:1;
        u32 platform_drv_attrs_registered:1;
@@ -277,8 +279,10 @@ struct thinkpad_id_data {
        char *bios_version_str; /* Something like 1ZET51WW (1.03z) */
        char *ec_version_str;   /* Something like 1ZHT51WW-1.04a */
 
-       u16 bios_model;         /* Big Endian, TP-1Y = 0x5931, 0 = unknown */
+       u16 bios_model;         /* 1Y = 0x5931, 0 = unknown */
        u16 ec_model;
+       u16 bios_release;       /* 1ZETK1WW = 0x314b, 0 = unknown */
+       u16 ec_release;
 
        char *model_str;        /* ThinkPad T43 */
        char *nummodel_str;     /* 9384A9C for a 9384-A9C model */
@@ -355,6 +359,73 @@ static void tpacpi_log_usertask(const char * const what)
                } \
        } while (0)
 
+/*
+ * Quirk handling helpers
+ *
+ * ThinkPad IDs and versions seen in the field so far
+ * are two-characters from the set [0-9A-Z], i.e. base 36.
+ *
+ * We use values well outside that range as specials.
+ */
+
+#define TPACPI_MATCH_ANY               0xffffU
+#define TPACPI_MATCH_UNKNOWN           0U
+
+/* TPID('1', 'Y') == 0x5931 */
+#define TPID(__c1, __c2) (((__c2) << 8) | (__c1))
+
+#define TPACPI_Q_IBM(__id1, __id2, __quirk)    \
+       { .vendor = PCI_VENDOR_ID_IBM,          \
+         .bios = TPID(__id1, __id2),           \
+         .ec = TPACPI_MATCH_ANY,               \
+         .quirks = (__quirk) }
+
+#define TPACPI_Q_LNV(__id1, __id2, __quirk)    \
+       { .vendor = PCI_VENDOR_ID_LENOVO,       \
+         .bios = TPID(__id1, __id2),           \
+         .ec = TPACPI_MATCH_ANY,               \
+         .quirks = (__quirk) }
+
+struct tpacpi_quirk {
+       unsigned int vendor;
+       u16 bios;
+       u16 ec;
+       unsigned long quirks;
+};
+
+/**
+ * tpacpi_check_quirks() - search BIOS/EC version on a list
+ * @qlist:             array of &struct tpacpi_quirk
+ * @qlist_size:                number of elements in @qlist
+ *
+ * Iterates over a quirks list until one is found that matches the
+ * ThinkPad's vendor, BIOS and EC model.
+ *
+ * Returns 0 if nothing matches, otherwise returns the quirks field of
+ * the matching &struct tpacpi_quirk entry.
+ *
+ * The match criteria is: vendor, ec and bios much match.
+ */
+static unsigned long __init tpacpi_check_quirks(
+                       const struct tpacpi_quirk *qlist,
+                       unsigned int qlist_size)
+{
+       while (qlist_size) {
+               if ((qlist->vendor == thinkpad_id.vendor ||
+                               qlist->vendor == TPACPI_MATCH_ANY) &&
+                   (qlist->bios == thinkpad_id.bios_model ||
+                               qlist->bios == TPACPI_MATCH_ANY) &&
+                   (qlist->ec == thinkpad_id.ec_model ||
+                               qlist->ec == TPACPI_MATCH_ANY))
+                       return qlist->quirks;
+
+               qlist_size--;
+               qlist++;
+       }
+       return 0;
+}
+
+
 /****************************************************************************
  ****************************************************************************
  *
@@ -2880,7 +2951,7 @@ static int __init hotkey_init(struct ibm_init_struct *iibm)
                /* update bright_acpimode... */
                tpacpi_check_std_acpi_brightness_support();
 
-       if (tp_features.bright_acpimode) {
+       if (tp_features.bright_acpimode && acpi_video_backlight_support()) {
                printk(TPACPI_INFO
                       "This ThinkPad has standard ACPI backlight "
                       "brightness control, supported by the ACPI "
@@ -4773,7 +4844,7 @@ TPACPI_HANDLE(led, ec, "SLED",    /* 570 */
           "LED",               /* all others */
           );                   /* R30, R31 */
 
-#define TPACPI_LED_NUMLEDS 8
+#define TPACPI_LED_NUMLEDS 16
 static struct tpacpi_led_classdev *tpacpi_leds;
 static enum led_status_t tpacpi_led_state_cache[TPACPI_LED_NUMLEDS];
 static const char * const tpacpi_led_names[TPACPI_LED_NUMLEDS] = {
@@ -4786,15 +4857,20 @@ static const char * const tpacpi_led_names[TPACPI_LED_NUMLEDS] = {
        "tpacpi::dock_batt",
        "tpacpi::unknown_led",
        "tpacpi::standby",
+       "tpacpi::dock_status1",
+       "tpacpi::dock_status2",
+       "tpacpi::unknown_led2",
+       "tpacpi::unknown_led3",
+       "tpacpi::thinkvantage",
 };
-#define TPACPI_SAFE_LEDS       0x0081U
+#define TPACPI_SAFE_LEDS       0x1081U
 
 static inline bool tpacpi_is_led_restricted(const unsigned int led)
 {
 #ifdef CONFIG_THINKPAD_ACPI_UNSAFE_LEDS
        return false;
 #else
-       return (TPACPI_SAFE_LEDS & (1 << led)) == 0;
+       return (1U & (TPACPI_SAFE_LEDS >> led)) == 0;
 #endif
 }
 
@@ -4956,6 +5032,10 @@ static int __init tpacpi_init_led(unsigned int led)
 
        tpacpi_leds[led].led = led;
 
+       /* LEDs with no name don't get registered */
+       if (!tpacpi_led_names[led])
+               return 0;
+
        tpacpi_leds[led].led_classdev.brightness_set = &led_sysfs_set;
        tpacpi_leds[led].led_classdev.blink_set = &led_sysfs_blink_set;
        if (led_supported == TPACPI_LED_570)
@@ -4974,10 +5054,59 @@ static int __init tpacpi_init_led(unsigned int led)
        return rc;
 }
 
+static const struct tpacpi_quirk led_useful_qtable[] __initconst = {
+       TPACPI_Q_IBM('1', 'E', 0x009f), /* A30 */
+       TPACPI_Q_IBM('1', 'N', 0x009f), /* A31 */
+       TPACPI_Q_IBM('1', 'G', 0x009f), /* A31 */
+
+       TPACPI_Q_IBM('1', 'I', 0x0097), /* T30 */
+       TPACPI_Q_IBM('1', 'R', 0x0097), /* T40, T41, T42, R50, R51 */
+       TPACPI_Q_IBM('7', '0', 0x0097), /* T43, R52 */
+       TPACPI_Q_IBM('1', 'Y', 0x0097), /* T43 */
+       TPACPI_Q_IBM('1', 'W', 0x0097), /* R50e */
+       TPACPI_Q_IBM('1', 'V', 0x0097), /* R51 */
+       TPACPI_Q_IBM('7', '8', 0x0097), /* R51e */
+       TPACPI_Q_IBM('7', '6', 0x0097), /* R52 */
+
+       TPACPI_Q_IBM('1', 'K', 0x00bf), /* X30 */
+       TPACPI_Q_IBM('1', 'Q', 0x00bf), /* X31, X32 */
+       TPACPI_Q_IBM('1', 'U', 0x00bf), /* X40 */
+       TPACPI_Q_IBM('7', '4', 0x00bf), /* X41 */
+       TPACPI_Q_IBM('7', '5', 0x00bf), /* X41t */
+
+       TPACPI_Q_IBM('7', '9', 0x1f97), /* T60 (1) */
+       TPACPI_Q_IBM('7', '7', 0x1f97), /* Z60* (1) */
+       TPACPI_Q_IBM('7', 'F', 0x1f97), /* Z61* (1) */
+       TPACPI_Q_IBM('7', 'B', 0x1fb7), /* X60 (1) */
+
+       /* (1) - may have excess leds enabled on MSB */
+
+       /* Defaults (order matters, keep last, don't reorder!) */
+       { /* Lenovo */
+         .vendor = PCI_VENDOR_ID_LENOVO,
+         .bios = TPACPI_MATCH_ANY, .ec = TPACPI_MATCH_ANY,
+         .quirks = 0x1fffU,
+       },
+       { /* IBM ThinkPads with no EC version string */
+         .vendor = PCI_VENDOR_ID_IBM,
+         .bios = TPACPI_MATCH_ANY, .ec = TPACPI_MATCH_UNKNOWN,
+         .quirks = 0x00ffU,
+       },
+       { /* IBM ThinkPads with EC version string */
+         .vendor = PCI_VENDOR_ID_IBM,
+         .bios = TPACPI_MATCH_ANY, .ec = TPACPI_MATCH_ANY,
+         .quirks = 0x00bfU,
+       },
+};
+
+#undef TPACPI_LEDQ_IBM
+#undef TPACPI_LEDQ_LNV
+
 static int __init led_init(struct ibm_init_struct *iibm)
 {
        unsigned int i;
        int rc;
+       unsigned long useful_leds;
 
        vdbg_printk(TPACPI_DBG_INIT, "initializing LED subdriver\n");
 
@@ -4999,6 +5128,9 @@ static int __init led_init(struct ibm_init_struct *iibm)
        vdbg_printk(TPACPI_DBG_INIT, "LED commands are %s, mode %d\n",
                str_supported(led_supported), led_supported);
 
+       if (led_supported == TPACPI_LED_NONE)
+               return 1;
+
        tpacpi_leds = kzalloc(sizeof(*tpacpi_leds) * TPACPI_LED_NUMLEDS,
                              GFP_KERNEL);
        if (!tpacpi_leds) {
@@ -5006,8 +5138,12 @@ static int __init led_init(struct ibm_init_struct *iibm)
                return -ENOMEM;
        }
 
+       useful_leds = tpacpi_check_quirks(led_useful_qtable,
+                                         ARRAY_SIZE(led_useful_qtable));
+
        for (i = 0; i < TPACPI_LED_NUMLEDS; i++) {
-               if (!tpacpi_is_led_restricted(i)) {
+               if (!tpacpi_is_led_restricted(i) &&
+                   test_bit(i, &useful_leds)) {
                        rc = tpacpi_init_led(i);
                        if (rc < 0) {
                                led_exit();
@@ -5017,12 +5153,11 @@ static int __init led_init(struct ibm_init_struct *iibm)
        }
 
 #ifdef CONFIG_THINKPAD_ACPI_UNSAFE_LEDS
-       if (led_supported != TPACPI_LED_NONE)
-               printk(TPACPI_NOTICE
-                       "warning: userspace override of important "
-                       "firmware LEDs is enabled\n");
+       printk(TPACPI_NOTICE
+               "warning: userspace override of important "
+               "firmware LEDs is enabled\n");
 #endif
-       return (led_supported != TPACPI_LED_NONE)? 0 : 1;
+       return 0;
 }
 
 #define str_led_status(s) \
@@ -5052,7 +5187,7 @@ static int led_read(char *p)
        }
 
        len += sprintf(p + len, "commands:\t"
-                      "<led> on, <led> off, <led> blink (<led> is 0-7)\n");
+                      "<led> on, <led> off, <led> blink (<led> is 0-15)\n");
 
        return len;
 }
@@ -5067,7 +5202,7 @@ static int led_write(char *buf)
                return -ENODEV;
 
        while ((cmd = next_cmd(&buf))) {
-               if (sscanf(cmd, "%d", &led) != 1 || led < 0 || led > 7)
+               if (sscanf(cmd, "%d", &led) != 1 || led < 0 || led > 15)
                        return -EINVAL;
 
                if (strstr(cmd, "off")) {
@@ -5101,8 +5236,17 @@ static struct ibm_struct led_driver_data = {
 
 TPACPI_HANDLE(beep, ec, "BEEP");       /* all except R30, R31 */
 
+#define TPACPI_BEEP_Q1 0x0001
+
+static const struct tpacpi_quirk beep_quirk_table[] __initconst = {
+       TPACPI_Q_IBM('I', 'M', TPACPI_BEEP_Q1), /* 570 */
+       TPACPI_Q_IBM('I', 'U', TPACPI_BEEP_Q1), /* 570E - unverified */
+};
+
 static int __init beep_init(struct ibm_init_struct *iibm)
 {
+       unsigned long quirks;
+
        vdbg_printk(TPACPI_DBG_INIT, "initializing beep subdriver\n");
 
        TPACPI_ACPIHANDLE_INIT(beep);
@@ -5110,6 +5254,11 @@ static int __init beep_init(struct ibm_init_struct *iibm)
        vdbg_printk(TPACPI_DBG_INIT, "beep is %s\n",
                str_supported(beep_handle != NULL));
 
+       quirks = tpacpi_check_quirks(beep_quirk_table,
+                                    ARRAY_SIZE(beep_quirk_table));
+
+       tp_features.beep_needs_two_args = !!(quirks & TPACPI_BEEP_Q1);
+
        return (beep_handle)? 0 : 1;
 }
 
@@ -5141,8 +5290,15 @@ static int beep_write(char *buf)
                        /* beep_cmd set */
                } else
                        return -EINVAL;
-               if (!acpi_evalf(beep_handle, NULL, NULL, "vdd", beep_cmd, 0))
-                       return -EIO;
+               if (tp_features.beep_needs_two_args) {
+                       if (!acpi_evalf(beep_handle, NULL, NULL, "vdd",
+                                       beep_cmd, 0))
+                               return -EIO;
+               } else {
+                       if (!acpi_evalf(beep_handle, NULL, NULL, "vd",
+                                       beep_cmd))
+                               return -EIO;
+               }
        }
 
        return 0;
@@ -5569,6 +5725,10 @@ static struct ibm_struct ecdump_driver_data = {
  *   Bit 3-0: backlight brightness level
  *
  * brightness_get_raw returns status data in the HBRV layout
+ *
+ * WARNING: The X61 has been verified to use HBRV for something else, so
+ * this should be used _only_ on IBM ThinkPads, and maybe with some careful
+ * testing on the very early *60 Lenovo models...
  */
 
 enum {
@@ -5869,6 +6029,12 @@ static int __init brightness_init(struct ibm_init_struct *iibm)
                           brightness_mode);
        }
 
+       /* Safety */
+       if (thinkpad_id.vendor != PCI_VENDOR_ID_IBM &&
+           (brightness_mode == TPACPI_BRGHT_MODE_ECNVRAM ||
+            brightness_mode == TPACPI_BRGHT_MODE_EC))
+               return -EINVAL;
+
        if (tpacpi_brightness_get_raw(&b) < 0)
                return 1;
 
@@ -6161,6 +6327,21 @@ static struct ibm_struct volume_driver_data = {
  *     For firmware bugs, refer to:
  *     http://thinkwiki.org/wiki/Embedded_Controller_Firmware#Firmware_Issues
  *
+ *     ----
+ *
+ *     ThinkPad EC register 0x31 bit 0 (only on select models)
+ *
+ *     When bit 0 of EC register 0x31 is zero, the tachometer registers
+ *     show the speed of the main fan.  When bit 0 of EC register 0x31
+ *     is one, the tachometer registers show the speed of the auxiliary
+ *     fan.
+ *
+ *     Fan control seems to affect both fans, regardless of the state
+ *     of this bit.
+ *
+ *     So far, only the firmware for the X60/X61 non-tablet versions
+ *     seem to support this (firmware TP-7M).
+ *
  * TPACPI_FAN_WR_ACPI_FANS:
  *     ThinkPad X31, X40, X41.  Not available in the X60.
  *
@@ -6187,6 +6368,8 @@ enum {                                    /* Fan control constants */
        fan_status_offset = 0x2f,       /* EC register 0x2f */
        fan_rpm_offset = 0x84,          /* EC register 0x84: LSB, 0x85 MSB (RPM)
                                         * 0x84 must be read before 0x85 */
+       fan_select_offset = 0x31,       /* EC register 0x31 (Firmware 7M)
+                                          bit 0 selects which fan is active */
 
        TP_EC_FAN_FULLSPEED = 0x40,     /* EC fan mode: full speed */
        TP_EC_FAN_AUTO      = 0x80,     /* EC fan mode: auto fan control */
@@ -6249,30 +6432,18 @@ TPACPI_HANDLE(sfan, ec, "SFAN", /* 570 */
  * We assume 0x07 really means auto mode while this quirk is active,
  * as this is far more likely than the ThinkPad being in level 7,
  * which is only used by the firmware during thermal emergencies.
+ *
+ * Enable for TP-1Y (T43), TP-78 (R51e), TP-76 (R52),
+ * TP-70 (T43, R52), which are known to be buggy.
  */
 
-static void fan_quirk1_detect(void)
+static void fan_quirk1_setup(void)
 {
-       /* In some ThinkPads, neither the EC nor the ACPI
-        * DSDT initialize the HFSP register, and it ends up
-        * being initially set to 0x07 when it *could* be
-        * either 0x07 or 0x80.
-        *
-        * Enable for TP-1Y (T43), TP-78 (R51e),
-        * TP-76 (R52), TP-70 (T43, R52), which are known
-        * to be buggy. */
        if (fan_control_initial_status == 0x07) {
-               switch (thinkpad_id.ec_model) {
-               case 0x5931: /* TP-1Y */
-               case 0x3837: /* TP-78 */
-               case 0x3637: /* TP-76 */
-               case 0x3037: /* TP-70 */
-                       printk(TPACPI_NOTICE
-                              "fan_init: initial fan status is unknown, "
-                              "assuming it is in auto mode\n");
-                       tp_features.fan_ctrl_status_undef = 1;
-                       ;;
-               }
+               printk(TPACPI_NOTICE
+                      "fan_init: initial fan status is unknown, "
+                      "assuming it is in auto mode\n");
+               tp_features.fan_ctrl_status_undef = 1;
        }
 }
 
@@ -6292,6 +6463,38 @@ static void fan_quirk1_handle(u8 *fan_status)
        }
 }
 
+/* Select main fan on X60/X61, NOOP on others */
+static bool fan_select_fan1(void)
+{
+       if (tp_features.second_fan) {
+               u8 val;
+
+               if (ec_read(fan_select_offset, &val) < 0)
+                       return false;
+               val &= 0xFEU;
+               if (ec_write(fan_select_offset, val) < 0)
+                       return false;
+       }
+       return true;
+}
+
+/* Select secondary fan on X60/X61 */
+static bool fan_select_fan2(void)
+{
+       u8 val;
+
+       if (!tp_features.second_fan)
+               return false;
+
+       if (ec_read(fan_select_offset, &val) < 0)
+               return false;
+       val |= 0x01U;
+       if (ec_write(fan_select_offset, val) < 0)
+               return false;
+
+       return true;
+}
+
 /*
  * Call with fan_mutex held
  */
@@ -6369,6 +6572,8 @@ static int fan_get_speed(unsigned int *speed)
        switch (fan_status_access_mode) {
        case TPACPI_FAN_RD_TPEC:
                /* all except 570, 600e/x, 770e, 770x */
+               if (unlikely(!fan_select_fan1()))
+                       return -EIO;
                if (unlikely(!acpi_ec_read(fan_rpm_offset, &lo) ||
                             !acpi_ec_read(fan_rpm_offset + 1, &hi)))
                        return -EIO;
@@ -6385,6 +6590,34 @@ static int fan_get_speed(unsigned int *speed)
        return 0;
 }
 
+static int fan2_get_speed(unsigned int *speed)
+{
+       u8 hi, lo;
+       bool rc;
+
+       switch (fan_status_access_mode) {
+       case TPACPI_FAN_RD_TPEC:
+               /* all except 570, 600e/x, 770e, 770x */
+               if (unlikely(!fan_select_fan2()))
+                       return -EIO;
+               rc = !acpi_ec_read(fan_rpm_offset, &lo) ||
+                            !acpi_ec_read(fan_rpm_offset + 1, &hi);
+               fan_select_fan1(); /* play it safe */
+               if (rc)
+                       return -EIO;
+
+               if (likely(speed))
+                       *speed = (hi << 8) | lo;
+
+               break;
+
+       default:
+               return -ENXIO;
+       }
+
+       return 0;
+}
+
 static int fan_set_level(int level)
 {
        if (!fan_control_allowed)
@@ -6790,6 +7023,25 @@ static struct device_attribute dev_attr_fan_fan1_input =
        __ATTR(fan1_input, S_IRUGO,
                fan_fan1_input_show, NULL);
 
+/* sysfs fan fan2_input ------------------------------------------------ */
+static ssize_t fan_fan2_input_show(struct device *dev,
+                          struct device_attribute *attr,
+                          char *buf)
+{
+       int res;
+       unsigned int speed;
+
+       res = fan2_get_speed(&speed);
+       if (res < 0)
+               return res;
+
+       return snprintf(buf, PAGE_SIZE, "%u\n", speed);
+}
+
+static struct device_attribute dev_attr_fan_fan2_input =
+       __ATTR(fan2_input, S_IRUGO,
+               fan_fan2_input_show, NULL);
+
 /* sysfs fan fan_watchdog (hwmon driver) ------------------------------- */
 static ssize_t fan_fan_watchdog_show(struct device_driver *drv,
                                     char *buf)
@@ -6823,6 +7075,7 @@ static DRIVER_ATTR(fan_watchdog, S_IWUSR | S_IRUGO,
 static struct attribute *fan_attributes[] = {
        &dev_attr_fan_pwm1_enable.attr, &dev_attr_fan_pwm1.attr,
        &dev_attr_fan_fan1_input.attr,
+       NULL, /* for fan2_input */
        NULL
 };
 
@@ -6830,9 +7083,36 @@ static const struct attribute_group fan_attr_group = {
        .attrs = fan_attributes,
 };
 
+#define        TPACPI_FAN_Q1   0x0001          /* Unitialized HFSP */
+#define TPACPI_FAN_2FAN        0x0002          /* EC 0x31 bit 0 selects fan2 */
+
+#define TPACPI_FAN_QI(__id1, __id2, __quirks)  \
+       { .vendor = PCI_VENDOR_ID_IBM,          \
+         .bios = TPACPI_MATCH_ANY,             \
+         .ec = TPID(__id1, __id2),             \
+         .quirks = __quirks }
+
+#define TPACPI_FAN_QL(__id1, __id2, __quirks)  \
+       { .vendor = PCI_VENDOR_ID_LENOVO,       \
+         .bios = TPACPI_MATCH_ANY,             \
+         .ec = TPID(__id1, __id2),             \
+         .quirks = __quirks }
+
+static const struct tpacpi_quirk fan_quirk_table[] __initconst = {
+       TPACPI_FAN_QI('1', 'Y', TPACPI_FAN_Q1),
+       TPACPI_FAN_QI('7', '8', TPACPI_FAN_Q1),
+       TPACPI_FAN_QI('7', '6', TPACPI_FAN_Q1),
+       TPACPI_FAN_QI('7', '0', TPACPI_FAN_Q1),
+       TPACPI_FAN_QL('7', 'M', TPACPI_FAN_2FAN),
+};
+
+#undef TPACPI_FAN_QL
+#undef TPACPI_FAN_QI
+
 static int __init fan_init(struct ibm_init_struct *iibm)
 {
        int rc;
+       unsigned long quirks;
 
        vdbg_printk(TPACPI_DBG_INIT | TPACPI_DBG_FAN,
                        "initializing fan subdriver\n");
@@ -6843,12 +7123,16 @@ static int __init fan_init(struct ibm_init_struct *iibm)
        fan_control_commands = 0;
        fan_watchdog_maxinterval = 0;
        tp_features.fan_ctrl_status_undef = 0;
+       tp_features.second_fan = 0;
        fan_control_desired_level = 7;
 
        TPACPI_ACPIHANDLE_INIT(fans);
        TPACPI_ACPIHANDLE_INIT(gfan);
        TPACPI_ACPIHANDLE_INIT(sfan);
 
+       quirks = tpacpi_check_quirks(fan_quirk_table,
+                                    ARRAY_SIZE(fan_quirk_table));
+
        if (gfan_handle) {
                /* 570, 600e/x, 770e, 770x */
                fan_status_access_mode = TPACPI_FAN_RD_ACPI_GFAN;
@@ -6858,7 +7142,13 @@ static int __init fan_init(struct ibm_init_struct *iibm)
                if (likely(acpi_ec_read(fan_status_offset,
                                        &fan_control_initial_status))) {
                        fan_status_access_mode = TPACPI_FAN_RD_TPEC;
-                       fan_quirk1_detect();
+                       if (quirks & TPACPI_FAN_Q1)
+                               fan_quirk1_setup();
+                       if (quirks & TPACPI_FAN_2FAN) {
+                               tp_features.second_fan = 1;
+                               dbg_printk(TPACPI_DBG_INIT | TPACPI_DBG_FAN,
+                                       "secondary fan support enabled\n");
+                       }
                } else {
                        printk(TPACPI_ERR
                               "ThinkPad ACPI EC access misbehaving, "
@@ -6914,6 +7204,11 @@ static int __init fan_init(struct ibm_init_struct *iibm)
 
        if (fan_status_access_mode != TPACPI_FAN_NONE ||
            fan_control_access_mode != TPACPI_FAN_WR_NONE) {
+               if (tp_features.second_fan) {
+                       /* attach second fan tachometer */
+                       fan_attributes[ARRAY_SIZE(fan_attributes)-2] =
+                                       &dev_attr_fan_fan2_input.attr;
+               }
                rc = sysfs_create_group(&tpacpi_sensors_pdev->dev.kobj,
                                         &fan_attr_group);
                if (rc < 0)
@@ -7385,6 +7680,24 @@ err_out:
 
 /* Probing */
 
+static bool __pure __init tpacpi_is_fw_digit(const char c)
+{
+       return (c >= '0' && c <= '9') || (c >= 'A' && c <= 'Z');
+}
+
+/* Most models: xxyTkkWW (#.##c); Ancient 570/600 and -SL lacks (#.##c) */
+static bool __pure __init tpacpi_is_valid_fw_id(const char* const s,
+                                               const char t)
+{
+       return s && strlen(s) >= 8 &&
+               tpacpi_is_fw_digit(s[0]) &&
+               tpacpi_is_fw_digit(s[1]) &&
+               s[2] == t && s[3] == 'T' &&
+               tpacpi_is_fw_digit(s[4]) &&
+               tpacpi_is_fw_digit(s[5]) &&
+               s[6] == 'W' && s[7] == 'W';
+}
+
 /* returns 0 - probe ok, or < 0 - probe error.
  * Probe ok doesn't mean thinkpad found.
  * On error, kfree() cleanup on tp->* is not performed, caller must do it */
@@ -7411,10 +7724,15 @@ static int __must_check __init get_thinkpad_model_data(
        tp->bios_version_str = kstrdup(s, GFP_KERNEL);
        if (s && !tp->bios_version_str)
                return -ENOMEM;
-       if (!tp->bios_version_str)
+
+       /* Really ancient ThinkPad 240X will fail this, which is fine */
+       if (!tpacpi_is_valid_fw_id(tp->bios_version_str, 'E'))
                return 0;
+
        tp->bios_model = tp->bios_version_str[0]
                         | (tp->bios_version_str[1] << 8);
+       tp->bios_release = (tp->bios_version_str[4] << 8)
+                        | tp->bios_version_str[5];
 
        /*
         * ThinkPad T23 or newer, A31 or newer, R50e or newer,
@@ -7433,8 +7751,21 @@ static int __must_check __init get_thinkpad_model_data(
                        tp->ec_version_str = kstrdup(ec_fw_string, GFP_KERNEL);
                        if (!tp->ec_version_str)
                                return -ENOMEM;
-                       tp->ec_model = ec_fw_string[0]
-                                       | (ec_fw_string[1] << 8);
+
+                       if (tpacpi_is_valid_fw_id(ec_fw_string, 'H')) {
+                               tp->ec_model = ec_fw_string[0]
+                                               | (ec_fw_string[1] << 8);
+                               tp->ec_release = (ec_fw_string[4] << 8)
+                                               | ec_fw_string[5];
+                       } else {
+                               printk(TPACPI_NOTICE
+                                       "ThinkPad firmware release %s "
+                                       "doesn't match the known patterns\n",
+                                       ec_fw_string);
+                               printk(TPACPI_NOTICE
+                                       "please report this to %s\n",
+                                       TPACPI_MAIL);
+                       }
                        break;
                }
        }
index 7f207f335beca2c53d8120c3a4681ff139cb7282..ef3a2cd3a7a0ac80a188cfb5cacbda03373cf3e3 100644 (file)
@@ -287,6 +287,25 @@ static void pnpacpi_parse_allocated_address_space(struct pnp_dev *dev,
                                ACPI_DECODE_16);
 }
 
+static void pnpacpi_parse_allocated_ext_address_space(struct pnp_dev *dev,
+                                                     struct acpi_resource *res)
+{
+       struct acpi_resource_extended_address64 *p = &res->data.ext_address64;
+
+       if (p->producer_consumer == ACPI_PRODUCER)
+               return;
+
+       if (p->resource_type == ACPI_MEMORY_RANGE)
+               pnpacpi_parse_allocated_memresource(dev,
+                       p->minimum, p->address_length,
+                       p->info.mem.write_protect);
+       else if (p->resource_type == ACPI_IO_RANGE)
+               pnpacpi_parse_allocated_ioresource(dev,
+                       p->minimum, p->address_length,
+                       p->granularity == 0xfff ? ACPI_DECODE_10 :
+                               ACPI_DECODE_16);
+}
+
 static acpi_status pnpacpi_allocated_resource(struct acpi_resource *res,
                                              void *data)
 {
@@ -400,8 +419,7 @@ static acpi_status pnpacpi_allocated_resource(struct acpi_resource *res,
                break;
 
        case ACPI_RESOURCE_TYPE_EXTENDED_ADDRESS64:
-               if (res->data.ext_address64.producer_consumer == ACPI_PRODUCER)
-                       return AE_OK;
+               pnpacpi_parse_allocated_ext_address_space(dev, res);
                break;
 
        case ACPI_RESOURCE_TYPE_EXTENDED_IRQ:
@@ -630,6 +648,28 @@ static __init void pnpacpi_parse_address_option(struct pnp_dev *dev,
                                           IORESOURCE_IO_FIXED);
 }
 
+static __init void pnpacpi_parse_ext_address_option(struct pnp_dev *dev,
+                                                   unsigned int option_flags,
+                                                   struct acpi_resource *r)
+{
+       struct acpi_resource_extended_address64 *p = &r->data.ext_address64;
+       unsigned char flags = 0;
+
+       if (p->address_length == 0)
+               return;
+
+       if (p->resource_type == ACPI_MEMORY_RANGE) {
+               if (p->info.mem.write_protect == ACPI_READ_WRITE_MEMORY)
+                       flags = IORESOURCE_MEM_WRITEABLE;
+               pnp_register_mem_resource(dev, option_flags, p->minimum,
+                                         p->minimum, 0, p->address_length,
+                                         flags);
+       } else if (p->resource_type == ACPI_IO_RANGE)
+               pnp_register_port_resource(dev, option_flags, p->minimum,
+                                          p->minimum, 0, p->address_length,
+                                          IORESOURCE_IO_FIXED);
+}
+
 struct acpipnp_parse_option_s {
        struct pnp_dev *dev;
        unsigned int option_flags;
@@ -711,6 +751,7 @@ static __init acpi_status pnpacpi_option_resource(struct acpi_resource *res,
                break;
 
        case ACPI_RESOURCE_TYPE_EXTENDED_ADDRESS64:
+               pnpacpi_parse_ext_address_option(dev, option_flags, res);
                break;
 
        case ACPI_RESOURCE_TYPE_EXTENDED_IRQ:
@@ -765,6 +806,7 @@ static int pnpacpi_supported_resource(struct acpi_resource *res)
        case ACPI_RESOURCE_TYPE_ADDRESS16:
        case ACPI_RESOURCE_TYPE_ADDRESS32:
        case ACPI_RESOURCE_TYPE_ADDRESS64:
+       case ACPI_RESOURCE_TYPE_EXTENDED_ADDRESS64:
        case ACPI_RESOURCE_TYPE_EXTENDED_IRQ:
                return 1;
        }
index 33da1127992aca4c36cfa04b1dfbb7a354edf38d..7eda34838bfe979e22bff2939237c8c9847671cc 100644 (file)
@@ -82,6 +82,14 @@ config BATTERY_DA9030
          Say Y here to enable support for batteries charger integrated into
          DA9030 PMIC.
 
+config BATTERY_MAX17040
+       tristate "Maxim MAX17040 Fuel Gauge"
+       depends on I2C
+       help
+         MAX17040 is fuel-gauge systems for lithium-ion (Li+) batteries
+         in handheld and portable equipment. The MAX17040 is configured
+         to operate with a single lithium cell
+
 config CHARGER_PCF50633
        tristate "NXP PCF50633 MBC"
        depends on MFD_PCF50633
index 2fcf41d13e5cae530c79478578485fe59493cb8b..daf3179689aaecb61611604f526d2f6e090c6b00 100644 (file)
@@ -25,4 +25,5 @@ obj-$(CONFIG_BATTERY_TOSA)    += tosa_battery.o
 obj-$(CONFIG_BATTERY_WM97XX)   += wm97xx_battery.o
 obj-$(CONFIG_BATTERY_BQ27x00)  += bq27x00_battery.o
 obj-$(CONFIG_BATTERY_DA9030)   += da9030_battery.o
-obj-$(CONFIG_CHARGER_PCF50633) += pcf50633-charger.o
\ No newline at end of file
+obj-$(CONFIG_BATTERY_MAX17040) += max17040_battery.o
+obj-$(CONFIG_CHARGER_PCF50633) += pcf50633-charger.o
index 1662bb0f23a5bc1a8f84a077099b84d292a2a8d9..3364198134a1d55a96789d1a7333a36432e14059 100644 (file)
@@ -22,8 +22,6 @@
 #include <linux/debugfs.h>
 #include <linux/seq_file.h>
 
-#define DA9030_STATUS_CHDET    (1 << 3)
-
 #define DA9030_FAULT_LOG               0x0a
 #define DA9030_FAULT_LOG_OVER_TEMP     (1 << 7)
 #define DA9030_FAULT_LOG_VBAT_OVER     (1 << 4)
@@ -244,6 +242,8 @@ static void da9030_set_charge(struct da9030_charger *charger, int on)
        }
 
        da903x_write(charger->master, DA9030_CHARGE_CONTROL, val);
+
+       power_supply_changed(&charger->psy);
 }
 
 static void da9030_charger_check_state(struct da9030_charger *charger)
@@ -258,6 +258,12 @@ static void da9030_charger_check_state(struct da9030_charger *charger)
                        da9030_set_charge(charger, 1);
                }
        } else {
+               /* Charger has been pulled out */
+               if (!charger->chdet) {
+                       da9030_set_charge(charger, 0);
+                       return;
+               }
+
                if (charger->adc.vbat_res >=
                    charger->thresholds.vbat_charge_stop) {
                        da9030_set_charge(charger, 0);
@@ -395,13 +401,11 @@ static int da9030_battery_event(struct notifier_block *nb, unsigned long event,
 {
        struct da9030_charger *charger =
                container_of(nb, struct da9030_charger, nb);
-       int status;
 
        switch (event) {
        case DA9030_EVENT_CHDET:
-               status = da903x_query_status(charger->master,
-                                            DA9030_STATUS_CHDET);
-               da9030_set_charge(charger, status);
+               cancel_delayed_work_sync(&charger->work);
+               schedule_work(&charger->work.work);
                break;
        case DA9030_EVENT_VBATMON:
                da9030_battery_vbat_event(charger);
@@ -565,7 +569,8 @@ static int da9030_battery_remove(struct platform_device *dev)
        da903x_unregister_notifier(charger->master, &charger->nb,
                                   DA9030_EVENT_CHDET | DA9030_EVENT_VBATMON |
                                   DA9030_EVENT_CHIOVER | DA9030_EVENT_TBAT);
-       cancel_delayed_work(&charger->work);
+       cancel_delayed_work_sync(&charger->work);
+       da9030_set_charge(charger, 0);
        power_supply_unregister(&charger->psy);
 
        kfree(charger);
index a52d4a11652d57aa7b045fa225777fdaecb252f2..520b5c49ff3049275dbeada16c80b93135cf47ea 100644 (file)
@@ -62,6 +62,10 @@ static unsigned int cache_time = 1000;
 module_param(cache_time, uint, 0644);
 MODULE_PARM_DESC(cache_time, "cache time in milliseconds");
 
+static unsigned int pmod_enabled;
+module_param(pmod_enabled, bool, 0644);
+MODULE_PARM_DESC(pmod_enabled, "PMOD enable bit");
+
 /* Some batteries have their rated capacity stored a N * 10 mAh, while
  * others use an index into this table. */
 static int rated_capacities[] = {
@@ -259,6 +263,17 @@ static void ds2760_battery_update_status(struct ds2760_device_info *di)
                power_supply_changed(&di->bat);
 }
 
+static void ds2760_battery_write_status(struct ds2760_device_info *di,
+                                       char status)
+{
+       if (status == di->raw[DS2760_STATUS_REG])
+               return;
+
+       w1_ds2760_write(di->w1_dev, &status, DS2760_STATUS_WRITE_REG, 1);
+       w1_ds2760_store_eeprom(di->w1_dev, DS2760_EEPROM_BLOCK1);
+       w1_ds2760_recall_eeprom(di->w1_dev, DS2760_EEPROM_BLOCK1);
+}
+
 static void ds2760_battery_work(struct work_struct *work)
 {
        struct ds2760_device_info *di = container_of(work,
@@ -342,9 +357,9 @@ static enum power_supply_property ds2760_battery_props[] = {
 
 static int ds2760_battery_probe(struct platform_device *pdev)
 {
+       char status;
        int retval = 0;
        struct ds2760_device_info *di;
-       struct ds2760_platform_data *pdata;
 
        di = kzalloc(sizeof(*di), GFP_KERNEL);
        if (!di) {
@@ -354,14 +369,13 @@ static int ds2760_battery_probe(struct platform_device *pdev)
 
        platform_set_drvdata(pdev, di);
 
-       pdata = pdev->dev.platform_data;
-       di->dev         = &pdev->dev;
-       di->w1_dev           = pdev->dev.parent;
-       di->bat.name       = dev_name(&pdev->dev);
-       di->bat.type       = POWER_SUPPLY_TYPE_BATTERY;
-       di->bat.properties     = ds2760_battery_props;
-       di->bat.num_properties = ARRAY_SIZE(ds2760_battery_props);
-       di->bat.get_property   = ds2760_battery_get_property;
+       di->dev                 = &pdev->dev;
+       di->w1_dev              = pdev->dev.parent;
+       di->bat.name            = dev_name(&pdev->dev);
+       di->bat.type            = POWER_SUPPLY_TYPE_BATTERY;
+       di->bat.properties      = ds2760_battery_props;
+       di->bat.num_properties  = ARRAY_SIZE(ds2760_battery_props);
+       di->bat.get_property    = ds2760_battery_get_property;
        di->bat.external_power_changed =
                                  ds2760_battery_external_power_changed;
 
@@ -373,6 +387,16 @@ static int ds2760_battery_probe(struct platform_device *pdev)
                goto batt_failed;
        }
 
+       /* enable sleep mode feature */
+       ds2760_battery_read_status(di);
+       status = di->raw[DS2760_STATUS_REG];
+       if (pmod_enabled)
+               status |= DS2760_STATUS_PMOD;
+       else
+               status &= ~DS2760_STATUS_PMOD;
+
+       ds2760_battery_write_status(di, status);
+
        INIT_DELAYED_WORK(&di->monitor_work, ds2760_battery_work);
        di->monitor_wqueue = create_singlethread_workqueue(dev_name(&pdev->dev));
        if (!di->monitor_wqueue) {
diff --git a/drivers/power/max17040_battery.c b/drivers/power/max17040_battery.c
new file mode 100644 (file)
index 0000000..87b98bf
--- /dev/null
@@ -0,0 +1,309 @@
+/*
+ *  max17040_battery.c
+ *  fuel-gauge systems for lithium-ion (Li+) batteries
+ *
+ *  Copyright (C) 2009 Samsung Electronics
+ *  Minkyu Kang <mk7.kang@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/mutex.h>
+#include <linux/err.h>
+#include <linux/i2c.h>
+#include <linux/delay.h>
+#include <linux/power_supply.h>
+#include <linux/max17040_battery.h>
+
+#define MAX17040_VCELL_MSB     0x02
+#define MAX17040_VCELL_LSB     0x03
+#define MAX17040_SOC_MSB       0x04
+#define MAX17040_SOC_LSB       0x05
+#define MAX17040_MODE_MSB      0x06
+#define MAX17040_MODE_LSB      0x07
+#define MAX17040_VER_MSB       0x08
+#define MAX17040_VER_LSB       0x09
+#define MAX17040_RCOMP_MSB     0x0C
+#define MAX17040_RCOMP_LSB     0x0D
+#define MAX17040_CMD_MSB       0xFE
+#define MAX17040_CMD_LSB       0xFF
+
+#define MAX17040_DELAY         1000
+#define MAX17040_BATTERY_FULL  95
+
+struct max17040_chip {
+       struct i2c_client               *client;
+       struct delayed_work             work;
+       struct power_supply             battery;
+       struct max17040_platform_data   *pdata;
+
+       /* State Of Connect */
+       int online;
+       /* battery voltage */
+       int vcell;
+       /* battery capacity */
+       int soc;
+       /* State Of Charge */
+       int status;
+};
+
+static int max17040_get_property(struct power_supply *psy,
+                           enum power_supply_property psp,
+                           union power_supply_propval *val)
+{
+       struct max17040_chip *chip = container_of(psy,
+                               struct max17040_chip, battery);
+
+       switch (psp) {
+       case POWER_SUPPLY_PROP_STATUS:
+               val->intval = chip->status;
+               break;
+       case POWER_SUPPLY_PROP_ONLINE:
+               val->intval = chip->online;
+               break;
+       case POWER_SUPPLY_PROP_VOLTAGE_NOW:
+               val->intval = chip->vcell;
+               break;
+       case POWER_SUPPLY_PROP_CAPACITY:
+               val->intval = chip->soc;
+               break;
+       default:
+               return -EINVAL;
+       }
+       return 0;
+}
+
+static int max17040_write_reg(struct i2c_client *client, int reg, u8 value)
+{
+       int ret;
+
+       ret = i2c_smbus_write_byte_data(client, reg, value);
+
+       if (ret < 0)
+               dev_err(&client->dev, "%s: err %d\n", __func__, ret);
+
+       return ret;
+}
+
+static int max17040_read_reg(struct i2c_client *client, int reg)
+{
+       int ret;
+
+       ret = i2c_smbus_read_byte_data(client, reg);
+
+       if (ret < 0)
+               dev_err(&client->dev, "%s: err %d\n", __func__, ret);
+
+       return ret;
+}
+
+static void max17040_reset(struct i2c_client *client)
+{
+       max17040_write_reg(client, MAX17040_CMD_MSB, 0x54);
+       max17040_write_reg(client, MAX17040_CMD_LSB, 0x00);
+}
+
+static void max17040_get_vcell(struct i2c_client *client)
+{
+       struct max17040_chip *chip = i2c_get_clientdata(client);
+       u8 msb;
+       u8 lsb;
+
+       msb = max17040_read_reg(client, MAX17040_VCELL_MSB);
+       lsb = max17040_read_reg(client, MAX17040_VCELL_LSB);
+
+       chip->vcell = (msb << 4) + (lsb >> 4);
+}
+
+static void max17040_get_soc(struct i2c_client *client)
+{
+       struct max17040_chip *chip = i2c_get_clientdata(client);
+       u8 msb;
+       u8 lsb;
+
+       msb = max17040_read_reg(client, MAX17040_SOC_MSB);
+       lsb = max17040_read_reg(client, MAX17040_SOC_LSB);
+
+       chip->soc = msb;
+}
+
+static void max17040_get_version(struct i2c_client *client)
+{
+       u8 msb;
+       u8 lsb;
+
+       msb = max17040_read_reg(client, MAX17040_VER_MSB);
+       lsb = max17040_read_reg(client, MAX17040_VER_LSB);
+
+       dev_info(&client->dev, "MAX17040 Fuel-Gauge Ver %d%d\n", msb, lsb);
+}
+
+static void max17040_get_online(struct i2c_client *client)
+{
+       struct max17040_chip *chip = i2c_get_clientdata(client);
+
+       if (chip->pdata->battery_online)
+               chip->online = chip->pdata->battery_online();
+       else
+               chip->online = 1;
+}
+
+static void max17040_get_status(struct i2c_client *client)
+{
+       struct max17040_chip *chip = i2c_get_clientdata(client);
+
+       if (!chip->pdata->charger_online || !chip->pdata->charger_enable) {
+               chip->status = POWER_SUPPLY_STATUS_UNKNOWN;
+               return;
+       }
+
+       if (chip->pdata->charger_online()) {
+               if (chip->pdata->charger_enable())
+                       chip->status = POWER_SUPPLY_STATUS_CHARGING;
+               else
+                       chip->status = POWER_SUPPLY_STATUS_NOT_CHARGING;
+       } else {
+               chip->status = POWER_SUPPLY_STATUS_DISCHARGING;
+       }
+
+       if (chip->soc > MAX17040_BATTERY_FULL)
+               chip->status = POWER_SUPPLY_STATUS_FULL;
+}
+
+static void max17040_work(struct work_struct *work)
+{
+       struct max17040_chip *chip;
+
+       chip = container_of(work, struct max17040_chip, work.work);
+
+       max17040_get_vcell(chip->client);
+       max17040_get_soc(chip->client);
+       max17040_get_online(chip->client);
+       max17040_get_status(chip->client);
+
+       schedule_delayed_work(&chip->work, MAX17040_DELAY);
+}
+
+static enum power_supply_property max17040_battery_props[] = {
+       POWER_SUPPLY_PROP_STATUS,
+       POWER_SUPPLY_PROP_ONLINE,
+       POWER_SUPPLY_PROP_VOLTAGE_NOW,
+       POWER_SUPPLY_PROP_CAPACITY,
+};
+
+static int __devinit max17040_probe(struct i2c_client *client,
+                       const struct i2c_device_id *id)
+{
+       struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent);
+       struct max17040_chip *chip;
+       int ret;
+
+       if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE))
+               return -EIO;
+
+       chip = kzalloc(sizeof(*chip), GFP_KERNEL);
+       if (!chip)
+               return -ENOMEM;
+
+       chip->client = client;
+       chip->pdata = client->dev.platform_data;
+
+       i2c_set_clientdata(client, chip);
+
+       chip->battery.name              = "battery";
+       chip->battery.type              = POWER_SUPPLY_TYPE_BATTERY;
+       chip->battery.get_property      = max17040_get_property;
+       chip->battery.properties        = max17040_battery_props;
+       chip->battery.num_properties    = ARRAY_SIZE(max17040_battery_props);
+
+       ret = power_supply_register(&client->dev, &chip->battery);
+       if (ret) {
+               dev_err(&client->dev, "failed: power supply register\n");
+               i2c_set_clientdata(client, NULL);
+               kfree(chip);
+               return ret;
+       }
+
+       max17040_reset(client);
+       max17040_get_version(client);
+
+       INIT_DELAYED_WORK_DEFERRABLE(&chip->work, max17040_work);
+       schedule_delayed_work(&chip->work, MAX17040_DELAY);
+
+       return 0;
+}
+
+static int __devexit max17040_remove(struct i2c_client *client)
+{
+       struct max17040_chip *chip = i2c_get_clientdata(client);
+
+       power_supply_unregister(&chip->battery);
+       cancel_delayed_work(&chip->work);
+       i2c_set_clientdata(client, NULL);
+       kfree(chip);
+       return 0;
+}
+
+#ifdef CONFIG_PM
+
+static int max17040_suspend(struct i2c_client *client,
+               pm_message_t state)
+{
+       struct max17040_chip *chip = i2c_get_clientdata(client);
+
+       cancel_delayed_work(&chip->work);
+       return 0;
+}
+
+static int max17040_resume(struct i2c_client *client)
+{
+       struct max17040_chip *chip = i2c_get_clientdata(client);
+
+       schedule_delayed_work(&chip->work, MAX17040_DELAY);
+       return 0;
+}
+
+#else
+
+#define max17040_suspend NULL
+#define max17040_resume NULL
+
+#endif /* CONFIG_PM */
+
+static const struct i2c_device_id max17040_id[] = {
+       { "max17040", 0 },
+       { }
+};
+MODULE_DEVICE_TABLE(i2c, max17040_id);
+
+static struct i2c_driver max17040_i2c_driver = {
+       .driver = {
+               .name   = "max17040",
+       },
+       .probe          = max17040_probe,
+       .remove         = __devexit_p(max17040_remove),
+       .suspend        = max17040_suspend,
+       .resume         = max17040_resume,
+       .id_table       = max17040_id,
+};
+
+static int __init max17040_init(void)
+{
+       return i2c_add_driver(&max17040_i2c_driver);
+}
+module_init(max17040_init);
+
+static void __exit max17040_exit(void)
+{
+       i2c_del_driver(&max17040_i2c_driver);
+}
+module_exit(max17040_exit);
+
+MODULE_AUTHOR("Minkyu Kang <mk7.kang@samsung.com>");
+MODULE_DESCRIPTION("MAX17040 Fuel Gauge");
+MODULE_LICENSE("GPL");
index 8bde92126d34794e6cd58e55f1d715216c92819b..b787335a8419352fa4cef23af9fccd2fd4f508ac 100644 (file)
@@ -33,14 +33,14 @@ static enum power_supply_property *prop;
 
 static unsigned long wm97xx_read_bat(struct power_supply *bat_ps)
 {
-       return wm97xx_read_aux_adc(bat_ps->dev->parent->driver_data,
+       return wm97xx_read_aux_adc(dev_get_drvdata(bat_ps->dev->parent),
                                        pdata->batt_aux) * pdata->batt_mult /
                                        pdata->batt_div;
 }
 
 static unsigned long wm97xx_read_temp(struct power_supply *bat_ps)
 {
-       return wm97xx_read_aux_adc(bat_ps->dev->parent->driver_data,
+       return wm97xx_read_aux_adc(dev_get_drvdata(bat_ps->dev->parent),
                                        pdata->temp_aux) * pdata->temp_mult /
                                        pdata->temp_div;
 }
index aafd3e6ebb0dfa92725f63798de226d5bf20ac72..a118eb0f1e6729029be1a4fdb61aea52634ed260 100644 (file)
@@ -1,8 +1,8 @@
 /*
  * Blackfin On-Chip Real Time Clock Driver
- *  Supports BF52[257]/BF53[123]/BF53[467]/BF54[24789]
+ *  Supports BF51x/BF52x/BF53[123]/BF53[467]/BF54x
  *
- * Copyright 2004-2008 Analog Devices Inc.
+ * Copyright 2004-2009 Analog Devices Inc.
  *
  * Enter bugs at http://blackfin.uclinux.org/
  *
@@ -363,7 +363,7 @@ static int __devinit bfin_rtc_probe(struct platform_device *pdev)
        struct bfin_rtc *rtc;
        struct device *dev = &pdev->dev;
        int ret = 0;
-       unsigned long timeout;
+       unsigned long timeout = jiffies + HZ;
 
        dev_dbg_stamp(dev);
 
@@ -374,32 +374,32 @@ static int __devinit bfin_rtc_probe(struct platform_device *pdev)
        platform_set_drvdata(pdev, rtc);
        device_init_wakeup(dev, 1);
 
+       /* Register our RTC with the RTC framework */
+       rtc->rtc_dev = rtc_device_register(pdev->name, dev, &bfin_rtc_ops,
+                                               THIS_MODULE);
+       if (unlikely(IS_ERR(rtc->rtc_dev))) {
+               ret = PTR_ERR(rtc->rtc_dev);
+               goto err;
+       }
+
        /* Grab the IRQ and init the hardware */
        ret = request_irq(IRQ_RTC, bfin_rtc_interrupt, IRQF_SHARED, pdev->name, dev);
        if (unlikely(ret))
-               goto err;
+               goto err_reg;
        /* sometimes the bootloader touched things, but the write complete was not
         * enabled, so let's just do a quick timeout here since the IRQ will not fire ...
         */
-       timeout = jiffies + HZ;
        while (bfin_read_RTC_ISTAT() & RTC_ISTAT_WRITE_PENDING)
                if (time_after(jiffies, timeout))
                        break;
        bfin_rtc_reset(dev, RTC_ISTAT_WRITE_COMPLETE);
        bfin_write_RTC_SWCNT(0);
 
-       /* Register our RTC with the RTC framework */
-       rtc->rtc_dev = rtc_device_register(pdev->name, dev, &bfin_rtc_ops, THIS_MODULE);
-       if (unlikely(IS_ERR(rtc->rtc_dev))) {
-               ret = PTR_ERR(rtc->rtc_dev);
-               goto err_irq;
-       }
-
        return 0;
 
- err_irq:
-       free_irq(IRQ_RTC, dev);
- err:
+err_reg:
+       rtc_device_unregister(rtc->rtc_dev);
+err:
        kfree(rtc);
        return ret;
 }
index 32b27739ec2a4567acd1d2cb2e38535c385d4f27..713f7bf5afb330c508b5d2482804f97ed0083470 100644 (file)
@@ -283,7 +283,7 @@ static void ds1374_work(struct work_struct *work)
 
        stat = i2c_smbus_read_byte_data(client, DS1374_REG_SR);
        if (stat < 0)
-               return;
+               goto unlock;
 
        if (stat & DS1374_REG_SR_AF) {
                stat &= ~DS1374_REG_SR_AF;
@@ -302,7 +302,7 @@ static void ds1374_work(struct work_struct *work)
 out:
        if (!ds1374->exiting)
                enable_irq(client->irq);
-
+unlock:
        mutex_unlock(&ds1374->mutex);
 }
 
index f11297aff854a3bf680d84c382581083e853df5d..2c839d0d21bd2011a82514b31807d2d3d6b591fc 100644 (file)
@@ -1,7 +1,7 @@
 /*
  *  Driver for NEC VR4100 series Real Time Clock unit.
  *
- *  Copyright (C) 2003-2008  Yoichi Yuasa <yoichi_yuasa@tripeaks.co.jp>
+ *  Copyright (C) 2003-2008  Yoichi Yuasa <yuasa@linux-mips.org>
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
@@ -33,7 +33,7 @@
 #include <asm/io.h>
 #include <asm/uaccess.h>
 
-MODULE_AUTHOR("Yoichi Yuasa <yoichi_yuasa@tripeaks.co.jp>");
+MODULE_AUTHOR("Yoichi Yuasa <yuasa@linux-mips.org>");
 MODULE_DESCRIPTION("NEC VR4100 series RTC driver");
 MODULE_LICENSE("GPL v2");
 
index f8b1f04f26b8ec248c0b69260f9e79d0a44ee8ec..c11770f5b368fe21dabef1ea826a280207176187 100644 (file)
@@ -1696,8 +1696,7 @@ static void dasd_eckd_handle_unsolicited_interrupt(struct dasd_device *device,
                DBF_DEV_EVENT(DBF_ERR, device, "%s",
                            "unsolicited interrupt received "
                            "(sense available)");
-               device->discipline->dump_sense_dbf(device, NULL, irb,
-                                                  "unsolicited");
+               device->discipline->dump_sense_dbf(device, irb, "unsolicited");
        }
 
        dasd_schedule_device_bh(device);
@@ -2941,42 +2940,20 @@ dasd_eckd_dump_ccw_range(struct ccw1 *from, struct ccw1 *to, char *page)
 }
 
 static void
-dasd_eckd_dump_sense_dbf(struct dasd_device *device, struct dasd_ccw_req *req,
-                        struct irb *irb, char *reason)
+dasd_eckd_dump_sense_dbf(struct dasd_device *device, struct irb *irb,
+                        char *reason)
 {
        u64 *sense;
-       int sl;
-       struct tsb *tsb;
 
-       sense = NULL;
-       tsb = NULL;
-       if (req && scsw_is_tm(&req->irb.scsw)) {
-               if (irb->scsw.tm.tcw)
-                       tsb = tcw_get_tsb(
-                               (struct tcw *)(unsigned long)irb->scsw.tm.tcw);
-               if (tsb && (irb->scsw.tm.fcxs == 0x01)) {
-                       switch (tsb->flags & 0x07) {
-                       case 1: /* tsa_iostat */
-                               sense = (u64 *)tsb->tsa.iostat.sense;
-                       break;
-                       case 2: /* ts_ddpc */
-                               sense = (u64 *)tsb->tsa.ddpc.sense;
-                       break;
-                       case 3: /* tsa_intrg */
-                       break;
-                       }
-               }
-       } else {
-               if (irb->esw.esw0.erw.cons)
-                       sense = (u64 *)irb->ecw;
-       }
+       sense = (u64 *) dasd_get_sense(irb);
        if (sense) {
-               for (sl = 0; sl < 4; sl++) {
-                       DBF_DEV_EVENT(DBF_EMERG, device,
-                                     "%s: %016llx %016llx %016llx %016llx",
-                                     reason, sense[0], sense[1], sense[2],
-                                     sense[3]);
-               }
+               DBF_DEV_EVENT(DBF_EMERG, device,
+                             "%s: %s %02x%02x%02x %016llx %016llx %016llx "
+                             "%016llx", reason,
+                             scsw_is_tm(&irb->scsw) ? "t" : "c",
+                             scsw_cc(&irb->scsw), scsw_cstat(&irb->scsw),
+                             scsw_dstat(&irb->scsw), sense[0], sense[1],
+                             sense[2], sense[3]);
        } else {
                DBF_DEV_EVENT(DBF_EMERG, device, "%s",
                              "SORRY - NO VALID SENSE AVAILABLE\n");
index d970ce2814bedf9af63b5a74e1eb8ff967641820..cb8f9cef742903bc25d6a2402e90d82506c2e446 100644 (file)
@@ -172,7 +172,7 @@ dasd_log_sense_dbf(struct dasd_ccw_req *cqr, struct irb *irb)
        device = cqr->startdev;
        /* dump sense data to s390 debugfeature*/
        if (device->discipline && device->discipline->dump_sense_dbf)
-               device->discipline->dump_sense_dbf(device, cqr, irb, "log");
+               device->discipline->dump_sense_dbf(device, irb, "log");
 }
 EXPORT_SYMBOL(dasd_log_sense_dbf);
 
index e21ee735f92673c4df91fb91a4c788f0b1d97b46..31849ad5e59fe6ddb84dbbb2ce2692165565b2a8 100644 (file)
@@ -241,7 +241,7 @@ static void dasd_fba_handle_unsolicited_interrupt(struct dasd_device *device,
        /* check for unsolicited interrupts */
        DBF_DEV_EVENT(DBF_WARNING, device, "%s",
                    "unsolicited interrupt received");
-       device->discipline->dump_sense_dbf(device, NULL, irb, "unsolicited");
+       device->discipline->dump_sense_dbf(device, irb, "unsolicited");
        dasd_schedule_device_bh(device);
        return;
 };
@@ -444,17 +444,20 @@ dasd_fba_fill_info(struct dasd_device * device,
 }
 
 static void
-dasd_fba_dump_sense_dbf(struct dasd_device *device, struct dasd_ccw_req *req,
-                        struct irb *irb, char *reason)
+dasd_fba_dump_sense_dbf(struct dasd_device *device, struct irb *irb,
+                       char *reason)
 {
-       int sl;
-       if (irb->esw.esw0.erw.cons) {
-               for (sl = 0; sl < 4; sl++) {
-                       DBF_DEV_EVENT(DBF_EMERG, device,
-                                     "%s: %08x %08x %08x %08x",
-                                     reason, irb->ecw[8 * 0], irb->ecw[8 * 1],
-                                     irb->ecw[8 * 2], irb->ecw[8 * 3]);
-               }
+       u64 *sense;
+
+       sense = (u64 *) dasd_get_sense(irb);
+       if (sense) {
+               DBF_DEV_EVENT(DBF_EMERG, device,
+                             "%s: %s %02x%02x%02x %016llx %016llx %016llx "
+                             "%016llx", reason,
+                             scsw_is_tm(&irb->scsw) ? "t" : "c",
+                             scsw_cc(&irb->scsw), scsw_cstat(&irb->scsw),
+                             scsw_dstat(&irb->scsw), sense[0], sense[1],
+                             sense[2], sense[3]);
        } else {
                DBF_DEV_EVENT(DBF_EMERG, device, "%s",
                              "SORRY - NO VALID SENSE AVAILABLE\n");
index fd63b2f2bda9baeaefb4e0edefb2bd2407c4c913..b699ca356ac55077d287591e31225eb0a6fdea58 100644 (file)
@@ -284,8 +284,7 @@ struct dasd_discipline {
        dasd_erp_fn_t(*erp_postaction) (struct dasd_ccw_req *);
        void (*dump_sense) (struct dasd_device *, struct dasd_ccw_req *,
                            struct irb *);
-       void (*dump_sense_dbf) (struct dasd_device *, struct dasd_ccw_req *,
-                           struct irb *, char *);
+       void (*dump_sense_dbf) (struct dasd_device *, struct irb *, char *);
 
        void (*handle_unsolicited_interrupt) (struct dasd_device *,
                                              struct irb *);
index 4ce3f72ee1c13e2485e9a781b389f0eda2fd1c08..df918ef27965ccb6513e32635af8bb41bba561e0 100644 (file)
@@ -16,6 +16,7 @@
 #include <linux/major.h>
 #include <linux/fs.h>
 #include <linux/blkpg.h>
+#include <linux/smp_lock.h>
 
 #include <asm/ccwdev.h>
 #include <asm/cmb.h>
index 016f9e9d259186e14351168b682b168fb25ab58b..d34617682a6295172a2c0d5d5fa47e258e4d2b23 100644 (file)
@@ -964,7 +964,8 @@ static int dcssblk_freeze(struct device *dev)
                        break;
        }
        if (rc)
-               pr_err("Suspend failed because device %s is writeable.\n",
+               pr_err("Suspending the system failed because DCSS device %s "
+                      "is writable\n",
                       dev_info->segment_name);
        return rc;
 }
@@ -987,8 +988,8 @@ static int dcssblk_restore(struct device *dev)
                                goto out_panic;
                        }
                        if (start != entry->start || end != entry->end) {
-                               pr_err("Mismatch of start / end address after "
-                                      "resuming device %s\n",
+                               pr_err("The address range of DCSS %s changed "
+                                      "while the system was suspended\n",
                                       entry->segment_name);
                                goto out_panic;
                        }
index 2e9e1ecd6d82b2d1f03181d4237d04ff37dedab6..db442cd6621ec9d838325c15c2f47cbb102992a1 100644 (file)
@@ -443,7 +443,7 @@ fail:
  */
 static void xpram_resume_error(const char *message)
 {
-       pr_err("Resume error: %s\n", message);
+       pr_err("Resuming the system failed: %s\n", message);
        panic("xpram resume error\n");
 }
 
index 7892550d793280298175061811a59f2bb07b9256..3234e90bd7f99b6bc632c9844e53e4e479f0aae2 100644 (file)
@@ -320,7 +320,7 @@ static int mon_open(struct inode *inode, struct file *filp)
                goto out_path;
        }
        filp->private_data = monpriv;
-       dev_set_drvdata(&monreader_device, monpriv);
+       dev_set_drvdata(monreader_device, monpriv);
        unlock_kernel();
        return nonseekable_open(inode, filp);
 
@@ -463,7 +463,7 @@ static struct miscdevice mon_dev = {
  *****************************************************************************/
 static int monreader_freeze(struct device *dev)
 {
-       struct mon_private *monpriv = dev_get_drvdata(&dev);
+       struct mon_private *monpriv = dev_get_drvdata(dev);
        int rc;
 
        if (!monpriv)
index 85f491ea929c0da0df28ee54676949354f51b7b0..7a7bfc947d97eb3b502ccb39ee4fd21f751bdb5e 100644 (file)
@@ -92,5 +92,10 @@ void sclp_set_columns(struct sclp_buffer *, unsigned short);
 void sclp_set_htab(struct sclp_buffer *, unsigned short);
 int sclp_chars_in_buffer(struct sclp_buffer *);
 
+#ifdef CONFIG_SCLP_CONSOLE
 void sclp_console_pm_event(enum sclp_pm_event sclp_pm_event);
+#else
+static inline void sclp_console_pm_event(enum sclp_pm_event sclp_pm_event) { }
+#endif
+
 #endif /* __SCLP_RW_H__ */
index cb7854c10c0479585d1879f9c0a3fe8a90a713a1..f2bc287b69e4e4c1c5c35f01ddb500d2ca63aed9 100644 (file)
@@ -250,14 +250,14 @@ static int vmwdt_resume(void)
 static int vmwdt_suspend(void)
 {
        if (test_and_set_bit(VMWDT_OPEN, &vmwdt_is_open)) {
-               pr_err("The watchdog is in use. "
-                       "This prevents hibernation or suspend.\n");
+               pr_err("The system cannot be suspended while the watchdog"
+                       " is in use\n");
                return NOTIFY_BAD;
        }
        if (test_bit(VMWDT_RUNNING, &vmwdt_is_open)) {
                clear_bit(VMWDT_OPEN, &vmwdt_is_open);
-               pr_err("The watchdog is running. "
-                       "This prevents hibernation or suspend.\n");
+               pr_err("The system cannot be suspended while the watchdog"
+                       " is running\n");
                return NOTIFY_BAD;
        }
        return NOTIFY_DONE;
index 0471f88004836df15f2da6b3bba4ead0489e4439..4240b05aef6d191f8c7f5782ac2c51b07a403de3 100644 (file)
@@ -2826,8 +2826,7 @@ int NCR5380_abort(Scsi_Cmnd *cmd)
         */
 
        local_irq_restore(flags);
-       printk(KERN_INFO "scsi%d: warning : SCSI command probably completed successfully\n"
-              KERN_INFO "        before abortion\n", HOSTNO);
+       printk(KERN_INFO "scsi%d: warning : SCSI command probably completed successfully before abortion\n", HOSTNO);
 
        /* Maybe it is sufficient just to release the ST-DMA lock... (if
         * possible at all) At least, we should check if the lock could be
index 25a2032bfa2615c466de3dc9bcc1f2fbd56e0ec6..70d060b7ff4f6e36ed4d090a030baf7c7da1ece9 100644 (file)
@@ -1,4 +1,4 @@
-EXTRA_CFLAGS += -I$(TOPDIR)/drivers/net/cxgb3
+EXTRA_CFLAGS += -I$(srctree)/drivers/net/cxgb3
 
 cxgb3i-y := cxgb3i_init.o cxgb3i_iscsi.o cxgb3i_pdu.o cxgb3i_offload.o cxgb3i_ddp.o
 obj-$(CONFIG_SCSI_CXGB3_ISCSI) += cxgb3i.o
index 74369a3f963b66bdbdbaa0b71bdd6f848a074048..c399f485aa7d1228c415c703c85ceddafcbdc0cf 100644 (file)
@@ -13,6 +13,7 @@
 
 #include <linux/inet.h>
 #include <linux/crypto.h>
+#include <linux/if_vlan.h>
 #include <net/dst.h>
 #include <net/tcp.h>
 #include <scsi/scsi_cmnd.h>
@@ -184,6 +185,9 @@ static struct cxgb3i_hba *cxgb3i_hba_find_by_netdev(struct net_device *ndev)
        struct cxgb3i_adapter *snic;
        int i;
 
+       if (ndev->priv_flags & IFF_802_1Q_VLAN)
+               ndev = vlan_dev_real_dev(ndev);
+
        read_lock(&cxgb3i_snic_rwlock);
        list_for_each_entry(snic, &cxgb3i_snic_list, list_head) {
                for (i = 0; i < snic->hba_cnt; i++) {
index a84072865fc2615a7a9fcce47c48b94fe05f4592..2c266c01dc5ad2848abc5df36bd3b05b1afa5f5f 100644 (file)
@@ -473,16 +473,16 @@ static int __devinit fnic_probe(struct pci_dev *pdev,
         * limitation for the device.  Try 40-bit first, and
         * fail to 32-bit.
         */
-       err = pci_set_dma_mask(pdev, DMA_40BIT_MASK);
+       err = pci_set_dma_mask(pdev, DMA_BIT_MASK(40));
        if (err) {
-               err = pci_set_dma_mask(pdev, DMA_32BIT_MASK);
+               err = pci_set_dma_mask(pdev, DMA_BIT_MASK(32));
                if (err) {
                        shost_printk(KERN_ERR, fnic->lport->host,
                                     "No usable DMA configuration "
                                     "aborting\n");
                        goto err_out_release_regions;
                }
-               err = pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK);
+               err = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32));
                if (err) {
                        shost_printk(KERN_ERR, fnic->lport->host,
                                     "Unable to obtain 32-bit DMA "
@@ -490,7 +490,7 @@ static int __devinit fnic_probe(struct pci_dev *pdev,
                        goto err_out_release_regions;
                }
        } else {
-               err = pci_set_consistent_dma_mask(pdev, DMA_40BIT_MASK);
+               err = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(40));
                if (err) {
                        shost_printk(KERN_ERR, fnic->lport->host,
                                     "Unable to obtain 40-bit DMA "
index eabf365028568437be0fbd3acbe81abf9dc932c6..bfc996971b814009ac996b295414eacc668c5fe9 100644 (file)
@@ -245,7 +245,7 @@ static inline int fnic_queue_wq_copy_desc(struct fnic *fnic,
                                          struct vnic_wq_copy *wq,
                                          struct fnic_io_req *io_req,
                                          struct scsi_cmnd *sc,
-                                         u32 sg_count)
+                                         int sg_count)
 {
        struct scatterlist *sg;
        struct fc_rport *rport = starget_to_rport(scsi_target(sc->device));
@@ -260,9 +260,6 @@ static inline int fnic_queue_wq_copy_desc(struct fnic *fnic,
        char msg[2];
 
        if (sg_count) {
-               BUG_ON(sg_count < 0);
-               BUG_ON(sg_count > FNIC_MAX_SG_DESC_CNT);
-
                /* For each SGE, create a device desc entry */
                desc = io_req->sgl_list;
                for_each_sg(scsi_sglist(sc), sg, sg_count, i) {
@@ -344,7 +341,7 @@ int fnic_queuecommand(struct scsi_cmnd *sc, void (*done)(struct scsi_cmnd *))
        struct fnic *fnic;
        struct vnic_wq_copy *wq;
        int ret;
-       u32 sg_count;
+       int sg_count;
        unsigned long flags;
        unsigned long ptr;
 
index 869a11bdccbdf3cf63773b2bebc1ff1358d623a8..9928704e235f4f1d5d35c48fd877781297f78a50 100644 (file)
@@ -1095,9 +1095,14 @@ static void adapter_info_rsp(struct srp_event_struct *evt_struct)
                                MAX_INDIRECT_BUFS);
                        hostdata->host->sg_tablesize = MAX_INDIRECT_BUFS;
                }
+
+               if (hostdata->madapter_info.os_type == 3) {
+                       enable_fast_fail(hostdata);
+                       return;
+               }
        }
 
-       enable_fast_fail(hostdata);
+       send_srp_login(hostdata);
 }
 
 /**
index b12ad7c7c6736908419987896a2402898ba2620e..18735b39b3d39c8547e27b8037fbef033a0df76a 100644 (file)
@@ -75,8 +75,9 @@ static int mac53c94_queue(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *
                int i;
                printk(KERN_DEBUG "mac53c94_queue %p: command is", cmd);
                for (i = 0; i < cmd->cmd_len; ++i)
-                       printk(" %.2x", cmd->cmnd[i]);
-               printk("\n" KERN_DEBUG "use_sg=%d request_bufflen=%d request_buffer=%p\n",
+                       printk(KERN_CONT " %.2x", cmd->cmnd[i]);
+               printk(KERN_CONT "\n");
+               printk(KERN_DEBUG "use_sg=%d request_bufflen=%d request_buffer=%p\n",
                       scsi_sg_count(cmd), scsi_bufflen(cmd), scsi_sglist(cmd));
        }
 #endif
index 650bcef08f2a4d080f5e325a7fd82766179aeb7b..cd78c501803a733759f768e049860f6acdd68f21 100644 (file)
@@ -9,7 +9,6 @@
 
 #include <linux/moduleparam.h>
 #include <linux/vmalloc.h>
-#include <linux/smp_lock.h>
 #include <linux/list.h>
 
 #include <scsi/scsi_tcq.h>
index 2eee9e6e4fe8f975eb580329cd4814244b482a0b..292c02f810d04a4bc7d66f27a77209a302fe5e14 100644 (file)
@@ -3670,13 +3670,14 @@ static void
 fc_bsg_goose_queue(struct fc_rport *rport)
 {
        int flagset;
+       unsigned long flags;
 
        if (!rport->rqst_q)
                return;
 
        get_device(&rport->dev);
 
-       spin_lock(rport->rqst_q->queue_lock);
+       spin_lock_irqsave(rport->rqst_q->queue_lock, flags);
        flagset = test_bit(QUEUE_FLAG_REENTER, &rport->rqst_q->queue_flags) &&
                  !test_bit(QUEUE_FLAG_REENTER, &rport->rqst_q->queue_flags);
        if (flagset)
@@ -3684,7 +3685,7 @@ fc_bsg_goose_queue(struct fc_rport *rport)
        __blk_run_queue(rport->rqst_q);
        if (flagset)
                queue_flag_clear(QUEUE_FLAG_REENTER, rport->rqst_q);
-       spin_unlock(rport->rqst_q->queue_lock);
+       spin_unlock_irqrestore(rport->rqst_q->queue_lock, flags);
 
        put_device(&rport->dev);
 }
index 8201387b4daa29c374cc850107f8b3d6d21ae0dd..9230402c45afcbe0c1a06188b83c99a3f39a104b 100644 (file)
@@ -210,13 +210,11 @@ static void sg_put_dev(Sg_device *sdp);
 static int sg_allow_access(struct file *filp, unsigned char *cmd)
 {
        struct sg_fd *sfp = (struct sg_fd *)filp->private_data;
-       struct request_queue *q = sfp->parentdp->device->request_queue;
 
        if (sfp->parentdp->device->type == TYPE_SCANNER)
                return 0;
 
-       return blk_verify_command(&q->cmd_filter,
-                                 cmd, filp->f_mode & FMODE_WRITE);
+       return blk_verify_command(cmd, filp->f_mode & FMODE_WRITE);
 }
 
 static int
@@ -621,7 +619,7 @@ sg_write(struct file *filp, const char __user *buf, size_t count, loff_t * ppos)
                if (strcmp(current->comm, cmd) && printk_ratelimit()) {
                        printk(KERN_WARNING
                               "sg_write: data in/out %d/%d bytes for SCSI command 0x%x--"
-                              "guessing data in;\n" KERN_WARNING "   "
+                              "guessing data in;\n   "
                               "program %s not setting count and/or reply_len properly\n",
                               old_hdr.reply_len - (int)SZ_SG_HEADER,
                               input_size, (unsigned int) cmnd[0],
@@ -1658,6 +1656,10 @@ static int sg_start_req(Sg_request *srp, unsigned char *cmd)
                md->nr_entries = req_schp->k_use_sg;
                md->offset = 0;
                md->null_mapped = hp->dxferp ? 0 : 1;
+               if (dxfer_dir == SG_DXFER_TO_FROM_DEV)
+                       md->from_user = 1;
+               else
+                       md->from_user = 0;
        }
 
        if (iov_count) {
index bcaba86060abe0787936bff42143776ec81a712e..75da6e58ce550ecd03031cb05ee4d8a8b9290ba1 100644 (file)
@@ -2860,8 +2860,7 @@ static int NCR5380_abort(struct scsi_cmnd *cmd)
  */
 
     local_irq_restore(flags);
-    printk(KERN_INFO "scsi%d: warning : SCSI command probably completed successfully\n"
-           KERN_INFO "        before abortion\n", HOSTNO); 
+    printk(KERN_INFO "scsi%d: warning : SCSI command probably completed successfully before abortion\n", HOSTNO); 
 
     return SCSI_ABORT_NOT_RUNNING;
 }
index 97f3158fa7b546700ab670f3373598c5895cb546..27e84e4b1fa98857d571f3abafdfe9f4b03cf7ad 100644 (file)
@@ -134,7 +134,7 @@ zalon_probe(struct parisc_device *dev)
 
        host = ncr_attach(&zalon7xx_template, unit, &device);
        if (!host)
-               goto fail;
+               return -ENODEV;
 
        if (request_irq(dev->irq, ncr53c8xx_intr, IRQF_SHARED, "zalon", host)) {
          dev_printk(KERN_ERR, &dev->dev, "irq problem with %d, detaching\n ",
index e371a9c15341e2598825affdbd2ef1d727dfbde7..e7108e75653da8a75326d420133b1e471a68c655 100644 (file)
@@ -60,11 +60,12 @@ struct serial_private {
 
 static void moan_device(const char *str, struct pci_dev *dev)
 {
-       printk(KERN_WARNING "%s: %s\n"
-              KERN_WARNING "Please send the output of lspci -vv, this\n"
-              KERN_WARNING "message (0x%04x,0x%04x,0x%04x,0x%04x), the\n"
-              KERN_WARNING "manufacturer and name of serial board or\n"
-              KERN_WARNING "modem board to rmk+serial@arm.linux.org.uk.\n",
+       printk(KERN_WARNING
+              "%s: %s\n"
+              "Please send the output of lspci -vv, this\n"
+              "message (0x%04x,0x%04x,0x%04x,0x%04x), the\n"
+              "manufacturer and name of serial board or\n"
+              "modem board to rmk+serial@arm.linux.org.uk.\n",
               pci_name(dev), str, dev->vendor, dev->device,
               dev->subsystem_vendor, dev->subsystem_device);
 }
@@ -398,8 +399,7 @@ static int sbs_init(struct pci_dev *dev)
 {
        u8 __iomem *p;
 
-       p = ioremap_nocache(pci_resource_start(dev, 0),
-                                               pci_resource_len(dev, 0));
+       p = pci_ioremap_bar(dev, 0);
 
        if (p == NULL)
                return -ENOMEM;
@@ -423,8 +423,7 @@ static void __devexit sbs_exit(struct pci_dev *dev)
 {
        u8 __iomem *p;
 
-       p = ioremap_nocache(pci_resource_start(dev, 0),
-                                       pci_resource_len(dev, 0));
+       p = pci_ioremap_bar(dev, 0);
        /* FIXME: What if resource_len < OCT_REG_CR_OFF */
        if (p != NULL)
                writeb(0, p + OCT_REG_CR_OFF);
@@ -761,6 +760,8 @@ static int pci_netmos_init(struct pci_dev *dev)
        /* subdevice 0x00PS means <P> parallel, <S> serial */
        unsigned int num_serial = dev->subsystem_device & 0xf;
 
+       if (dev->device == PCI_DEVICE_ID_NETMOS_9901)
+               return 0;
        if (dev->subsystem_vendor == PCI_VENDOR_ID_IBM &&
                        dev->subsystem_device == 0x0299)
                return 0;
@@ -3559,6 +3560,10 @@ static struct pci_device_id serial_pci_tbl[] = {
                PCI_VENDOR_ID_IBM, 0x0299,
                0, 0, pbn_b0_bt_2_115200 },
 
+       {       PCI_VENDOR_ID_NETMOS, PCI_DEVICE_ID_NETMOS_9901,
+               0xA000, 0x1000,
+               0, 0, pbn_b0_1_115200 },
+
        /*
         * These entries match devices with class COMMUNICATION_SERIAL,
         * COMMUNICATION_MODEM or COMMUNICATION_MULTISERIAL
index 34b4ae0fe76041f4eda4132e1a81a54784652557..c108b1a0ce988de4fd91d905d7b26fc205c00e7d 100644 (file)
@@ -236,7 +236,6 @@ static int sport_startup(struct uart_port *port)
        int retval;
 
        pr_debug("%s enter\n", __func__);
-       memset(buffer, 20, '\0');
        snprintf(buffer, 20, "%s rx", up->name);
        retval = request_irq(up->rx_irq, sport_uart_rx_irq, IRQF_SAMPLE_RANDOM, buffer, up);
        if (retval) {
index 9f2891c2c4a21f93e4cc6289e4b95c286a655455..cd1b6a45bb8241b3cbdadc0f03021dc634adace4 100644 (file)
@@ -1548,8 +1548,7 @@ static int __devinit icom_probe(struct pci_dev *dev,
                goto probe_exit1;
        }
 
-        icom_adapter->base_addr = ioremap(icom_adapter->base_addr_pci,
-                                               pci_resource_len(dev, 0));
+        icom_adapter->base_addr = pci_ioremap_bar(dev, 0);
 
        if (!icom_adapter->base_addr)
                goto probe_exit1;
index 107ce2e187b8fc1c1773530a74b0779fdce283de..00f4577d2f7fc514a523f2ec534d09b73bac7d72 100644 (file)
@@ -467,7 +467,7 @@ int __devinit jsm_uart_port_init(struct jsm_board *brd)
                        printk(KERN_INFO "jsm: linemap is full, added device failed\n");
                        continue;
                } else
-                       set_bit((int)line, linemap);
+                       set_bit(line, linemap);
                brd->channels[i]->uart_port.line = line;
                if (uart_add_one_port (&jsm_uart_driver, &brd->channels[i]->uart_port))
                        printk(KERN_INFO "jsm: add device failed\n");
@@ -503,7 +503,7 @@ int jsm_remove_uart_port(struct jsm_board *brd)
 
                ch = brd->channels[i];
 
-               clear_bit((int)(ch->uart_port.line), linemap);
+               clear_bit(ch->uart_port.line, linemap);
                uart_remove_one_port(&jsm_uart_driver, &brd->channels[i]->uart_port);
        }
 
index 698048f64f5e9aa0ef49d51578460978815b1dc6..f7c24baa141673a03084e3951b80d345c205d3c6 100644 (file)
@@ -730,7 +730,6 @@ static int __devexit msm_serial_remove(struct platform_device *pdev)
 }
 
 static struct platform_driver msm_platform_driver = {
-       .probe = msm_serial_probe,
        .remove = msm_serial_remove,
        .driver = {
                .name = "msm_serial",
index 7313c2edcb831b873d89156bb6200179dd642fb8..54dd16d66a4bc7e2a1152c87828c7eab0b14ba3b 100644 (file)
@@ -461,6 +461,94 @@ static void serial_txx9_break_ctl(struct uart_port *port, int break_state)
        spin_unlock_irqrestore(&up->port.lock, flags);
 }
 
+#if defined(CONFIG_SERIAL_TXX9_CONSOLE) || (CONFIG_CONSOLE_POLL)
+/*
+ *     Wait for transmitter & holding register to empty
+ */
+static void wait_for_xmitr(struct uart_txx9_port *up)
+{
+       unsigned int tmout = 10000;
+
+       /* Wait up to 10ms for the character(s) to be sent. */
+       while (--tmout &&
+              !(sio_in(up, TXX9_SICISR) & TXX9_SICISR_TXALS))
+               udelay(1);
+
+       /* Wait up to 1s for flow control if necessary */
+       if (up->port.flags & UPF_CONS_FLOW) {
+               tmout = 1000000;
+               while (--tmout &&
+                      (sio_in(up, TXX9_SICISR) & TXX9_SICISR_CTSS))
+                       udelay(1);
+       }
+}
+#endif
+
+#ifdef CONFIG_CONSOLE_POLL
+/*
+ * Console polling routines for writing and reading from the uart while
+ * in an interrupt or debug context.
+ */
+
+static int serial_txx9_get_poll_char(struct uart_port *port)
+{
+       unsigned int ier;
+       unsigned char c;
+       struct uart_txx9_port *up = (struct uart_txx9_port *)port;
+
+       /*
+        *      First save the IER then disable the interrupts
+        */
+       ier = sio_in(up, TXX9_SIDICR);
+       sio_out(up, TXX9_SIDICR, 0);
+
+       while (sio_in(up, TXX9_SIDISR) & TXX9_SIDISR_UVALID)
+               ;
+
+       c = sio_in(up, TXX9_SIRFIFO);
+
+       /*
+        *      Finally, clear RX interrupt status
+        *      and restore the IER
+        */
+       sio_mask(up, TXX9_SIDISR, TXX9_SIDISR_RDIS);
+       sio_out(up, TXX9_SIDICR, ier);
+       return c;
+}
+
+
+static void serial_txx9_put_poll_char(struct uart_port *port, unsigned char c)
+{
+       unsigned int ier;
+       struct uart_txx9_port *up = (struct uart_txx9_port *)port;
+
+       /*
+        *      First save the IER then disable the interrupts
+        */
+       ier = sio_in(up, TXX9_SIDICR);
+       sio_out(up, TXX9_SIDICR, 0);
+
+       wait_for_xmitr(up);
+       /*
+        *      Send the character out.
+        *      If a LF, also do CR...
+        */
+       sio_out(up, TXX9_SITFIFO, c);
+       if (c == 10) {
+               wait_for_xmitr(up);
+               sio_out(up, TXX9_SITFIFO, 13);
+       }
+
+       /*
+        *      Finally, wait for transmitter to become empty
+        *      and restore the IER
+        */
+       wait_for_xmitr(up);
+       sio_out(up, TXX9_SIDICR, ier);
+}
+
+#endif /* CONFIG_CONSOLE_POLL */
+
 static int serial_txx9_startup(struct uart_port *port)
 {
        struct uart_txx9_port *up = (struct uart_txx9_port *)port;
@@ -781,6 +869,10 @@ static struct uart_ops serial_txx9_pops = {
        .release_port   = serial_txx9_release_port,
        .request_port   = serial_txx9_request_port,
        .config_port    = serial_txx9_config_port,
+#ifdef CONFIG_CONSOLE_POLL
+       .poll_get_char  = serial_txx9_get_poll_char,
+       .poll_put_char  = serial_txx9_put_poll_char,
+#endif
 };
 
 static struct uart_txx9_port serial_txx9_ports[UART_NR];
@@ -803,27 +895,6 @@ static void __init serial_txx9_register_ports(struct uart_driver *drv,
 
 #ifdef CONFIG_SERIAL_TXX9_CONSOLE
 
-/*
- *     Wait for transmitter & holding register to empty
- */
-static inline void wait_for_xmitr(struct uart_txx9_port *up)
-{
-       unsigned int tmout = 10000;
-
-       /* Wait up to 10ms for the character(s) to be sent. */
-       while (--tmout &&
-              !(sio_in(up, TXX9_SICISR) & TXX9_SICISR_TXALS))
-               udelay(1);
-
-       /* Wait up to 1s for flow control if necessary */
-       if (up->port.flags & UPF_CONS_FLOW) {
-               tmout = 1000000;
-               while (--tmout &&
-                      (sio_in(up, TXX9_SICISR) & TXX9_SICISR_CTSS))
-                       udelay(1);
-       }
-}
-
 static void serial_txx9_console_putchar(struct uart_port *port, int ch)
 {
        struct uart_txx9_port *up = (struct uart_txx9_port *)port;
index 66f52674ca0cb6872cfd580571b29d485dd59a44..8e2feb563347151d220ed23155074dc5e0f0c761 100644 (file)
@@ -707,24 +707,25 @@ static irqreturn_t sci_br_interrupt(int irq, void *ptr)
 
 static irqreturn_t sci_mpxed_interrupt(int irq, void *ptr)
 {
-       unsigned short ssr_status, scr_status;
+       unsigned short ssr_status, scr_status, err_enabled;
        struct uart_port *port = ptr;
        irqreturn_t ret = IRQ_NONE;
 
        ssr_status = sci_in(port, SCxSR);
        scr_status = sci_in(port, SCSCR);
+       err_enabled = scr_status & (SCI_CTRL_FLAGS_REIE | SCI_CTRL_FLAGS_RIE);
 
        /* Tx Interrupt */
-       if ((ssr_status & 0x0020) && (scr_status & SCI_CTRL_FLAGS_TIE))
+       if ((ssr_status & SCxSR_TDxE(port)) && (scr_status & SCI_CTRL_FLAGS_TIE))
                ret = sci_tx_interrupt(irq, ptr);
        /* Rx Interrupt */
-       if ((ssr_status & 0x0002) && (scr_status & SCI_CTRL_FLAGS_RIE))
+       if ((ssr_status & SCxSR_RDxF(port)) && (scr_status & SCI_CTRL_FLAGS_RIE))
                ret = sci_rx_interrupt(irq, ptr);
        /* Error Interrupt */
-       if ((ssr_status & 0x0080) && (scr_status & SCI_CTRL_FLAGS_REIE))
+       if ((ssr_status & SCxSR_ERRORS(port)) && err_enabled)
                ret = sci_er_interrupt(irq, ptr);
        /* Break Interrupt */
-       if ((ssr_status & 0x0010) && (scr_status & SCI_CTRL_FLAGS_REIE))
+       if ((ssr_status & SCxSR_BRK(port)) && err_enabled)
                ret = sci_br_interrupt(irq, ptr);
 
        return ret;
index 0573f3b5175e463f1675e4d4bdd5b0dceb17c47c..dac550e57c29c192e60ec351f191adad98e2f4da 100644 (file)
@@ -1,7 +1,7 @@
 /*
  *  Driver for NEC VR4100 series Serial Interface Unit.
  *
- *  Copyright (C) 2004-2008  Yoichi Yuasa <yoichi_yuasa@tripeaks.co.jp>
+ *  Copyright (C) 2004-2008  Yoichi Yuasa <yuasa@linux-mips.org>
  *
  *  Based on drivers/serial/8250.c, by Russell King.
  *
index aa90ddb370662b7d13b787febb0fa8f569b3bad0..8980a5640bd9d16021367720b77690d783dfac3b 100644 (file)
@@ -514,6 +514,8 @@ static int __init uwire_probe(struct platform_device *pdev)
        /* the spi->mode bits understood by this driver: */
        master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH;
 
+       master->flags = SPI_MASTER_HALF_DUPLEX;
+
        master->bus_num = 2;    /* "official" */
        master->num_chipselect = 4;
        master->setup = uwire_setup;
index 2a5abc08e8571d49143aa9287785aed1201156aa..f1db395dd88981ca4bf7f2e8777c8e9f2c6cceee 100644 (file)
@@ -258,6 +258,11 @@ static void bitbang_work(struct work_struct *work)
        struct spi_bitbang      *bitbang =
                container_of(work, struct spi_bitbang, work);
        unsigned long           flags;
+       int                     do_setup = -1;
+       int                     (*setup_transfer)(struct spi_device *,
+                                       struct spi_transfer *);
+
+       setup_transfer = bitbang->setup_transfer;
 
        spin_lock_irqsave(&bitbang->lock, flags);
        bitbang->busy = 1;
@@ -269,8 +274,6 @@ static void bitbang_work(struct work_struct *work)
                unsigned                tmp;
                unsigned                cs_change;
                int                     status;
-               int                     (*setup_transfer)(struct spi_device *,
-                                               struct spi_transfer *);
 
                m = container_of(bitbang->queue.next, struct spi_message,
                                queue);
@@ -287,19 +290,19 @@ static void bitbang_work(struct work_struct *work)
                tmp = 0;
                cs_change = 1;
                status = 0;
-               setup_transfer = NULL;
 
                list_for_each_entry (t, &m->transfers, transfer_list) {
 
-                       /* override or restore speed and wordsize */
-                       if (t->speed_hz || t->bits_per_word) {
-                               setup_transfer = bitbang->setup_transfer;
+                       /* override speed or wordsize? */
+                       if (t->speed_hz || t->bits_per_word)
+                               do_setup = 1;
+
+                       /* init (-1) or override (1) transfer params */
+                       if (do_setup != 0) {
                                if (!setup_transfer) {
                                        status = -ENOPROTOOPT;
                                        break;
                                }
-                       }
-                       if (setup_transfer) {
                                status = setup_transfer(spi, t);
                                if (status < 0)
                                        break;
@@ -363,9 +366,10 @@ static void bitbang_work(struct work_struct *work)
                m->status = status;
                m->complete(m->context);
 
-               /* restore speed and wordsize */
-               if (setup_transfer)
+               /* restore speed and wordsize if it was overridden */
+               if (do_setup == 1)
                        setup_transfer(spi, NULL);
+               do_setup = 0;
 
                /* normally deactivate chipselect ... unless no error and
                 * cs_change has hinted that the next message will probably
index 5d869c4d3eb2a2e3dd9f46ae3ebf1cfbd333e61f..606e7a40a8da85d415b7d69efe65664528b681bd 100644 (file)
@@ -58,15 +58,20 @@ static unsigned long        minors[N_SPI_MINORS / BITS_PER_LONG];
 
 
 /* Bit masks for spi_device.mode management.  Note that incorrect
- * settings for CS_HIGH and 3WIRE can cause *lots* of trouble for other
- * devices on a shared bus:  CS_HIGH, because this device will be
- * active when it shouldn't be;  3WIRE, because when active it won't
- * behave as it should.
+ * settings for some settings can cause *lots* of trouble for other
+ * devices on a shared bus:
  *
- * REVISIT should changing those two modes be privileged?
+ *  - CS_HIGH ... this device will be active when it shouldn't be
+ *  - 3WIRE ... when active, it won't behave as it should
+ *  - NO_CS ... there will be no explicit message boundaries; this
+ *     is completely incompatible with the shared bus model
+ *  - READY ... transfers may proceed when they shouldn't.
+ *
+ * REVISIT should changing those flags be privileged?
  */
 #define SPI_MODE_MASK          (SPI_CPHA | SPI_CPOL | SPI_CS_HIGH \
-                               | SPI_LSB_FIRST | SPI_3WIRE | SPI_LOOP)
+                               | SPI_LSB_FIRST | SPI_3WIRE | SPI_LOOP \
+                               | SPI_NO_CS | SPI_READY)
 
 struct spidev_data {
        dev_t                   devt;
index 3fd3e3b412b6598d0c32a70bc691ced97769a596..3c6feed46f6ea48b12d3083e1d95f1c33921029e 100644 (file)
@@ -49,29 +49,54 @@ static const u32 ipsflag_irq_shift[] = {
 
 static inline u32 ssb_irqflag(struct ssb_device *dev)
 {
-       return ssb_read32(dev, SSB_TPSFLAG) & SSB_TPSFLAG_BPFLAG;
+       u32 tpsflag = ssb_read32(dev, SSB_TPSFLAG);
+       if (tpsflag)
+               return ssb_read32(dev, SSB_TPSFLAG) & SSB_TPSFLAG_BPFLAG;
+       else
+               /* not irq supported */
+               return 0x3f;
+}
+
+static struct ssb_device *find_device(struct ssb_device *rdev, int irqflag)
+{
+       struct ssb_bus *bus = rdev->bus;
+       int i;
+       for (i = 0; i < bus->nr_devices; i++) {
+               struct ssb_device *dev;
+               dev = &(bus->devices[i]);
+               if (ssb_irqflag(dev) == irqflag)
+                       return dev;
+       }
+       return NULL;
 }
 
 /* Get the MIPS IRQ assignment for a specified device.
  * If unassigned, 0 is returned.
+ * If disabled, 5 is returned.
+ * If not supported, 6 is returned.
  */
 unsigned int ssb_mips_irq(struct ssb_device *dev)
 {
        struct ssb_bus *bus = dev->bus;
+       struct ssb_device *mdev = bus->mipscore.dev;
        u32 irqflag;
        u32 ipsflag;
        u32 tmp;
        unsigned int irq;
 
        irqflag = ssb_irqflag(dev);
+       if (irqflag == 0x3f)
+               return 6;
        ipsflag = ssb_read32(bus->mipscore.dev, SSB_IPSFLAG);
        for (irq = 1; irq <= 4; irq++) {
                tmp = ((ipsflag & ipsflag_irq_mask[irq]) >> ipsflag_irq_shift[irq]);
                if (tmp == irqflag)
                        break;
        }
-       if (irq == 5)
-               irq = 0;
+       if (irq == 5) {
+               if ((1 << irqflag) & ssb_read32(mdev, SSB_INTVEC))
+                       irq = 0;
+       }
 
        return irq;
 }
@@ -97,25 +122,56 @@ static void set_irq(struct ssb_device *dev, unsigned int irq)
        struct ssb_device *mdev = bus->mipscore.dev;
        u32 irqflag = ssb_irqflag(dev);
 
+       BUG_ON(oldirq == 6);
+
        dev->irq = irq + 2;
 
-       ssb_dprintk(KERN_INFO PFX
-                   "set_irq: core 0x%04x, irq %d => %d\n",
-                   dev->id.coreid, oldirq, irq);
        /* clear the old irq */
        if (oldirq == 0)
                ssb_write32(mdev, SSB_INTVEC, (~(1 << irqflag) & ssb_read32(mdev, SSB_INTVEC)));
-       else
+       else if (oldirq != 5)
                clear_irq(bus, oldirq);
 
        /* assign the new one */
        if (irq == 0) {
                ssb_write32(mdev, SSB_INTVEC, ((1 << irqflag) | ssb_read32(mdev, SSB_INTVEC)));
        } else {
+               u32 ipsflag = ssb_read32(mdev, SSB_IPSFLAG);
+               if ((ipsflag & ipsflag_irq_mask[irq]) != ipsflag_irq_mask[irq]) {
+                       u32 oldipsflag = (ipsflag & ipsflag_irq_mask[irq]) >> ipsflag_irq_shift[irq];
+                       struct ssb_device *olddev = find_device(dev, oldipsflag);
+                       if (olddev)
+                               set_irq(olddev, 0);
+               }
                irqflag <<= ipsflag_irq_shift[irq];
-               irqflag |= (ssb_read32(mdev, SSB_IPSFLAG) & ~ipsflag_irq_mask[irq]);
+               irqflag |= (ipsflag & ~ipsflag_irq_mask[irq]);
                ssb_write32(mdev, SSB_IPSFLAG, irqflag);
        }
+       ssb_dprintk(KERN_INFO PFX
+                   "set_irq: core 0x%04x, irq %d => %d\n",
+                   dev->id.coreid, oldirq+2, irq+2);
+}
+
+static void print_irq(struct ssb_device *dev, unsigned int irq)
+{
+       int i;
+       static const char *irq_name[] = {"2(S)", "3", "4", "5", "6", "D", "I"};
+       ssb_dprintk(KERN_INFO PFX
+               "core 0x%04x, irq :", dev->id.coreid);
+       for (i = 0; i <= 6; i++) {
+               ssb_dprintk(" %s%s", irq_name[i], i==irq?"*":" ");
+       }
+       ssb_dprintk("\n");
+}
+
+static void dump_irq(struct ssb_bus *bus)
+{
+       int i;
+       for (i = 0; i < bus->nr_devices; i++) {
+               struct ssb_device *dev;
+               dev = &(bus->devices[i]);
+               print_irq(dev, ssb_mips_irq(dev));
+       }
 }
 
 static void ssb_mips_serial_init(struct ssb_mipscore *mcore)
@@ -197,16 +253,23 @@ void ssb_mipscore_init(struct ssb_mipscore *mcore)
 
        /* Assign IRQs to all cores on the bus, start with irq line 2, because serial usually takes 1 */
        for (irq = 2, i = 0; i < bus->nr_devices; i++) {
+               int mips_irq;
                dev = &(bus->devices[i]);
-               dev->irq = ssb_mips_irq(dev) + 2;
+               mips_irq = ssb_mips_irq(dev);
+               if (mips_irq > 4)
+                       dev->irq = 0;
+               else
+                       dev->irq = mips_irq + 2;
+               if (dev->irq > 5)
+                       continue;
                switch (dev->id.coreid) {
                case SSB_DEV_USB11_HOST:
                        /* shouldn't need a separate irq line for non-4710, most of them have a proper
                         * external usb controller on the pci */
                        if ((bus->chip_id == 0x4710) && (irq <= 4)) {
                                set_irq(dev, irq++);
-                               break;
                        }
+                       break;
                        /* fallthrough */
                case SSB_DEV_PCI:
                case SSB_DEV_ETHERNET:
@@ -220,6 +283,8 @@ void ssb_mipscore_init(struct ssb_mipscore *mcore)
                        }
                }
        }
+       ssb_dprintk(KERN_INFO PFX "after irq reconfiguration\n");
+       dump_irq(bus);
 
        ssb_mips_serial_init(mcore);
        ssb_mips_flash_detect(mcore);
index fbfadbac67e887d190ac1c93b87d957cf90146fa..100e7a5c5ea1f3a48991845ba1e1cf06758e462c 100644 (file)
@@ -583,7 +583,7 @@ static int ssb_pcmcia_sprom_write_all(struct ssb_bus *bus, const u16 *sprom)
                        ssb_printk(".");
                err = ssb_pcmcia_sprom_write(bus, i, sprom[i]);
                if (err) {
-                       ssb_printk("\n" KERN_NOTICE PFX
+                       ssb_printk(KERN_NOTICE PFX
                                   "Failed to write to SPROM.\n");
                        failed = 1;
                        break;
@@ -591,7 +591,7 @@ static int ssb_pcmcia_sprom_write_all(struct ssb_bus *bus, const u16 *sprom)
        }
        err = ssb_pcmcia_sprom_command(bus, SSB_PCMCIA_SPROMCTL_WRITEDIS);
        if (err) {
-               ssb_printk("\n" KERN_NOTICE PFX
+               ssb_printk(KERN_NOTICE PFX
                           "Could not disable SPROM write access.\n");
                failed = 1;
        }
@@ -678,7 +678,8 @@ int ssb_pcmcia_get_invariants(struct ssb_bus *bus,
                        sprom->board_rev = tuple.TupleData[1];
                        break;
                case SSB_PCMCIA_CIS_PA:
-                       GOTO_ERROR_ON(tuple.TupleDataLen != 9,
+                       GOTO_ERROR_ON((tuple.TupleDataLen != 9) &&
+                                     (tuple.TupleDataLen != 10),
                                      "pa tpl size");
                        sprom->pa0b0 = tuple.TupleData[1] |
                                 ((u16)tuple.TupleData[2] << 8);
@@ -718,7 +719,8 @@ int ssb_pcmcia_get_invariants(struct ssb_bus *bus,
                        sprom->antenna_gain.ghz5.a3 = tuple.TupleData[1];
                        break;
                case SSB_PCMCIA_CIS_BFLAGS:
-                       GOTO_ERROR_ON(tuple.TupleDataLen != 3,
+                       GOTO_ERROR_ON((tuple.TupleDataLen != 3) &&
+                                     (tuple.TupleDataLen != 5),
                                      "bfl tpl size");
                        sprom->boardflags_lo = tuple.TupleData[1] |
                                         ((u16)tuple.TupleData[2] << 8);
index baf83c6a9412418be67392cb9dfc4a4425e26143..e3c3adc282e2592376a1fe5bca9b68a5d7e18096 100644 (file)
@@ -45,6 +45,8 @@ Devices: [JR3] PCI force sensor board (jr3_pci)
 #include <linux/delay.h>
 #include <linux/ctype.h>
 #include <linux/firmware.h>
+#include <linux/jiffies.h>
+#include <linux/timer.h>
 #include "comedi_pci.h"
 #include "jr3_pci.h"
 
index 92121cf8c45cddb758a108febd5bd878c8757b92..5d9bab352c1d549806e36e1fca4520385ef8eb26 100644 (file)
@@ -111,9 +111,13 @@ static const struct s626_board s626_boards[] = {
 #define PCI_VENDOR_ID_S626 0x1131
 #define PCI_DEVICE_ID_S626 0x7146
 
+/*
+ * For devices with vendor:device id == 0x1131:0x7146 you must specify
+ * also subvendor:subdevice ids, because otherwise it will conflict with
+ * Philips SAA7146 media/dvb based cards.
+ */
 static DEFINE_PCI_DEVICE_TABLE(s626_pci_table) = {
-       {PCI_VENDOR_ID_S626, PCI_DEVICE_ID_S626, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-               0},
+       {PCI_VENDOR_ID_S626, PCI_DEVICE_ID_S626, 0x6000, 0x0272, 0, 0, 0},
        {0}
 };
 
@@ -499,25 +503,26 @@ static int s626_attach(struct comedi_device *dev, struct comedi_devconfig *it)
        resource_size_t resourceStart;
        dma_addr_t appdma;
        struct comedi_subdevice *s;
-       struct pci_dev *pdev;
+       const struct pci_device_id *ids;
+       struct pci_dev *pdev = NULL;
 
        if (alloc_private(dev, sizeof(struct s626_private)) < 0)
                return -ENOMEM;
 
-       for (pdev = pci_get_device(PCI_VENDOR_ID_S626, PCI_DEVICE_ID_S626,
-                       NULL); pdev != NULL;
-               pdev = pci_get_device(PCI_VENDOR_ID_S626,
-                       PCI_DEVICE_ID_S626, pdev)) {
-               if (it->options[0] || it->options[1]) {
-                       if (pdev->bus->number == it->options[0] &&
-                               PCI_SLOT(pdev->devfn) == it->options[1]) {
+       for (i = 0; i < (ARRAY_SIZE(s626_pci_table) - 1) && !pdev; i++) {
+               ids = &s626_pci_table[i];
+               do {
+                       pdev = pci_get_subsys(ids->vendor, ids->device, ids->subvendor,
+                                             ids->subdevice, pdev);
+
+                       if ((it->options[0] || it->options[1]) && pdev) {
                                /* matches requested bus/slot */
+                               if (pdev->bus->number == it->options[0] &&
+                                   PCI_SLOT(pdev->devfn) == it->options[1])
+                                       break;
+                       } else
                                break;
-                       }
-               } else {
-                       /* no bus/slot specified */
-                       break;
-               }
+               } while (1);
        }
        devpriv->pdev = pdev;
 
index a5e4acab089e034c5ddd1faba37df5313526c6d1..bb22347af60e8f2ecd852ed68ffb0ef9c95899ee 100644 (file)
@@ -17,6 +17,7 @@
 
 #include <linux/module.h>
 #include <linux/init.h>
+#include <linux/smp_lock.h>
 #include <linux/usb.h>
 #include <dvb-usb.h>
 
index 6ec25203089c84f7a467327b322e324d98fcee00..d6ce39823de673378daae4696e17dcbe63210761 100644 (file)
@@ -7,4 +7,4 @@ TODO:
        - possible comedi merge
 
 Please send cleanup patches to Greg Kroah-Hartman <greg@kroah.com>
-and CC: David Kiliani <mail@davidkiliani.de>
+and CC: David Kiliani <mail@davidkiliani.de> and Meilhaus Support <support@meilhaus.de>
index 3c839e37d37f5ac2bb71b57b97455e1ee17dcda4..c0a583cc22274e6b29e82d344c3c630c12e5801f 100644 (file)
@@ -12,7 +12,6 @@
 obj-${CONFIG_OCTEON_ETHERNET} :=  octeon-ethernet.o
 
 octeon-ethernet-objs := ethernet.o
-octeon-ethernet-objs += ethernet-common.o
 octeon-ethernet-objs += ethernet-mdio.o
 octeon-ethernet-objs += ethernet-mem.o
 octeon-ethernet-objs += ethernet-proc.o
diff --git a/drivers/staging/octeon/ethernet-common.c b/drivers/staging/octeon/ethernet-common.c
deleted file mode 100644 (file)
index 3e6f5b8..0000000
+++ /dev/null
@@ -1,328 +0,0 @@
-/**********************************************************************
- * Author: Cavium Networks
- *
- * Contact: support@caviumnetworks.com
- * This file is part of the OCTEON SDK
- *
- * Copyright (c) 2003-2007 Cavium Networks
- *
- * This file is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License, Version 2, as
- * published by the Free Software Foundation.
- *
- * This file is distributed in the hope that it will be useful, but
- * AS-IS and WITHOUT ANY WARRANTY; without even the implied warranty
- * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, TITLE, or
- * NONINFRINGEMENT.  See the GNU General Public License for more
- * details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this file; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
- * or visit http://www.gnu.org/licenses/.
- *
- * This file may also be available under a different license from Cavium.
- * Contact Cavium Networks for more information
-**********************************************************************/
-#include <linux/kernel.h>
-#include <linux/mii.h>
-#include <net/dst.h>
-
-#include <asm/atomic.h>
-#include <asm/octeon/octeon.h>
-
-#include "ethernet-defines.h"
-#include "ethernet-tx.h"
-#include "ethernet-mdio.h"
-#include "ethernet-util.h"
-#include "octeon-ethernet.h"
-#include "ethernet-common.h"
-
-#include "cvmx-pip.h"
-#include "cvmx-pko.h"
-#include "cvmx-fau.h"
-#include "cvmx-helper.h"
-
-#include "cvmx-gmxx-defs.h"
-
-/**
- * Get the low level ethernet statistics
- *
- * @dev:    Device to get the statistics from
- * Returns Pointer to the statistics
- */
-static struct net_device_stats *cvm_oct_common_get_stats(struct net_device *dev)
-{
-       cvmx_pip_port_status_t rx_status;
-       cvmx_pko_port_status_t tx_status;
-       struct octeon_ethernet *priv = netdev_priv(dev);
-
-       if (priv->port < CVMX_PIP_NUM_INPUT_PORTS) {
-               if (octeon_is_simulation()) {
-                       /* The simulator doesn't support statistics */
-                       memset(&rx_status, 0, sizeof(rx_status));
-                       memset(&tx_status, 0, sizeof(tx_status));
-               } else {
-                       cvmx_pip_get_port_status(priv->port, 1, &rx_status);
-                       cvmx_pko_get_port_status(priv->port, 1, &tx_status);
-               }
-
-               priv->stats.rx_packets += rx_status.inb_packets;
-               priv->stats.tx_packets += tx_status.packets;
-               priv->stats.rx_bytes += rx_status.inb_octets;
-               priv->stats.tx_bytes += tx_status.octets;
-               priv->stats.multicast += rx_status.multicast_packets;
-               priv->stats.rx_crc_errors += rx_status.inb_errors;
-               priv->stats.rx_frame_errors += rx_status.fcs_align_err_packets;
-
-               /*
-                * The drop counter must be incremented atomically
-                * since the RX tasklet also increments it.
-                */
-#ifdef CONFIG_64BIT
-               atomic64_add(rx_status.dropped_packets,
-                            (atomic64_t *)&priv->stats.rx_dropped);
-#else
-               atomic_add(rx_status.dropped_packets,
-                            (atomic_t *)&priv->stats.rx_dropped);
-#endif
-       }
-
-       return &priv->stats;
-}
-
-/**
- * Set the multicast list. Currently unimplemented.
- *
- * @dev:    Device to work on
- */
-static void cvm_oct_common_set_multicast_list(struct net_device *dev)
-{
-       union cvmx_gmxx_prtx_cfg gmx_cfg;
-       struct octeon_ethernet *priv = netdev_priv(dev);
-       int interface = INTERFACE(priv->port);
-       int index = INDEX(priv->port);
-
-       if ((interface < 2)
-           && (cvmx_helper_interface_get_mode(interface) !=
-               CVMX_HELPER_INTERFACE_MODE_SPI)) {
-               union cvmx_gmxx_rxx_adr_ctl control;
-               control.u64 = 0;
-               control.s.bcst = 1;     /* Allow broadcast MAC addresses */
-
-               if (dev->mc_list || (dev->flags & IFF_ALLMULTI) ||
-                   (dev->flags & IFF_PROMISC))
-                       /* Force accept multicast packets */
-                       control.s.mcst = 2;
-               else
-                       /* Force reject multicat packets */
-                       control.s.mcst = 1;
-
-               if (dev->flags & IFF_PROMISC)
-                       /*
-                        * Reject matches if promisc. Since CAM is
-                        * shut off, should accept everything.
-                        */
-                       control.s.cam_mode = 0;
-               else
-                       /* Filter packets based on the CAM */
-                       control.s.cam_mode = 1;
-
-               gmx_cfg.u64 =
-                   cvmx_read_csr(CVMX_GMXX_PRTX_CFG(index, interface));
-               cvmx_write_csr(CVMX_GMXX_PRTX_CFG(index, interface),
-                              gmx_cfg.u64 & ~1ull);
-
-               cvmx_write_csr(CVMX_GMXX_RXX_ADR_CTL(index, interface),
-                              control.u64);
-               if (dev->flags & IFF_PROMISC)
-                       cvmx_write_csr(CVMX_GMXX_RXX_ADR_CAM_EN
-                                      (index, interface), 0);
-               else
-                       cvmx_write_csr(CVMX_GMXX_RXX_ADR_CAM_EN
-                                      (index, interface), 1);
-
-               cvmx_write_csr(CVMX_GMXX_PRTX_CFG(index, interface),
-                              gmx_cfg.u64);
-       }
-}
-
-/**
- * Set the hardware MAC address for a device
- *
- * @dev:    Device to change the MAC address for
- * @addr:   Address structure to change it too. MAC address is addr + 2.
- * Returns Zero on success
- */
-static int cvm_oct_common_set_mac_address(struct net_device *dev, void *addr)
-{
-       struct octeon_ethernet *priv = netdev_priv(dev);
-       union cvmx_gmxx_prtx_cfg gmx_cfg;
-       int interface = INTERFACE(priv->port);
-       int index = INDEX(priv->port);
-
-       memcpy(dev->dev_addr, addr + 2, 6);
-
-       if ((interface < 2)
-           && (cvmx_helper_interface_get_mode(interface) !=
-               CVMX_HELPER_INTERFACE_MODE_SPI)) {
-               int i;
-               uint8_t *ptr = addr;
-               uint64_t mac = 0;
-               for (i = 0; i < 6; i++)
-                       mac = (mac << 8) | (uint64_t) (ptr[i + 2]);
-
-               gmx_cfg.u64 =
-                   cvmx_read_csr(CVMX_GMXX_PRTX_CFG(index, interface));
-               cvmx_write_csr(CVMX_GMXX_PRTX_CFG(index, interface),
-                              gmx_cfg.u64 & ~1ull);
-
-               cvmx_write_csr(CVMX_GMXX_SMACX(index, interface), mac);
-               cvmx_write_csr(CVMX_GMXX_RXX_ADR_CAM0(index, interface),
-                              ptr[2]);
-               cvmx_write_csr(CVMX_GMXX_RXX_ADR_CAM1(index, interface),
-                              ptr[3]);
-               cvmx_write_csr(CVMX_GMXX_RXX_ADR_CAM2(index, interface),
-                              ptr[4]);
-               cvmx_write_csr(CVMX_GMXX_RXX_ADR_CAM3(index, interface),
-                              ptr[5]);
-               cvmx_write_csr(CVMX_GMXX_RXX_ADR_CAM4(index, interface),
-                              ptr[6]);
-               cvmx_write_csr(CVMX_GMXX_RXX_ADR_CAM5(index, interface),
-                              ptr[7]);
-               cvm_oct_common_set_multicast_list(dev);
-               cvmx_write_csr(CVMX_GMXX_PRTX_CFG(index, interface),
-                              gmx_cfg.u64);
-       }
-       return 0;
-}
-
-/**
- * Change the link MTU. Unimplemented
- *
- * @dev:     Device to change
- * @new_mtu: The new MTU
- *
- * Returns Zero on success
- */
-static int cvm_oct_common_change_mtu(struct net_device *dev, int new_mtu)
-{
-       struct octeon_ethernet *priv = netdev_priv(dev);
-       int interface = INTERFACE(priv->port);
-       int index = INDEX(priv->port);
-#if defined(CONFIG_VLAN_8021Q) || defined(CONFIG_VLAN_8021Q_MODULE)
-       int vlan_bytes = 4;
-#else
-       int vlan_bytes = 0;
-#endif
-
-       /*
-        * Limit the MTU to make sure the ethernet packets are between
-        * 64 bytes and 65535 bytes.
-        */
-       if ((new_mtu + 14 + 4 + vlan_bytes < 64)
-           || (new_mtu + 14 + 4 + vlan_bytes > 65392)) {
-               pr_err("MTU must be between %d and %d.\n",
-                      64 - 14 - 4 - vlan_bytes, 65392 - 14 - 4 - vlan_bytes);
-               return -EINVAL;
-       }
-       dev->mtu = new_mtu;
-
-       if ((interface < 2)
-           && (cvmx_helper_interface_get_mode(interface) !=
-               CVMX_HELPER_INTERFACE_MODE_SPI)) {
-               /* Add ethernet header and FCS, and VLAN if configured. */
-               int max_packet = new_mtu + 14 + 4 + vlan_bytes;
-
-               if (OCTEON_IS_MODEL(OCTEON_CN3XXX)
-                   || OCTEON_IS_MODEL(OCTEON_CN58XX)) {
-                       /* Signal errors on packets larger than the MTU */
-                       cvmx_write_csr(CVMX_GMXX_RXX_FRM_MAX(index, interface),
-                                      max_packet);
-               } else {
-                       /*
-                        * Set the hardware to truncate packets larger
-                        * than the MTU and smaller the 64 bytes.
-                        */
-                       union cvmx_pip_frm_len_chkx frm_len_chk;
-                       frm_len_chk.u64 = 0;
-                       frm_len_chk.s.minlen = 64;
-                       frm_len_chk.s.maxlen = max_packet;
-                       cvmx_write_csr(CVMX_PIP_FRM_LEN_CHKX(interface),
-                                      frm_len_chk.u64);
-               }
-               /*
-                * Set the hardware to truncate packets larger than
-                * the MTU. The jabber register must be set to a
-                * multiple of 8 bytes, so round up.
-                */
-               cvmx_write_csr(CVMX_GMXX_RXX_JABBER(index, interface),
-                              (max_packet + 7) & ~7u);
-       }
-       return 0;
-}
-
-/**
- * Per network device initialization
- *
- * @dev:    Device to initialize
- * Returns Zero on success
- */
-int cvm_oct_common_init(struct net_device *dev)
-{
-       static int count;
-       char mac[8] = { 0x00, 0x00,
-               octeon_bootinfo->mac_addr_base[0],
-               octeon_bootinfo->mac_addr_base[1],
-               octeon_bootinfo->mac_addr_base[2],
-               octeon_bootinfo->mac_addr_base[3],
-               octeon_bootinfo->mac_addr_base[4],
-               octeon_bootinfo->mac_addr_base[5] + count
-       };
-       struct octeon_ethernet *priv = netdev_priv(dev);
-
-       /*
-        * Force the interface to use the POW send if always_use_pow
-        * was specified or it is in the pow send list.
-        */
-       if ((pow_send_group != -1)
-           && (always_use_pow || strstr(pow_send_list, dev->name)))
-               priv->queue = -1;
-
-       if (priv->queue != -1) {
-               dev->hard_start_xmit = cvm_oct_xmit;
-               if (USE_HW_TCPUDP_CHECKSUM)
-                       dev->features |= NETIF_F_IP_CSUM;
-       } else
-               dev->hard_start_xmit = cvm_oct_xmit_pow;
-       count++;
-
-       dev->get_stats = cvm_oct_common_get_stats;
-       dev->set_mac_address = cvm_oct_common_set_mac_address;
-       dev->set_multicast_list = cvm_oct_common_set_multicast_list;
-       dev->change_mtu = cvm_oct_common_change_mtu;
-       dev->do_ioctl = cvm_oct_ioctl;
-       /* We do our own locking, Linux doesn't need to */
-       dev->features |= NETIF_F_LLTX;
-       SET_ETHTOOL_OPS(dev, &cvm_oct_ethtool_ops);
-#ifdef CONFIG_NET_POLL_CONTROLLER
-       dev->poll_controller = cvm_oct_poll_controller;
-#endif
-
-       cvm_oct_mdio_setup_device(dev);
-       dev->set_mac_address(dev, mac);
-       dev->change_mtu(dev, dev->mtu);
-
-       /*
-        * Zero out stats for port so we won't mistakenly show
-        * counters from the bootloader.
-        */
-       memset(dev->get_stats(dev), 0, sizeof(struct net_device_stats));
-
-       return 0;
-}
-
-void cvm_oct_common_uninit(struct net_device *dev)
-{
-       /* Currently nothing to do */
-}
diff --git a/drivers/staging/octeon/ethernet-common.h b/drivers/staging/octeon/ethernet-common.h
deleted file mode 100644 (file)
index 2bd9cd7..0000000
+++ /dev/null
@@ -1,29 +0,0 @@
-/*********************************************************************
- * Author: Cavium Networks
- *
- * Contact: support@caviumnetworks.com
- * This file is part of the OCTEON SDK
- *
- * Copyright (c) 2003-2007 Cavium Networks
- *
- * This file is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License, Version 2, as
- * published by the Free Software Foundation.
- *
- * This file is distributed in the hope that it will be useful, but
- * AS-IS and WITHOUT ANY WARRANTY; without even the implied warranty
- * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, TITLE, or
- * NONINFRINGEMENT.  See the GNU General Public License for more
- * details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this file; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
- * or visit http://www.gnu.org/licenses/.
- *
- * This file may also be available under a different license from Cavium.
- * Contact Cavium Networks for more information
-*********************************************************************/
-
-int cvm_oct_common_init(struct net_device *dev);
-void cvm_oct_common_uninit(struct net_device *dev);
index 8f7374e7664c4e04d7f6c63c4c2c543f159149ab..f13131b03c333912e8bbbd0fe44d3ace7df52ec2 100644 (file)
 
 /* Maximum number of packets to process per interrupt. */
 #define MAX_RX_PACKETS 120
+/* Maximum number of SKBs to try to free per xmit packet. */
+#define MAX_SKB_TO_FREE 10
 #define MAX_OUT_QUEUE_DEPTH 1000
 
 #ifndef CONFIG_SMP
index 8579f1670d1ecffcc0a1cab86150de047bfce121..8704133fe1272c03964dc110fa48c39b51d4b394 100644 (file)
@@ -33,7 +33,6 @@
 
 #include "ethernet-defines.h"
 #include "octeon-ethernet.h"
-#include "ethernet-common.h"
 #include "ethernet-util.h"
 
 #include "cvmx-helper.h"
@@ -265,7 +264,7 @@ static irqreturn_t cvm_oct_rgmii_rml_interrupt(int cpl, void *dev_id)
        return return_status;
 }
 
-static int cvm_oct_rgmii_open(struct net_device *dev)
+int cvm_oct_rgmii_open(struct net_device *dev)
 {
        union cvmx_gmxx_prtx_cfg gmx_cfg;
        struct octeon_ethernet *priv = netdev_priv(dev);
@@ -286,7 +285,7 @@ static int cvm_oct_rgmii_open(struct net_device *dev)
        return 0;
 }
 
-static int cvm_oct_rgmii_stop(struct net_device *dev)
+int cvm_oct_rgmii_stop(struct net_device *dev)
 {
        union cvmx_gmxx_prtx_cfg gmx_cfg;
        struct octeon_ethernet *priv = netdev_priv(dev);
@@ -305,9 +304,7 @@ int cvm_oct_rgmii_init(struct net_device *dev)
        int r;
 
        cvm_oct_common_init(dev);
-       dev->open = cvm_oct_rgmii_open;
-       dev->stop = cvm_oct_rgmii_stop;
-       dev->stop(dev);
+       dev->netdev_ops->ndo_stop(dev);
 
        /*
         * Due to GMX errata in CN3XXX series chips, it is necessary
index 58fa39c1d6757727285e20547269124cb2b1e4db..2b54996bd85dbe676a9bdc1daca400cae156f45c 100644 (file)
 #include "ethernet-defines.h"
 #include "octeon-ethernet.h"
 #include "ethernet-util.h"
-#include "ethernet-common.h"
 
 #include "cvmx-helper.h"
 
 #include "cvmx-gmxx-defs.h"
 
-static int cvm_oct_sgmii_open(struct net_device *dev)
+int cvm_oct_sgmii_open(struct net_device *dev)
 {
        union cvmx_gmxx_prtx_cfg gmx_cfg;
        struct octeon_ethernet *priv = netdev_priv(dev);
@@ -61,7 +60,7 @@ static int cvm_oct_sgmii_open(struct net_device *dev)
        return 0;
 }
 
-static int cvm_oct_sgmii_stop(struct net_device *dev)
+int cvm_oct_sgmii_stop(struct net_device *dev)
 {
        union cvmx_gmxx_prtx_cfg gmx_cfg;
        struct octeon_ethernet *priv = netdev_priv(dev);
@@ -113,9 +112,7 @@ int cvm_oct_sgmii_init(struct net_device *dev)
 {
        struct octeon_ethernet *priv = netdev_priv(dev);
        cvm_oct_common_init(dev);
-       dev->open = cvm_oct_sgmii_open;
-       dev->stop = cvm_oct_sgmii_stop;
-       dev->stop(dev);
+       dev->netdev_ops->ndo_stop(dev);
        if (!octeon_is_simulation())
                priv->poll = cvm_oct_sgmii_poll;
 
index e0971bbe4ddc252f130fe1fc474cd636cda152dc..66190b0cb68f355c6f482bba828cdcc6c4228017 100644 (file)
@@ -33,7 +33,6 @@
 
 #include "ethernet-defines.h"
 #include "octeon-ethernet.h"
-#include "ethernet-common.h"
 #include "ethernet-util.h"
 
 #include "cvmx-spi.h"
index 77b7122c8fdb66d8bad1b4a4f39524bec0423617..81a851390f1bfc47d762a912114fbce62d14210f 100644 (file)
@@ -47,6 +47,7 @@
 
 #include "ethernet-defines.h"
 #include "octeon-ethernet.h"
+#include "ethernet-tx.h"
 #include "ethernet-util.h"
 
 #include "cvmx-wqe.h"
@@ -82,8 +83,10 @@ int cvm_oct_xmit(struct sk_buff *skb, struct net_device *dev)
        uint64_t old_scratch2;
        int dropped;
        int qos;
+       int queue_it_up;
        struct octeon_ethernet *priv = netdev_priv(dev);
-       int32_t in_use;
+       int32_t skb_to_free;
+       int32_t undo;
        int32_t buffers_to_free;
 #if REUSE_SKBUFFS_WITHOUT_FREE
        unsigned char *fpa_head;
@@ -120,15 +123,15 @@ int cvm_oct_xmit(struct sk_buff *skb, struct net_device *dev)
                old_scratch2 = cvmx_scratch_read64(CVMX_SCR_SCRATCH + 8);
 
                /*
-                * Assume we're going to be able t osend this
-                * packet. Fetch and increment the number of pending
-                * packets for output.
+                * Fetch and increment the number of packets to be
+                * freed.
                 */
                cvmx_fau_async_fetch_and_add32(CVMX_SCR_SCRATCH + 8,
                                               FAU_NUM_PACKET_BUFFERS_TO_FREE,
                                               0);
                cvmx_fau_async_fetch_and_add32(CVMX_SCR_SCRATCH,
-                                              priv->fau + qos * 4, 1);
+                                              priv->fau + qos * 4,
+                                              MAX_SKB_TO_FREE);
        }
 
        /*
@@ -253,10 +256,10 @@ int cvm_oct_xmit(struct sk_buff *skb, struct net_device *dev)
 
        /*
         * The skbuff will be reused without ever being freed. We must
-        * cleanup a bunch of Linux stuff.
+        * cleanup a bunch of core things.
         */
-       dst_release(skb->dst);
-       skb->dst = NULL;
+       dst_release(skb_dst(skb));
+       skb_dst_set(skb, NULL);
 #ifdef CONFIG_XFRM
        secpath_put(skb->sp);
        skb->sp = NULL;
@@ -286,15 +289,29 @@ dont_put_skbuff_in_hw:
        if (USE_ASYNC_IOBDMA) {
                /* Get the number of skbuffs in use by the hardware */
                CVMX_SYNCIOBDMA;
-               in_use = cvmx_scratch_read64(CVMX_SCR_SCRATCH);
+               skb_to_free = cvmx_scratch_read64(CVMX_SCR_SCRATCH);
                buffers_to_free = cvmx_scratch_read64(CVMX_SCR_SCRATCH + 8);
        } else {
                /* Get the number of skbuffs in use by the hardware */
-               in_use = cvmx_fau_fetch_and_add32(priv->fau + qos * 4, 1);
+               skb_to_free = cvmx_fau_fetch_and_add32(priv->fau + qos * 4,
+                                                      MAX_SKB_TO_FREE);
                buffers_to_free =
                    cvmx_fau_fetch_and_add32(FAU_NUM_PACKET_BUFFERS_TO_FREE, 0);
        }
 
+       /*
+        * We try to claim MAX_SKB_TO_FREE buffers.  If there were not
+        * that many available, we have to un-claim (undo) any that
+        * were in excess.  If skb_to_free is positive we will free
+        * that many buffers.
+        */
+       undo = skb_to_free > 0 ?
+               MAX_SKB_TO_FREE : skb_to_free + MAX_SKB_TO_FREE;
+       if (undo > 0)
+               cvmx_fau_atomic_add32(priv->fau+qos*4, -undo);
+       skb_to_free = -skb_to_free > MAX_SKB_TO_FREE ?
+               MAX_SKB_TO_FREE : -skb_to_free;
+
        /*
         * If we're sending faster than the receive can free them then
         * don't do the HW free.
@@ -330,38 +347,31 @@ dont_put_skbuff_in_hw:
                cvmx_scratch_write64(CVMX_SCR_SCRATCH + 8, old_scratch2);
        }
 
+       queue_it_up = 0;
        if (unlikely(dropped)) {
                dev_kfree_skb_any(skb);
-               cvmx_fau_atomic_add32(priv->fau + qos * 4, -1);
                priv->stats.tx_dropped++;
        } else {
                if (USE_SKBUFFS_IN_HW) {
                        /* Put this packet on the queue to be freed later */
                        if (pko_command.s.dontfree)
-                               skb_queue_tail(&priv->tx_free_list[qos], skb);
-                       else {
+                               queue_it_up = 1;
+                       else
                                cvmx_fau_atomic_add32
                                    (FAU_NUM_PACKET_BUFFERS_TO_FREE, -1);
-                               cvmx_fau_atomic_add32(priv->fau + qos * 4, -1);
-                       }
                } else {
                        /* Put this packet on the queue to be freed later */
-                       skb_queue_tail(&priv->tx_free_list[qos], skb);
+                       queue_it_up = 1;
                }
        }
 
-       /* Free skbuffs not in use by the hardware, possibly two at a time */
-       if (skb_queue_len(&priv->tx_free_list[qos]) > in_use) {
+       if (queue_it_up) {
                spin_lock(&priv->tx_free_list[qos].lock);
-               /*
-                * Check again now that we have the lock. It might
-                * have changed.
-                */
-               if (skb_queue_len(&priv->tx_free_list[qos]) > in_use)
-                       dev_kfree_skb(__skb_dequeue(&priv->tx_free_list[qos]));
-               if (skb_queue_len(&priv->tx_free_list[qos]) > in_use)
-                       dev_kfree_skb(__skb_dequeue(&priv->tx_free_list[qos]));
+               __skb_queue_tail(&priv->tx_free_list[qos], skb);
+               cvm_oct_free_tx_skbs(priv, skb_to_free, qos, 0);
                spin_unlock(&priv->tx_free_list[qos].lock);
+       } else {
+               cvm_oct_free_tx_skbs(priv, skb_to_free, qos, 1);
        }
 
        return 0;
index 5106236fe9819fc44c0c190b08367712aad78b1c..c0bebf750bc059acc8d4a8a52b4ab3451e81250d 100644 (file)
@@ -30,3 +30,28 @@ int cvm_oct_xmit_pow(struct sk_buff *skb, struct net_device *dev);
 int cvm_oct_transmit_qos(struct net_device *dev, void *work_queue_entry,
                         int do_free, int qos);
 void cvm_oct_tx_shutdown(struct net_device *dev);
+
+/**
+ * Free dead transmit skbs.
+ *
+ * @priv:              The driver data
+ * @skb_to_free:       The number of SKBs to free (free none if negative).
+ * @qos:               The queue to free from.
+ * @take_lock:         If true, acquire the skb list lock.
+ */
+static inline void cvm_oct_free_tx_skbs(struct octeon_ethernet *priv,
+                                       int skb_to_free,
+                                       int qos, int take_lock)
+{
+       /* Free skbuffs not in use by the hardware.  */
+       if (skb_to_free > 0) {
+               if (take_lock)
+                       spin_lock(&priv->tx_free_list[qos].lock);
+               while (skb_to_free > 0) {
+                       dev_kfree_skb(__skb_dequeue(&priv->tx_free_list[qos]));
+                       skb_to_free--;
+               }
+               if (take_lock)
+                       spin_unlock(&priv->tx_free_list[qos].lock);
+       }
+}
index f08eb32e04fcd9e987e8fc9cb82c8c4f03944cc5..0c2e7cc40f35338dc2e7ed8f179d2e5bf21c43be 100644 (file)
 
 #include "ethernet-defines.h"
 #include "octeon-ethernet.h"
-#include "ethernet-common.h"
 #include "ethernet-util.h"
 
 #include "cvmx-helper.h"
 
 #include "cvmx-gmxx-defs.h"
 
-static int cvm_oct_xaui_open(struct net_device *dev)
+int cvm_oct_xaui_open(struct net_device *dev)
 {
        union cvmx_gmxx_prtx_cfg gmx_cfg;
        struct octeon_ethernet *priv = netdev_priv(dev);
@@ -60,7 +59,7 @@ static int cvm_oct_xaui_open(struct net_device *dev)
        return 0;
 }
 
-static int cvm_oct_xaui_stop(struct net_device *dev)
+int cvm_oct_xaui_stop(struct net_device *dev)
 {
        union cvmx_gmxx_prtx_cfg gmx_cfg;
        struct octeon_ethernet *priv = netdev_priv(dev);
@@ -112,9 +111,7 @@ int cvm_oct_xaui_init(struct net_device *dev)
 {
        struct octeon_ethernet *priv = netdev_priv(dev);
        cvm_oct_common_init(dev);
-       dev->open = cvm_oct_xaui_open;
-       dev->stop = cvm_oct_xaui_stop;
-       dev->stop(dev);
+       dev->netdev_ops->ndo_stop(dev);
        if (!octeon_is_simulation())
                priv->poll = cvm_oct_xaui_poll;
 
index e8ef9e0b791fd48fd1d63874a27c09907573a2e4..b8479517dce28b9fa76af52c532c8af556cb54e5 100644 (file)
 #include <asm/octeon/octeon.h>
 
 #include "ethernet-defines.h"
+#include "octeon-ethernet.h"
 #include "ethernet-mem.h"
 #include "ethernet-rx.h"
 #include "ethernet-tx.h"
+#include "ethernet-mdio.h"
 #include "ethernet-util.h"
 #include "ethernet-proc.h"
-#include "ethernet-common.h"
-#include "octeon-ethernet.h"
+
 
 #include "cvmx-pip.h"
 #include "cvmx-pko.h"
@@ -51,6 +52,7 @@
 #include "cvmx-ipd.h"
 #include "cvmx-helper.h"
 
+#include "cvmx-gmxx-defs.h"
 #include "cvmx-smix-defs.h"
 
 #if defined(CONFIG_CAVIUM_OCTEON_NUM_PACKET_BUFFERS) \
@@ -129,53 +131,55 @@ extern struct semaphore mdio_sem;
  */
 static void cvm_do_timer(unsigned long arg)
 {
+       int32_t skb_to_free, undo;
+       int queues_per_port;
+       int qos;
+       struct octeon_ethernet *priv;
        static int port;
-       if (port < CVMX_PIP_NUM_INPUT_PORTS) {
-               if (cvm_oct_device[port]) {
-                       int queues_per_port;
-                       int qos;
-                       struct octeon_ethernet *priv =
-                               netdev_priv(cvm_oct_device[port]);
-                       if (priv->poll) {
-                               /* skip polling if we don't get the lock */
-                               if (!down_trylock(&mdio_sem)) {
-                                       priv->poll(cvm_oct_device[port]);
-                                       up(&mdio_sem);
-                               }
-                       }
 
-                       queues_per_port = cvmx_pko_get_num_queues(port);
-                       /* Drain any pending packets in the free list */
-                       for (qos = 0; qos < queues_per_port; qos++) {
-                               if (skb_queue_len(&priv->tx_free_list[qos])) {
-                                       spin_lock(&priv->tx_free_list[qos].
-                                                 lock);
-                                       while (skb_queue_len
-                                              (&priv->tx_free_list[qos]) >
-                                              cvmx_fau_fetch_and_add32(priv->
-                                                                       fau +
-                                                                       qos * 4,
-                                                                       0))
-                                               dev_kfree_skb(__skb_dequeue
-                                                             (&priv->
-                                                              tx_free_list
-                                                              [qos]));
-                                       spin_unlock(&priv->tx_free_list[qos].
-                                                   lock);
-                               }
-                       }
-                       cvm_oct_device[port]->get_stats(cvm_oct_device[port]);
-               }
-               port++;
-               /* Poll the next port in a 50th of a second.
-                  This spreads the polling of ports out a little bit */
-               mod_timer(&cvm_oct_poll_timer, jiffies + HZ / 50);
-       } else {
+       if (port >= CVMX_PIP_NUM_INPUT_PORTS) {
+               /*
+                * All ports have been polled. Start the next
+                * iteration through the ports in one second.
+                */
                port = 0;
-               /* All ports have been polled. Start the next iteration through
-                  the ports in one second */
                mod_timer(&cvm_oct_poll_timer, jiffies + HZ);
+               return;
+       }
+       if (!cvm_oct_device[port])
+               goto out;
+
+       priv = netdev_priv(cvm_oct_device[port]);
+       if (priv->poll) {
+               /* skip polling if we don't get the lock */
+               if (!down_trylock(&mdio_sem)) {
+                       priv->poll(cvm_oct_device[port]);
+                       up(&mdio_sem);
+               }
        }
+
+       queues_per_port = cvmx_pko_get_num_queues(port);
+       /* Drain any pending packets in the free list */
+       for (qos = 0; qos < queues_per_port; qos++) {
+               if (skb_queue_len(&priv->tx_free_list[qos]) == 0)
+                       continue;
+               skb_to_free = cvmx_fau_fetch_and_add32(priv->fau + qos * 4,
+                                                      MAX_SKB_TO_FREE);
+               undo = skb_to_free > 0 ?
+                       MAX_SKB_TO_FREE : skb_to_free + MAX_SKB_TO_FREE;
+               if (undo > 0)
+                       cvmx_fau_atomic_add32(priv->fau+qos*4, -undo);
+               skb_to_free = -skb_to_free > MAX_SKB_TO_FREE ?
+                       MAX_SKB_TO_FREE : -skb_to_free;
+               cvm_oct_free_tx_skbs(priv, skb_to_free, qos, 1);
+       }
+       cvm_oct_device[port]->netdev_ops->ndo_get_stats(cvm_oct_device[port]);
+
+out:
+       port++;
+       /* Poll the next port in a 50th of a second.
+          This spreads the polling of ports out a little bit */
+       mod_timer(&cvm_oct_poll_timer, jiffies + HZ / 50);
 }
 
 /**
@@ -245,6 +249,362 @@ int cvm_oct_free_work(void *work_queue_entry)
 }
 EXPORT_SYMBOL(cvm_oct_free_work);
 
+/**
+ * Get the low level ethernet statistics
+ *
+ * @dev:    Device to get the statistics from
+ * Returns Pointer to the statistics
+ */
+static struct net_device_stats *cvm_oct_common_get_stats(struct net_device *dev)
+{
+       cvmx_pip_port_status_t rx_status;
+       cvmx_pko_port_status_t tx_status;
+       struct octeon_ethernet *priv = netdev_priv(dev);
+
+       if (priv->port < CVMX_PIP_NUM_INPUT_PORTS) {
+               if (octeon_is_simulation()) {
+                       /* The simulator doesn't support statistics */
+                       memset(&rx_status, 0, sizeof(rx_status));
+                       memset(&tx_status, 0, sizeof(tx_status));
+               } else {
+                       cvmx_pip_get_port_status(priv->port, 1, &rx_status);
+                       cvmx_pko_get_port_status(priv->port, 1, &tx_status);
+               }
+
+               priv->stats.rx_packets += rx_status.inb_packets;
+               priv->stats.tx_packets += tx_status.packets;
+               priv->stats.rx_bytes += rx_status.inb_octets;
+               priv->stats.tx_bytes += tx_status.octets;
+               priv->stats.multicast += rx_status.multicast_packets;
+               priv->stats.rx_crc_errors += rx_status.inb_errors;
+               priv->stats.rx_frame_errors += rx_status.fcs_align_err_packets;
+
+               /*
+                * The drop counter must be incremented atomically
+                * since the RX tasklet also increments it.
+                */
+#ifdef CONFIG_64BIT
+               atomic64_add(rx_status.dropped_packets,
+                            (atomic64_t *)&priv->stats.rx_dropped);
+#else
+               atomic_add(rx_status.dropped_packets,
+                            (atomic_t *)&priv->stats.rx_dropped);
+#endif
+       }
+
+       return &priv->stats;
+}
+
+/**
+ * Change the link MTU. Unimplemented
+ *
+ * @dev:     Device to change
+ * @new_mtu: The new MTU
+ *
+ * Returns Zero on success
+ */
+static int cvm_oct_common_change_mtu(struct net_device *dev, int new_mtu)
+{
+       struct octeon_ethernet *priv = netdev_priv(dev);
+       int interface = INTERFACE(priv->port);
+       int index = INDEX(priv->port);
+#if defined(CONFIG_VLAN_8021Q) || defined(CONFIG_VLAN_8021Q_MODULE)
+       int vlan_bytes = 4;
+#else
+       int vlan_bytes = 0;
+#endif
+
+       /*
+        * Limit the MTU to make sure the ethernet packets are between
+        * 64 bytes and 65535 bytes.
+        */
+       if ((new_mtu + 14 + 4 + vlan_bytes < 64)
+           || (new_mtu + 14 + 4 + vlan_bytes > 65392)) {
+               pr_err("MTU must be between %d and %d.\n",
+                      64 - 14 - 4 - vlan_bytes, 65392 - 14 - 4 - vlan_bytes);
+               return -EINVAL;
+       }
+       dev->mtu = new_mtu;
+
+       if ((interface < 2)
+           && (cvmx_helper_interface_get_mode(interface) !=
+               CVMX_HELPER_INTERFACE_MODE_SPI)) {
+               /* Add ethernet header and FCS, and VLAN if configured. */
+               int max_packet = new_mtu + 14 + 4 + vlan_bytes;
+
+               if (OCTEON_IS_MODEL(OCTEON_CN3XXX)
+                   || OCTEON_IS_MODEL(OCTEON_CN58XX)) {
+                       /* Signal errors on packets larger than the MTU */
+                       cvmx_write_csr(CVMX_GMXX_RXX_FRM_MAX(index, interface),
+                                      max_packet);
+               } else {
+                       /*
+                        * Set the hardware to truncate packets larger
+                        * than the MTU and smaller the 64 bytes.
+                        */
+                       union cvmx_pip_frm_len_chkx frm_len_chk;
+                       frm_len_chk.u64 = 0;
+                       frm_len_chk.s.minlen = 64;
+                       frm_len_chk.s.maxlen = max_packet;
+                       cvmx_write_csr(CVMX_PIP_FRM_LEN_CHKX(interface),
+                                      frm_len_chk.u64);
+               }
+               /*
+                * Set the hardware to truncate packets larger than
+                * the MTU. The jabber register must be set to a
+                * multiple of 8 bytes, so round up.
+                */
+               cvmx_write_csr(CVMX_GMXX_RXX_JABBER(index, interface),
+                              (max_packet + 7) & ~7u);
+       }
+       return 0;
+}
+
+/**
+ * Set the multicast list. Currently unimplemented.
+ *
+ * @dev:    Device to work on
+ */
+static void cvm_oct_common_set_multicast_list(struct net_device *dev)
+{
+       union cvmx_gmxx_prtx_cfg gmx_cfg;
+       struct octeon_ethernet *priv = netdev_priv(dev);
+       int interface = INTERFACE(priv->port);
+       int index = INDEX(priv->port);
+
+       if ((interface < 2)
+           && (cvmx_helper_interface_get_mode(interface) !=
+               CVMX_HELPER_INTERFACE_MODE_SPI)) {
+               union cvmx_gmxx_rxx_adr_ctl control;
+               control.u64 = 0;
+               control.s.bcst = 1;     /* Allow broadcast MAC addresses */
+
+               if (dev->mc_list || (dev->flags & IFF_ALLMULTI) ||
+                   (dev->flags & IFF_PROMISC))
+                       /* Force accept multicast packets */
+                       control.s.mcst = 2;
+               else
+                       /* Force reject multicat packets */
+                       control.s.mcst = 1;
+
+               if (dev->flags & IFF_PROMISC)
+                       /*
+                        * Reject matches if promisc. Since CAM is
+                        * shut off, should accept everything.
+                        */
+                       control.s.cam_mode = 0;
+               else
+                       /* Filter packets based on the CAM */
+                       control.s.cam_mode = 1;
+
+               gmx_cfg.u64 =
+                   cvmx_read_csr(CVMX_GMXX_PRTX_CFG(index, interface));
+               cvmx_write_csr(CVMX_GMXX_PRTX_CFG(index, interface),
+                              gmx_cfg.u64 & ~1ull);
+
+               cvmx_write_csr(CVMX_GMXX_RXX_ADR_CTL(index, interface),
+                              control.u64);
+               if (dev->flags & IFF_PROMISC)
+                       cvmx_write_csr(CVMX_GMXX_RXX_ADR_CAM_EN
+                                      (index, interface), 0);
+               else
+                       cvmx_write_csr(CVMX_GMXX_RXX_ADR_CAM_EN
+                                      (index, interface), 1);
+
+               cvmx_write_csr(CVMX_GMXX_PRTX_CFG(index, interface),
+                              gmx_cfg.u64);
+       }
+}
+
+/**
+ * Set the hardware MAC address for a device
+ *
+ * @dev:    Device to change the MAC address for
+ * @addr:   Address structure to change it too. MAC address is addr + 2.
+ * Returns Zero on success
+ */
+static int cvm_oct_common_set_mac_address(struct net_device *dev, void *addr)
+{
+       struct octeon_ethernet *priv = netdev_priv(dev);
+       union cvmx_gmxx_prtx_cfg gmx_cfg;
+       int interface = INTERFACE(priv->port);
+       int index = INDEX(priv->port);
+
+       memcpy(dev->dev_addr, addr + 2, 6);
+
+       if ((interface < 2)
+           && (cvmx_helper_interface_get_mode(interface) !=
+               CVMX_HELPER_INTERFACE_MODE_SPI)) {
+               int i;
+               uint8_t *ptr = addr;
+               uint64_t mac = 0;
+               for (i = 0; i < 6; i++)
+                       mac = (mac << 8) | (uint64_t) (ptr[i + 2]);
+
+               gmx_cfg.u64 =
+                   cvmx_read_csr(CVMX_GMXX_PRTX_CFG(index, interface));
+               cvmx_write_csr(CVMX_GMXX_PRTX_CFG(index, interface),
+                              gmx_cfg.u64 & ~1ull);
+
+               cvmx_write_csr(CVMX_GMXX_SMACX(index, interface), mac);
+               cvmx_write_csr(CVMX_GMXX_RXX_ADR_CAM0(index, interface),
+                              ptr[2]);
+               cvmx_write_csr(CVMX_GMXX_RXX_ADR_CAM1(index, interface),
+                              ptr[3]);
+               cvmx_write_csr(CVMX_GMXX_RXX_ADR_CAM2(index, interface),
+                              ptr[4]);
+               cvmx_write_csr(CVMX_GMXX_RXX_ADR_CAM3(index, interface),
+                              ptr[5]);
+               cvmx_write_csr(CVMX_GMXX_RXX_ADR_CAM4(index, interface),
+                              ptr[6]);
+               cvmx_write_csr(CVMX_GMXX_RXX_ADR_CAM5(index, interface),
+                              ptr[7]);
+               cvm_oct_common_set_multicast_list(dev);
+               cvmx_write_csr(CVMX_GMXX_PRTX_CFG(index, interface),
+                              gmx_cfg.u64);
+       }
+       return 0;
+}
+
+/**
+ * Per network device initialization
+ *
+ * @dev:    Device to initialize
+ * Returns Zero on success
+ */
+int cvm_oct_common_init(struct net_device *dev)
+{
+       static int count;
+       char mac[8] = { 0x00, 0x00,
+               octeon_bootinfo->mac_addr_base[0],
+               octeon_bootinfo->mac_addr_base[1],
+               octeon_bootinfo->mac_addr_base[2],
+               octeon_bootinfo->mac_addr_base[3],
+               octeon_bootinfo->mac_addr_base[4],
+               octeon_bootinfo->mac_addr_base[5] + count
+       };
+       struct octeon_ethernet *priv = netdev_priv(dev);
+
+       /*
+        * Force the interface to use the POW send if always_use_pow
+        * was specified or it is in the pow send list.
+        */
+       if ((pow_send_group != -1)
+           && (always_use_pow || strstr(pow_send_list, dev->name)))
+               priv->queue = -1;
+
+       if (priv->queue != -1 && USE_HW_TCPUDP_CHECKSUM)
+               dev->features |= NETIF_F_IP_CSUM;
+
+       count++;
+
+       /* We do our own locking, Linux doesn't need to */
+       dev->features |= NETIF_F_LLTX;
+       SET_ETHTOOL_OPS(dev, &cvm_oct_ethtool_ops);
+
+       cvm_oct_mdio_setup_device(dev);
+       dev->netdev_ops->ndo_set_mac_address(dev, mac);
+       dev->netdev_ops->ndo_change_mtu(dev, dev->mtu);
+
+       /*
+        * Zero out stats for port so we won't mistakenly show
+        * counters from the bootloader.
+        */
+       memset(dev->netdev_ops->ndo_get_stats(dev), 0,
+              sizeof(struct net_device_stats));
+
+       return 0;
+}
+
+void cvm_oct_common_uninit(struct net_device *dev)
+{
+       /* Currently nothing to do */
+}
+
+static const struct net_device_ops cvm_oct_npi_netdev_ops = {
+       .ndo_init               = cvm_oct_common_init,
+       .ndo_uninit             = cvm_oct_common_uninit,
+       .ndo_start_xmit         = cvm_oct_xmit,
+       .ndo_set_multicast_list = cvm_oct_common_set_multicast_list,
+       .ndo_set_mac_address    = cvm_oct_common_set_mac_address,
+       .ndo_do_ioctl           = cvm_oct_ioctl,
+       .ndo_change_mtu         = cvm_oct_common_change_mtu,
+       .ndo_get_stats          = cvm_oct_common_get_stats,
+#ifdef CONFIG_NET_POLL_CONTROLLER
+       .ndo_poll_controller    = cvm_oct_poll_controller,
+#endif
+};
+static const struct net_device_ops cvm_oct_xaui_netdev_ops = {
+       .ndo_init               = cvm_oct_xaui_init,
+       .ndo_uninit             = cvm_oct_xaui_uninit,
+       .ndo_open               = cvm_oct_xaui_open,
+       .ndo_stop               = cvm_oct_xaui_stop,
+       .ndo_start_xmit         = cvm_oct_xmit,
+       .ndo_set_multicast_list = cvm_oct_common_set_multicast_list,
+       .ndo_set_mac_address    = cvm_oct_common_set_mac_address,
+       .ndo_do_ioctl           = cvm_oct_ioctl,
+       .ndo_change_mtu         = cvm_oct_common_change_mtu,
+       .ndo_get_stats          = cvm_oct_common_get_stats,
+#ifdef CONFIG_NET_POLL_CONTROLLER
+       .ndo_poll_controller    = cvm_oct_poll_controller,
+#endif
+};
+static const struct net_device_ops cvm_oct_sgmii_netdev_ops = {
+       .ndo_init               = cvm_oct_sgmii_init,
+       .ndo_uninit             = cvm_oct_sgmii_uninit,
+       .ndo_open               = cvm_oct_sgmii_open,
+       .ndo_stop               = cvm_oct_sgmii_stop,
+       .ndo_start_xmit         = cvm_oct_xmit,
+       .ndo_set_multicast_list = cvm_oct_common_set_multicast_list,
+       .ndo_set_mac_address    = cvm_oct_common_set_mac_address,
+       .ndo_do_ioctl           = cvm_oct_ioctl,
+       .ndo_change_mtu         = cvm_oct_common_change_mtu,
+       .ndo_get_stats          = cvm_oct_common_get_stats,
+#ifdef CONFIG_NET_POLL_CONTROLLER
+       .ndo_poll_controller    = cvm_oct_poll_controller,
+#endif
+};
+static const struct net_device_ops cvm_oct_spi_netdev_ops = {
+       .ndo_init               = cvm_oct_spi_init,
+       .ndo_uninit             = cvm_oct_spi_uninit,
+       .ndo_start_xmit         = cvm_oct_xmit,
+       .ndo_set_multicast_list = cvm_oct_common_set_multicast_list,
+       .ndo_set_mac_address    = cvm_oct_common_set_mac_address,
+       .ndo_do_ioctl           = cvm_oct_ioctl,
+       .ndo_change_mtu         = cvm_oct_common_change_mtu,
+       .ndo_get_stats          = cvm_oct_common_get_stats,
+#ifdef CONFIG_NET_POLL_CONTROLLER
+       .ndo_poll_controller    = cvm_oct_poll_controller,
+#endif
+};
+static const struct net_device_ops cvm_oct_rgmii_netdev_ops = {
+       .ndo_init               = cvm_oct_rgmii_init,
+       .ndo_uninit             = cvm_oct_rgmii_uninit,
+       .ndo_open               = cvm_oct_rgmii_open,
+       .ndo_stop               = cvm_oct_rgmii_stop,
+       .ndo_start_xmit         = cvm_oct_xmit,
+       .ndo_set_multicast_list = cvm_oct_common_set_multicast_list,
+       .ndo_set_mac_address    = cvm_oct_common_set_mac_address,
+       .ndo_do_ioctl           = cvm_oct_ioctl,
+       .ndo_change_mtu         = cvm_oct_common_change_mtu,
+       .ndo_get_stats          = cvm_oct_common_get_stats,
+#ifdef CONFIG_NET_POLL_CONTROLLER
+       .ndo_poll_controller    = cvm_oct_poll_controller,
+#endif
+};
+static const struct net_device_ops cvm_oct_pow_netdev_ops = {
+       .ndo_init               = cvm_oct_common_init,
+       .ndo_start_xmit         = cvm_oct_xmit_pow,
+       .ndo_set_multicast_list = cvm_oct_common_set_multicast_list,
+       .ndo_set_mac_address    = cvm_oct_common_set_mac_address,
+       .ndo_do_ioctl           = cvm_oct_ioctl,
+       .ndo_change_mtu         = cvm_oct_common_change_mtu,
+       .ndo_get_stats          = cvm_oct_common_get_stats,
+#ifdef CONFIG_NET_POLL_CONTROLLER
+       .ndo_poll_controller    = cvm_oct_poll_controller,
+#endif
+};
+
 /**
  * Module/ driver initialization. Creates the linux network
  * devices.
@@ -303,7 +663,7 @@ static int __init cvm_oct_init_module(void)
                        struct octeon_ethernet *priv = netdev_priv(dev);
                        memset(priv, 0, sizeof(struct octeon_ethernet));
 
-                       dev->init = cvm_oct_common_init;
+                       dev->netdev_ops = &cvm_oct_pow_netdev_ops;
                        priv->imode = CVMX_HELPER_INTERFACE_MODE_DISABLED;
                        priv->port = CVMX_PIP_NUM_INPUT_PORTS;
                        priv->queue = -1;
@@ -372,44 +732,38 @@ static int __init cvm_oct_init_module(void)
                                break;
 
                        case CVMX_HELPER_INTERFACE_MODE_NPI:
-                               dev->init = cvm_oct_common_init;
-                               dev->uninit = cvm_oct_common_uninit;
+                               dev->netdev_ops = &cvm_oct_npi_netdev_ops;
                                strcpy(dev->name, "npi%d");
                                break;
 
                        case CVMX_HELPER_INTERFACE_MODE_XAUI:
-                               dev->init = cvm_oct_xaui_init;
-                               dev->uninit = cvm_oct_xaui_uninit;
+                               dev->netdev_ops = &cvm_oct_xaui_netdev_ops;
                                strcpy(dev->name, "xaui%d");
                                break;
 
                        case CVMX_HELPER_INTERFACE_MODE_LOOP:
-                               dev->init = cvm_oct_common_init;
-                               dev->uninit = cvm_oct_common_uninit;
+                               dev->netdev_ops = &cvm_oct_npi_netdev_ops;
                                strcpy(dev->name, "loop%d");
                                break;
 
                        case CVMX_HELPER_INTERFACE_MODE_SGMII:
-                               dev->init = cvm_oct_sgmii_init;
-                               dev->uninit = cvm_oct_sgmii_uninit;
+                               dev->netdev_ops = &cvm_oct_sgmii_netdev_ops;
                                strcpy(dev->name, "eth%d");
                                break;
 
                        case CVMX_HELPER_INTERFACE_MODE_SPI:
-                               dev->init = cvm_oct_spi_init;
-                               dev->uninit = cvm_oct_spi_uninit;
+                               dev->netdev_ops = &cvm_oct_spi_netdev_ops;
                                strcpy(dev->name, "spi%d");
                                break;
 
                        case CVMX_HELPER_INTERFACE_MODE_RGMII:
                        case CVMX_HELPER_INTERFACE_MODE_GMII:
-                               dev->init = cvm_oct_rgmii_init;
-                               dev->uninit = cvm_oct_rgmii_uninit;
+                               dev->netdev_ops = &cvm_oct_rgmii_netdev_ops;
                                strcpy(dev->name, "eth%d");
                                break;
                        }
 
-                       if (!dev->init) {
+                       if (!dev->netdev_ops) {
                                kfree(dev);
                        } else if (register_netdev(dev) < 0) {
                                pr_err("Failed to register ethernet device "
index b3199076ef5e4af6a36cdd24552f6052d77fb8c0..3aef9878fc0ad0cb178f4f9537761bb8ecb0303d 100644 (file)
@@ -111,12 +111,23 @@ static inline int cvm_oct_transmit(struct net_device *dev,
 
 extern int cvm_oct_rgmii_init(struct net_device *dev);
 extern void cvm_oct_rgmii_uninit(struct net_device *dev);
+extern int cvm_oct_rgmii_open(struct net_device *dev);
+extern int cvm_oct_rgmii_stop(struct net_device *dev);
+
 extern int cvm_oct_sgmii_init(struct net_device *dev);
 extern void cvm_oct_sgmii_uninit(struct net_device *dev);
+extern int cvm_oct_sgmii_open(struct net_device *dev);
+extern int cvm_oct_sgmii_stop(struct net_device *dev);
+
 extern int cvm_oct_spi_init(struct net_device *dev);
 extern void cvm_oct_spi_uninit(struct net_device *dev);
 extern int cvm_oct_xaui_init(struct net_device *dev);
 extern void cvm_oct_xaui_uninit(struct net_device *dev);
+extern int cvm_oct_xaui_open(struct net_device *dev);
+extern int cvm_oct_xaui_stop(struct net_device *dev);
+
+extern int cvm_oct_common_init(struct net_device *dev);
+extern void cvm_oct_common_uninit(struct net_device *dev);
 
 extern int always_use_pow;
 extern int pow_send_group;
index 1cdfe69585ea666d63b8e16175f2705c1529461b..2f8155c1968b31652f63f781c0e15071fd25afe6 100644 (file)
@@ -444,8 +444,7 @@ static void piusb_write_bulk_callback(struct urb *urb)
                        __func__, status);
 
        pdx->pendingWrite = 0;
-       usb_buffer_free(urb->dev, urb->transfer_buffer_length,
-                       urb->transfer_buffer, urb->transfer_dma);
+       kfree(urb->transfer_buffer);
 }
 
 int piusb_output(struct ioctl_struct *io, unsigned char *uBuf, int len,
@@ -457,9 +456,7 @@ int piusb_output(struct ioctl_struct *io, unsigned char *uBuf, int len,
 
        urb = usb_alloc_urb(0, GFP_KERNEL);
        if (urb != NULL) {
-               kbuf =
-                   usb_buffer_alloc(pdx->udev, len, GFP_KERNEL,
-                                    &urb->transfer_dma);
+               kbuf = kmalloc(len, GFP_KERNEL);
                if (!kbuf) {
                        dev_err(&pdx->udev->dev, "buffer_alloc failed\n");
                        return -ENOMEM;
@@ -470,7 +467,6 @@ int piusb_output(struct ioctl_struct *io, unsigned char *uBuf, int len,
                }
                usb_fill_bulk_urb(urb, pdx->udev, pdx->hEP[io->endpoint], kbuf,
                                  len, piusb_write_bulk_callback, pdx);
-               urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
                err = usb_submit_urb(urb, GFP_KERNEL);
                if (err) {
                        dev_err(&pdx->udev->dev,
@@ -641,7 +637,7 @@ static int MapUserBuffer(struct ioctl_struct *io, struct device_extension *pdx)
        numPagesRequired =
            ((uaddr & ~PAGE_MASK) + count + ~PAGE_MASK) >> PAGE_SHIFT;
        dbg("Number of pages needed = %d", numPagesRequired);
-       maplist_p = vmalloc(numPagesRequired * sizeof(struct page));
+       maplist_p = vmalloc(numPagesRequired * sizeof(struct page *));
        if (!maplist_p) {
                dbg("Can't Allocate Memory for maplist_p");
                return -ENOMEM;
@@ -712,9 +708,7 @@ static int MapUserBuffer(struct ioctl_struct *io, struct device_extension *pdx)
                usb_fill_bulk_urb(pdx->PixelUrb[frameInfo][i],
                                  pdx->udev,
                                  epAddr,
-                                 (dma_addr_t *) sg_dma_address(&pdx->
-                                                               sgl[frameInfo]
-                                                               [i]),
+                                 NULL, // non-DMA HC? buy a better hardware
                                  sg_dma_len(&pdx->sgl[frameInfo][i]),
                                  piusb_readPIXEL_callback, (void *)pdx);
                pdx->PixelUrb[frameInfo][i]->transfer_dma =
index 5e5b3f2b7eb1e757975763c64409058ebf345015..29e3b53e52a1be04c06797344ed95ff810d23e40 100644 (file)
@@ -89,6 +89,7 @@
        {USB_DEVICE(0x0DF6,0x002C)}, /* Sitecom */              \
        {USB_DEVICE(0x0DF6,0x002D)}, /* Sitecom */              \
        {USB_DEVICE(0x0DF6,0x0039)}, /* Sitecom */              \
+       {USB_DEVICE(0x0DF6,0x003F)}, /* Sitecom WL-608 */       \
        {USB_DEVICE(0x14B2,0x3C06)}, /* Conceptronic */         \
        {USB_DEVICE(0x14B2,0x3C28)}, /* Conceptronic */         \
        {USB_DEVICE(0x2019,0xED06)}, /* Planex Communications, Inc. */          \
index 93af37e2d31a0b453031ffff3c79f852f6d79022..54b4b718f84a5f09fa2cd3a491f423d781276bc7 100644 (file)
@@ -461,19 +461,19 @@ int ieee80211_wx_get_name(struct ieee80211_device *ieee,
                             struct iw_request_info *info,
                             union iwreq_data *wrqu, char *extra)
 {
-       strcpy(wrqu->name, "802.11");
+       strlcpy(wrqu->name, "802.11", IFNAMSIZ);
        if(ieee->modulation & IEEE80211_CCK_MODULATION){
-               strcat(wrqu->name, "b");
+               strlcat(wrqu->name, "b", IFNAMSIZ);
                if(ieee->modulation & IEEE80211_OFDM_MODULATION)
-                       strcat(wrqu->name, "/g");
+                       strlcat(wrqu->name, "/g", IFNAMSIZ);
        }else if(ieee->modulation & IEEE80211_OFDM_MODULATION)
-               strcat(wrqu->name, "g");
+               strlcat(wrqu->name, "g", IFNAMSIZ);
 
        if((ieee->state == IEEE80211_LINKED) ||
                (ieee->state == IEEE80211_LINKED_SCANNING))
-               strcat(wrqu->name," linked");
+               strlcat(wrqu->name,"  link", IFNAMSIZ);
        else if(ieee->state != IEEE80211_NOLINK)
-               strcat(wrqu->name," link..");
+               strlcat(wrqu->name," .....", IFNAMSIZ);
 
 
        return 0;
index 4b5552c5926e33c79309c73610d70bb453f30be2..770f41280f21d5412a93761b2ea8522b88fce4f9 100644 (file)
@@ -1,6 +1,6 @@
 config RTL8192SU
        tristate "RealTek RTL8192SU Wireless LAN NIC driver"
        depends on PCI
-       depends on WIRELESS_EXT && COMPAT_NET_DEV_OPS
+       depends on WIRELESS_EXT
        default N
        ---help---
index f408b4583b82981a1626a909e8505e76fc0e1349..759032db4a3482fd03fdfc2f3c1f49aa152c03ae 100644 (file)
@@ -118,7 +118,6 @@ struct net_device *alloc_ieee80211(int sizeof_priv)
 #else
        ieee = (struct ieee80211_device *)dev->priv;
 #endif
-       dev->hard_start_xmit = ieee80211_xmit;
 
        memset(ieee, 0, sizeof(struct ieee80211_device)+sizeof_priv);
        ieee->dev = dev;
index 1f50c46dcb90636d765ebf879d0d39e61fe15473..191dc3fbbe32e09d1efbf3f3a66fee78c68703c8 100644 (file)
@@ -548,21 +548,21 @@ int ieee80211_wx_get_name(struct ieee80211_device *ieee,
                             struct iw_request_info *info,
                             union iwreq_data *wrqu, char *extra)
 {
-       strcpy(wrqu->name, "802.11");
+       strlcpy(wrqu->name, "802.11", IFNAMSIZ);
        if(ieee->modulation & IEEE80211_CCK_MODULATION){
-               strcat(wrqu->name, "b");
+               strlcat(wrqu->name, "b", IFNAMSIZ);
                if(ieee->modulation & IEEE80211_OFDM_MODULATION)
-                       strcat(wrqu->name, "/g");
+                       strlcat(wrqu->name, "/g", IFNAMSIZ);
        }else if(ieee->modulation & IEEE80211_OFDM_MODULATION)
-               strcat(wrqu->name, "g");
+               strlcat(wrqu->name, "g", IFNAMSIZ);
        if (ieee->mode & (IEEE_N_24G | IEEE_N_5G))
-               strcat(wrqu->name, "/n");
+               strlcat(wrqu->name, "/n", IFNAMSIZ);
 
        if((ieee->state == IEEE80211_LINKED) ||
                (ieee->state == IEEE80211_LINKED_SCANNING))
-               strcat(wrqu->name," linked");
+               strlcat(wrqu->name, "  link", IFNAMSIZ);
        else if(ieee->state != IEEE80211_NOLINK)
-               strcat(wrqu->name," link..");
+               strlcat(wrqu->name, " .....", IFNAMSIZ);
 
 
        return 0;
index f1423d714496ac97ce40b193cb2a573d4897ebf6..4ab250743e81984c0dbcf9282bffc23ee7248984 100644 (file)
@@ -12132,6 +12132,19 @@ static void HalUsbSetQueuePipeMapping8192SUsb(struct usb_interface *intf, struct
 }
 #endif
 
+static const struct net_device_ops rtl8192_netdev_ops = {
+       .ndo_open               = rtl8192_open,
+       .ndo_stop               = rtl8192_close,
+       .ndo_get_stats          = rtl8192_stats,
+       .ndo_tx_timeout         = tx_timeout,
+       .ndo_do_ioctl           = rtl8192_ioctl,
+       .ndo_set_multicast_list = r8192_set_multicast,
+       .ndo_set_mac_address    = r8192_set_mac_adr,
+       .ndo_validate_addr      = eth_validate_addr,
+       .ndo_change_mtu         = eth_change_mtu,
+       .ndo_start_xmit         = ieee80211_xmit,
+};
+
 #if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0)
 static int __devinit rtl8192_usb_probe(struct usb_interface *intf,
                         const struct usb_device_id *id)
@@ -12186,15 +12199,7 @@ static void * __devinit rtl8192_usb_probe(struct usb_device *udev,
        priv->ops = &rtl8192u_ops;
 #endif
 
-       dev->open = rtl8192_open;
-       dev->stop = rtl8192_close;
-       //dev->hard_start_xmit = rtl8192_8023_hard_start_xmit;
-       dev->tx_timeout = tx_timeout;
-       //dev->wireless_handlers = &r8192_wx_handlers_def;
-       dev->do_ioctl = rtl8192_ioctl;
-       dev->set_multicast_list = r8192_set_multicast;
-       dev->set_mac_address = r8192_set_mac_adr;
-       dev->get_stats = rtl8192_stats;
+       dev->netdev_ops = &rtl8192_netdev_ops;
 
          //DMESG("Oops: i'm coming\n");
 #if WIRELESS_EXT >= 12
index 92c95aa36638077cea8b5328b4aafcda480c33bf..b1531a8d0cde12d0ee656d074ce45452fb834ac7 100644 (file)
@@ -35,7 +35,9 @@ int rtl8192U_suspend(struct usb_interface *intf, pm_message_t state)
                      return 0;
                 }
 
-               dev->stop(dev);
+               if (dev->netdev_ops->ndo_stop)
+                       dev->netdev_ops->ndo_stop(dev);
+
                mdelay(10);
 
                netif_device_detach(dev);
@@ -61,7 +63,9 @@ int rtl8192U_resume (struct usb_interface *intf)
                }
 
                netif_device_attach(dev);
-               dev->open(dev);
+
+               if (dev->netdev_ops->ndo_open)
+                       dev->netdev_ops->ndo_open(dev);
        }
 
         return 0;
index 90b29b564631656711694df46111dff8c4e8cda0..a9bd4106beb78a3701f99fb46d8a162b68c8e9f9 100644 (file)
@@ -866,7 +866,7 @@ static void qt_release(struct usb_serial *serial)
 
 }
 
-int qt_open(struct tty_struct *tty,
+static int qt_open(struct tty_struct *tty,
            struct usb_serial_port *port, struct file *filp)
 {
        struct usb_serial *serial;
@@ -1041,17 +1041,19 @@ static void qt_block_until_empty(struct tty_struct *tty,
        }
 }
 
-static void qt_close(struct tty_struct *tty, struct usb_serial_port *port,
-                    struct file *filp)
+static void qt_close( struct usb_serial_port *port)
 {
        struct usb_serial *serial = port->serial;
        struct quatech_port *qt_port;
        struct quatech_port *port0;
+       struct tty_struct *tty;
        int status;
        unsigned int index;
        status = 0;
 
        dbg("%s - port %d\n", __func__, port->number);
+
+       tty = tty_port_tty_get(&port->port);
        index = tty->index - serial->minor;
 
        qt_port = qt_get_port_private(port);
index cfdaac9b747edbc15cc3c0c0746772815b6ddd9c..a137c78fac0982ee293860344bc172b757fb7ead 100644 (file)
@@ -2235,24 +2235,6 @@ static void stlc45xx_op_remove_interface(struct ieee80211_hw *hw,
        stlc45xx_debug(DEBUG_FUNC, "%s", __func__);
 }
 
-static int stlc45xx_op_config_interface(struct ieee80211_hw *hw,
-                                       struct ieee80211_vif *vif,
-                                       struct ieee80211_if_conf *conf)
-{
-       struct stlc45xx *stlc = hw->priv;
-
-       stlc45xx_debug(DEBUG_FUNC, "%s", __func__);
-
-       mutex_lock(&stlc->mutex);
-
-       memcpy(stlc->bssid, conf->bssid, ETH_ALEN);
-       stlc45xx_tx_setup(stlc);
-
-       mutex_unlock(&stlc->mutex);
-
-       return 0;
-}
-
 static int stlc45xx_op_config(struct ieee80211_hw *hw, u32 changed)
 {
        struct stlc45xx *stlc = hw->priv;
@@ -2295,6 +2277,14 @@ static void stlc45xx_op_bss_info_changed(struct ieee80211_hw *hw,
 {
        struct stlc45xx *stlc = hw->priv;
 
+       stlc45xx_debug(DEBUG_FUNC, "%s", __func__);
+       mutex_lock(&stlc->mutex);
+
+       memcpy(stlc->bssid, info->bssid, ETH_ALEN);
+       stlc45xx_tx_setup(stlc);
+
+       mutex_unlock(&stlc->mutex);
+
        if (changed & BSS_CHANGED_ASSOC) {
                stlc->associated = info->assoc;
                if (info->assoc)
@@ -2357,7 +2347,6 @@ static const struct ieee80211_ops stlc45xx_ops = {
        .add_interface = stlc45xx_op_add_interface,
        .remove_interface = stlc45xx_op_remove_interface,
        .config = stlc45xx_op_config,
-       .config_interface = stlc45xx_op_config_interface,
        .configure_filter = stlc45xx_op_configure_filter,
        .tx = stlc45xx_op_tx,
        .bss_info_changed = stlc45xx_op_bss_info_changed,
index 22f93dd0ba034ac741dcba70642fbf5272957070..251220dc885140479590224f80a9c0abcb5ee54a 100644 (file)
@@ -18,6 +18,7 @@
  */
 
 #include <linux/kernel.h>
+#include <linux/smp_lock.h>
 #include <linux/file.h>
 #include <linux/tcp.h>
 #include <linux/in.h>
index a10ed27acbc2028ad1cf683f2fa3bd0d121286d2..f43ca416e4a88c4f989a31495181f4a6d155227b 100644 (file)
@@ -344,7 +344,7 @@ static CHIP_INFO chip_info_table[]= {
 };
 
 static struct pci_device_id device_id_table[] __devinitdata = {
-{ 0x1106, 0x3253, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (int)&chip_info_table[0]},
+{ 0x1106, 0x3253, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long)&chip_info_table[0]},
 { 0, }
 };
 #endif
@@ -369,7 +369,7 @@ static int  device_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
 
 #ifdef CONFIG_PM
 static int device_notify_reboot(struct notifier_block *, unsigned long event, void *ptr);
-static int viawget_suspend(struct pci_dev *pcid, u32 state);
+static int viawget_suspend(struct pci_dev *pcid, pm_message_t state);
 static int viawget_resume(struct pci_dev *pcid);
 struct notifier_block device_notifier = {
         notifier_call:  device_notify_reboot,
@@ -3941,7 +3941,7 @@ device_notify_reboot(struct notifier_block *nb, unsigned long event, void *p)
         while ((pdev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, pdev)) != NULL) {
             if(pci_dev_driver(pdev) == &device_driver) {
                 if (pci_get_drvdata(pdev))
-                    viawget_suspend(pdev, 3);
+                    viawget_suspend(pdev, PMSG_HIBERNATE);
             }
         }
     }
@@ -3949,7 +3949,7 @@ device_notify_reboot(struct notifier_block *nb, unsigned long event, void *p)
 }
 
 static int
-viawget_suspend(struct pci_dev *pcid, u32 state)
+viawget_suspend(struct pci_dev *pcid, pm_message_t state)
 {
     int power_status;   // to silence the compiler
 
@@ -3971,7 +3971,7 @@ viawget_suspend(struct pci_dev *pcid, u32 state)
     memset(pMgmt->abyCurrBSSID, 0, 6);
     pMgmt->eCurrState = WMAC_STATE_IDLE;
     pci_disable_device(pcid);
-    power_status = pci_set_power_state(pcid, state);
+    power_status = pci_set_power_state(pcid, pci_choose_state(pcid, state));
     spin_unlock_irq(&pDevice->lock);
     return 0;
 }
index a913efc69669a221d336006a35d5155000a6081a..40de151f27898a1e20b82f22d80ccbc9448be558 100644 (file)
 #include <linux/fs.h>          /* everything... */
 #include <linux/errno.h>       /* error codes */
 #include <linux/slab.h>
+#include <linux/smp_lock.h>
 #include <linux/mm.h>
 #include <linux/ioport.h>
 #include <linux/interrupt.h>
index b52cc830c0b49c90ba097bdeadfc4140d9c29d8f..f3873f650bb43f7f68f79ee87a8c8cdf13784b3a 100644 (file)
@@ -23,7 +23,6 @@
 #include <linux/errno.h>
 #include <linux/phonedev.h>
 #include <linux/init.h>
-#include <linux/smp_lock.h>
 #include <asm/uaccess.h>
 #include <asm/system.h>
 
index 38bfdb0f666058061081e6035512843cb0eaa850..5b15d9d8896b9b0efe08a7d44303486e6f290811 100644 (file)
@@ -387,6 +387,7 @@ static void acm_rx_tasklet(unsigned long _acm)
        struct acm_ru *rcv;
        unsigned long flags;
        unsigned char throttled;
+       struct usb_host_endpoint *ep;
 
        dbg("Entering acm_rx_tasklet");
 
@@ -462,11 +463,20 @@ urbs:
 
                rcv->buffer = buf;
 
-               usb_fill_bulk_urb(rcv->urb, acm->dev,
-                                 acm->rx_endpoint,
-                                 buf->base,
-                                 acm->readsize,
-                                 acm_read_bulk, rcv);
+               ep = (usb_pipein(acm->rx_endpoint) ? acm->dev->ep_in : acm->dev->ep_out)
+                               [usb_pipeendpoint(acm->rx_endpoint)];
+               if (usb_endpoint_xfer_int(&ep->desc))
+                       usb_fill_int_urb(rcv->urb, acm->dev,
+                                        acm->rx_endpoint,
+                                        buf->base,
+                                        acm->readsize,
+                                        acm_read_bulk, rcv, ep->desc.bInterval);
+               else
+                       usb_fill_bulk_urb(rcv->urb, acm->dev,
+                                         acm->rx_endpoint,
+                                         buf->base,
+                                         acm->readsize,
+                                         acm_read_bulk, rcv);
                rcv->urb->transfer_dma = buf->dma;
                rcv->urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
 
@@ -550,7 +560,7 @@ static void acm_waker(struct work_struct *waker)
 static int acm_tty_open(struct tty_struct *tty, struct file *filp)
 {
        struct acm *acm;
-       int rv = -EINVAL;
+       int rv = -ENODEV;
        int i;
        dbg("Entering acm_tty_open.");
 
@@ -677,7 +687,7 @@ static void acm_tty_close(struct tty_struct *tty, struct file *filp)
 
        /* Perform the closing process and see if we need to do the hardware
           shutdown */
-       if (tty_port_close_start(&acm->port, tty, filp) == 0)
+       if (!acm || tty_port_close_start(&acm->port, tty, filp) == 0)
                return;
        acm_port_down(acm, 0);
        tty_port_close_end(&acm->port, tty);
@@ -1227,9 +1237,14 @@ made_compressed_probe:
                        goto alloc_fail7;
                }
 
-               usb_fill_bulk_urb(snd->urb, usb_dev,
-                       usb_sndbulkpipe(usb_dev, epwrite->bEndpointAddress),
-                       NULL, acm->writesize, acm_write_bulk, snd);
+               if (usb_endpoint_xfer_int(epwrite))
+                       usb_fill_int_urb(snd->urb, usb_dev,
+                               usb_sndbulkpipe(usb_dev, epwrite->bEndpointAddress),
+                               NULL, acm->writesize, acm_write_bulk, snd, epwrite->bInterval);
+               else
+                       usb_fill_bulk_urb(snd->urb, usb_dev,
+                               usb_sndbulkpipe(usb_dev, epwrite->bEndpointAddress),
+                               NULL, acm->writesize, acm_write_bulk, snd);
                snd->urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
                snd->instance = acm;
        }
index 0fe434505ac44d8d6d9c066738b36dacdd0c62ac..ba589d4ca8bcb9e8783cc47bce18cab3faaa8301 100644 (file)
@@ -15,7 +15,6 @@
 #include <linux/errno.h>
 #include <linux/slab.h>
 #include <linux/module.h>
-#include <linux/smp_lock.h>
 #include <linux/mutex.h>
 #include <linux/uaccess.h>
 #include <linux/bitops.h>
index 3703789d0d2af8a7459138adb5903c548e704425..b09a527f73411499e2ab712c0f4d1b6f7d2c1946 100644 (file)
@@ -751,7 +751,7 @@ static int get_capabilities(struct usbtmc_device_data *data)
 {
        struct device *dev = &data->usb_dev->dev;
        char *buffer;
-       int rv;
+       int rv = 0;
 
        buffer = kmalloc(0x18, GFP_KERNEL);
        if (!buffer)
@@ -763,7 +763,7 @@ static int get_capabilities(struct usbtmc_device_data *data)
                             0, 0, buffer, 0x18, USBTMC_TIMEOUT);
        if (rv < 0) {
                dev_err(dev, "usb_control_msg returned %d\n", rv);
-               return rv;
+               goto err_out;
        }
 
        dev_dbg(dev, "GET_CAPABILITIES returned %x\n", buffer[0]);
@@ -773,7 +773,8 @@ static int get_capabilities(struct usbtmc_device_data *data)
        dev_dbg(dev, "USB488 device capabilities are %x\n", buffer[15]);
        if (buffer[0] != USBTMC_STATUS_SUCCESS) {
                dev_err(dev, "GET_CAPABILITIES returned %x\n", buffer[0]);
-               return -EPERM;
+               rv = -EPERM;
+               goto err_out;
        }
 
        data->capabilities.interface_capabilities = buffer[4];
@@ -781,8 +782,9 @@ static int get_capabilities(struct usbtmc_device_data *data)
        data->capabilities.usb488_interface_capabilities = buffer[14];
        data->capabilities.usb488_device_capabilities = buffer[15];
 
+err_out:
        kfree(buffer);
-       return 0;
+       return rv;
 }
 
 #define capability_attribute(name)                                     \
index 69280c35b5cbc6d93cc50c99d7f4a7f747c1fc99..ad925946f869ea1ed435851b1efebd0cf7d200b4 100644 (file)
@@ -28,7 +28,7 @@ comment "Miscellaneous USB options"
        depends on USB
 
 config USB_DEVICEFS
-       bool "USB device filesystem (DEPRECATED)" if EMBEDDED
+       bool "USB device filesystem (DEPRECATED)"
        depends on USB
        ---help---
          If you say Y here (and to "/proc file system support" in the "File
index 73c108d117b4b3da95587c5366a4498a695a8e74..96f11715cd269b4cb8594c12c4c027ae50350af8 100644 (file)
@@ -136,17 +136,19 @@ static const struct class_info clas_info[] =
        {USB_CLASS_AUDIO,               "audio"},
        {USB_CLASS_COMM,                "comm."},
        {USB_CLASS_HID,                 "HID"},
-       {USB_CLASS_HUB,                 "hub"},
        {USB_CLASS_PHYSICAL,            "PID"},
+       {USB_CLASS_STILL_IMAGE,         "still"},
        {USB_CLASS_PRINTER,             "print"},
        {USB_CLASS_MASS_STORAGE,        "stor."},
+       {USB_CLASS_HUB,                 "hub"},
        {USB_CLASS_CDC_DATA,            "data"},
-       {USB_CLASS_APP_SPEC,            "app."},
-       {USB_CLASS_VENDOR_SPEC,         "vend."},
-       {USB_CLASS_STILL_IMAGE,         "still"},
        {USB_CLASS_CSCID,               "scard"},
        {USB_CLASS_CONTENT_SEC,         "c-sec"},
        {USB_CLASS_VIDEO,               "video"},
+       {USB_CLASS_WIRELESS_CONTROLLER, "wlcon"},
+       {USB_CLASS_MISC,                "misc"},
+       {USB_CLASS_APP_SPEC,            "app."},
+       {USB_CLASS_VENDOR_SPEC,         "vend."},
        {-1,                            "unk."}         /* leave as last */
 };
 
index 308609039c73e1bbf1252adee9f2e276cc73c852..38b8bce782d6d12cbcb01a8b83452948e48570f7 100644 (file)
@@ -325,21 +325,34 @@ static void async_completed(struct urb *urb)
        struct async *as = urb->context;
        struct dev_state *ps = as->ps;
        struct siginfo sinfo;
+       struct pid *pid = NULL;
+       uid_t uid = 0;
+       uid_t euid = 0;
+       u32 secid = 0;
+       int signr;
 
        spin_lock(&ps->lock);
        list_move_tail(&as->asynclist, &ps->async_completed);
-       spin_unlock(&ps->lock);
        as->status = urb->status;
-       if (as->signr) {
+       signr = as->signr;
+       if (signr) {
                sinfo.si_signo = as->signr;
                sinfo.si_errno = as->status;
                sinfo.si_code = SI_ASYNCIO;
                sinfo.si_addr = as->userurb;
-               kill_pid_info_as_uid(as->signr, &sinfo, as->pid, as->uid,
-                                     as->euid, as->secid);
+               pid = as->pid;
+               uid = as->uid;
+               euid = as->euid;
+               secid = as->secid;
        }
        snoop(&urb->dev->dev, "urb complete\n");
        snoop_urb(urb, as->userurb);
+       spin_unlock(&ps->lock);
+
+       if (signr)
+               kill_pid_info_as_uid(sinfo.si_signo, &sinfo, pid, uid,
+                                     euid, secid);
+
        wake_up(&ps->wait);
 }
 
@@ -982,7 +995,7 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb,
                                USBDEVFS_URB_ZERO_PACKET |
                                USBDEVFS_URB_NO_INTERRUPT))
                return -EINVAL;
-       if (!uurb->buffer)
+       if (uurb->buffer_length > 0 && !uurb->buffer)
                return -EINVAL;
        if (!(uurb->type == USBDEVFS_URB_TYPE_CONTROL &&
            (uurb->endpoint & ~USB_ENDPOINT_DIR_MASK) == 0)) {
@@ -1038,11 +1051,6 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb,
                        is_in = 0;
                        uurb->endpoint &= ~USB_DIR_IN;
                }
-               if (!access_ok(is_in ? VERIFY_WRITE : VERIFY_READ,
-                               uurb->buffer, uurb->buffer_length)) {
-                       kfree(dr);
-                       return -EFAULT;
-               }
                snoop(&ps->dev->dev, "control urb: bRequest=%02x "
                        "bRrequestType=%02x wValue=%04x "
                        "wIndex=%04x wLength=%04x\n",
@@ -1062,9 +1070,6 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb,
                uurb->number_of_packets = 0;
                if (uurb->buffer_length > MAX_USBFS_BUFFER_SIZE)
                        return -EINVAL;
-               if (!access_ok(is_in ? VERIFY_WRITE : VERIFY_READ,
-                               uurb->buffer, uurb->buffer_length))
-                       return -EFAULT;
                snoop(&ps->dev->dev, "bulk urb\n");
                break;
 
@@ -1106,28 +1111,35 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb,
                        return -EINVAL;
                if (uurb->buffer_length > MAX_USBFS_BUFFER_SIZE)
                        return -EINVAL;
-               if (!access_ok(is_in ? VERIFY_WRITE : VERIFY_READ,
-                               uurb->buffer, uurb->buffer_length))
-                       return -EFAULT;
                snoop(&ps->dev->dev, "interrupt urb\n");
                break;
 
        default:
                return -EINVAL;
        }
-       as = alloc_async(uurb->number_of_packets);
-       if (!as) {
+       if (uurb->buffer_length > 0 &&
+                       !access_ok(is_in ? VERIFY_WRITE : VERIFY_READ,
+                               uurb->buffer, uurb->buffer_length)) {
                kfree(isopkt);
                kfree(dr);
-               return -ENOMEM;
+               return -EFAULT;
        }
-       as->urb->transfer_buffer = kmalloc(uurb->buffer_length, GFP_KERNEL);
-       if (!as->urb->transfer_buffer) {
+       as = alloc_async(uurb->number_of_packets);
+       if (!as) {
                kfree(isopkt);
                kfree(dr);
-               free_async(as);
                return -ENOMEM;
        }
+       if (uurb->buffer_length > 0) {
+               as->urb->transfer_buffer = kmalloc(uurb->buffer_length,
+                               GFP_KERNEL);
+               if (!as->urb->transfer_buffer) {
+                       kfree(isopkt);
+                       kfree(dr);
+                       free_async(as);
+                       return -ENOMEM;
+               }
+       }
        as->urb->dev = ps->dev;
        as->urb->pipe = (uurb->type << 30) |
                        __create_pipe(ps->dev, uurb->endpoint & 0xf) |
@@ -1169,7 +1181,7 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb,
        kfree(isopkt);
        as->ps = ps;
        as->userurb = arg;
-       if (uurb->endpoint & USB_DIR_IN)
+       if (is_in && uurb->buffer_length > 0)
                as->userbuffer = uurb->buffer;
        else
                as->userbuffer = NULL;
@@ -1179,9 +1191,9 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb,
        as->uid = cred->uid;
        as->euid = cred->euid;
        security_task_getsecid(current, &as->secid);
-       if (!is_in) {
+       if (!is_in && uurb->buffer_length > 0) {
                if (copy_from_user(as->urb->transfer_buffer, uurb->buffer,
-                               as->urb->transfer_buffer_length)) {
+                               uurb->buffer_length)) {
                        free_async(as);
                        return -EFAULT;
                }
@@ -1231,22 +1243,22 @@ static int processcompl(struct async *as, void __user * __user *arg)
        if (as->userbuffer)
                if (copy_to_user(as->userbuffer, urb->transfer_buffer,
                                 urb->transfer_buffer_length))
-                       return -EFAULT;
+                       goto err_out;
        if (put_user(as->status, &userurb->status))
-               return -EFAULT;
+               goto err_out;
        if (put_user(urb->actual_length, &userurb->actual_length))
-               return -EFAULT;
+               goto err_out;
        if (put_user(urb->error_count, &userurb->error_count))
-               return -EFAULT;
+               goto err_out;
 
        if (usb_endpoint_xfer_isoc(&urb->ep->desc)) {
                for (i = 0; i < urb->number_of_packets; i++) {
                        if (put_user(urb->iso_frame_desc[i].actual_length,
                                     &userurb->iso_frame_desc[i].actual_length))
-                               return -EFAULT;
+                               goto err_out;
                        if (put_user(urb->iso_frame_desc[i].status,
                                     &userurb->iso_frame_desc[i].status))
-                               return -EFAULT;
+                               goto err_out;
                }
        }
 
@@ -1255,6 +1267,10 @@ static int processcompl(struct async *as, void __user * __user *arg)
        if (put_user(addr, (void __user * __user *)arg))
                return -EFAULT;
        return 0;
+
+err_out:
+       free_async(as);
+       return -EFAULT;
 }
 
 static struct async *reap_as(struct dev_state *ps)
index ce3f453f02ef5efe5b5034f3bedfa5a062e0db25..95ccfa0b9fc52876f5166b3edea039409adf9a33 100644 (file)
@@ -648,7 +648,7 @@ void usb_hcd_poll_rh_status(struct usb_hcd *hcd)
        struct urb      *urb;
        int             length;
        unsigned long   flags;
-       char            buffer[4];      /* Any root hubs with > 31 ports? */
+       char            buffer[6];      /* Any root hubs with > 31 ports? */
 
        if (unlikely(!hcd->rh_registered))
                return;
index d397ecfd5b178d881f97c72e51989bfccbe2a064..ec5c67ea07b745a95b92e8db88349abadc1bbca1 100644 (file)
@@ -227,6 +227,10 @@ struct hc_driver {
                /* has a port been handed over to a companion? */
        int     (*port_handed_over)(struct usb_hcd *, int);
 
+               /* CLEAR_TT_BUFFER completion callback */
+       void    (*clear_tt_buffer_complete)(struct usb_hcd *,
+                               struct usb_host_endpoint *);
+
        /* xHCI specific functions */
                /* Called by usb_alloc_dev to alloc HC device structures */
        int     (*alloc_dev)(struct usb_hcd *, struct usb_device *);
index 2af3b4f0605405dd723b1ccd4f853f7f85dc1848..71f86c60d83c3962cf8b7eabe1d709d2d87b7a76 100644 (file)
@@ -450,10 +450,10 @@ hub_clear_tt_buffer (struct usb_device *hdev, u16 devinfo, u16 tt)
  * talking to TTs must queue control transfers (not just bulk and iso), so
  * both can talk to the same hub concurrently.
  */
-static void hub_tt_kevent (struct work_struct *work)
+static void hub_tt_work(struct work_struct *work)
 {
        struct usb_hub          *hub =
-               container_of(work, struct usb_hub, tt.kevent);
+               container_of(work, struct usb_hub, tt.clear_work);
        unsigned long           flags;
        int                     limit = 100;
 
@@ -462,6 +462,7 @@ static void hub_tt_kevent (struct work_struct *work)
                struct list_head        *next;
                struct usb_tt_clear     *clear;
                struct usb_device       *hdev = hub->hdev;
+               const struct hc_driver  *drv;
                int                     status;
 
                next = hub->tt.clear_list.next;
@@ -471,21 +472,25 @@ static void hub_tt_kevent (struct work_struct *work)
                /* drop lock so HCD can concurrently report other TT errors */
                spin_unlock_irqrestore (&hub->tt.lock, flags);
                status = hub_clear_tt_buffer (hdev, clear->devinfo, clear->tt);
-               spin_lock_irqsave (&hub->tt.lock, flags);
-
                if (status)
                        dev_err (&hdev->dev,
                                "clear tt %d (%04x) error %d\n",
                                clear->tt, clear->devinfo, status);
+
+               /* Tell the HCD, even if the operation failed */
+               drv = clear->hcd->driver;
+               if (drv->clear_tt_buffer_complete)
+                       (drv->clear_tt_buffer_complete)(clear->hcd, clear->ep);
+
                kfree(clear);
+               spin_lock_irqsave(&hub->tt.lock, flags);
        }
        spin_unlock_irqrestore (&hub->tt.lock, flags);
 }
 
 /**
- * usb_hub_tt_clear_buffer - clear control/bulk TT state in high speed hub
- * @udev: the device whose split transaction failed
- * @pipe: identifies the endpoint of the failed transaction
+ * usb_hub_clear_tt_buffer - clear control/bulk TT state in high speed hub
+ * @urb: an URB associated with the failed or incomplete split transaction
  *
  * High speed HCDs use this to tell the hub driver that some split control or
  * bulk transaction failed in a way that requires clearing internal state of
@@ -495,8 +500,10 @@ static void hub_tt_kevent (struct work_struct *work)
  * It may not be possible for that hub to handle additional full (or low)
  * speed transactions until that state is fully cleared out.
  */
-void usb_hub_tt_clear_buffer (struct usb_device *udev, int pipe)
+int usb_hub_clear_tt_buffer(struct urb *urb)
 {
+       struct usb_device       *udev = urb->dev;
+       int                     pipe = urb->pipe;
        struct usb_tt           *tt = udev->tt;
        unsigned long           flags;
        struct usb_tt_clear     *clear;
@@ -508,7 +515,7 @@ void usb_hub_tt_clear_buffer (struct usb_device *udev, int pipe)
        if ((clear = kmalloc (sizeof *clear, GFP_ATOMIC)) == NULL) {
                dev_err (&udev->dev, "can't save CLEAR_TT_BUFFER state\n");
                /* FIXME recover somehow ... RESET_TT? */
-               return;
+               return -ENOMEM;
        }
 
        /* info that CLEAR_TT_BUFFER needs */
@@ -520,14 +527,19 @@ void usb_hub_tt_clear_buffer (struct usb_device *udev, int pipe)
                        : (USB_ENDPOINT_XFER_BULK << 11);
        if (usb_pipein (pipe))
                clear->devinfo |= 1 << 15;
-       
+
+       /* info for completion callback */
+       clear->hcd = bus_to_hcd(udev->bus);
+       clear->ep = urb->ep;
+
        /* tell keventd to clear state for this TT */
        spin_lock_irqsave (&tt->lock, flags);
        list_add_tail (&clear->clear_list, &tt->clear_list);
-       schedule_work (&tt->kevent);
+       schedule_work(&tt->clear_work);
        spin_unlock_irqrestore (&tt->lock, flags);
+       return 0;
 }
-EXPORT_SYMBOL_GPL(usb_hub_tt_clear_buffer);
+EXPORT_SYMBOL_GPL(usb_hub_clear_tt_buffer);
 
 /* If do_delay is false, return the number of milliseconds the caller
  * needs to delay.
@@ -818,7 +830,7 @@ static void hub_quiesce(struct usb_hub *hub, enum hub_quiescing_type type)
        if (hub->has_indicators)
                cancel_delayed_work_sync(&hub->leds);
        if (hub->tt.hub)
-               cancel_work_sync(&hub->tt.kevent);
+               cancel_work_sync(&hub->tt.clear_work);
 }
 
 /* caller has locked the hub device */
@@ -935,7 +947,7 @@ static int hub_configure(struct usb_hub *hub,
 
        spin_lock_init (&hub->tt.lock);
        INIT_LIST_HEAD (&hub->tt.clear_list);
-       INIT_WORK (&hub->tt.kevent, hub_tt_kevent);
+       INIT_WORK(&hub->tt.clear_work, hub_tt_work);
        switch (hdev->descriptor.bDeviceProtocol) {
                case 0:
                        break;
index 889c0f32a40b729431f2dab51d13aead39f5f3e8..de8081f065edda76ae95a415b98c6db86a0d9a57 100644 (file)
@@ -188,16 +188,18 @@ struct usb_tt {
        /* for control/bulk error recovery (CLEAR_TT_BUFFER) */
        spinlock_t              lock;
        struct list_head        clear_list;     /* of usb_tt_clear */
-       struct work_struct                      kevent;
+       struct work_struct      clear_work;
 };
 
 struct usb_tt_clear {
        struct list_head        clear_list;
        unsigned                tt;
        u16                     devinfo;
+       struct usb_hcd          *hcd;
+       struct usb_host_endpoint        *ep;
 };
 
-extern void usb_hub_tt_clear_buffer(struct usb_device *dev, int pipe);
+extern int usb_hub_clear_tt_buffer(struct urb *urb);
 extern void usb_ep0_reinit(struct usb_device *);
 
 #endif /* __LINUX_HUB_H */
index 2bed83caacb1a0c714a2e05af21242bbb504dcad..9720e699f4729737cbdd90946f234e567fc0d874 100644 (file)
@@ -806,6 +806,48 @@ static int usb_string_sub(struct usb_device *dev, unsigned int langid,
        return rc;
 }
 
+static int usb_get_langid(struct usb_device *dev, unsigned char *tbuf)
+{
+       int err;
+
+       if (dev->have_langid)
+               return 0;
+
+       if (dev->string_langid < 0)
+               return -EPIPE;
+
+       err = usb_string_sub(dev, 0, 0, tbuf);
+
+       /* If the string was reported but is malformed, default to english
+        * (0x0409) */
+       if (err == -ENODATA || (err > 0 && err < 4)) {
+               dev->string_langid = 0x0409;
+               dev->have_langid = 1;
+               dev_err(&dev->dev,
+                       "string descriptor 0 malformed (err = %d), "
+                       "defaulting to 0x%04x\n",
+                               err, dev->string_langid);
+               return 0;
+       }
+
+       /* In case of all other errors, we assume the device is not able to
+        * deal with strings at all. Set string_langid to -1 in order to
+        * prevent any string to be retrieved from the device */
+       if (err < 0) {
+               dev_err(&dev->dev, "string descriptor 0 read error: %d\n",
+                                       err);
+               dev->string_langid = -1;
+               return -EPIPE;
+       }
+
+       /* always use the first langid listed */
+       dev->string_langid = tbuf[2] | (tbuf[3] << 8);
+       dev->have_langid = 1;
+       dev_dbg(&dev->dev, "default language 0x%04x\n",
+                               dev->string_langid);
+       return 0;
+}
+
 /**
  * usb_string - returns UTF-8 version of a string descriptor
  * @dev: the device whose string descriptor is being retrieved
@@ -837,24 +879,9 @@ int usb_string(struct usb_device *dev, int index, char *buf, size_t size)
        if (!tbuf)
                return -ENOMEM;
 
-       /* get langid for strings if it's not yet known */
-       if (!dev->have_langid) {
-               err = usb_string_sub(dev, 0, 0, tbuf);
-               if (err < 0) {
-                       dev_err(&dev->dev,
-                               "string descriptor 0 read error: %d\n",
-                               err);
-               } else if (err < 4) {
-                       dev_err(&dev->dev, "string descriptor 0 too short\n");
-               } else {
-                       dev->string_langid = tbuf[2] | (tbuf[3] << 8);
-                       /* always use the first langid listed */
-                       dev_dbg(&dev->dev, "default language 0x%04x\n",
-                               dev->string_langid);
-               }
-
-               dev->have_langid = 1;
-       }
+       err = usb_get_langid(dev, tbuf);
+       if (err < 0)
+               goto errout;
 
        err = usb_string_sub(dev, dev->string_langid, index, tbuf);
        if (err < 0)
index 5d1ddf485d1eb6d5d55e12a4eca7536e10a75838..7f8e83a954ac6881861bdc0d2e334ea85944db7a 100644 (file)
@@ -286,6 +286,27 @@ config USB_S3C_HSOTG
        default USB_GADGET
        select USB_GADGET_SELECTED
 
+config USB_GADGET_IMX
+       boolean "Freescale IMX USB Peripheral Controller"
+       depends on ARCH_MX1
+       help
+          Freescale's IMX series include an integrated full speed
+          USB 1.1 device controller.  The controller in the IMX series
+          is register-compatible.
+
+          It has Six fixed-function endpoints, as well as endpoint
+          zero (for control transfers).
+
+          Say "y" to link the driver statically, or "m" to build a
+          dynamically linked module called "imx_udc" and force all
+          gadget drivers to also be dynamically linked.
+
+config USB_IMX
+       tristate
+       depends on USB_GADGET_IMX
+       default USB_GADGET
+       select USB_GADGET_SELECTED
+
 config USB_GADGET_S3C2410
        boolean "S3C2410 USB Device Controller"
        depends on ARCH_S3C2410
@@ -321,27 +342,6 @@ config USB_GADGET_MUSB_HDRC
          This OTG-capable silicon IP is used in dual designs including
          the TI DaVinci, OMAP 243x, OMAP 343x, TUSB 6010, and ADI Blackfin
 
-config USB_GADGET_IMX
-       boolean "Freescale IMX USB Peripheral Controller"
-       depends on ARCH_MX1
-       help
-          Freescale's IMX series include an integrated full speed
-          USB 1.1 device controller.  The controller in the IMX series
-          is register-compatible.
-
-          It has Six fixed-function endpoints, as well as endpoint
-          zero (for control transfers).
-
-          Say "y" to link the driver statically, or "m" to build a
-          dynamically linked module called "imx_udc" and force all
-          gadget drivers to also be dynamically linked.
-
-config USB_IMX
-       tristate
-       depends on USB_GADGET_IMX
-       default USB_GADGET
-       select USB_GADGET_SELECTED
-
 config USB_GADGET_M66592
        boolean "Renesas M66592 USB Peripheral Controller"
        select USB_GADGET_DUALSPEED
@@ -604,6 +604,7 @@ config USB_ZERO_HNPTEST
 config USB_AUDIO
        tristate "Audio Gadget (EXPERIMENTAL)"
        depends on SND
+       select SND_PCM
        help
          Gadget Audio is compatible with USB Audio Class specification 1.0.
          It will include at least one AudioControl interface, zero or more
index 826f3adde5d8a4ac0df29265d88cadd1ab541d05..77352ccc245e0ab3a456b22ce0ed6a8b2f7e411b 100644 (file)
@@ -48,7 +48,6 @@
 #include <linux/ioport.h>
 #include <linux/sched.h>
 #include <linux/slab.h>
-#include <linux/smp_lock.h>
 #include <linux/errno.h>
 #include <linux/init.h>
 #include <linux/timer.h>
index 94de7e864614961f322412d2855289041fdda22e..9f80f4e970bd00693cf3140483940eb46843cdef 100644 (file)
@@ -42,9 +42,9 @@
  * Instead:  allocate your own, using normal USB-IF procedures.
  */
 
-/* Thanks to NetChip Technologies for donating this product ID. */
-#define AUDIO_VENDOR_NUM               0x0525  /* NetChip */
-#define AUDIO_PRODUCT_NUM              0xa4a1  /* Linux-USB Audio Gadget */
+/* Thanks to Linux Foundation for donating this product ID. */
+#define AUDIO_VENDOR_NUM               0x1d6b  /* Linux Foundation */
+#define AUDIO_PRODUCT_NUM              0x0101  /* Linux-USB Audio Gadget */
 
 /*-------------------------------------------------------------------------*/
 
index d006dc652e025558e3157691b0f855b43452a6ad..bd102f5052ba67453c3a2dd30a2eefde46ce59ee 100644 (file)
@@ -293,15 +293,16 @@ static int __init eth_bind(struct usb_composite_dev *cdev)
                /* CDC Subset */
                eth_config_driver.label = "CDC Subset/SAFE";
 
-               device_desc.idVendor = cpu_to_le16(SIMPLE_VENDOR_NUM),
-               device_desc.idProduct = cpu_to_le16(SIMPLE_PRODUCT_NUM),
-               device_desc.bDeviceClass = USB_CLASS_VENDOR_SPEC;
+               device_desc.idVendor = cpu_to_le16(SIMPLE_VENDOR_NUM);
+               device_desc.idProduct = cpu_to_le16(SIMPLE_PRODUCT_NUM);
+               if (!has_rndis())
+                       device_desc.bDeviceClass = USB_CLASS_VENDOR_SPEC;
        }
 
        if (has_rndis()) {
                /* RNDIS plus ECM-or-Subset */
-               device_desc.idVendor = cpu_to_le16(RNDIS_VENDOR_NUM),
-               device_desc.idProduct = cpu_to_le16(RNDIS_PRODUCT_NUM),
+               device_desc.idVendor = cpu_to_le16(RNDIS_VENDOR_NUM);
+               device_desc.idProduct = cpu_to_le16(RNDIS_PRODUCT_NUM);
                device_desc.bNumConfigurations = 2;
        }
 
index 6829d5961359278745a63d0f3ef73cb68c5164ab..a3913519fd5841cefc0718639af38b2bbf62ae40 100644 (file)
@@ -34,7 +34,6 @@
 #include <linux/ioport.h>
 #include <linux/sched.h>
 #include <linux/slab.h>
-#include <linux/smp_lock.h>
 #include <linux/errno.h>
 #include <linux/init.h>
 #include <linux/timer.h>
index 0ce4e2819847c13fb7548fcf910923495d4588ba..ed21e263f832f05d977aa4c4acd41881dd013002 100644 (file)
@@ -139,7 +139,7 @@ static int is_vbus_present(void)
 {
        struct pxa2xx_udc_mach_info             *mach = the_controller->mach;
 
-       if (mach->gpio_vbus) {
+       if (gpio_is_valid(mach->gpio_vbus)) {
                int value = gpio_get_value(mach->gpio_vbus);
 
                if (mach->gpio_vbus_inverted)
@@ -158,7 +158,7 @@ static void pullup_off(void)
        struct pxa2xx_udc_mach_info             *mach = the_controller->mach;
        int off_level = mach->gpio_pullup_inverted;
 
-       if (mach->gpio_pullup)
+       if (gpio_is_valid(mach->gpio_pullup))
                gpio_set_value(mach->gpio_pullup, off_level);
        else if (mach->udc_command)
                mach->udc_command(PXA2XX_UDC_CMD_DISCONNECT);
@@ -169,7 +169,7 @@ static void pullup_on(void)
        struct pxa2xx_udc_mach_info             *mach = the_controller->mach;
        int on_level = !mach->gpio_pullup_inverted;
 
-       if (mach->gpio_pullup)
+       if (gpio_is_valid(mach->gpio_pullup))
                gpio_set_value(mach->gpio_pullup, on_level);
        else if (mach->udc_command)
                mach->udc_command(PXA2XX_UDC_CMD_CONNECT);
@@ -1000,7 +1000,7 @@ static int pxa25x_udc_pullup(struct usb_gadget *_gadget, int is_active)
        udc = container_of(_gadget, struct pxa25x_udc, gadget);
 
        /* not all boards support pullup control */
-       if (!udc->mach->gpio_pullup && !udc->mach->udc_command)
+       if (!gpio_is_valid(udc->mach->gpio_pullup) && !udc->mach->udc_command)
                return -EOPNOTSUPP;
 
        udc->pullup = (is_active != 0);
@@ -1802,11 +1802,13 @@ pxa25x_udc_irq(int irq, void *_dev)
                                        USIR0 |= tmp;
                                        handled = 1;
                                }
+#ifndef        CONFIG_USB_PXA25X_SMALL
                                if (usir1 & tmp) {
                                        handle_ep(&dev->ep[i+8]);
                                        USIR1 |= tmp;
                                        handled = 1;
                                }
+#endif
                        }
                }
 
@@ -2160,7 +2162,7 @@ static int __init pxa25x_udc_probe(struct platform_device *pdev)
        dev->dev = &pdev->dev;
        dev->mach = pdev->dev.platform_data;
 
-       if (dev->mach->gpio_vbus) {
+       if (gpio_is_valid(dev->mach->gpio_vbus)) {
                if ((retval = gpio_request(dev->mach->gpio_vbus,
                                "pxa25x_udc GPIO VBUS"))) {
                        dev_dbg(&pdev->dev,
@@ -2173,7 +2175,7 @@ static int __init pxa25x_udc_probe(struct platform_device *pdev)
        } else
                vbus_irq = 0;
 
-       if (dev->mach->gpio_pullup) {
+       if (gpio_is_valid(dev->mach->gpio_pullup)) {
                if ((retval = gpio_request(dev->mach->gpio_pullup,
                                "pca25x_udc GPIO PULLUP"))) {
                        dev_dbg(&pdev->dev,
@@ -2256,10 +2258,10 @@ lubbock_fail0:
 #endif
        free_irq(irq, dev);
  err_irq1:
-       if (dev->mach->gpio_pullup)
+       if (gpio_is_valid(dev->mach->gpio_pullup))
                gpio_free(dev->mach->gpio_pullup);
  err_gpio_pullup:
-       if (dev->mach->gpio_vbus)
+       if (gpio_is_valid(dev->mach->gpio_vbus))
                gpio_free(dev->mach->gpio_vbus);
  err_gpio_vbus:
        clk_put(dev->clk);
@@ -2294,11 +2296,11 @@ static int __exit pxa25x_udc_remove(struct platform_device *pdev)
                free_irq(LUBBOCK_USB_IRQ, dev);
        }
 #endif
-       if (dev->mach->gpio_vbus) {
+       if (gpio_is_valid(dev->mach->gpio_vbus)) {
                free_irq(gpio_to_irq(dev->mach->gpio_vbus), dev);
                gpio_free(dev->mach->gpio_vbus);
        }
-       if (dev->mach->gpio_pullup)
+       if (gpio_is_valid(dev->mach->gpio_pullup))
                gpio_free(dev->mach->gpio_pullup);
 
        clk_put(dev->clk);
@@ -2329,7 +2331,7 @@ static int pxa25x_udc_suspend(struct platform_device *dev, pm_message_t state)
        struct pxa25x_udc       *udc = platform_get_drvdata(dev);
        unsigned long flags;
 
-       if (!udc->mach->gpio_pullup && !udc->mach->udc_command)
+       if (!gpio_is_valid(udc->mach->gpio_pullup) && !udc->mach->udc_command)
                WARNING("USB host won't detect disconnect!\n");
        udc->suspended = 1;
 
index 2b4660e08c4db367af0e6c5159855b675616eb9a..ca41b0b5afb352233e86c5ccbd45dace08f4431a 100644 (file)
@@ -442,6 +442,8 @@ gen_ndis_query_resp (int configNr, u32 OID, u8 *buf, unsigned buf_len,
 
        case OID_802_3_MAC_OPTIONS:
                pr_debug("%s: OID_802_3_MAC_OPTIONS\n", __func__);
+               *outbuf = cpu_to_le32(0);
+               retval = 0;
                break;
 
        /* ieee802.3 statistics OIDs (table 4-4) */
index 9a2b8920532d0ad0fa248a7ca073051d55be8405..a9b452fe622195ad832acdc78fba40759218f820 100644 (file)
@@ -28,7 +28,6 @@
 #include <linux/ioport.h>
 #include <linux/sched.h>
 #include <linux/slab.h>
-#include <linux/smp_lock.h>
 #include <linux/errno.h>
 #include <linux/init.h>
 #include <linux/timer.h>
index 1576a0520adf35ba813ef9ebd30cd8fb28f16e62..1a920c70b5a150f0a2670f8d170d579c582544ac 100644 (file)
@@ -181,26 +181,27 @@ config USB_OHCI_HCD_PPC_SOC
          Enables support for the USB controller on the MPC52xx or
          STB03xxx processor chip.  If unsure, say Y.
 
-config USB_OHCI_HCD_PPC_OF
-       bool "OHCI support for PPC USB controller on OF platform bus"
-       depends on USB_OHCI_HCD && PPC_OF
-       default y
-       ---help---
-         Enables support for the USB controller PowerPC present on the
-         OpenFirmware platform bus.
-
 config USB_OHCI_HCD_PPC_OF_BE
-       bool "Support big endian HC"
-       depends on USB_OHCI_HCD_PPC_OF
-       default y
+       bool "OHCI support for OF platform bus (big endian)"
+       depends on USB_OHCI_HCD && PPC_OF
        select USB_OHCI_BIG_ENDIAN_DESC
        select USB_OHCI_BIG_ENDIAN_MMIO
+       ---help---
+         Enables support for big-endian USB controllers present on the
+         OpenFirmware platform bus.
 
 config USB_OHCI_HCD_PPC_OF_LE
-       bool "Support little endian HC"
-       depends on USB_OHCI_HCD_PPC_OF
-       default n
+       bool "OHCI support for OF platform bus (little endian)"
+       depends on USB_OHCI_HCD && PPC_OF
        select USB_OHCI_LITTLE_ENDIAN
+       ---help---
+         Enables support for little-endian USB controllers present on the
+         OpenFirmware platform bus.
+
+config USB_OHCI_HCD_PPC_OF
+       bool
+       depends on USB_OHCI_HCD && PPC_OF
+       default USB_OHCI_HCD_PPC_OF_BE || USB_OHCI_HCD_PPC_OF_LE
 
 config USB_OHCI_HCD_PCI
        bool "OHCI support for PCI-bus USB controllers"
@@ -337,10 +338,10 @@ config USB_R8A66597_HCD
 
 config SUPERH_ON_CHIP_R8A66597
        boolean "Enable SuperH on-chip R8A66597 USB"
-       depends on USB_R8A66597_HCD && (CPU_SUBTYPE_SH7366 || CPU_SUBTYPE_SH7723)
+       depends on USB_R8A66597_HCD && (CPU_SUBTYPE_SH7366 || CPU_SUBTYPE_SH7723 || CPU_SUBTYPE_SH7724)
        help
           This driver enables support for the on-chip R8A66597 in the
-          SH7366 and SH7723 processors.
+          SH7366, SH7723 and SH7724 processors.
 
 config USB_WHCI_HCD
        tristate "Wireless USB Host Controller Interface (WHCI) driver (EXPERIMENTAL)"
index c3a778bd359c9b883bd6e361e78951818fd3a280..59d208d94d4e772d5b1a8cc6f8a009d94132625f 100644 (file)
@@ -113,6 +113,8 @@ static const struct hc_driver ehci_au1xxx_hc_driver = {
        .bus_resume             = ehci_bus_resume,
        .relinquish_port        = ehci_relinquish_port,
        .port_handed_over       = ehci_port_handed_over,
+
+       .clear_tt_buffer_complete       = ehci_clear_tt_buffer_complete,
 };
 
 static int ehci_hcd_au1xxx_drv_probe(struct platform_device *pdev)
index bf86809c5120795eac8521b68e2159d2fef37127..991174937db31ed5d829d6e1fdc0b3ea024e47bd 100644 (file)
@@ -325,6 +325,8 @@ static const struct hc_driver ehci_fsl_hc_driver = {
        .bus_resume = ehci_bus_resume,
        .relinquish_port = ehci_relinquish_port,
        .port_handed_over = ehci_port_handed_over,
+
+       .clear_tt_buffer_complete = ehci_clear_tt_buffer_complete,
 };
 
 static int ehci_fsl_drv_probe(struct platform_device *pdev)
index 2b72473544d31d798034ed5aa92cb555384a8055..7d03549c3339ecc5ebdc5025db1d9f3b6d42f148 100644 (file)
@@ -1003,6 +1003,8 @@ idle_timeout:
                schedule_timeout_uninterruptible(1);
                goto rescan;
        case QH_STATE_IDLE:             /* fully unlinked */
+               if (qh->clearing_tt)
+                       goto idle_timeout;
                if (list_empty (&qh->qtd_list)) {
                        qh_put (qh);
                        break;
@@ -1030,12 +1032,14 @@ ehci_endpoint_reset(struct usb_hcd *hcd, struct usb_host_endpoint *ep)
        struct ehci_hcd         *ehci = hcd_to_ehci(hcd);
        struct ehci_qh          *qh;
        int                     eptype = usb_endpoint_type(&ep->desc);
+       int                     epnum = usb_endpoint_num(&ep->desc);
+       int                     is_out = usb_endpoint_dir_out(&ep->desc);
+       unsigned long           flags;
 
        if (eptype != USB_ENDPOINT_XFER_BULK && eptype != USB_ENDPOINT_XFER_INT)
                return;
 
- rescan:
-       spin_lock_irq(&ehci->lock);
+       spin_lock_irqsave(&ehci->lock, flags);
        qh = ep->hcpriv;
 
        /* For Bulk and Interrupt endpoints we maintain the toggle state
@@ -1044,29 +1048,24 @@ ehci_endpoint_reset(struct usb_hcd *hcd, struct usb_host_endpoint *ep)
         * the toggle bit in the QH.
         */
        if (qh) {
+               usb_settoggle(qh->dev, epnum, is_out, 0);
                if (!list_empty(&qh->qtd_list)) {
                        WARN_ONCE(1, "clear_halt for a busy endpoint\n");
-               } else if (qh->qh_state == QH_STATE_IDLE) {
-                       qh->hw_token &= ~cpu_to_hc32(ehci, QTD_TOGGLE);
-               } else {
-                       /* It's not safe to write into the overlay area
-                        * while the QH is active.  Unlink it first and
-                        * wait for the unlink to complete.
+               } else if (qh->qh_state == QH_STATE_LINKED) {
+
+                       /* The toggle value in the QH can't be updated
+                        * while the QH is active.  Unlink it now;
+                        * re-linking will call qh_refresh().
                         */
-                       if (qh->qh_state == QH_STATE_LINKED) {
-                               if (eptype == USB_ENDPOINT_XFER_BULK) {
-                                       unlink_async(ehci, qh);
-                               } else {
-                                       intr_deschedule(ehci, qh);
-                                       (void) qh_schedule(ehci, qh);
-                               }
+                       if (eptype == USB_ENDPOINT_XFER_BULK) {
+                               unlink_async(ehci, qh);
+                       } else {
+                               intr_deschedule(ehci, qh);
+                               (void) qh_schedule(ehci, qh);
                        }
-                       spin_unlock_irq(&ehci->lock);
-                       schedule_timeout_uninterruptible(1);
-                       goto rescan;
                }
        }
-       spin_unlock_irq(&ehci->lock);
+       spin_unlock_irqrestore(&ehci->lock, flags);
 }
 
 static int ehci_get_frame (struct usb_hcd *hcd)
index a44bb4a949543d797f336827edb8ac6fa088d8ac..89b7c70c6ed6f015077a6a0233b78b080f581043 100644 (file)
@@ -61,6 +61,8 @@ static const struct hc_driver ixp4xx_ehci_hc_driver = {
 #endif
        .relinquish_port        = ehci_relinquish_port,
        .port_handed_over       = ehci_port_handed_over,
+
+       .clear_tt_buffer_complete       = ehci_clear_tt_buffer_complete,
 };
 
 static int ixp4xx_ehci_probe(struct platform_device *pdev)
index 770dd9aba62a9f07aabd9863e59fc4acae6a81dd..dc2ac613a9d1c34e2942ff55bf639fcb9d0be29b 100644 (file)
@@ -165,6 +165,8 @@ static const struct hc_driver ehci_orion_hc_driver = {
        .bus_resume = ehci_bus_resume,
        .relinquish_port = ehci_relinquish_port,
        .port_handed_over = ehci_port_handed_over,
+
+       .clear_tt_buffer_complete = ehci_clear_tt_buffer_complete,
 };
 
 static void __init
index f3683e1da16134b3c20a6239b5edfd406af923aa..c2f1b7df918cd52ddd62385e3f02f5696d7f6f06 100644 (file)
@@ -404,6 +404,8 @@ static const struct hc_driver ehci_pci_hc_driver = {
        .bus_resume =           ehci_bus_resume,
        .relinquish_port =      ehci_relinquish_port,
        .port_handed_over =     ehci_port_handed_over,
+
+       .clear_tt_buffer_complete       = ehci_clear_tt_buffer_complete,
 };
 
 /*-------------------------------------------------------------------------*/
index fbd272288fc2cf799ef1d075adea282dd01aa863..36f96da129f5c637208031ec04913be3f0cc6e67 100644 (file)
@@ -79,6 +79,8 @@ static const struct hc_driver ehci_ppc_of_hc_driver = {
 #endif
        .relinquish_port        = ehci_relinquish_port,
        .port_handed_over       = ehci_port_handed_over,
+
+       .clear_tt_buffer_complete       = ehci_clear_tt_buffer_complete,
 };
 
 
index 93f7035d00a16ad1da984e9f1b81c521afa79cba..1dee33b9139e65d1f8714234c7ecde9e7b3d0d24 100644 (file)
@@ -75,6 +75,8 @@ static const struct hc_driver ps3_ehci_hc_driver = {
 #endif
        .relinquish_port        = ehci_relinquish_port,
        .port_handed_over       = ehci_port_handed_over,
+
+       .clear_tt_buffer_complete       = ehci_clear_tt_buffer_complete,
 };
 
 static int __devinit ps3_ehci_probe(struct ps3_system_bus_device *dev)
index 3192f683f8073293a6366b532ced3ff0dd5007f1..9a1384747f3bc8ca092b226d6de8fed5d6850276 100644 (file)
@@ -93,6 +93,22 @@ qh_update (struct ehci_hcd *ehci, struct ehci_qh *qh, struct ehci_qtd *qtd)
        qh->hw_qtd_next = QTD_NEXT(ehci, qtd->qtd_dma);
        qh->hw_alt_next = EHCI_LIST_END(ehci);
 
+       /* Except for control endpoints, we make hardware maintain data
+        * toggle (like OHCI) ... here (re)initialize the toggle in the QH,
+        * and set the pseudo-toggle in udev. Only usb_clear_halt() will
+        * ever clear it.
+        */
+       if (!(qh->hw_info1 & cpu_to_hc32(ehci, 1 << 14))) {
+               unsigned        is_out, epnum;
+
+               is_out = !(qtd->hw_token & cpu_to_hc32(ehci, 1 << 8));
+               epnum = (hc32_to_cpup(ehci, &qh->hw_info1) >> 8) & 0x0f;
+               if (unlikely (!usb_gettoggle (qh->dev, epnum, is_out))) {
+                       qh->hw_token &= ~cpu_to_hc32(ehci, QTD_TOGGLE);
+                       usb_settoggle (qh->dev, epnum, is_out, 1);
+               }
+       }
+
        /* HC must see latest qtd and qh data before we clear ACTIVE+HALT */
        wmb ();
        qh->hw_token &= cpu_to_hc32(ehci, QTD_TOGGLE | QTD_STS_PING);
@@ -123,6 +139,55 @@ qh_refresh (struct ehci_hcd *ehci, struct ehci_qh *qh)
 
 /*-------------------------------------------------------------------------*/
 
+static void qh_link_async(struct ehci_hcd *ehci, struct ehci_qh *qh);
+
+static void ehci_clear_tt_buffer_complete(struct usb_hcd *hcd,
+               struct usb_host_endpoint *ep)
+{
+       struct ehci_hcd         *ehci = hcd_to_ehci(hcd);
+       struct ehci_qh          *qh = ep->hcpriv;
+       unsigned long           flags;
+
+       spin_lock_irqsave(&ehci->lock, flags);
+       qh->clearing_tt = 0;
+       if (qh->qh_state == QH_STATE_IDLE && !list_empty(&qh->qtd_list)
+                       && HC_IS_RUNNING(hcd->state))
+               qh_link_async(ehci, qh);
+       spin_unlock_irqrestore(&ehci->lock, flags);
+}
+
+static void ehci_clear_tt_buffer(struct ehci_hcd *ehci, struct ehci_qh *qh,
+               struct urb *urb, u32 token)
+{
+
+       /* If an async split transaction gets an error or is unlinked,
+        * the TT buffer may be left in an indeterminate state.  We
+        * have to clear the TT buffer.
+        *
+        * Note: this routine is never called for Isochronous transfers.
+        */
+       if (urb->dev->tt && !usb_pipeint(urb->pipe) && !qh->clearing_tt) {
+#ifdef DEBUG
+               struct usb_device *tt = urb->dev->tt->hub;
+               dev_dbg(&tt->dev,
+                       "clear tt buffer port %d, a%d ep%d t%08x\n",
+                       urb->dev->ttport, urb->dev->devnum,
+                       usb_pipeendpoint(urb->pipe), token);
+#endif /* DEBUG */
+               if (!ehci_is_TDI(ehci)
+                               || urb->dev->tt->hub !=
+                                  ehci_to_hcd(ehci)->self.root_hub) {
+                       if (usb_hub_clear_tt_buffer(urb) == 0)
+                               qh->clearing_tt = 1;
+               } else {
+
+                       /* REVISIT ARC-derived cores don't clear the root
+                        * hub TT buffer in this way...
+                        */
+               }
+       }
+}
+
 static int qtd_copy_status (
        struct ehci_hcd *ehci,
        struct urb *urb,
@@ -149,6 +214,14 @@ static int qtd_copy_status (
                if (token & QTD_STS_BABBLE) {
                        /* FIXME "must" disable babbling device's port too */
                        status = -EOVERFLOW;
+               /* CERR nonzero + halt --> stall */
+               } else if (QTD_CERR(token)) {
+                       status = -EPIPE;
+
+               /* In theory, more than one of the following bits can be set
+                * since they are sticky and the transaction is retried.
+                * Which to test first is rather arbitrary.
+                */
                } else if (token & QTD_STS_MMF) {
                        /* fs/ls interrupt xfer missed the complete-split */
                        status = -EPROTO;
@@ -157,21 +230,15 @@ static int qtd_copy_status (
                                ? -ENOSR  /* hc couldn't read data */
                                : -ECOMM; /* hc couldn't write data */
                } else if (token & QTD_STS_XACT) {
-                       /* timeout, bad crc, wrong PID, etc; retried */
-                       if (QTD_CERR (token))
-                               status = -EPIPE;
-                       else {
-                               ehci_dbg (ehci, "devpath %s ep%d%s 3strikes\n",
-                                       urb->dev->devpath,
-                                       usb_pipeendpoint (urb->pipe),
-                                       usb_pipein (urb->pipe) ? "in" : "out");
-                               status = -EPROTO;
-                       }
-               /* CERR nonzero + no errors + halt --> stall */
-               } else if (QTD_CERR (token))
-                       status = -EPIPE;
-               else    /* unknown */
+                       /* timeout, bad CRC, wrong PID, etc */
+                       ehci_dbg(ehci, "devpath %s ep%d%s 3strikes\n",
+                               urb->dev->devpath,
+                               usb_pipeendpoint(urb->pipe),
+                               usb_pipein(urb->pipe) ? "in" : "out");
+                       status = -EPROTO;
+               } else {        /* unknown */
                        status = -EPROTO;
+               }
 
                ehci_vdbg (ehci,
                        "dev%d ep%d%s qtd token %08x --> status %d\n",
@@ -179,28 +246,6 @@ static int qtd_copy_status (
                        usb_pipeendpoint (urb->pipe),
                        usb_pipein (urb->pipe) ? "in" : "out",
                        token, status);
-
-               /* if async CSPLIT failed, try cleaning out the TT buffer */
-               if (status != -EPIPE
-                               && urb->dev->tt
-                               && !usb_pipeint(urb->pipe)
-                               && ((token & QTD_STS_MMF) != 0
-                                       || QTD_CERR(token) == 0)
-                               && (!ehci_is_TDI(ehci)
-                                       || urb->dev->tt->hub !=
-                                          ehci_to_hcd(ehci)->self.root_hub)) {
-#ifdef DEBUG
-                       struct usb_device *tt = urb->dev->tt->hub;
-                       dev_dbg (&tt->dev,
-                               "clear tt buffer port %d, a%d ep%d t%08x\n",
-                               urb->dev->ttport, urb->dev->devnum,
-                               usb_pipeendpoint (urb->pipe), token);
-#endif /* DEBUG */
-                       /* REVISIT ARC-derived cores don't clear the root
-                        * hub TT buffer in this way...
-                        */
-                       usb_hub_tt_clear_buffer (urb->dev, urb->pipe);
-               }
        }
 
        return status;
@@ -391,9 +436,16 @@ qh_completions (struct ehci_hcd *ehci, struct ehci_qh *qh)
                        /* qh unlinked; token in overlay may be most current */
                        if (state == QH_STATE_IDLE
                                        && cpu_to_hc32(ehci, qtd->qtd_dma)
-                                               == qh->hw_current)
+                                               == qh->hw_current) {
                                token = hc32_to_cpu(ehci, qh->hw_token);
 
+                               /* An unlink may leave an incomplete
+                                * async transaction in the TT buffer.
+                                * We have to clear it.
+                                */
+                               ehci_clear_tt_buffer(ehci, qh, urb, token);
+                       }
+
                        /* force halt for unlinked or blocked qh, so we'll
                         * patch the qh later and so that completions can't
                         * activate it while we "know" it's stopped.
@@ -419,6 +471,13 @@ halt:
                                        && (qtd->hw_alt_next
                                                & EHCI_LIST_END(ehci)))
                                last_status = -EINPROGRESS;
+
+                       /* As part of low/full-speed endpoint-halt processing
+                        * we must clear the TT buffer (11.17.5).
+                        */
+                       if (unlikely(last_status != -EINPROGRESS &&
+                                       last_status != -EREMOTEIO))
+                               ehci_clear_tt_buffer(ehci, qh, urb, token);
                }
 
                /* if we're removing something not at the queue head,
@@ -834,6 +893,7 @@ done:
        qh->qh_state = QH_STATE_IDLE;
        qh->hw_info1 = cpu_to_hc32(ehci, info1);
        qh->hw_info2 = cpu_to_hc32(ehci, info2);
+       usb_settoggle (urb->dev, usb_pipeendpoint (urb->pipe), !is_input, 1);
        qh_refresh (ehci, qh);
        return qh;
 }
@@ -847,6 +907,10 @@ static void qh_link_async (struct ehci_hcd *ehci, struct ehci_qh *qh)
        __hc32          dma = QH_NEXT(ehci, qh->qh_dma);
        struct ehci_qh  *head;
 
+       /* Don't link a QH if there's a Clear-TT-Buffer pending */
+       if (unlikely(qh->clearing_tt))
+               return;
+
        /* (re)start the async schedule? */
        head = ehci->async;
        timer_action_done (ehci, TIMER_ASYNC_OFF);
@@ -864,7 +928,7 @@ static void qh_link_async (struct ehci_hcd *ehci, struct ehci_qh *qh)
                }
        }
 
-       /* clear halt and maybe recover from silicon quirk */
+       /* clear halt and/or toggle; and maybe recover from silicon quirk */
        if (qh->qh_state == QH_STATE_IDLE)
                qh_refresh (ehci, qh);
 
index 9d1babc7ff6553c64de8cec32fcfcff3f5ce5967..74f7f83b29ad9485ec9242afdbc1f91115a98f76 100644 (file)
@@ -1619,11 +1619,14 @@ itd_complete (
                                desc->status = -EPROTO;
 
                        /* HC need not update length with this error */
-                       if (!(t & EHCI_ISOC_BABBLE))
-                               desc->actual_length = EHCI_ITD_LENGTH (t);
+                       if (!(t & EHCI_ISOC_BABBLE)) {
+                               desc->actual_length = EHCI_ITD_LENGTH(t);
+                               urb->actual_length += desc->actual_length;
+                       }
                } else if (likely ((t & EHCI_ISOC_ACTIVE) == 0)) {
                        desc->status = 0;
-                       desc->actual_length = EHCI_ITD_LENGTH (t);
+                       desc->actual_length = EHCI_ITD_LENGTH(t);
+                       urb->actual_length += desc->actual_length;
                } else {
                        /* URB was too late */
                        desc->status = -EXDEV;
@@ -2014,7 +2017,8 @@ sitd_complete (
                        desc->status = -EPROTO;
        } else {
                desc->status = 0;
-               desc->actual_length = desc->length - SITD_LENGTH (t);
+               desc->actual_length = desc->length - SITD_LENGTH(t);
+               urb->actual_length += desc->actual_length;
        }
        stream->depth -= stream->interval << 3;
 
index 90ad3395bb21f0f96923ab21431dc7c44165badb..2bfff30f4704f7521678239df30c07323e0d3e59 100644 (file)
@@ -354,7 +354,9 @@ struct ehci_qh {
        unsigned short          period;         /* polling interval */
        unsigned short          start;          /* where polling starts */
 #define NO_FRAME ((unsigned short)~0)                  /* pick new start */
+
        struct usb_device       *dev;           /* access to TT */
+       unsigned                clearing_tt:1;  /* Clear-TT-Buf in progress */
 } __attribute__ ((aligned (32)));
 
 /*-------------------------------------------------------------------------*/
index bb63b68ddb7745486e841f3bdb73b011d1be12da..62a226b616707a2dcb0ba7667f537f4d8bb7481c 100644 (file)
@@ -576,9 +576,7 @@ irqreturn_t fhci_irq(struct usb_hcd *hcd)
                        out_be16(&usb->fhci->regs->usb_event,
                                 usb->saved_msk);
                } else if (usb->port_status == FHCI_PORT_DISABLED) {
-                       if (fhci_ioports_check_bus_state(fhci) == 1 &&
-                                       usb->port_status != FHCI_PORT_LOW &&
-                                       usb->port_status != FHCI_PORT_FULL)
+                       if (fhci_ioports_check_bus_state(fhci) == 1)
                                fhci_device_connected_interrupt(fhci);
                }
                usb_er &= ~USB_E_RESET_MASK;
@@ -605,9 +603,7 @@ irqreturn_t fhci_irq(struct usb_hcd *hcd)
        }
 
        if (usb_er & USB_E_IDLE_MASK) {
-               if (usb->port_status == FHCI_PORT_DISABLED &&
-                               usb->port_status != FHCI_PORT_LOW &&
-                               usb->port_status != FHCI_PORT_FULL) {
+               if (usb->port_status == FHCI_PORT_DISABLED) {
                        usb_er &= ~USB_E_RESET_MASK;
                        fhci_device_connected_interrupt(fhci);
                } else if (usb->port_status ==
index 3fa3a17027963af75a2d15d5c5da7990b7c5fc7f..d4feebfc63bd1b51088a9e22cc618db1eb0f092b 100644 (file)
@@ -361,7 +361,7 @@ static int __devexit isp1760_plat_remove(struct platform_device *pdev)
 
 static struct platform_driver isp1760_plat_driver = {
        .probe  = isp1760_plat_probe,
-       .remove = isp1760_plat_remove,
+       .remove = __devexit_p(isp1760_plat_remove),
        .driver = {
                .name   = "isp1760",
        },
index 56976cc0352a9ae9e87a0a1cb681135410e0e581..e18f74946e6824a427bd5b3b0185ee79ffebcd35 100644 (file)
@@ -26,7 +26,6 @@
 #include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/sched.h>
-#include <linux/smp_lock.h>
 #include <linux/errno.h>
 #include <linux/init.h>
 #include <linux/timer.h>
index 3c5fe5cee05abab286dcc2f00d6cc1f70b031e06..90e1a8dedfa91404f8ce1ac48b159818eead87b8 100644 (file)
@@ -18,6 +18,7 @@
 #include <linux/init.h>
 #include <linux/slab.h>
 #include <linux/sched.h>
+#include <linux/smp_lock.h>
 #include <linux/poll.h>
 #include <linux/usb/iowarrior.h>
 
index deb95bb49fd195d333a77152e21fef88f2d26ae3..d645f3899fe1c52a09599e90d241006337591381 100644 (file)
@@ -32,6 +32,7 @@
 #include <linux/kernel.h>
 #include <linux/signal.h>
 #include <linux/sched.h>
+#include <linux/smp_lock.h>
 #include <linux/errno.h>
 #include <linux/random.h>
 #include <linux/poll.h>
index e0ff9ccd866baff21039a6dadbb920a08e866636..29092b8e59ceb7347a2f217282d7918eaf98cfe2 100644 (file)
@@ -16,6 +16,7 @@
 #include <linux/kernel.h>
 #include <linux/init.h>
 #include <linux/slab.h>
+#include <linux/smp_lock.h>
 #include <linux/errno.h>
 #include <linux/mutex.h>
 #include <asm/uaccess.h>
index f8d9045d668a15659fadf2af3fecf374623402f5..0f7a30b7d2d16e08f7c63ddc1711833d0667fc15 100644 (file)
@@ -1261,7 +1261,7 @@ static int mon_alloc_buff(struct mon_pgmap *map, int npages)
                        return -ENOMEM;
                }
                map[n].ptr = (unsigned char *) vaddr;
-               map[n].pg = virt_to_page(vaddr);
+               map[n].pg = virt_to_page((void *) vaddr);
        }
        return 0;
 }
index 8a39de3e6e471c9c8f8c7b72f5b515218cb816c4..59bf949e589b85a086be064ffb037a77bedc7e24 100644 (file)
@@ -5,7 +5,6 @@
 
 #include <linux/slab.h>
 #include <linux/list.h>
-#include <linux/smp_lock.h>
 #include <linux/errno.h>
 #include <linux/dmapool.h>
 
index 180d7daa4099d50231f81f92c8ce537ab72dcbcc..e16ff605c458aa5a5b29e224deec2033adb96851 100644 (file)
 #include <mach/hardware.h>
 #include <mach/memory.h>
 #include <mach/gpio.h>
+#include <mach/cputype.h>
 
 #include <asm/mach-types.h>
 
 #include "musb_core.h"
 
 #ifdef CONFIG_MACH_DAVINCI_EVM
-#define GPIO_nVBUS_DRV         87
+#define GPIO_nVBUS_DRV         144
 #endif
 
 #include "davinci.h"
@@ -329,7 +330,6 @@ static irqreturn_t davinci_interrupt(int irq, void *__hci)
                        mod_timer(&otg_workaround, jiffies + POLL_SECONDS * HZ);
                        WARNING("VBUS error workaround (delay coming)\n");
                } else if (is_host_enabled(musb) && drvvbus) {
-                       musb->is_active = 1;
                        MUSB_HST_MODE(musb);
                        musb->xceiv->default_a = 1;
                        musb->xceiv->state = OTG_STATE_A_WAIT_VRISE;
@@ -343,7 +343,9 @@ static irqreturn_t davinci_interrupt(int irq, void *__hci)
                        portstate(musb->port1_status &= ~USB_PORT_STAT_POWER);
                }
 
-               /* NOTE:  this must complete poweron within 100 msec */
+               /* NOTE:  this must complete poweron within 100 msec
+                * (OTG_TIME_A_WAIT_VRISE) but we don't check for that.
+                */
                davinci_source_power(musb, drvvbus, 0);
                DBG(2, "VBUS %s (%s)%s, devctl %02x\n",
                                drvvbus ? "on" : "off",
@@ -411,6 +413,21 @@ int __init musb_platform_init(struct musb *musb)
                __raw_writel(phy_ctrl, USB_PHY_CTRL);
        }
 
+       /* On dm355, the default-A state machine needs DRVVBUS control.
+        * If we won't be a host, there's no need to turn it on.
+        */
+       if (cpu_is_davinci_dm355()) {
+               u32     deepsleep = __raw_readl(DM355_DEEPSLEEP);
+
+               if (is_host_enabled(musb)) {
+                       deepsleep &= ~DRVVBUS_OVERRIDE;
+               } else {
+                       deepsleep &= ~DRVVBUS_FORCE;
+                       deepsleep |= DRVVBUS_OVERRIDE;
+               }
+               __raw_writel(deepsleep, DM355_DEEPSLEEP);
+       }
+
        /* reset the controller */
        musb_writel(tibase, DAVINCI_USB_CTRL_REG, 0x1);
 
@@ -437,6 +454,15 @@ int musb_platform_exit(struct musb *musb)
        if (is_host_enabled(musb))
                del_timer_sync(&otg_workaround);
 
+       /* force VBUS off */
+       if (cpu_is_davinci_dm355()) {
+               u32     deepsleep = __raw_readl(DM355_DEEPSLEEP);
+
+               deepsleep &= ~DRVVBUS_FORCE;
+               deepsleep |= DRVVBUS_OVERRIDE;
+               __raw_writel(deepsleep, DM355_DEEPSLEEP);
+       }
+
        davinci_source_power(musb, 0 /*off*/, 1);
 
        /* delay, to avoid problems with module reload */
index f3772ca3b2cf799569389870e60a159732f5ca70..381d648a36b8122e974b0f4c5e0001611d8f0e49 100644 (file)
@@ -38,7 +38,6 @@
 #include <linux/slab.h>
 #include <linux/list.h>
 #include <linux/interrupt.h>
-#include <linux/smp_lock.h>
 #include <linux/errno.h>
 #include <linux/timer.h>
 #include <linux/clk.h>
index 94a2a350a4141521e9e4d93426700ed3a31aaf6b..cf94511485f258a07d60186d43e3687fcf959a87 100644 (file)
@@ -373,7 +373,7 @@ static void musb_advance_schedule(struct musb *musb, struct urb *urb,
                musb_save_toggle(qh, is_in, urb);
                break;
        case USB_ENDPOINT_XFER_ISOC:
-               if (urb->error_count)
+               if (status == 0 && urb->error_count)
                        status = -EXDEV;
                break;
        }
@@ -2235,13 +2235,30 @@ static void musb_h_stop(struct usb_hcd *hcd)
 static int musb_bus_suspend(struct usb_hcd *hcd)
 {
        struct musb     *musb = hcd_to_musb(hcd);
+       u8              devctl;
 
-       if (musb->xceiv->state == OTG_STATE_A_SUSPEND)
+       if (!is_host_active(musb))
                return 0;
 
-       if (is_host_active(musb) && musb->is_active) {
-               WARNING("trying to suspend as %s is_active=%i\n",
-                       otg_state_string(musb), musb->is_active);
+       switch (musb->xceiv->state) {
+       case OTG_STATE_A_SUSPEND:
+               return 0;
+       case OTG_STATE_A_WAIT_VRISE:
+               /* ID could be grounded even if there's no device
+                * on the other end of the cable.  NOTE that the
+                * A_WAIT_VRISE timers are messy with MUSB...
+                */
+               devctl = musb_readb(musb->mregs, MUSB_DEVCTL);
+               if ((devctl & MUSB_DEVCTL_VBUS) == MUSB_DEVCTL_VBUS)
+                       musb->xceiv->state = OTG_STATE_A_WAIT_BCON;
+               break;
+       default:
+               break;
+       }
+
+       if (musb->is_active) {
+               WARNING("trying to suspend as %s while active\n",
+                               otg_state_string(musb));
                return -EBUSY;
        } else
                return 0;
index 69feeec1628ce28bd8744ef5c6048d0b7a12746c..aa884d072f0b4c7202e5b421e52b0ca37a5163de 100644 (file)
@@ -59,18 +59,4 @@ config NOP_USB_XCEIV
         built-in with usb ip or which are autonomous and doesn't require any
         phy programming such as ISP1x04 etc.
 
-config USB_LANGWELL_OTG
-       tristate "Intel Langwell USB OTG dual-role support"
-       depends on USB && MRST
-       select USB_OTG
-       select USB_OTG_UTILS
-       help
-         Say Y here if you want to build Intel Langwell USB OTG
-         transciever driver in kernel. This driver implements role
-         switch between EHCI host driver and Langwell USB OTG
-         client driver.
-
-         To compile this driver as a module, choose M here: the
-         module will be called langwell_otg.
-
 endif # USB || OTG
index 6d1abdd3c0ac9cc1a2cd688dd9fda768ee2562a1..208167856529f26225807cd7edea4fb29a3640e9 100644 (file)
@@ -9,7 +9,6 @@ obj-$(CONFIG_USB_OTG_UTILS)     += otg.o
 obj-$(CONFIG_USB_GPIO_VBUS)    += gpio_vbus.o
 obj-$(CONFIG_ISP1301_OMAP)     += isp1301_omap.o
 obj-$(CONFIG_TWL4030_USB)      += twl4030-usb.o
-obj-$(CONFIG_USB_LANGWELL_OTG) += langwell_otg.o
 obj-$(CONFIG_NOP_USB_XCEIV)    += nop-usb-xceiv.o
 
 ccflags-$(CONFIG_USB_DEBUG)    += -DDEBUG
diff --git a/drivers/usb/otg/langwell_otg.c b/drivers/usb/otg/langwell_otg.c
deleted file mode 100644 (file)
index 6f628d0..0000000
+++ /dev/null
@@ -1,1915 +0,0 @@
-/*
- * Intel Langwell USB OTG transceiver driver
- * Copyright (C) 2008 - 2009, Intel Corporation.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms and conditions of the GNU General Public License,
- * version 2, as published by the Free Software Foundation.
- *
- * This program is distributed in the hope it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
- *
- */
-/* This driver helps to switch Langwell OTG controller function between host
- * and peripheral. It works with EHCI driver and Langwell client controller
- * driver together.
- */
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/pci.h>
-#include <linux/errno.h>
-#include <linux/interrupt.h>
-#include <linux/kernel.h>
-#include <linux/device.h>
-#include <linux/moduleparam.h>
-#include <linux/usb/ch9.h>
-#include <linux/usb/gadget.h>
-#include <linux/usb.h>
-#include <linux/usb/otg.h>
-#include <linux/notifier.h>
-#include <asm/ipc_defs.h>
-#include <linux/delay.h>
-#include "../core/hcd.h"
-
-#include <linux/usb/langwell_otg.h>
-
-#define        DRIVER_DESC             "Intel Langwell USB OTG transceiver driver"
-#define        DRIVER_VERSION          "3.0.0.32L.0002"
-
-MODULE_DESCRIPTION(DRIVER_DESC);
-MODULE_AUTHOR("Henry Yuan <hang.yuan@intel.com>, Hao Wu <hao.wu@intel.com>");
-MODULE_VERSION(DRIVER_VERSION);
-MODULE_LICENSE("GPL");
-
-static const char driver_name[] = "langwell_otg";
-
-static int langwell_otg_probe(struct pci_dev *pdev,
-                       const struct pci_device_id *id);
-static void langwell_otg_remove(struct pci_dev *pdev);
-static int langwell_otg_suspend(struct pci_dev *pdev, pm_message_t message);
-static int langwell_otg_resume(struct pci_dev *pdev);
-
-static int langwell_otg_set_host(struct otg_transceiver *otg,
-                               struct usb_bus *host);
-static int langwell_otg_set_peripheral(struct otg_transceiver *otg,
-                               struct usb_gadget *gadget);
-static int langwell_otg_start_srp(struct otg_transceiver *otg);
-
-static const struct pci_device_id pci_ids[] = {{
-       .class =        ((PCI_CLASS_SERIAL_USB << 8) | 0xfe),
-       .class_mask =   ~0,
-       .vendor =       0x8086,
-       .device =       0x0811,
-       .subvendor =    PCI_ANY_ID,
-       .subdevice =    PCI_ANY_ID,
-}, { /* end: all zeroes */ }
-};
-
-static struct pci_driver otg_pci_driver = {
-       .name =         (char *) driver_name,
-       .id_table =     pci_ids,
-
-       .probe =        langwell_otg_probe,
-       .remove =       langwell_otg_remove,
-
-       .suspend =      langwell_otg_suspend,
-       .resume =       langwell_otg_resume,
-};
-
-static const char *state_string(enum usb_otg_state state)
-{
-       switch (state) {
-       case OTG_STATE_A_IDLE:
-               return "a_idle";
-       case OTG_STATE_A_WAIT_VRISE:
-               return "a_wait_vrise";
-       case OTG_STATE_A_WAIT_BCON:
-               return "a_wait_bcon";
-       case OTG_STATE_A_HOST:
-               return "a_host";
-       case OTG_STATE_A_SUSPEND:
-               return "a_suspend";
-       case OTG_STATE_A_PERIPHERAL:
-               return "a_peripheral";
-       case OTG_STATE_A_WAIT_VFALL:
-               return "a_wait_vfall";
-       case OTG_STATE_A_VBUS_ERR:
-               return "a_vbus_err";
-       case OTG_STATE_B_IDLE:
-               return "b_idle";
-       case OTG_STATE_B_SRP_INIT:
-               return "b_srp_init";
-       case OTG_STATE_B_PERIPHERAL:
-               return "b_peripheral";
-       case OTG_STATE_B_WAIT_ACON:
-               return "b_wait_acon";
-       case OTG_STATE_B_HOST:
-               return "b_host";
-       default:
-               return "UNDEFINED";
-       }
-}
-
-/* HSM timers */
-static inline struct langwell_otg_timer *otg_timer_initializer
-(void (*function)(unsigned long), unsigned long expires, unsigned long data)
-{
-       struct langwell_otg_timer *timer;
-       timer = kmalloc(sizeof(struct langwell_otg_timer), GFP_KERNEL);
-       timer->function = function;
-       timer->expires = expires;
-       timer->data = data;
-       return timer;
-}
-
-static struct langwell_otg_timer *a_wait_vrise_tmr, *a_wait_bcon_tmr,
-       *a_aidl_bdis_tmr, *b_ase0_brst_tmr, *b_se0_srp_tmr, *b_srp_res_tmr,
-       *b_bus_suspend_tmr;
-
-static struct list_head active_timers;
-
-static struct langwell_otg *the_transceiver;
-
-/* host/client notify transceiver when event affects HNP state */
-void langwell_update_transceiver()
-{
-       otg_dbg("transceiver driver is notified\n");
-       queue_work(the_transceiver->qwork, &the_transceiver->work);
-}
-EXPORT_SYMBOL(langwell_update_transceiver);
-
-static int langwell_otg_set_host(struct otg_transceiver *otg,
-                                       struct usb_bus *host)
-{
-       otg->host = host;
-
-       return 0;
-}
-
-static int langwell_otg_set_peripheral(struct otg_transceiver *otg,
-                                       struct usb_gadget *gadget)
-{
-       otg->gadget = gadget;
-
-       return 0;
-}
-
-static int langwell_otg_set_power(struct otg_transceiver *otg,
-                               unsigned mA)
-{
-       return 0;
-}
-
-/* A-device drives vbus, controlled through PMIC CHRGCNTL register*/
-static void langwell_otg_drv_vbus(int on)
-{
-       struct ipc_pmic_reg_data        pmic_data = {0};
-       struct ipc_pmic_reg_data        battery_data;
-
-       /* Check if battery is attached or not */
-       battery_data.pmic_reg_data[0].register_address = 0xd2;
-       battery_data.ioc = 0;
-       battery_data.num_entries = 1;
-       if (ipc_pmic_register_read(&battery_data)) {
-               otg_dbg("Failed to read PMIC register 0xd2.\n");
-               return;
-       }
-
-       if ((battery_data.pmic_reg_data[0].value & 0x20) == 0) {
-               otg_dbg("no battery attached\n");
-               return;
-       }
-
-       /* Workaround for battery attachment issue */
-       if (battery_data.pmic_reg_data[0].value == 0x34) {
-               otg_dbg("battery \n");
-               return;
-       }
-
-       otg_dbg("battery attached\n");
-
-       pmic_data.ioc = 0;
-       pmic_data.pmic_reg_data[0].register_address = 0xD4;
-       pmic_data.num_entries = 1;
-       if (on)
-               pmic_data.pmic_reg_data[0].value = 0x20;
-       else
-               pmic_data.pmic_reg_data[0].value = 0xc0;
-
-       if (ipc_pmic_register_write(&pmic_data, TRUE))
-               otg_dbg("Failed to write PMIC.\n");
-
-}
-
-/* charge vbus or discharge vbus through a resistor to ground */
-static void langwell_otg_chrg_vbus(int on)
-{
-
-       u32     val;
-
-       val = readl(the_transceiver->regs + CI_OTGSC);
-
-       if (on)
-               writel((val & ~OTGSC_INTSTS_MASK) | OTGSC_VC,
-                               the_transceiver->regs + CI_OTGSC);
-       else
-               writel((val & ~OTGSC_INTSTS_MASK) | OTGSC_VD,
-                               the_transceiver->regs + CI_OTGSC);
-
-}
-
-/* Start SRP */
-static int langwell_otg_start_srp(struct otg_transceiver *otg)
-{
-       u32     val;
-
-       otg_dbg("Start SRP ->\n");
-
-       val = readl(the_transceiver->regs + CI_OTGSC);
-
-       writel((val & ~OTGSC_INTSTS_MASK) | OTGSC_HADP,
-               the_transceiver->regs + CI_OTGSC);
-
-       /* Check if the data plus is finished or not */
-       msleep(8);
-       val = readl(the_transceiver->regs + CI_OTGSC);
-       if (val & (OTGSC_HADP | OTGSC_DP))
-               otg_dbg("DataLine SRP Error\n");
-
-       /* FIXME: VBus SRP */
-
-       return 0;
-}
-
-
-/* stop SOF via bus_suspend */
-static void langwell_otg_loc_sof(int on)
-{
-       struct usb_hcd  *hcd;
-       int             err;
-
-       otg_dbg("loc_sof -> %d\n", on);
-
-       hcd = bus_to_hcd(the_transceiver->otg.host);
-       if (on)
-               err = hcd->driver->bus_resume(hcd);
-       else
-               err = hcd->driver->bus_suspend(hcd);
-
-       if (err)
-               otg_dbg("Failed to resume/suspend bus - %d\n", err);
-}
-
-static void langwell_otg_phy_low_power(int on)
-{
-       u32     val;
-
-       otg_dbg("phy low power mode-> %d\n", on);
-
-       val = readl(the_transceiver->regs + CI_HOSTPC1);
-       if (on)
-               writel(val | HOSTPC1_PHCD, the_transceiver->regs + CI_HOSTPC1);
-       else
-               writel(val & ~HOSTPC1_PHCD, the_transceiver->regs + CI_HOSTPC1);
-}
-
-/* Enable/Disable OTG interrupt */
-static void langwell_otg_intr(int on)
-{
-       u32 val;
-
-       otg_dbg("interrupt -> %d\n", on);
-
-       val = readl(the_transceiver->regs + CI_OTGSC);
-       if (on) {
-               val = val | (OTGSC_INTEN_MASK | OTGSC_IDPU);
-               writel(val, the_transceiver->regs + CI_OTGSC);
-       } else {
-               val = val & ~(OTGSC_INTEN_MASK | OTGSC_IDPU);
-               writel(val, the_transceiver->regs + CI_OTGSC);
-       }
-}
-
-/* set HAAR: Hardware Assist Auto-Reset */
-static void langwell_otg_HAAR(int on)
-{
-       u32     val;
-
-       otg_dbg("HAAR -> %d\n", on);
-
-       val = readl(the_transceiver->regs + CI_OTGSC);
-       if (on)
-               writel((val & ~OTGSC_INTSTS_MASK) | OTGSC_HAAR,
-                               the_transceiver->regs + CI_OTGSC);
-       else
-               writel((val & ~OTGSC_INTSTS_MASK) & ~OTGSC_HAAR,
-                               the_transceiver->regs + CI_OTGSC);
-}
-
-/* set HABA: Hardware Assist B-Disconnect to A-Connect */
-static void langwell_otg_HABA(int on)
-{
-       u32     val;
-
-       otg_dbg("HABA -> %d\n", on);
-
-       val = readl(the_transceiver->regs + CI_OTGSC);
-       if (on)
-               writel((val & ~OTGSC_INTSTS_MASK) | OTGSC_HABA,
-                               the_transceiver->regs + CI_OTGSC);
-       else
-               writel((val & ~OTGSC_INTSTS_MASK) & ~OTGSC_HABA,
-                               the_transceiver->regs + CI_OTGSC);
-}
-
-static int langwell_otg_check_se0_srp(int on)
-{
-       u32 val;
-
-       int delay_time = TB_SE0_SRP * 10; /* step is 100us */
-
-       otg_dbg("check_se0_srp -> \n");
-
-       do {
-               udelay(100);
-               if (!delay_time--)
-                       break;
-               val = readl(the_transceiver->regs + CI_PORTSC1);
-               val &= PORTSC_LS;
-       } while (!val);
-
-       otg_dbg("check_se0_srp <- \n");
-       return val;
-}
-
-/* The timeout callback function to set time out bit */
-static void set_tmout(unsigned long indicator)
-{
-       *(int *)indicator = 1;
-}
-
-void langwell_otg_nsf_msg(unsigned long indicator)
-{
-       switch (indicator) {
-       case 2:
-       case 4:
-       case 6:
-       case 7:
-               printk(KERN_ERR "OTG:NSF-%lu - deivce not responding\n",
-                               indicator);
-               break;
-       case 3:
-               printk(KERN_ERR "OTG:NSF-%lu - deivce not supported\n",
-                               indicator);
-               break;
-       default:
-               printk(KERN_ERR "Do not have this kind of NSF\n");
-               break;
-       }
-}
-
-/* Initialize timers */
-static void langwell_otg_init_timers(struct otg_hsm *hsm)
-{
-       /* HSM used timers */
-       a_wait_vrise_tmr = otg_timer_initializer(&set_tmout, TA_WAIT_VRISE,
-                               (unsigned long)&hsm->a_wait_vrise_tmout);
-       a_wait_bcon_tmr = otg_timer_initializer(&set_tmout, TA_WAIT_BCON,
-                               (unsigned long)&hsm->a_wait_bcon_tmout);
-       a_aidl_bdis_tmr = otg_timer_initializer(&set_tmout, TA_AIDL_BDIS,
-                               (unsigned long)&hsm->a_aidl_bdis_tmout);
-       b_ase0_brst_tmr = otg_timer_initializer(&set_tmout, TB_ASE0_BRST,
-                               (unsigned long)&hsm->b_ase0_brst_tmout);
-       b_se0_srp_tmr = otg_timer_initializer(&set_tmout, TB_SE0_SRP,
-                               (unsigned long)&hsm->b_se0_srp);
-       b_srp_res_tmr = otg_timer_initializer(&set_tmout, TB_SRP_RES,
-                               (unsigned long)&hsm->b_srp_res_tmout);
-       b_bus_suspend_tmr = otg_timer_initializer(&set_tmout, TB_BUS_SUSPEND,
-                               (unsigned long)&hsm->b_bus_suspend_tmout);
-}
-
-/* Free timers */
-static void langwell_otg_free_timers(void)
-{
-       kfree(a_wait_vrise_tmr);
-       kfree(a_wait_bcon_tmr);
-       kfree(a_aidl_bdis_tmr);
-       kfree(b_ase0_brst_tmr);
-       kfree(b_se0_srp_tmr);
-       kfree(b_srp_res_tmr);
-       kfree(b_bus_suspend_tmr);
-}
-
-/* Add timer to timer list */
-static void langwell_otg_add_timer(void *gtimer)
-{
-       struct langwell_otg_timer *timer = (struct langwell_otg_timer *)gtimer;
-       struct langwell_otg_timer *tmp_timer;
-       u32     val32;
-
-       /* Check if the timer is already in the active list,
-        * if so update timer count
-        */
-       list_for_each_entry(tmp_timer, &active_timers, list)
-               if (tmp_timer == timer) {
-                       timer->count = timer->expires;
-                       return;
-               }
-       timer->count = timer->expires;
-
-       if (list_empty(&active_timers)) {
-               val32 = readl(the_transceiver->regs + CI_OTGSC);
-               writel(val32 | OTGSC_1MSE, the_transceiver->regs + CI_OTGSC);
-       }
-
-       list_add_tail(&timer->list, &active_timers);
-}
-
-/* Remove timer from the timer list; clear timeout status */
-static void langwell_otg_del_timer(void *gtimer)
-{
-       struct langwell_otg_timer *timer = (struct langwell_otg_timer *)gtimer;
-       struct langwell_otg_timer *tmp_timer, *del_tmp;
-       u32 val32;
-
-       list_for_each_entry_safe(tmp_timer, del_tmp, &active_timers, list)
-               if (tmp_timer == timer)
-                       list_del(&timer->list);
-
-       if (list_empty(&active_timers)) {
-               val32 = readl(the_transceiver->regs + CI_OTGSC);
-               writel(val32 & ~OTGSC_1MSE, the_transceiver->regs + CI_OTGSC);
-       }
-}
-
-/* Reduce timer count by 1, and find timeout conditions.*/
-static int langwell_otg_tick_timer(u32 *int_sts)
-{
-       struct langwell_otg_timer *tmp_timer, *del_tmp;
-       int expired = 0;
-
-       list_for_each_entry_safe(tmp_timer, del_tmp, &active_timers, list) {
-               tmp_timer->count--;
-               /* check if timer expires */
-               if (!tmp_timer->count) {
-                       list_del(&tmp_timer->list);
-                       tmp_timer->function(tmp_timer->data);
-                       expired = 1;
-               }
-       }
-
-       if (list_empty(&active_timers)) {
-               otg_dbg("tick timer: disable 1ms int\n");
-               *int_sts = *int_sts & ~OTGSC_1MSE;
-       }
-       return expired;
-}
-
-static void reset_otg(void)
-{
-       u32     val;
-       int     delay_time = 1000;
-
-       otg_dbg("reseting OTG controller ...\n");
-       val = readl(the_transceiver->regs + CI_USBCMD);
-       writel(val | USBCMD_RST, the_transceiver->regs + CI_USBCMD);
-       do {
-               udelay(100);
-               if (!delay_time--)
-                       otg_dbg("reset timeout\n");
-               val = readl(the_transceiver->regs + CI_USBCMD);
-               val &= USBCMD_RST;
-       } while (val != 0);
-       otg_dbg("reset done.\n");
-}
-
-static void set_host_mode(void)
-{
-       u32     val;
-
-       reset_otg();
-       val = readl(the_transceiver->regs + CI_USBMODE);
-       val = (val & (~USBMODE_CM)) | USBMODE_HOST;
-       writel(val, the_transceiver->regs + CI_USBMODE);
-}
-
-static void set_client_mode(void)
-{
-       u32     val;
-
-       reset_otg();
-       val = readl(the_transceiver->regs + CI_USBMODE);
-       val = (val & (~USBMODE_CM)) | USBMODE_DEVICE;
-       writel(val, the_transceiver->regs + CI_USBMODE);
-}
-
-static void init_hsm(void)
-{
-       struct langwell_otg     *langwell = the_transceiver;
-       u32                     val32;
-
-       /* read OTGSC after reset */
-       val32 = readl(langwell->regs + CI_OTGSC);
-       otg_dbg("%s: OTGSC init value = 0x%x\n", __func__, val32);
-
-       /* set init state */
-       if (val32 & OTGSC_ID) {
-               langwell->hsm.id = 1;
-               langwell->otg.default_a = 0;
-               set_client_mode();
-               langwell->otg.state = OTG_STATE_B_IDLE;
-               langwell_otg_drv_vbus(0);
-       } else {
-               langwell->hsm.id = 0;
-               langwell->otg.default_a = 1;
-               set_host_mode();
-               langwell->otg.state = OTG_STATE_A_IDLE;
-       }
-
-       /* set session indicator */
-       if (val32 & OTGSC_BSE)
-               langwell->hsm.b_sess_end = 1;
-       if (val32 & OTGSC_BSV)
-               langwell->hsm.b_sess_vld = 1;
-       if (val32 & OTGSC_ASV)
-               langwell->hsm.a_sess_vld = 1;
-       if (val32 & OTGSC_AVV)
-               langwell->hsm.a_vbus_vld = 1;
-
-       /* defautly power the bus */
-       langwell->hsm.a_bus_req = 1;
-       langwell->hsm.a_bus_drop = 0;
-       /* defautly don't request bus as B device */
-       langwell->hsm.b_bus_req = 0;
-       /* no system error */
-       langwell->hsm.a_clr_err = 0;
-}
-
-static irqreturn_t otg_dummy_irq(int irq, void *_dev)
-{
-       void __iomem    *reg_base = _dev;
-       u32     val;
-       u32     int_mask = 0;
-
-       val = readl(reg_base + CI_USBMODE);
-       if ((val & USBMODE_CM) != USBMODE_DEVICE)
-               return IRQ_NONE;
-
-       val = readl(reg_base + CI_USBSTS);
-       int_mask = val & INTR_DUMMY_MASK;
-
-       if (int_mask == 0)
-               return IRQ_NONE;
-
-       /* clear hsm.b_conn here since host driver can't detect it
-       *  otg_dummy_irq called means B-disconnect happened.
-       */
-       if (the_transceiver->hsm.b_conn) {
-               the_transceiver->hsm.b_conn = 0;
-               if (spin_trylock(&the_transceiver->wq_lock)) {
-                       queue_work(the_transceiver->qwork,
-                               &the_transceiver->work);
-                       spin_unlock(&the_transceiver->wq_lock);
-               }
-       }
-       /* Clear interrupts */
-       writel(int_mask, reg_base + CI_USBSTS);
-       return IRQ_HANDLED;
-}
-
-static irqreturn_t otg_irq(int irq, void *_dev)
-{
-       struct  langwell_otg *langwell = _dev;
-       u32     int_sts, int_en;
-       u32     int_mask = 0;
-       int     flag = 0;
-
-       int_sts = readl(langwell->regs + CI_OTGSC);
-       int_en = (int_sts & OTGSC_INTEN_MASK) >> 8;
-       int_mask = int_sts & int_en;
-       if (int_mask == 0)
-               return IRQ_NONE;
-
-       if (int_mask & OTGSC_IDIS) {
-               otg_dbg("%s: id change int\n", __func__);
-               langwell->hsm.id = (int_sts & OTGSC_ID) ? 1 : 0;
-               flag = 1;
-       }
-       if (int_mask & OTGSC_DPIS) {
-               otg_dbg("%s: data pulse int\n", __func__);
-               langwell->hsm.a_srp_det = (int_sts & OTGSC_DPS) ? 1 : 0;
-               flag = 1;
-       }
-       if (int_mask & OTGSC_BSEIS) {
-               otg_dbg("%s: b session end int\n", __func__);
-               langwell->hsm.b_sess_end = (int_sts & OTGSC_BSE) ? 1 : 0;
-               flag = 1;
-       }
-       if (int_mask & OTGSC_BSVIS) {
-               otg_dbg("%s: b session valid int\n", __func__);
-               langwell->hsm.b_sess_vld = (int_sts & OTGSC_BSV) ? 1 : 0;
-               flag = 1;
-       }
-       if (int_mask & OTGSC_ASVIS) {
-               otg_dbg("%s: a session valid int\n", __func__);
-               langwell->hsm.a_sess_vld = (int_sts & OTGSC_ASV) ? 1 : 0;
-               flag = 1;
-       }
-       if (int_mask & OTGSC_AVVIS) {
-               otg_dbg("%s: a vbus valid int\n", __func__);
-               langwell->hsm.a_vbus_vld = (int_sts & OTGSC_AVV) ? 1 : 0;
-               flag = 1;
-       }
-
-       if (int_mask & OTGSC_1MSS) {
-               /* need to schedule otg_work if any timer is expired */
-               if (langwell_otg_tick_timer(&int_sts))
-                       flag = 1;
-       }
-
-       writel((int_sts & ~OTGSC_INTSTS_MASK) | int_mask,
-                       langwell->regs + CI_OTGSC);
-       if (flag)
-               queue_work(langwell->qwork, &langwell->work);
-
-       return IRQ_HANDLED;
-}
-
-static void langwell_otg_work(struct work_struct *work)
-{
-       struct langwell_otg *langwell = container_of(work,
-                                       struct langwell_otg, work);
-       int     retval;
-
-       otg_dbg("%s: old state = %s\n", __func__,
-                       state_string(langwell->otg.state));
-
-       switch (langwell->otg.state) {
-       case OTG_STATE_UNDEFINED:
-       case OTG_STATE_B_IDLE:
-               if (!langwell->hsm.id) {
-                       langwell_otg_del_timer(b_srp_res_tmr);
-                       langwell->otg.default_a = 1;
-                       langwell->hsm.a_srp_det = 0;
-
-                       langwell_otg_chrg_vbus(0);
-                       langwell_otg_drv_vbus(0);
-
-                       set_host_mode();
-                       langwell->otg.state = OTG_STATE_A_IDLE;
-                       queue_work(langwell->qwork, &langwell->work);
-               } else if (langwell->hsm.b_srp_res_tmout) {
-                       langwell->hsm.b_srp_res_tmout = 0;
-                       langwell->hsm.b_bus_req = 0;
-                       langwell_otg_nsf_msg(6);
-               } else if (langwell->hsm.b_sess_vld) {
-                       langwell_otg_del_timer(b_srp_res_tmr);
-                       langwell->hsm.b_sess_end = 0;
-                       langwell->hsm.a_bus_suspend = 0;
-
-                       langwell_otg_chrg_vbus(0);
-                       if (langwell->client_ops) {
-                               langwell->client_ops->resume(langwell->pdev);
-                               langwell->otg.state = OTG_STATE_B_PERIPHERAL;
-                       } else
-                               otg_dbg("client driver not loaded.\n");
-
-               } else if (langwell->hsm.b_bus_req &&
-                               (langwell->hsm.b_sess_end)) {
-                       /* workaround for b_se0_srp detection */
-                       retval = langwell_otg_check_se0_srp(0);
-                       if (retval) {
-                               langwell->hsm.b_bus_req = 0;
-                               otg_dbg("LS is not SE0, try again later\n");
-                       } else {
-                               /* Start SRP */
-                               langwell_otg_start_srp(&langwell->otg);
-                               langwell_otg_add_timer(b_srp_res_tmr);
-                       }
-               }
-               break;
-       case OTG_STATE_B_SRP_INIT:
-               if (!langwell->hsm.id) {
-                       langwell->otg.default_a = 1;
-                       langwell->hsm.a_srp_det = 0;
-
-                       langwell_otg_drv_vbus(0);
-                       langwell_otg_chrg_vbus(0);
-
-                       langwell->otg.state = OTG_STATE_A_IDLE;
-                       queue_work(langwell->qwork, &langwell->work);
-               } else if (langwell->hsm.b_sess_vld) {
-                       langwell_otg_chrg_vbus(0);
-                       if (langwell->client_ops) {
-                               langwell->client_ops->resume(langwell->pdev);
-                               langwell->otg.state = OTG_STATE_B_PERIPHERAL;
-                       } else
-                               otg_dbg("client driver not loaded.\n");
-               }
-               break;
-       case OTG_STATE_B_PERIPHERAL:
-               if (!langwell->hsm.id) {
-                       langwell->otg.default_a = 1;
-                       langwell->hsm.a_srp_det = 0;
-
-                       langwell_otg_drv_vbus(0);
-                       langwell_otg_chrg_vbus(0);
-                       set_host_mode();
-
-                       if (langwell->client_ops) {
-                               langwell->client_ops->suspend(langwell->pdev,
-                                       PMSG_FREEZE);
-                       } else
-                               otg_dbg("client driver has been removed.\n");
-
-                       langwell->otg.state = OTG_STATE_A_IDLE;
-                       queue_work(langwell->qwork, &langwell->work);
-               } else if (!langwell->hsm.b_sess_vld) {
-                       langwell->hsm.b_hnp_enable = 0;
-
-                       if (langwell->client_ops) {
-                               langwell->client_ops->suspend(langwell->pdev,
-                                       PMSG_FREEZE);
-                       } else
-                               otg_dbg("client driver has been removed.\n");
-
-                       langwell->otg.state = OTG_STATE_B_IDLE;
-               } else if (langwell->hsm.b_bus_req && langwell->hsm.b_hnp_enable
-                       && langwell->hsm.a_bus_suspend) {
-
-                       if (langwell->client_ops) {
-                               langwell->client_ops->suspend(langwell->pdev,
-                                       PMSG_FREEZE);
-                       } else
-                               otg_dbg("client driver has been removed.\n");
-
-                       langwell_otg_HAAR(1);
-                       langwell->hsm.a_conn = 0;
-
-                       if (langwell->host_ops) {
-                               langwell->host_ops->probe(langwell->pdev,
-                                       langwell->host_ops->id_table);
-                               langwell->otg.state = OTG_STATE_B_WAIT_ACON;
-                       } else
-                               otg_dbg("host driver not loaded.\n");
-
-                       langwell->hsm.a_bus_resume = 0;
-                       langwell->hsm.b_ase0_brst_tmout = 0;
-                       langwell_otg_add_timer(b_ase0_brst_tmr);
-               }
-               break;
-
-       case OTG_STATE_B_WAIT_ACON:
-               if (!langwell->hsm.id) {
-                       langwell_otg_del_timer(b_ase0_brst_tmr);
-                       langwell->otg.default_a = 1;
-                       langwell->hsm.a_srp_det = 0;
-
-                       langwell_otg_drv_vbus(0);
-                       langwell_otg_chrg_vbus(0);
-                       set_host_mode();
-
-                       langwell_otg_HAAR(0);
-                       if (langwell->host_ops)
-                               langwell->host_ops->remove(langwell->pdev);
-                       else
-                               otg_dbg("host driver has been removed.\n");
-                       langwell->otg.state = OTG_STATE_A_IDLE;
-                       queue_work(langwell->qwork, &langwell->work);
-               } else if (!langwell->hsm.b_sess_vld) {
-                       langwell_otg_del_timer(b_ase0_brst_tmr);
-                       langwell->hsm.b_hnp_enable = 0;
-                       langwell->hsm.b_bus_req = 0;
-                       langwell_otg_chrg_vbus(0);
-                       langwell_otg_HAAR(0);
-
-                       if (langwell->host_ops)
-                               langwell->host_ops->remove(langwell->pdev);
-                       else
-                               otg_dbg("host driver has been removed.\n");
-                       langwell->otg.state = OTG_STATE_B_IDLE;
-               } else if (langwell->hsm.a_conn) {
-                       langwell_otg_del_timer(b_ase0_brst_tmr);
-                       langwell_otg_HAAR(0);
-                       langwell->otg.state = OTG_STATE_B_HOST;
-                       queue_work(langwell->qwork, &langwell->work);
-               } else if (langwell->hsm.a_bus_resume ||
-                               langwell->hsm.b_ase0_brst_tmout) {
-                       langwell_otg_del_timer(b_ase0_brst_tmr);
-                       langwell_otg_HAAR(0);
-                       langwell_otg_nsf_msg(7);
-
-                       if (langwell->host_ops)
-                               langwell->host_ops->remove(langwell->pdev);
-                       else
-                               otg_dbg("host driver has been removed.\n");
-
-                       langwell->hsm.a_bus_suspend = 0;
-                       langwell->hsm.b_bus_req = 0;
-
-                       if (langwell->client_ops)
-                               langwell->client_ops->resume(langwell->pdev);
-                       else
-                               otg_dbg("client driver not loaded.\n");
-
-                       langwell->otg.state = OTG_STATE_B_PERIPHERAL;
-               }
-               break;
-
-       case OTG_STATE_B_HOST:
-               if (!langwell->hsm.id) {
-                       langwell->otg.default_a = 1;
-                       langwell->hsm.a_srp_det = 0;
-
-                       langwell_otg_drv_vbus(0);
-                       langwell_otg_chrg_vbus(0);
-                       set_host_mode();
-                       if (langwell->host_ops)
-                               langwell->host_ops->remove(langwell->pdev);
-                       else
-                               otg_dbg("host driver has been removed.\n");
-                       langwell->otg.state = OTG_STATE_A_IDLE;
-                       queue_work(langwell->qwork, &langwell->work);
-               } else if (!langwell->hsm.b_sess_vld) {
-                       langwell->hsm.b_hnp_enable = 0;
-                       langwell->hsm.b_bus_req = 0;
-                       langwell_otg_chrg_vbus(0);
-                       if (langwell->host_ops)
-                               langwell->host_ops->remove(langwell->pdev);
-                       else
-                               otg_dbg("host driver has been removed.\n");
-                       langwell->otg.state = OTG_STATE_B_IDLE;
-               } else if ((!langwell->hsm.b_bus_req) ||
-                               (!langwell->hsm.a_conn)) {
-                       langwell->hsm.b_bus_req = 0;
-                       langwell_otg_loc_sof(0);
-                       if (langwell->host_ops)
-                               langwell->host_ops->remove(langwell->pdev);
-                       else
-                               otg_dbg("host driver has been removed.\n");
-
-                       langwell->hsm.a_bus_suspend = 0;
-
-                       if (langwell->client_ops)
-                               langwell->client_ops->resume(langwell->pdev);
-                       else
-                               otg_dbg("client driver not loaded.\n");
-
-                       langwell->otg.state = OTG_STATE_B_PERIPHERAL;
-               }
-               break;
-
-       case OTG_STATE_A_IDLE:
-               langwell->otg.default_a = 1;
-               if (langwell->hsm.id) {
-                       langwell->otg.default_a = 0;
-                       langwell->hsm.b_bus_req = 0;
-                       langwell_otg_drv_vbus(0);
-                       langwell_otg_chrg_vbus(0);
-
-                       langwell->otg.state = OTG_STATE_B_IDLE;
-                       queue_work(langwell->qwork, &langwell->work);
-               } else if (langwell->hsm.a_sess_vld) {
-                       langwell_otg_drv_vbus(1);
-                       langwell->hsm.a_srp_det = 1;
-                       langwell->hsm.a_wait_vrise_tmout = 0;
-                       langwell_otg_add_timer(a_wait_vrise_tmr);
-                       langwell->otg.state = OTG_STATE_A_WAIT_VRISE;
-                       queue_work(langwell->qwork, &langwell->work);
-               } else if (!langwell->hsm.a_bus_drop &&
-                       (langwell->hsm.a_srp_det || langwell->hsm.a_bus_req)) {
-                       langwell_otg_drv_vbus(1);
-                       langwell->hsm.a_wait_vrise_tmout = 0;
-                       langwell_otg_add_timer(a_wait_vrise_tmr);
-                       langwell->otg.state = OTG_STATE_A_WAIT_VRISE;
-                       queue_work(langwell->qwork, &langwell->work);
-               }
-               break;
-       case OTG_STATE_A_WAIT_VRISE:
-               if (langwell->hsm.id) {
-                       langwell_otg_del_timer(a_wait_vrise_tmr);
-                       langwell->hsm.b_bus_req = 0;
-                       langwell->otg.default_a = 0;
-                       langwell_otg_drv_vbus(0);
-                       langwell->otg.state = OTG_STATE_B_IDLE;
-               } else if (langwell->hsm.a_vbus_vld) {
-                       langwell_otg_del_timer(a_wait_vrise_tmr);
-                       if (langwell->host_ops)
-                               langwell->host_ops->probe(langwell->pdev,
-                                               langwell->host_ops->id_table);
-                       else
-                               otg_dbg("host driver not loaded.\n");
-                       langwell->hsm.b_conn = 0;
-                       langwell->hsm.a_set_b_hnp_en = 0;
-                       langwell->hsm.a_wait_bcon_tmout = 0;
-                       langwell_otg_add_timer(a_wait_bcon_tmr);
-                       langwell->otg.state = OTG_STATE_A_WAIT_BCON;
-               } else if (langwell->hsm.a_wait_vrise_tmout) {
-                       if (langwell->hsm.a_vbus_vld) {
-                               if (langwell->host_ops)
-                                       langwell->host_ops->probe(
-                                               langwell->pdev,
-                                               langwell->host_ops->id_table);
-                               else
-                                       otg_dbg("host driver not loaded.\n");
-                               langwell->hsm.b_conn = 0;
-                               langwell->hsm.a_set_b_hnp_en = 0;
-                               langwell->hsm.a_wait_bcon_tmout = 0;
-                               langwell_otg_add_timer(a_wait_bcon_tmr);
-                               langwell->otg.state = OTG_STATE_A_WAIT_BCON;
-                       } else {
-                               langwell_otg_drv_vbus(0);
-                               langwell->otg.state = OTG_STATE_A_VBUS_ERR;
-                       }
-               }
-               break;
-       case OTG_STATE_A_WAIT_BCON:
-               if (langwell->hsm.id) {
-                       langwell_otg_del_timer(a_wait_bcon_tmr);
-
-                       langwell->otg.default_a = 0;
-                       langwell->hsm.b_bus_req = 0;
-                       if (langwell->host_ops)
-                               langwell->host_ops->remove(langwell->pdev);
-                       else
-                               otg_dbg("host driver has been removed.\n");
-                       langwell_otg_drv_vbus(0);
-                       langwell->otg.state = OTG_STATE_B_IDLE;
-                       queue_work(langwell->qwork, &langwell->work);
-               } else if (!langwell->hsm.a_vbus_vld) {
-                       langwell_otg_del_timer(a_wait_bcon_tmr);
-
-                       if (langwell->host_ops)
-                               langwell->host_ops->remove(langwell->pdev);
-                       else
-                               otg_dbg("host driver has been removed.\n");
-                       langwell_otg_drv_vbus(0);
-                       langwell->otg.state = OTG_STATE_A_VBUS_ERR;
-               } else if (langwell->hsm.a_bus_drop ||
-                               (langwell->hsm.a_wait_bcon_tmout &&
-                               !langwell->hsm.a_bus_req)) {
-                       langwell_otg_del_timer(a_wait_bcon_tmr);
-
-                       if (langwell->host_ops)
-                               langwell->host_ops->remove(langwell->pdev);
-                       else
-                               otg_dbg("host driver has been removed.\n");
-                       langwell_otg_drv_vbus(0);
-                       langwell->otg.state = OTG_STATE_A_WAIT_VFALL;
-               } else if (langwell->hsm.b_conn) {
-                       langwell_otg_del_timer(a_wait_bcon_tmr);
-
-                       langwell->hsm.a_suspend_req = 0;
-                       langwell->otg.state = OTG_STATE_A_HOST;
-                       if (!langwell->hsm.a_bus_req &&
-                               langwell->hsm.a_set_b_hnp_en) {
-                               /* It is not safe enough to do a fast
-                                * transistion from A_WAIT_BCON to
-                                * A_SUSPEND */
-                               msleep(10000);
-                               if (langwell->hsm.a_bus_req)
-                                       break;
-
-                               if (request_irq(langwell->pdev->irq,
-                                       otg_dummy_irq, IRQF_SHARED,
-                                       driver_name, langwell->regs) != 0) {
-                                       otg_dbg("request interrupt %d fail\n",
-                                       langwell->pdev->irq);
-                               }
-
-                               langwell_otg_HABA(1);
-                               langwell->hsm.b_bus_resume = 0;
-                               langwell->hsm.a_aidl_bdis_tmout = 0;
-                               langwell_otg_add_timer(a_aidl_bdis_tmr);
-
-                               langwell_otg_loc_sof(0);
-                               langwell->otg.state = OTG_STATE_A_SUSPEND;
-                       } else if (!langwell->hsm.a_bus_req &&
-                               !langwell->hsm.a_set_b_hnp_en) {
-                               struct pci_dev *pdev = langwell->pdev;
-                               if (langwell->host_ops)
-                                       langwell->host_ops->remove(pdev);
-                               else
-                                       otg_dbg("host driver removed.\n");
-                               langwell_otg_drv_vbus(0);
-                               langwell->otg.state = OTG_STATE_A_WAIT_VFALL;
-                       }
-               }
-               break;
-       case OTG_STATE_A_HOST:
-               if (langwell->hsm.id) {
-                       langwell->otg.default_a = 0;
-                       langwell->hsm.b_bus_req = 0;
-                       if (langwell->host_ops)
-                               langwell->host_ops->remove(langwell->pdev);
-                       else
-                               otg_dbg("host driver has been removed.\n");
-                       langwell_otg_drv_vbus(0);
-                       langwell->otg.state = OTG_STATE_B_IDLE;
-                       queue_work(langwell->qwork, &langwell->work);
-               } else if (langwell->hsm.a_bus_drop ||
-               (!langwell->hsm.a_set_b_hnp_en && !langwell->hsm.a_bus_req)) {
-                       if (langwell->host_ops)
-                               langwell->host_ops->remove(langwell->pdev);
-                       else
-                               otg_dbg("host driver has been removed.\n");
-                       langwell_otg_drv_vbus(0);
-                       langwell->otg.state = OTG_STATE_A_WAIT_VFALL;
-               } else if (!langwell->hsm.a_vbus_vld) {
-                       if (langwell->host_ops)
-                               langwell->host_ops->remove(langwell->pdev);
-                       else
-                               otg_dbg("host driver has been removed.\n");
-                       langwell_otg_drv_vbus(0);
-                       langwell->otg.state = OTG_STATE_A_VBUS_ERR;
-               } else if (langwell->hsm.a_set_b_hnp_en
-                               && !langwell->hsm.a_bus_req) {
-                       /* Set HABA to enable hardware assistance to signal
-                        *  A-connect after receiver B-disconnect. Hardware
-                        *  will then set client mode and enable URE, SLE and
-                        *  PCE after the assistance. otg_dummy_irq is used to
-                        *  clean these ints when client driver is not resumed.
-                        */
-                       if (request_irq(langwell->pdev->irq,
-                               otg_dummy_irq, IRQF_SHARED, driver_name,
-                               langwell->regs) != 0) {
-                               otg_dbg("request interrupt %d failed\n",
-                                               langwell->pdev->irq);
-                       }
-
-                       /* set HABA */
-                       langwell_otg_HABA(1);
-                       langwell->hsm.b_bus_resume = 0;
-                       langwell->hsm.a_aidl_bdis_tmout = 0;
-                       langwell_otg_add_timer(a_aidl_bdis_tmr);
-                       langwell_otg_loc_sof(0);
-                       langwell->otg.state = OTG_STATE_A_SUSPEND;
-               } else if (!langwell->hsm.b_conn || !langwell->hsm.a_bus_req) {
-                       langwell->hsm.a_wait_bcon_tmout = 0;
-                       langwell->hsm.a_set_b_hnp_en = 0;
-                       langwell_otg_add_timer(a_wait_bcon_tmr);
-                       langwell->otg.state = OTG_STATE_A_WAIT_BCON;
-               }
-               break;
-       case OTG_STATE_A_SUSPEND:
-               if (langwell->hsm.id) {
-                       langwell_otg_del_timer(a_aidl_bdis_tmr);
-                       langwell_otg_HABA(0);
-                       free_irq(langwell->pdev->irq, langwell->regs);
-                       langwell->otg.default_a = 0;
-                       langwell->hsm.b_bus_req = 0;
-                       if (langwell->host_ops)
-                               langwell->host_ops->remove(langwell->pdev);
-                       else
-                               otg_dbg("host driver has been removed.\n");
-                       langwell_otg_drv_vbus(0);
-                       langwell->otg.state = OTG_STATE_B_IDLE;
-                       queue_work(langwell->qwork, &langwell->work);
-               } else if (langwell->hsm.a_bus_req ||
-                               langwell->hsm.b_bus_resume) {
-                       langwell_otg_del_timer(a_aidl_bdis_tmr);
-                       langwell_otg_HABA(0);
-                       free_irq(langwell->pdev->irq, langwell->regs);
-                       langwell->hsm.a_suspend_req = 0;
-                       langwell_otg_loc_sof(1);
-                       langwell->otg.state = OTG_STATE_A_HOST;
-               } else if (langwell->hsm.a_aidl_bdis_tmout ||
-                               langwell->hsm.a_bus_drop) {
-                       langwell_otg_del_timer(a_aidl_bdis_tmr);
-                       langwell_otg_HABA(0);
-                       free_irq(langwell->pdev->irq, langwell->regs);
-                       if (langwell->host_ops)
-                               langwell->host_ops->remove(langwell->pdev);
-                       else
-                               otg_dbg("host driver has been removed.\n");
-                       langwell_otg_drv_vbus(0);
-                       langwell->otg.state = OTG_STATE_A_WAIT_VFALL;
-               } else if (!langwell->hsm.b_conn &&
-                               langwell->hsm.a_set_b_hnp_en) {
-                       langwell_otg_del_timer(a_aidl_bdis_tmr);
-                       langwell_otg_HABA(0);
-                       free_irq(langwell->pdev->irq, langwell->regs);
-
-                       if (langwell->host_ops)
-                               langwell->host_ops->remove(langwell->pdev);
-                       else
-                               otg_dbg("host driver has been removed.\n");
-
-                       langwell->hsm.b_bus_suspend = 0;
-                       langwell->hsm.b_bus_suspend_vld = 0;
-                       langwell->hsm.b_bus_suspend_tmout = 0;
-
-                       /* msleep(200); */
-                       if (langwell->client_ops)
-                               langwell->client_ops->resume(langwell->pdev);
-                       else
-                               otg_dbg("client driver not loaded.\n");
-
-                       langwell_otg_add_timer(b_bus_suspend_tmr);
-                       langwell->otg.state = OTG_STATE_A_PERIPHERAL;
-                       break;
-               } else if (!langwell->hsm.a_vbus_vld) {
-                       langwell_otg_del_timer(a_aidl_bdis_tmr);
-                       langwell_otg_HABA(0);
-                       free_irq(langwell->pdev->irq, langwell->regs);
-                       if (langwell->host_ops)
-                               langwell->host_ops->remove(langwell->pdev);
-                       else
-                               otg_dbg("host driver has been removed.\n");
-                       langwell_otg_drv_vbus(0);
-                       langwell->otg.state = OTG_STATE_A_VBUS_ERR;
-               }
-               break;
-       case OTG_STATE_A_PERIPHERAL:
-               if (langwell->hsm.id) {
-                       langwell_otg_del_timer(b_bus_suspend_tmr);
-                       langwell->otg.default_a = 0;
-                       langwell->hsm.b_bus_req = 0;
-                       if (langwell->client_ops)
-                               langwell->client_ops->suspend(langwell->pdev,
-                                       PMSG_FREEZE);
-                       else
-                               otg_dbg("client driver has been removed.\n");
-                       langwell_otg_drv_vbus(0);
-                       langwell->otg.state = OTG_STATE_B_IDLE;
-                       queue_work(langwell->qwork, &langwell->work);
-               } else if (!langwell->hsm.a_vbus_vld) {
-                       langwell_otg_del_timer(b_bus_suspend_tmr);
-                       if (langwell->client_ops)
-                               langwell->client_ops->suspend(langwell->pdev,
-                                       PMSG_FREEZE);
-                       else
-                               otg_dbg("client driver has been removed.\n");
-                       langwell_otg_drv_vbus(0);
-                       langwell->otg.state = OTG_STATE_A_VBUS_ERR;
-               } else if (langwell->hsm.a_bus_drop) {
-                       langwell_otg_del_timer(b_bus_suspend_tmr);
-                       if (langwell->client_ops)
-                               langwell->client_ops->suspend(langwell->pdev,
-                                       PMSG_FREEZE);
-                       else
-                               otg_dbg("client driver has been removed.\n");
-                       langwell_otg_drv_vbus(0);
-                       langwell->otg.state = OTG_STATE_A_WAIT_VFALL;
-               } else if (langwell->hsm.b_bus_suspend) {
-                       langwell_otg_del_timer(b_bus_suspend_tmr);
-                       if (langwell->client_ops)
-                               langwell->client_ops->suspend(langwell->pdev,
-                                       PMSG_FREEZE);
-                       else
-                               otg_dbg("client driver has been removed.\n");
-
-                       if (langwell->host_ops)
-                               langwell->host_ops->probe(langwell->pdev,
-                                               langwell->host_ops->id_table);
-                       else
-                               otg_dbg("host driver not loaded.\n");
-                       langwell->hsm.a_set_b_hnp_en = 0;
-                       langwell->hsm.a_wait_bcon_tmout = 0;
-                       langwell_otg_add_timer(a_wait_bcon_tmr);
-                       langwell->otg.state = OTG_STATE_A_WAIT_BCON;
-               } else if (langwell->hsm.b_bus_suspend_tmout) {
-                       u32     val;
-                       val = readl(langwell->regs + CI_PORTSC1);
-                       if (!(val & PORTSC_SUSP))
-                               break;
-                       if (langwell->client_ops)
-                               langwell->client_ops->suspend(langwell->pdev,
-                                               PMSG_FREEZE);
-                       else
-                               otg_dbg("client driver has been removed.\n");
-                       if (langwell->host_ops)
-                               langwell->host_ops->probe(langwell->pdev,
-                                               langwell->host_ops->id_table);
-                       else
-                               otg_dbg("host driver not loaded.\n");
-                       langwell->hsm.a_set_b_hnp_en = 0;
-                       langwell->hsm.a_wait_bcon_tmout = 0;
-                       langwell_otg_add_timer(a_wait_bcon_tmr);
-                       langwell->otg.state = OTG_STATE_A_WAIT_BCON;
-               }
-               break;
-       case OTG_STATE_A_VBUS_ERR:
-               if (langwell->hsm.id) {
-                       langwell->otg.default_a = 0;
-                       langwell->hsm.a_clr_err = 0;
-                       langwell->hsm.a_srp_det = 0;
-                       langwell->otg.state = OTG_STATE_B_IDLE;
-                       queue_work(langwell->qwork, &langwell->work);
-               } else if (langwell->hsm.a_clr_err) {
-                       langwell->hsm.a_clr_err = 0;
-                       langwell->hsm.a_srp_det = 0;
-                       reset_otg();
-                       init_hsm();
-                       if (langwell->otg.state == OTG_STATE_A_IDLE)
-                               queue_work(langwell->qwork, &langwell->work);
-               }
-               break;
-       case OTG_STATE_A_WAIT_VFALL:
-               if (langwell->hsm.id) {
-                       langwell->otg.default_a = 0;
-                       langwell->otg.state = OTG_STATE_B_IDLE;
-                       queue_work(langwell->qwork, &langwell->work);
-               } else if (langwell->hsm.a_bus_req) {
-                       langwell_otg_drv_vbus(1);
-                       langwell->hsm.a_wait_vrise_tmout = 0;
-                       langwell_otg_add_timer(a_wait_vrise_tmr);
-                       langwell->otg.state = OTG_STATE_A_WAIT_VRISE;
-               } else if (!langwell->hsm.a_sess_vld) {
-                       langwell->hsm.a_srp_det = 0;
-                       langwell_otg_drv_vbus(0);
-                       set_host_mode();
-                       langwell->otg.state = OTG_STATE_A_IDLE;
-               }
-               break;
-       default:
-               ;
-       }
-
-       otg_dbg("%s: new state = %s\n", __func__,
-                       state_string(langwell->otg.state));
-}
-
-       static ssize_t
-show_registers(struct device *_dev, struct device_attribute *attr, char *buf)
-{
-       struct langwell_otg *langwell;
-       char *next;
-       unsigned size;
-       unsigned t;
-
-       langwell = the_transceiver;
-       next = buf;
-       size = PAGE_SIZE;
-
-       t = scnprintf(next, size,
-               "\n"
-               "USBCMD = 0x%08x \n"
-               "USBSTS = 0x%08x \n"
-               "USBINTR = 0x%08x \n"
-               "ASYNCLISTADDR = 0x%08x \n"
-               "PORTSC1 = 0x%08x \n"
-               "HOSTPC1 = 0x%08x \n"
-               "OTGSC = 0x%08x \n"
-               "USBMODE = 0x%08x \n",
-               readl(langwell->regs + 0x30),
-               readl(langwell->regs + 0x34),
-               readl(langwell->regs + 0x38),
-               readl(langwell->regs + 0x48),
-               readl(langwell->regs + 0x74),
-               readl(langwell->regs + 0xb4),
-               readl(langwell->regs + 0xf4),
-               readl(langwell->regs + 0xf8)
-               );
-       size -= t;
-       next += t;
-
-       return PAGE_SIZE - size;
-}
-static DEVICE_ATTR(registers, S_IRUGO, show_registers, NULL);
-
-static ssize_t
-show_hsm(struct device *_dev, struct device_attribute *attr, char *buf)
-{
-       struct langwell_otg *langwell;
-       char *next;
-       unsigned size;
-       unsigned t;
-
-       langwell = the_transceiver;
-       next = buf;
-       size = PAGE_SIZE;
-
-       t = scnprintf(next, size,
-               "\n"
-               "current state = %s\n"
-               "a_bus_resume = \t%d\n"
-               "a_bus_suspend = \t%d\n"
-               "a_conn = \t%d\n"
-               "a_sess_vld = \t%d\n"
-               "a_srp_det = \t%d\n"
-               "a_vbus_vld = \t%d\n"
-               "b_bus_resume = \t%d\n"
-               "b_bus_suspend = \t%d\n"
-               "b_conn = \t%d\n"
-               "b_se0_srp = \t%d\n"
-               "b_sess_end = \t%d\n"
-               "b_sess_vld = \t%d\n"
-               "id = \t%d\n"
-               "a_set_b_hnp_en = \t%d\n"
-               "b_srp_done = \t%d\n"
-               "b_hnp_enable = \t%d\n"
-               "a_wait_vrise_tmout = \t%d\n"
-               "a_wait_bcon_tmout = \t%d\n"
-               "a_aidl_bdis_tmout = \t%d\n"
-               "b_ase0_brst_tmout = \t%d\n"
-               "a_bus_drop = \t%d\n"
-               "a_bus_req = \t%d\n"
-               "a_clr_err = \t%d\n"
-               "a_suspend_req = \t%d\n"
-               "b_bus_req = \t%d\n"
-               "b_bus_suspend_tmout = \t%d\n"
-               "b_bus_suspend_vld = \t%d\n",
-               state_string(langwell->otg.state),
-               langwell->hsm.a_bus_resume,
-               langwell->hsm.a_bus_suspend,
-               langwell->hsm.a_conn,
-               langwell->hsm.a_sess_vld,
-               langwell->hsm.a_srp_det,
-               langwell->hsm.a_vbus_vld,
-               langwell->hsm.b_bus_resume,
-               langwell->hsm.b_bus_suspend,
-               langwell->hsm.b_conn,
-               langwell->hsm.b_se0_srp,
-               langwell->hsm.b_sess_end,
-               langwell->hsm.b_sess_vld,
-               langwell->hsm.id,
-               langwell->hsm.a_set_b_hnp_en,
-               langwell->hsm.b_srp_done,
-               langwell->hsm.b_hnp_enable,
-               langwell->hsm.a_wait_vrise_tmout,
-               langwell->hsm.a_wait_bcon_tmout,
-               langwell->hsm.a_aidl_bdis_tmout,
-               langwell->hsm.b_ase0_brst_tmout,
-               langwell->hsm.a_bus_drop,
-               langwell->hsm.a_bus_req,
-               langwell->hsm.a_clr_err,
-               langwell->hsm.a_suspend_req,
-               langwell->hsm.b_bus_req,
-               langwell->hsm.b_bus_suspend_tmout,
-               langwell->hsm.b_bus_suspend_vld
-               );
-       size -= t;
-       next += t;
-
-       return PAGE_SIZE - size;
-}
-static DEVICE_ATTR(hsm, S_IRUGO, show_hsm, NULL);
-
-static ssize_t
-get_a_bus_req(struct device *dev, struct device_attribute *attr, char *buf)
-{
-       struct langwell_otg *langwell;
-       char *next;
-       unsigned size;
-       unsigned t;
-
-       langwell =  the_transceiver;
-       next = buf;
-       size = PAGE_SIZE;
-
-       t = scnprintf(next, size, "%d", langwell->hsm.a_bus_req);
-       size -= t;
-       next += t;
-
-       return PAGE_SIZE - size;
-}
-
-static ssize_t
-set_a_bus_req(struct device *dev, struct device_attribute *attr,
-               const char *buf, size_t count)
-{
-       struct langwell_otg *langwell;
-       langwell = the_transceiver;
-       if (!langwell->otg.default_a)
-               return -1;
-       if (count > 2)
-               return -1;
-
-       if (buf[0] == '0') {
-               langwell->hsm.a_bus_req = 0;
-               otg_dbg("a_bus_req = 0\n");
-       } else if (buf[0] == '1') {
-               /* If a_bus_drop is TRUE, a_bus_req can't be set */
-               if (langwell->hsm.a_bus_drop)
-                       return -1;
-               langwell->hsm.a_bus_req = 1;
-               otg_dbg("a_bus_req = 1\n");
-       }
-       if (spin_trylock(&langwell->wq_lock)) {
-               queue_work(langwell->qwork, &langwell->work);
-               spin_unlock(&langwell->wq_lock);
-       }
-       return count;
-}
-static DEVICE_ATTR(a_bus_req, S_IRUGO | S_IWUGO, get_a_bus_req, set_a_bus_req);
-
-static ssize_t
-get_a_bus_drop(struct device *dev, struct device_attribute *attr, char *buf)
-{
-       struct langwell_otg *langwell;
-       char *next;
-       unsigned size;
-       unsigned t;
-
-       langwell =  the_transceiver;
-       next = buf;
-       size = PAGE_SIZE;
-
-       t = scnprintf(next, size, "%d", langwell->hsm.a_bus_drop);
-       size -= t;
-       next += t;
-
-       return PAGE_SIZE - size;
-}
-
-static ssize_t
-set_a_bus_drop(struct device *dev, struct device_attribute *attr,
-               const char *buf, size_t count)
-{
-       struct langwell_otg *langwell;
-       langwell = the_transceiver;
-       if (!langwell->otg.default_a)
-               return -1;
-       if (count > 2)
-               return -1;
-
-       if (buf[0] == '0') {
-               langwell->hsm.a_bus_drop = 0;
-               otg_dbg("a_bus_drop = 0\n");
-       } else if (buf[0] == '1') {
-               langwell->hsm.a_bus_drop = 1;
-               langwell->hsm.a_bus_req = 0;
-               otg_dbg("a_bus_drop = 1, then a_bus_req = 0\n");
-       }
-       if (spin_trylock(&langwell->wq_lock)) {
-               queue_work(langwell->qwork, &langwell->work);
-               spin_unlock(&langwell->wq_lock);
-       }
-       return count;
-}
-static DEVICE_ATTR(a_bus_drop, S_IRUGO | S_IWUGO,
-       get_a_bus_drop, set_a_bus_drop);
-
-static ssize_t
-get_b_bus_req(struct device *dev, struct device_attribute *attr, char *buf)
-{
-       struct langwell_otg *langwell;
-       char *next;
-       unsigned size;
-       unsigned t;
-
-       langwell =  the_transceiver;
-       next = buf;
-       size = PAGE_SIZE;
-
-       t = scnprintf(next, size, "%d", langwell->hsm.b_bus_req);
-       size -= t;
-       next += t;
-
-       return PAGE_SIZE - size;
-}
-
-static ssize_t
-set_b_bus_req(struct device *dev, struct device_attribute *attr,
-               const char *buf, size_t count)
-{
-       struct langwell_otg *langwell;
-       langwell = the_transceiver;
-
-       if (langwell->otg.default_a)
-               return -1;
-
-       if (count > 2)
-               return -1;
-
-       if (buf[0] == '0') {
-               langwell->hsm.b_bus_req = 0;
-               otg_dbg("b_bus_req = 0\n");
-       } else if (buf[0] == '1') {
-               langwell->hsm.b_bus_req = 1;
-               otg_dbg("b_bus_req = 1\n");
-       }
-       if (spin_trylock(&langwell->wq_lock)) {
-               queue_work(langwell->qwork, &langwell->work);
-               spin_unlock(&langwell->wq_lock);
-       }
-       return count;
-}
-static DEVICE_ATTR(b_bus_req, S_IRUGO | S_IWUGO, get_b_bus_req, set_b_bus_req);
-
-static ssize_t
-set_a_clr_err(struct device *dev, struct device_attribute *attr,
-               const char *buf, size_t count)
-{
-       struct langwell_otg *langwell;
-       langwell = the_transceiver;
-
-       if (!langwell->otg.default_a)
-               return -1;
-       if (count > 2)
-               return -1;
-
-       if (buf[0] == '1') {
-               langwell->hsm.a_clr_err = 1;
-               otg_dbg("a_clr_err = 1\n");
-       }
-       if (spin_trylock(&langwell->wq_lock)) {
-               queue_work(langwell->qwork, &langwell->work);
-               spin_unlock(&langwell->wq_lock);
-       }
-       return count;
-}
-static DEVICE_ATTR(a_clr_err, S_IWUGO, NULL, set_a_clr_err);
-
-static struct attribute *inputs_attrs[] = {
-       &dev_attr_a_bus_req.attr,
-       &dev_attr_a_bus_drop.attr,
-       &dev_attr_b_bus_req.attr,
-       &dev_attr_a_clr_err.attr,
-       NULL,
-};
-
-static struct attribute_group debug_dev_attr_group = {
-       .name = "inputs",
-       .attrs = inputs_attrs,
-};
-
-int langwell_register_host(struct pci_driver *host_driver)
-{
-       int     ret = 0;
-
-       the_transceiver->host_ops = host_driver;
-       queue_work(the_transceiver->qwork, &the_transceiver->work);
-       otg_dbg("host controller driver is registered\n");
-
-       return ret;
-}
-EXPORT_SYMBOL(langwell_register_host);
-
-void langwell_unregister_host(struct pci_driver *host_driver)
-{
-       if (the_transceiver->host_ops)
-               the_transceiver->host_ops->remove(the_transceiver->pdev);
-       the_transceiver->host_ops = NULL;
-       the_transceiver->hsm.a_bus_drop = 1;
-       queue_work(the_transceiver->qwork, &the_transceiver->work);
-       otg_dbg("host controller driver is unregistered\n");
-}
-EXPORT_SYMBOL(langwell_unregister_host);
-
-int langwell_register_peripheral(struct pci_driver *client_driver)
-{
-       int     ret = 0;
-
-       if (client_driver)
-               ret = client_driver->probe(the_transceiver->pdev,
-                               client_driver->id_table);
-       if (!ret) {
-               the_transceiver->client_ops = client_driver;
-               queue_work(the_transceiver->qwork, &the_transceiver->work);
-               otg_dbg("client controller driver is registered\n");
-       }
-
-       return ret;
-}
-EXPORT_SYMBOL(langwell_register_peripheral);
-
-void langwell_unregister_peripheral(struct pci_driver *client_driver)
-{
-       if (the_transceiver->client_ops)
-               the_transceiver->client_ops->remove(the_transceiver->pdev);
-       the_transceiver->client_ops = NULL;
-       the_transceiver->hsm.b_bus_req = 0;
-       queue_work(the_transceiver->qwork, &the_transceiver->work);
-       otg_dbg("client controller driver is unregistered\n");
-}
-EXPORT_SYMBOL(langwell_unregister_peripheral);
-
-static int langwell_otg_probe(struct pci_dev *pdev,
-               const struct pci_device_id *id)
-{
-       unsigned long           resource, len;
-       void __iomem            *base = NULL;
-       int                     retval;
-       u32                     val32;
-       struct langwell_otg     *langwell;
-       char                    qname[] = "langwell_otg_queue";
-
-       retval = 0;
-       otg_dbg("\notg controller is detected.\n");
-       if (pci_enable_device(pdev) < 0) {
-               retval = -ENODEV;
-               goto done;
-       }
-
-       langwell = kzalloc(sizeof *langwell, GFP_KERNEL);
-       if (langwell == NULL) {
-               retval = -ENOMEM;
-               goto done;
-       }
-       the_transceiver = langwell;
-
-       /* control register: BAR 0 */
-       resource = pci_resource_start(pdev, 0);
-       len = pci_resource_len(pdev, 0);
-       if (!request_mem_region(resource, len, driver_name)) {
-               retval = -EBUSY;
-               goto err;
-       }
-       langwell->region = 1;
-
-       base = ioremap_nocache(resource, len);
-       if (base == NULL) {
-               retval = -EFAULT;
-               goto err;
-       }
-       langwell->regs = base;
-
-       if (!pdev->irq) {
-               otg_dbg("No IRQ.\n");
-               retval = -ENODEV;
-               goto err;
-       }
-
-       langwell->qwork = create_workqueue(qname);
-       if (!langwell->qwork) {
-               otg_dbg("cannot create workqueue %s\n", qname);
-               retval = -ENOMEM;
-               goto err;
-       }
-       INIT_WORK(&langwell->work, langwell_otg_work);
-
-       /* OTG common part */
-       langwell->pdev = pdev;
-       langwell->otg.dev = &pdev->dev;
-       langwell->otg.label = driver_name;
-       langwell->otg.set_host = langwell_otg_set_host;
-       langwell->otg.set_peripheral = langwell_otg_set_peripheral;
-       langwell->otg.set_power = langwell_otg_set_power;
-       langwell->otg.start_srp = langwell_otg_start_srp;
-       langwell->otg.state = OTG_STATE_UNDEFINED;
-       if (otg_set_transceiver(&langwell->otg)) {
-               otg_dbg("can't set transceiver\n");
-               retval = -EBUSY;
-               goto err;
-       }
-
-       reset_otg();
-       init_hsm();
-
-       spin_lock_init(&langwell->lock);
-       spin_lock_init(&langwell->wq_lock);
-       INIT_LIST_HEAD(&active_timers);
-       langwell_otg_init_timers(&langwell->hsm);
-
-       if (request_irq(pdev->irq, otg_irq, IRQF_SHARED,
-                               driver_name, langwell) != 0) {
-               otg_dbg("request interrupt %d failed\n", pdev->irq);
-               retval = -EBUSY;
-               goto err;
-       }
-
-       /* enable OTGSC int */
-       val32 = OTGSC_DPIE | OTGSC_BSEIE | OTGSC_BSVIE |
-               OTGSC_ASVIE | OTGSC_AVVIE | OTGSC_IDIE | OTGSC_IDPU;
-       writel(val32, langwell->regs + CI_OTGSC);
-
-       retval = device_create_file(&pdev->dev, &dev_attr_registers);
-       if (retval < 0) {
-               otg_dbg("Can't register sysfs attribute: %d\n", retval);
-               goto err;
-       }
-
-       retval = device_create_file(&pdev->dev, &dev_attr_hsm);
-       if (retval < 0) {
-               otg_dbg("Can't hsm sysfs attribute: %d\n", retval);
-               goto err;
-       }
-
-       retval = sysfs_create_group(&pdev->dev.kobj, &debug_dev_attr_group);
-       if (retval < 0) {
-               otg_dbg("Can't register sysfs attr group: %d\n", retval);
-               goto err;
-       }
-
-       if (langwell->otg.state == OTG_STATE_A_IDLE)
-               queue_work(langwell->qwork, &langwell->work);
-
-       return 0;
-
-err:
-       if (the_transceiver)
-               langwell_otg_remove(pdev);
-done:
-       return retval;
-}
-
-static void langwell_otg_remove(struct pci_dev *pdev)
-{
-       struct langwell_otg *langwell;
-
-       langwell = the_transceiver;
-
-       if (langwell->qwork) {
-               flush_workqueue(langwell->qwork);
-               destroy_workqueue(langwell->qwork);
-       }
-       langwell_otg_free_timers();
-
-       /* disable OTGSC interrupt as OTGSC doesn't change in reset */
-       writel(0, langwell->regs + CI_OTGSC);
-
-       if (pdev->irq)
-               free_irq(pdev->irq, langwell);
-       if (langwell->regs)
-               iounmap(langwell->regs);
-       if (langwell->region)
-               release_mem_region(pci_resource_start(pdev, 0),
-                               pci_resource_len(pdev, 0));
-
-       otg_set_transceiver(NULL);
-       pci_disable_device(pdev);
-       sysfs_remove_group(&pdev->dev.kobj, &debug_dev_attr_group);
-       device_remove_file(&pdev->dev, &dev_attr_hsm);
-       device_remove_file(&pdev->dev, &dev_attr_registers);
-       kfree(langwell);
-       langwell = NULL;
-}
-
-static void transceiver_suspend(struct pci_dev *pdev)
-{
-       pci_save_state(pdev);
-       pci_set_power_state(pdev, PCI_D3hot);
-       langwell_otg_phy_low_power(1);
-}
-
-static int langwell_otg_suspend(struct pci_dev *pdev, pm_message_t message)
-{
-       int     ret = 0;
-       struct langwell_otg *langwell;
-
-       langwell = the_transceiver;
-
-       /* Disbale OTG interrupts */
-       langwell_otg_intr(0);
-
-       if (pdev->irq)
-               free_irq(pdev->irq, langwell);
-
-       /* Prevent more otg_work */
-       flush_workqueue(langwell->qwork);
-       spin_lock(&langwell->wq_lock);
-
-       /* start actions */
-       switch (langwell->otg.state) {
-       case OTG_STATE_A_IDLE:
-       case OTG_STATE_B_IDLE:
-       case OTG_STATE_A_WAIT_VFALL:
-       case OTG_STATE_A_VBUS_ERR:
-               transceiver_suspend(pdev);
-               break;
-       case OTG_STATE_A_WAIT_VRISE:
-               langwell_otg_del_timer(a_wait_vrise_tmr);
-               langwell->hsm.a_srp_det = 0;
-               langwell_otg_drv_vbus(0);
-               langwell->otg.state = OTG_STATE_A_IDLE;
-               transceiver_suspend(pdev);
-               break;
-       case OTG_STATE_A_WAIT_BCON:
-               langwell_otg_del_timer(a_wait_bcon_tmr);
-               if (langwell->host_ops)
-                       ret = langwell->host_ops->suspend(pdev, message);
-               langwell_otg_drv_vbus(0);
-               break;
-       case OTG_STATE_A_HOST:
-               if (langwell->host_ops)
-                       ret = langwell->host_ops->suspend(pdev, message);
-               langwell_otg_drv_vbus(0);
-               langwell_otg_phy_low_power(1);
-               break;
-       case OTG_STATE_A_SUSPEND:
-               langwell_otg_del_timer(a_aidl_bdis_tmr);
-               langwell_otg_HABA(0);
-               if (langwell->host_ops)
-                       langwell->host_ops->remove(pdev);
-               else
-                       otg_dbg("host driver has been removed.\n");
-               langwell_otg_drv_vbus(0);
-               transceiver_suspend(pdev);
-               langwell->otg.state = OTG_STATE_A_WAIT_VFALL;
-               break;
-       case OTG_STATE_A_PERIPHERAL:
-               if (langwell->client_ops)
-                       ret = langwell->client_ops->suspend(pdev, message);
-               else
-                       otg_dbg("client driver has been removed.\n");
-               langwell_otg_drv_vbus(0);
-               transceiver_suspend(pdev);
-               langwell->otg.state = OTG_STATE_A_WAIT_VFALL;
-               break;
-       case OTG_STATE_B_HOST:
-               if (langwell->host_ops)
-                       langwell->host_ops->remove(pdev);
-               else
-                       otg_dbg("host driver has been removed.\n");
-               langwell->hsm.b_bus_req = 0;
-               transceiver_suspend(pdev);
-               langwell->otg.state = OTG_STATE_B_IDLE;
-               break;
-       case OTG_STATE_B_PERIPHERAL:
-               if (langwell->client_ops)
-                       ret = langwell->client_ops->suspend(pdev, message);
-               else
-                       otg_dbg("client driver has been removed.\n");
-               break;
-       case OTG_STATE_B_WAIT_ACON:
-               langwell_otg_del_timer(b_ase0_brst_tmr);
-               langwell_otg_HAAR(0);
-               if (langwell->host_ops)
-                       langwell->host_ops->remove(pdev);
-               else
-                       otg_dbg("host driver has been removed.\n");
-               langwell->hsm.b_bus_req = 0;
-               langwell->otg.state = OTG_STATE_B_IDLE;
-               transceiver_suspend(pdev);
-               break;
-       default:
-               otg_dbg("error state before suspend\n ");
-               break;
-       }
-       spin_unlock(&langwell->wq_lock);
-
-       return ret;
-}
-
-static void transceiver_resume(struct pci_dev *pdev)
-{
-       pci_restore_state(pdev);
-       pci_set_power_state(pdev, PCI_D0);
-       langwell_otg_phy_low_power(0);
-}
-
-static int langwell_otg_resume(struct pci_dev *pdev)
-{
-       int     ret = 0;
-       struct langwell_otg *langwell;
-
-       langwell = the_transceiver;
-
-       spin_lock(&langwell->wq_lock);
-
-       switch (langwell->otg.state) {
-       case OTG_STATE_A_IDLE:
-       case OTG_STATE_B_IDLE:
-       case OTG_STATE_A_WAIT_VFALL:
-       case OTG_STATE_A_VBUS_ERR:
-               transceiver_resume(pdev);
-               break;
-       case OTG_STATE_A_WAIT_BCON:
-               langwell_otg_add_timer(a_wait_bcon_tmr);
-               langwell_otg_drv_vbus(1);
-               if (langwell->host_ops)
-                       ret = langwell->host_ops->resume(pdev);
-               break;
-       case OTG_STATE_A_HOST:
-               langwell_otg_drv_vbus(1);
-               langwell_otg_phy_low_power(0);
-               if (langwell->host_ops)
-                       ret = langwell->host_ops->resume(pdev);
-               break;
-       case OTG_STATE_B_PERIPHERAL:
-               if (langwell->client_ops)
-                       ret = langwell->client_ops->resume(pdev);
-               else
-                       otg_dbg("client driver not loaded.\n");
-               break;
-       default:
-               otg_dbg("error state before suspend\n ");
-               break;
-       }
-
-       if (request_irq(pdev->irq, otg_irq, IRQF_SHARED,
-                               driver_name, the_transceiver) != 0) {
-               otg_dbg("request interrupt %d failed\n", pdev->irq);
-               ret = -EBUSY;
-       }
-
-       /* enable OTG interrupts */
-       langwell_otg_intr(1);
-
-       spin_unlock(&langwell->wq_lock);
-
-       queue_work(langwell->qwork, &langwell->work);
-
-
-       return ret;
-}
-
-static int __init langwell_otg_init(void)
-{
-       return pci_register_driver(&otg_pci_driver);
-}
-module_init(langwell_otg_init);
-
-static void __exit langwell_otg_cleanup(void)
-{
-       pci_unregister_driver(&otg_pci_driver);
-}
-module_exit(langwell_otg_cleanup);
index 9ed5ea568679c3715eae4a03700d1ff8bd05e409..af456b48985f06f3ebe09ae43363f47f7d0bfec7 100644 (file)
@@ -53,6 +53,7 @@ EXPORT_SYMBOL(usb_nop_xceiv_register);
 void usb_nop_xceiv_unregister(void)
 {
        platform_device_unregister(pd);
+       pd = NULL;
 }
 EXPORT_SYMBOL(usb_nop_xceiv_unregister);
 
index 247b61bfb7f45f4d179abd6ef36f9611eea046da..0e4f2e41ace5b064193a46d3409d98df9099c117 100644 (file)
@@ -169,9 +169,11 @@ static int usb_console_setup(struct console *co, char *options)
                        kfree(tty);
                }
        }
-       /* So we know not to kill the hardware on a hangup on this
-          port. We have also bumped the use count by one so it won't go
-          idle */
+       /* Now that any required fake tty operations are completed restore
+        * the tty port count */
+       --port->port.count;
+       /* The console is special in terms of closing the device so
+        * indicate this port is now acting as a system console. */
        port->console = 1;
        retval = 0;
 
@@ -204,7 +206,7 @@ static void usb_console_write(struct console *co,
 
        dbg("%s - port %d, %d byte(s)", __func__, port->number, count);
 
-       if (!port->port.count) {
+       if (!port->console) {
                dbg("%s - port not opened", __func__);
                return;
        }
@@ -300,8 +302,7 @@ void usb_serial_console_exit(void)
 {
        if (usbcons_info.port) {
                unregister_console(&usbcons);
-               if (usbcons_info.port->port.count)
-                       usbcons_info.port->port.count--;
+               usbcons_info.port->console = 0;
                usbcons_info.port = NULL;
        }
 }
index 2b9eeda62bfe7beb12a4b3abb8aec6b3954e9f9c..e9a40b820fd4b28eac8053e40efa4082f7880b46 100644 (file)
@@ -67,6 +67,8 @@ static struct usb_device_id id_table [] = {
        { USB_DEVICE(0x10AB, 0x10C5) }, /* Siemens MC60 Cable */
        { USB_DEVICE(0x10B5, 0xAC70) }, /* Nokia CA-42 USB */
        { USB_DEVICE(0x10C4, 0x0F91) }, /* Vstabi */
+       { USB_DEVICE(0x10C4, 0x1101) }, /* Arkham Technology DS101 Bus Monitor */
+       { USB_DEVICE(0x10C4, 0x1601) }, /* Arkham Technology DS101 Adapter */
        { USB_DEVICE(0x10C4, 0x800A) }, /* SPORTident BSM7-D-USB main station */
        { USB_DEVICE(0x10C4, 0x803B) }, /* Pololu USB-serial converter */
        { USB_DEVICE(0x10C4, 0x8053) }, /* Enfora EDG1228 */
index 9734085fd2fee19f99051320db97ae22d867dc1e..59adfe123110b5e3c631f2ffa111d5b3c56680a7 100644 (file)
@@ -1228,8 +1228,8 @@ static void cypress_read_int_callback(struct urb *urb)
                /* precursor to disconnect so just go away */
                return;
        case -EPIPE:
-               usb_clear_halt(port->serial->dev, 0x81);
-               break;
+               /* Can't call usb_clear_halt while in_interrupt */
+               /* FALLS THROUGH */
        default:
                /* something ugly is going on... */
                dev_err(&urb->dev->dev,
index 3dc3768ca71ca0afb4a2a8f19541b3b345787b72..60c64cc5be2ae9dbbcef5720dc537af008839f67 100644 (file)
@@ -33,6 +33,7 @@
 #include <linux/errno.h>
 #include <linux/init.h>
 #include <linux/slab.h>
+#include <linux/smp_lock.h>
 #include <linux/tty.h>
 #include <linux/tty_driver.h>
 #include <linux/tty_flip.h>
@@ -107,6 +108,7 @@ struct ftdi_sio_quirk {
 
 static int   ftdi_jtag_probe(struct usb_serial *serial);
 static int   ftdi_mtxorb_hack_setup(struct usb_serial *serial);
+static int   ftdi_NDI_device_setup(struct usb_serial *serial);
 static void  ftdi_USB_UIRT_setup(struct ftdi_private *priv);
 static void  ftdi_HE_TIRA1_setup(struct ftdi_private *priv);
 
@@ -118,6 +120,10 @@ static struct ftdi_sio_quirk ftdi_mtxorb_hack_quirk = {
        .probe  = ftdi_mtxorb_hack_setup,
 };
 
+static struct ftdi_sio_quirk ftdi_NDI_device_quirk = {
+       .probe  = ftdi_NDI_device_setup,
+};
+
 static struct ftdi_sio_quirk ftdi_USB_UIRT_quirk = {
        .port_probe = ftdi_USB_UIRT_setup,
 };
@@ -191,6 +197,7 @@ static struct usb_device_id id_table_combined [] = {
        { USB_DEVICE(FTDI_VID, FTDI_MTXORB_4_PID) },
        { USB_DEVICE(FTDI_VID, FTDI_MTXORB_5_PID) },
        { USB_DEVICE(FTDI_VID, FTDI_MTXORB_6_PID) },
+       { USB_DEVICE(FTDI_VID, FTDI_R2000KU_TRUE_RNG) },
        { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0100_PID) },
        { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0101_PID) },
        { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0102_PID) },
@@ -579,6 +586,9 @@ static struct usb_device_id id_table_combined [] = {
        { USB_DEVICE(FTDI_VID, FTDI_CCSICDU20_0_PID) },
        { USB_DEVICE(FTDI_VID, FTDI_CCSICDU40_1_PID) },
        { USB_DEVICE(FTDI_VID, FTDI_CCSMACHX_2_PID) },
+       { USB_DEVICE(FTDI_VID, FTDI_CCSLOAD_N_GO_3_PID) },
+       { USB_DEVICE(FTDI_VID, FTDI_CCSICDU64_4_PID) },
+       { USB_DEVICE(FTDI_VID, FTDI_CCSPRIME8_5_PID) },
        { USB_DEVICE(FTDI_VID, INSIDE_ACCESSO) },
        { USB_DEVICE(INTREPID_VID, INTREPID_VALUECAN_PID) },
        { USB_DEVICE(INTREPID_VID, INTREPID_NEOVI_PID) },
@@ -644,6 +654,16 @@ static struct usb_device_id id_table_combined [] = {
        { USB_DEVICE(FTDI_VID, FTDI_TACTRIX_OPENPORT_13S_PID) },
        { USB_DEVICE(FTDI_VID, FTDI_TACTRIX_OPENPORT_13U_PID) },
        { USB_DEVICE(ELEKTOR_VID, ELEKTOR_FT323R_PID) },
+       { USB_DEVICE(FTDI_VID, FTDI_NDI_HUC_PID),
+               .driver_info = (kernel_ulong_t)&ftdi_NDI_device_quirk },
+       { USB_DEVICE(FTDI_VID, FTDI_NDI_SPECTRA_SCU_PID),
+               .driver_info = (kernel_ulong_t)&ftdi_NDI_device_quirk },
+       { USB_DEVICE(FTDI_VID, FTDI_NDI_FUTURE_2_PID),
+               .driver_info = (kernel_ulong_t)&ftdi_NDI_device_quirk },
+       { USB_DEVICE(FTDI_VID, FTDI_NDI_FUTURE_3_PID),
+               .driver_info = (kernel_ulong_t)&ftdi_NDI_device_quirk },
+       { USB_DEVICE(FTDI_VID, FTDI_NDI_AURORA_SCU_PID),
+               .driver_info = (kernel_ulong_t)&ftdi_NDI_device_quirk },
        { USB_DEVICE(TELLDUS_VID, TELLDUS_TELLSTICK_PID) },
        { USB_DEVICE(FTDI_VID, FTDI_MAXSTREAM_PID) },
        { USB_DEVICE(FTDI_VID, FTDI_PHI_FISCO_PID) },
@@ -660,6 +680,8 @@ static struct usb_device_id id_table_combined [] = {
                .driver_info = (kernel_ulong_t)&ftdi_jtag_quirk },
        { USB_DEVICE(FTDI_VID, LMI_LM3S_EVAL_BOARD_PID),
                .driver_info = (kernel_ulong_t)&ftdi_jtag_quirk },
+       { USB_DEVICE(FTDI_VID, FTDI_TURTELIZER_PID),
+               .driver_info = (kernel_ulong_t)&ftdi_jtag_quirk },
        { USB_DEVICE(RATOC_VENDOR_ID, RATOC_PRODUCT_ID_USB60F) },
        { USB_DEVICE(FTDI_VID, FTDI_REU_TINY_PID) },
        { USB_DEVICE(PAPOUCH_VID, PAPOUCH_QUIDO4x4_PID) },
@@ -667,7 +689,6 @@ static struct usb_device_id id_table_combined [] = {
        { USB_DEVICE(FTDI_VID, FTDI_DOMINTELL_DUSB_PID) },
        { USB_DEVICE(ALTI2_VID, ALTI2_N3_PID) },
        { USB_DEVICE(FTDI_VID, DIEBOLD_BCS_SE923_PID) },
-       { USB_DEVICE(FTDI_VID, FTDI_NDI_HUC_PID) },
        { USB_DEVICE(ATMEL_VID, STK541_PID) },
        { USB_DEVICE(DE_VID, STB_PID) },
        { USB_DEVICE(DE_VID, WHT_PID) },
@@ -1023,6 +1044,16 @@ static __u32 get_ftdi_divisor(struct tty_struct *tty,
        case FT2232C: /* FT2232C chip */
        case FT232RL:
                if (baud <= 3000000) {
+                       __u16 product_id = le16_to_cpu(
+                               port->serial->dev->descriptor.idProduct);
+                       if (((FTDI_NDI_HUC_PID == product_id) ||
+                            (FTDI_NDI_SPECTRA_SCU_PID == product_id) ||
+                            (FTDI_NDI_FUTURE_2_PID == product_id) ||
+                            (FTDI_NDI_FUTURE_3_PID == product_id) ||
+                            (FTDI_NDI_AURORA_SCU_PID == product_id)) &&
+                           (baud == 19200)) {
+                               baud = 1200000;
+                       }
                        div_value = ftdi_232bm_baud_to_divisor(baud);
                } else {
                        dbg("%s - Baud rate too high!", __func__);
@@ -1553,6 +1584,39 @@ static void ftdi_HE_TIRA1_setup(struct ftdi_private *priv)
        priv->force_rtscts = 1;
 } /* ftdi_HE_TIRA1_setup */
 
+/*
+ * Module parameter to control latency timer for NDI FTDI-based USB devices.
+ * If this value is not set in modprobe.conf.local its value will be set to 1ms.
+ */
+static int ndi_latency_timer = 1;
+
+/* Setup for the NDI FTDI-based USB devices, which requires hardwired
+ * baudrate (19200 gets mapped to 1200000).
+ *
+ * Called from usbserial:serial_probe.
+ */
+static int ftdi_NDI_device_setup(struct usb_serial *serial)
+{
+       struct usb_device *udev = serial->dev;
+       int latency = ndi_latency_timer;
+       int rv = 0;
+       char buf[1];
+
+       if (latency == 0)
+               latency = 1;
+       if (latency > 99)
+               latency = 99;
+
+       dbg("%s setting NDI device latency to %d", __func__, latency);
+       dev_info(&udev->dev, "NDI device with a latency value of %d", latency);
+
+       rv = usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
+                               FTDI_SIO_SET_LATENCY_TIMER_REQUEST,
+                               FTDI_SIO_SET_LATENCY_TIMER_REQUEST_TYPE,
+                               latency, 0, buf, 0, WDR_TIMEOUT);
+       return 0;
+}
+
 /*
  * First port on JTAG adaptors such as Olimex arm-usb-ocd or the FIC/OpenMoko
  * Neo1973 Debug Board is reserved for JTAG interface and can be accessed from
@@ -2121,7 +2185,7 @@ static void ftdi_process_read(struct work_struct *work)
                                /* Note that the error flag is duplicated for
                                   every character received since we don't know
                                   which character it applied to */
-                               if (!usb_serial_handle_sysrq_char(port,
+                               if (!usb_serial_handle_sysrq_char(tty, port,
                                                data[packet_offset + i]))
                                        tty_insert_flip_char(tty,
                                                data[packet_offset + i],
@@ -2622,3 +2686,5 @@ MODULE_PARM_DESC(vendor, "User specified vendor ID (default="
 module_param(product, ushort, 0);
 MODULE_PARM_DESC(product, "User specified product ID");
 
+module_param(ndi_latency_timer, int, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(ndi_latency_timer, "NDI device latency timer override");
index f1d440a728a376770617ad7776a52eba590cc282..c9fbd74150929d6849b773bf10d5cb8b7d92ffe1 100644 (file)
  *
  * Armin Laeuger originally sent the PID for the UM 100 module.
  */
+#define FTDI_R2000KU_TRUE_RNG  0xFB80  /* R2000KU TRUE RNG */
 #define FTDI_ELV_UR100_PID     0xFB58  /* USB-RS232-Umsetzer (UR 100) */
 #define FTDI_ELV_UM100_PID     0xFB5A  /* USB-Modul UM 100 */
 #define FTDI_ELV_UO100_PID     0xFB5B  /* USB-Modul UO 100 */
 #define FTDI_CCSICDU20_0_PID    0xF9D0
 #define FTDI_CCSICDU40_1_PID    0xF9D1
 #define FTDI_CCSMACHX_2_PID     0xF9D2
+#define FTDI_CCSLOAD_N_GO_3_PID 0xF9D3
+#define FTDI_CCSICDU64_4_PID    0xF9D4
+#define FTDI_CCSPRIME8_5_PID    0xF9D5
 
 /* Inside Accesso contactless reader (http://www.insidefr.com) */
 #define INSIDE_ACCESSO         0xFAD0
 /* Pyramid Computer GmbH */
 #define FTDI_PYRAMID_PID       0xE6C8  /* Pyramid Appliance Display */
 
+/*
+ * NDI (www.ndigital.com) product ids
+ */
+#define FTDI_NDI_HUC_PID               0xDA70  /* NDI Host USB Converter */
+#define FTDI_NDI_SPECTRA_SCU_PID       0xDA71  /* NDI Spectra SCU */
+#define FTDI_NDI_FUTURE_2_PID          0xDA72  /* NDI future device #2 */
+#define FTDI_NDI_FUTURE_3_PID          0xDA73  /* NDI future device #3 */
+#define FTDI_NDI_AURORA_SCU_PID                0xDA74  /* NDI Aurora SCU */
+
 /*
  * Posiflex inc retail equipment (http://www.posiflex.com.tw)
  */
 #define TML_VID                        0x1B91  /* Vendor ID */
 #define TML_USB_SERIAL_PID     0x0064  /* USB - Serial Converter */
 
-/* NDI Polaris System */
-#define FTDI_NDI_HUC_PID        0xDA70
-
 /* Propox devices */
 #define FTDI_PROPOX_JTAGCABLEII_PID    0xD738
 
 #define MARVELL_VID            0x9e88
 #define MARVELL_SHEEVAPLUG_PID 0x9e8f
 
+#define FTDI_TURTELIZER_PID    0xBDC8 /* JTAG/RS-232 adapter by egnite GmBH */
+
 /*
  *   BmRequestType:  1100 0000b
  *   bRequest:       FTDI_E2_READ
index 932d6241b787d2c399bae70f70bec85e4c979d71..ce57f6a32bdfb4cc7a5e30f78c1e8eca21a9364a 100644 (file)
@@ -424,10 +424,17 @@ static void flush_and_resubmit_read_urb(struct usb_serial_port *port)
        if (!tty)
                goto done;
 
-       /* Push data to tty */
-       for (i = 0; i < urb->actual_length; i++, ch++) {
-               if (!usb_serial_handle_sysrq_char(port, *ch))
-                       tty_insert_flip_char(tty, *ch, TTY_NORMAL);
+       /* The per character mucking around with sysrq path it too slow for
+          stuff like 3G modems, so shortcircuit it in the 99.9999999% of cases
+          where the USB serial is not a console anyway */
+       if (!port->console || !port->sysrq)
+               tty_insert_flip_string(tty, ch, urb->actual_length);
+       else {
+               /* Push data to tty */
+               for (i = 0; i < urb->actual_length; i++, ch++) {
+                       if (!usb_serial_handle_sysrq_char(tty, port, *ch))
+                               tty_insert_flip_char(tty, *ch, TTY_NORMAL);
+               }
        }
        tty_flip_buffer_push(tty);
        tty_kref_put(tty);
@@ -527,11 +534,12 @@ void usb_serial_generic_unthrottle(struct tty_struct *tty)
        }
 }
 
-int usb_serial_handle_sysrq_char(struct usb_serial_port *port, unsigned int ch)
+int usb_serial_handle_sysrq_char(struct tty_struct *tty,
+                       struct usb_serial_port *port, unsigned int ch)
 {
        if (port->sysrq && port->console) {
                if (ch && time_before(jiffies, port->sysrq)) {
-                       handle_sysrq(ch, tty_port_tty_get(&port->port));
+                       handle_sysrq(ch, tty);
                        port->sysrq = 0;
                        return 1;
                }
index c40f95c1951cf0cf17e8fedc4e8e9f4782324c67..c31940a307f8d3fbdb9ad223380fd36262e4927e 100644 (file)
@@ -26,6 +26,7 @@
 #include <linux/errno.h>
 #include <linux/init.h>
 #include <linux/slab.h>
+#include <linux/smp_lock.h>
 #include <linux/tty.h>
 #include <linux/tty_driver.h>
 #include <linux/tty_flip.h>
index 575816e6ba371fb4ef5fbeeba3668e559b86bfe2..98262dd552bb58c8b4d3b487b7dfb285cc9d64da 100644 (file)
@@ -206,6 +206,7 @@ static int  option_resume(struct usb_serial *serial);
 #define NOVATELWIRELESS_PRODUCT_MC950D         0x4400
 #define NOVATELWIRELESS_PRODUCT_U727           0x5010
 #define NOVATELWIRELESS_PRODUCT_MC760          0x6000
+#define NOVATELWIRELESS_PRODUCT_OVMC760                0x6002
 
 /* FUTURE NOVATEL PRODUCTS */
 #define NOVATELWIRELESS_PRODUCT_EVDO_HIGHSPEED 0X6001
@@ -307,11 +308,20 @@ static int  option_resume(struct usb_serial *serial);
 #define DLINK_VENDOR_ID                                0x1186
 #define DLINK_PRODUCT_DWM_652                  0x3e04
 
+#define QISDA_VENDOR_ID                                0x1da5
+#define QISDA_PRODUCT_H21_4512                 0x4512
+#define QISDA_PRODUCT_H21_4523                 0x4523
+#define QISDA_PRODUCT_H20_4515                 0x4515
+#define QISDA_PRODUCT_H20_4519                 0x4519
+
 
 /* TOSHIBA PRODUCTS */
 #define TOSHIBA_VENDOR_ID                      0x0930
 #define TOSHIBA_PRODUCT_HSDPA_MINICARD         0x1302
 
+#define ALINK_VENDOR_ID                                0x1e0e
+#define ALINK_PRODUCT_3GU                      0x9200
+
 static struct usb_device_id option_ids[] = {
        { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_COLT) },
        { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_RICOLA) },
@@ -430,6 +440,7 @@ static struct usb_device_id option_ids[] = {
        { USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, NOVATELWIRELESS_PRODUCT_MC727) }, /* Novatel MC727/U727/USB727 */
        { USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, NOVATELWIRELESS_PRODUCT_U727) }, /* Novatel MC727/U727/USB727 */
        { USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, NOVATELWIRELESS_PRODUCT_MC760) }, /* Novatel MC760/U760/USB760 */
+       { USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, NOVATELWIRELESS_PRODUCT_OVMC760) }, /* Novatel Ovation MC760 */
        { USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, NOVATELWIRELESS_PRODUCT_HSPA_FULLSPEED) }, /* Novatel HSPA product */
        { USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, NOVATELWIRELESS_PRODUCT_EVDO_EMBEDDED_FULLSPEED) }, /* Novatel EVDO Embedded product */
        { USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, NOVATELWIRELESS_PRODUCT_HSPA_EMBEDDED_FULLSPEED) }, /* Novatel HSPA Embedded product */
@@ -529,8 +540,13 @@ static struct usb_device_id option_ids[] = {
        { USB_DEVICE(ZTE_VENDOR_ID, ZTE_PRODUCT_CDMA_TECH) },
        { USB_DEVICE(BENQ_VENDOR_ID, BENQ_PRODUCT_H10) },
        { USB_DEVICE(DLINK_VENDOR_ID, DLINK_PRODUCT_DWM_652) },
-       { USB_DEVICE(0x1da5, 0x4515) }, /* BenQ H20 */
+       { USB_DEVICE(QISDA_VENDOR_ID, QISDA_PRODUCT_H21_4512) },
+       { USB_DEVICE(QISDA_VENDOR_ID, QISDA_PRODUCT_H21_4523) },
+       { USB_DEVICE(QISDA_VENDOR_ID, QISDA_PRODUCT_H20_4515) },
+       { USB_DEVICE(QISDA_VENDOR_ID, QISDA_PRODUCT_H20_4519) },
        { USB_DEVICE(TOSHIBA_VENDOR_ID, TOSHIBA_PRODUCT_HSDPA_MINICARD ) }, /* Toshiba 3G HSDPA == Novatel Expedite EU870D MiniCard */
+       { USB_DEVICE(ALINK_VENDOR_ID, 0x9000) },
+       { USB_DEVICE_AND_INTERFACE_INFO(ALINK_VENDOR_ID, ALINK_PRODUCT_3GU, 0xff, 0xff, 0xff) },
        { } /* Terminating entry */
 };
 MODULE_DEVICE_TABLE(usb, option_ids);
@@ -732,7 +748,6 @@ static int option_write(struct tty_struct *tty, struct usb_serial_port *port,
                memcpy(this_urb->transfer_buffer, buf, todo);
                this_urb->transfer_buffer_length = todo;
 
-               this_urb->dev = port->serial->dev;
                err = usb_submit_urb(this_urb, GFP_ATOMIC);
                if (err) {
                        dbg("usb_submit_urb %p (write bulk) failed "
@@ -860,7 +875,6 @@ static void option_instat_callback(struct urb *urb)
 
        /* Resubmit urb so we continue receiving IRQ data */
        if (status != -ESHUTDOWN && status != -ENOENT) {
-               urb->dev = serial->dev;
                err = usb_submit_urb(urb, GFP_ATOMIC);
                if (err)
                        dbg("%s: resubmit intr urb failed. (%d)",
@@ -921,23 +935,11 @@ static int option_open(struct tty_struct *tty,
 
        dbg("%s", __func__);
 
-       /* Reset low level data toggle and start reading from endpoints */
+       /* Start reading from the IN endpoint */
        for (i = 0; i < N_IN_URB; i++) {
                urb = portdata->in_urbs[i];
                if (!urb)
                        continue;
-               if (urb->dev != serial->dev) {
-                       dbg("%s: dev %p != %p", __func__,
-                               urb->dev, serial->dev);
-                       continue;
-               }
-
-               /*
-                * make sure endpoint data toggle is synchronized with the
-                * device
-                */
-               usb_clear_halt(urb->dev, urb->pipe);
-
                err = usb_submit_urb(urb, GFP_KERNEL);
                if (err) {
                        dbg("%s: submit urb %d failed (%d) %d",
@@ -946,16 +948,6 @@ static int option_open(struct tty_struct *tty,
                }
        }
 
-       /* Reset low level data toggle on out endpoints */
-       for (i = 0; i < N_OUT_URB; i++) {
-               urb = portdata->out_urbs[i];
-               if (!urb)
-                       continue;
-               urb->dev = serial->dev;
-               /* usb_settoggle(urb->dev, usb_pipeendpoint(urb->pipe),
-                               usb_pipeout(urb->pipe), 0); */
-       }
-
        option_send_setup(port);
 
        return 0;
@@ -1218,7 +1210,6 @@ static int option_resume(struct usb_serial *serial)
                        dbg("%s: No interrupt URB for port %d\n", __func__, i);
                        continue;
                }
-               port->interrupt_in_urb->dev = serial->dev;
                err = usb_submit_urb(port->interrupt_in_urb, GFP_NOIO);
                dbg("Submitted interrupt URB for port %d (result %d)", i, err);
                if (err < 0) {
index ec6c132a25b56f0a63ffa3b0b3a702594d1097b3..7d15bfa7c2dbfeb1c19768a2499ee2178d14efe0 100644 (file)
@@ -94,6 +94,7 @@ static struct usb_device_id id_table [] = {
        { USB_DEVICE(YCCABLE_VENDOR_ID, YCCABLE_PRODUCT_ID) },
        { USB_DEVICE(SUPERIAL_VENDOR_ID, SUPERIAL_PRODUCT_ID) },
        { USB_DEVICE(HP_VENDOR_ID, HP_LD220_PRODUCT_ID) },
+       { USB_DEVICE(CRESSI_VENDOR_ID, CRESSI_EDY_PRODUCT_ID) },
        { }                                     /* Terminating entry */
 };
 
@@ -971,18 +972,46 @@ exit:
                        __func__, retval);
 }
 
+static void pl2303_push_data(struct tty_struct *tty,
+               struct usb_serial_port *port, struct urb *urb,
+               u8 line_status)
+{
+       unsigned char *data = urb->transfer_buffer;
+       /* get tty_flag from status */
+       char tty_flag = TTY_NORMAL;
+       /* break takes precedence over parity, */
+       /* which takes precedence over framing errors */
+       if (line_status & UART_BREAK_ERROR)
+               tty_flag = TTY_BREAK;
+       else if (line_status & UART_PARITY_ERROR)
+               tty_flag = TTY_PARITY;
+       else if (line_status & UART_FRAME_ERROR)
+               tty_flag = TTY_FRAME;
+       dbg("%s - tty_flag = %d", __func__, tty_flag);
+
+       tty_buffer_request_room(tty, urb->actual_length + 1);
+       /* overrun is special, not associated with a char */
+       if (line_status & UART_OVERRUN_ERROR)
+               tty_insert_flip_char(tty, 0, TTY_OVERRUN);
+       if (port->console && port->sysrq) {
+               int i;
+               for (i = 0; i < urb->actual_length; ++i)
+                       if (!usb_serial_handle_sysrq_char(tty, port, data[i]))
+                               tty_insert_flip_char(tty, data[i], tty_flag);
+       } else
+               tty_insert_flip_string(tty, data, urb->actual_length);
+       tty_flip_buffer_push(tty);
+}
+
 static void pl2303_read_bulk_callback(struct urb *urb)
 {
        struct usb_serial_port *port =  urb->context;
        struct pl2303_private *priv = usb_get_serial_port_data(port);
        struct tty_struct *tty;
-       unsigned char *data = urb->transfer_buffer;
        unsigned long flags;
-       int i;
        int result;
        int status = urb->status;
        u8 line_status;
-       char tty_flag;
 
        dbg("%s - port %d", __func__, port->number);
 
@@ -1010,10 +1039,7 @@ static void pl2303_read_bulk_callback(struct urb *urb)
        }
 
        usb_serial_debug_data(debug, &port->dev, __func__,
-                             urb->actual_length, data);
-
-       /* get tty_flag from status */
-       tty_flag = TTY_NORMAL;
+                             urb->actual_length, urb->transfer_buffer);
 
        spin_lock_irqsave(&priv->lock, flags);
        line_status = priv->line_status;
@@ -1021,26 +1047,9 @@ static void pl2303_read_bulk_callback(struct urb *urb)
        spin_unlock_irqrestore(&priv->lock, flags);
        wake_up_interruptible(&priv->delta_msr_wait);
 
-       /* break takes precedence over parity, */
-       /* which takes precedence over framing errors */
-       if (line_status & UART_BREAK_ERROR)
-               tty_flag = TTY_BREAK;
-       else if (line_status & UART_PARITY_ERROR)
-               tty_flag = TTY_PARITY;
-       else if (line_status & UART_FRAME_ERROR)
-               tty_flag = TTY_FRAME;
-       dbg("%s - tty_flag = %d", __func__, tty_flag);
-
        tty = tty_port_tty_get(&port->port);
        if (tty && urb->actual_length) {
-               tty_buffer_request_room(tty, urb->actual_length + 1);
-               /* overrun is special, not associated with a char */
-               if (line_status & UART_OVERRUN_ERROR)
-                       tty_insert_flip_char(tty, 0, TTY_OVERRUN);
-               for (i = 0; i < urb->actual_length; ++i)
-                       if (!usb_serial_handle_sysrq_char(port, data[i]))
-                               tty_insert_flip_char(tty, data[i], tty_flag);
-               tty_flip_buffer_push(tty);
+               pl2303_push_data(tty, port, urb, line_status);
        }
        tty_kref_put(tty);
        /* Schedule the next read _if_ we are still open */
index 1d7a22e3a9fd1daa5df3c239185670763e7a5563..12aac7d2462dab327105a2fcf1f5344672efe121 100644 (file)
 /* Hewlett-Packard LD220-HP POS Pole Display */
 #define HP_VENDOR_ID           0x03f0
 #define HP_LD220_PRODUCT_ID    0x3524
+
+/* Cressi Edy (diving computer) PC interface */
+#define CRESSI_VENDOR_ID       0x04b8
+#define CRESSI_EDY_PRODUCT_ID  0x0521
index 032f7aeb40a42b17b71b1f4c2ae7b3d1ff221640..f48d05e0acc135e89a5e4a7518f3d1364b07e35d 100644 (file)
@@ -181,35 +181,50 @@ static const struct sierra_iface_info direct_ip_interface_blacklist = {
 };
 
 static struct usb_device_id id_table [] = {
+       { USB_DEVICE(0x0F3D, 0x0112) }, /* Airprime/Sierra PC 5220 */
+       { USB_DEVICE(0x03F0, 0x1B1D) }, /* HP ev2200 a.k.a MC5720 */
+       { USB_DEVICE(0x03F0, 0x1E1D) }, /* HP hs2300 a.k.a MC8775 */
+
        { USB_DEVICE(0x1199, 0x0017) }, /* Sierra Wireless EM5625 */
        { USB_DEVICE(0x1199, 0x0018) }, /* Sierra Wireless MC5720 */
        { USB_DEVICE(0x1199, 0x0218) }, /* Sierra Wireless MC5720 */
-       { USB_DEVICE(0x03f0, 0x1b1d) }, /* HP ev2200 a.k.a MC5720 */
        { USB_DEVICE(0x1199, 0x0020) }, /* Sierra Wireless MC5725 */
-       { USB_DEVICE(0x1199, 0x0024) }, /* Sierra Wireless MC5727 */
        { USB_DEVICE(0x1199, 0x0220) }, /* Sierra Wireless MC5725 */
+       { USB_DEVICE(0x1199, 0x0022) }, /* Sierra Wireless EM5725 */
+       { USB_DEVICE(0x1199, 0x0024) }, /* Sierra Wireless MC5727 */
+       { USB_DEVICE(0x1199, 0x0224) }, /* Sierra Wireless MC5727 */
        { USB_DEVICE(0x1199, 0x0019) }, /* Sierra Wireless AirCard 595 */
        { USB_DEVICE(0x1199, 0x0021) }, /* Sierra Wireless AirCard 597E */
+       { USB_DEVICE(0x1199, 0x0112) }, /* Sierra Wireless AirCard 580 */
        { USB_DEVICE(0x1199, 0x0120) }, /* Sierra Wireless USB Dongle 595U */
-        /* Sierra Wireless C597 */
+       /* Sierra Wireless C597 */
        { USB_DEVICE_AND_INTERFACE_INFO(0x1199, 0x0023, 0xFF, 0xFF, 0xFF) },
-        /* Sierra Wireless Device */
+       /* Sierra Wireless T598 */
        { USB_DEVICE_AND_INTERFACE_INFO(0x1199, 0x0025, 0xFF, 0xFF, 0xFF) },
-       { USB_DEVICE(0x1199, 0x0026) }, /* Sierra Wireless Device */
-       { USB_DEVICE(0x1199, 0x0027) }, /* Sierra Wireless Device */
-       { USB_DEVICE(0x1199, 0x0028) }, /* Sierra Wireless Device */
+       { USB_DEVICE(0x1199, 0x0026) }, /* Sierra Wireless T11 */
+       { USB_DEVICE(0x1199, 0x0027) }, /* Sierra Wireless AC402 */
+       { USB_DEVICE(0x1199, 0x0028) }, /* Sierra Wireless MC5728 */
+       { USB_DEVICE(0x1199, 0x0029) }, /* Sierra Wireless Device */
 
        { USB_DEVICE(0x1199, 0x6802) }, /* Sierra Wireless MC8755 */
-       { USB_DEVICE(0x1199, 0x6804) }, /* Sierra Wireless MC8755 */
        { USB_DEVICE(0x1199, 0x6803) }, /* Sierra Wireless MC8765 */
+       { USB_DEVICE(0x1199, 0x6804) }, /* Sierra Wireless MC8755 */
+       { USB_DEVICE(0x1199, 0x6805) }, /* Sierra Wireless MC8765 */
+       { USB_DEVICE(0x1199, 0x6808) }, /* Sierra Wireless MC8755 */
+       { USB_DEVICE(0x1199, 0x6809) }, /* Sierra Wireless MC8765 */
        { USB_DEVICE(0x1199, 0x6812) }, /* Sierra Wireless MC8775 & AC 875U */
-       { USB_DEVICE(0x1199, 0x6813) }, /* Sierra Wireless MC8775 (Lenovo) */
+       { USB_DEVICE(0x1199, 0x6813) }, /* Sierra Wireless MC8775 */
        { USB_DEVICE(0x1199, 0x6815) }, /* Sierra Wireless MC8775 */
-       { USB_DEVICE(0x03f0, 0x1e1d) }, /* HP hs2300 a.k.a MC8775 */
+       { USB_DEVICE(0x1199, 0x6816) }, /* Sierra Wireless MC8775 */
        { USB_DEVICE(0x1199, 0x6820) }, /* Sierra Wireless AirCard 875 */
        { USB_DEVICE(0x1199, 0x6821) }, /* Sierra Wireless AirCard 875U */
+       { USB_DEVICE(0x1199, 0x6822) }, /* Sierra Wireless AirCard 875E */
        { USB_DEVICE(0x1199, 0x6832) }, /* Sierra Wireless MC8780 */
        { USB_DEVICE(0x1199, 0x6833) }, /* Sierra Wireless MC8781 */
+       { USB_DEVICE(0x1199, 0x6834) }, /* Sierra Wireless MC8780 */
+       { USB_DEVICE(0x1199, 0x6835) }, /* Sierra Wireless MC8781 */
+       { USB_DEVICE(0x1199, 0x6838) }, /* Sierra Wireless MC8780 */
+       { USB_DEVICE(0x1199, 0x6839) }, /* Sierra Wireless MC8781 */
        { USB_DEVICE(0x1199, 0x683A) }, /* Sierra Wireless MC8785 */
        { USB_DEVICE(0x1199, 0x683B) }, /* Sierra Wireless MC8785 Composite */
        /* Sierra Wireless MC8790, MC8791, MC8792 Composite */
@@ -227,16 +242,13 @@ static struct usb_device_id id_table [] = {
        { USB_DEVICE(0x1199, 0x685A) }, /* Sierra Wireless AirCard 885 E */
        /* Sierra Wireless C885 */
        { USB_DEVICE_AND_INTERFACE_INFO(0x1199, 0x6880, 0xFF, 0xFF, 0xFF)},
-       /* Sierra Wireless Device */
+       /* Sierra Wireless C888, Air Card 501, USB 303, USB 304 */
        { USB_DEVICE_AND_INTERFACE_INFO(0x1199, 0x6890, 0xFF, 0xFF, 0xFF)},
-       /* Sierra Wireless Device */
+       /* Sierra Wireless C22/C33 */
        { USB_DEVICE_AND_INTERFACE_INFO(0x1199, 0x6891, 0xFF, 0xFF, 0xFF)},
-       /* Sierra Wireless Device */
+       /* Sierra Wireless HSPA Non-Composite Device */
        { USB_DEVICE_AND_INTERFACE_INFO(0x1199, 0x6892, 0xFF, 0xFF, 0xFF)},
-
-       { USB_DEVICE(0x1199, 0x0112) }, /* Sierra Wireless AirCard 580 */
-       { USB_DEVICE(0x0F3D, 0x0112) }, /* Airprime/Sierra PC 5220 */
-
+       { USB_DEVICE(0x1199, 0x6893) }, /* Sierra Wireless Device */
        { USB_DEVICE(0x1199, 0x68A3),   /* Sierra Wireless Direct IP modems */
          .driver_info = (kernel_ulong_t)&direct_ip_interface_blacklist
        },
@@ -814,7 +826,7 @@ static int sierra_startup(struct usb_serial *serial)
        return 0;
 }
 
-static void sierra_disconnect(struct usb_serial *serial)
+static void sierra_release(struct usb_serial *serial)
 {
        int i;
        struct usb_serial_port *port;
@@ -830,7 +842,6 @@ static void sierra_disconnect(struct usb_serial *serial)
                if (!portdata)
                        continue;
                kfree(portdata);
-               usb_set_serial_port_data(port, NULL);
        }
 }
 
@@ -853,7 +864,7 @@ static struct usb_serial_driver sierra_device = {
        .tiocmget          = sierra_tiocmget,
        .tiocmset          = sierra_tiocmset,
        .attach            = sierra_startup,
-       .disconnect        = sierra_disconnect,
+       .release           = sierra_release,
        .read_int_callback = sierra_instat_callback,
 };
 
index 991d8232e3765c39de562ec8e09181d0e8d4c547..14971a926990575aa6afd30c5c364d4b7f1e8539 100644 (file)
@@ -191,7 +191,6 @@ static struct usb_device_id ti_id_table_5052[5+TI_EXTRA_VID_PID_COUNT+1] = {
        { USB_DEVICE(TI_VENDOR_ID, TI_5152_BOOT_PRODUCT_ID) },
        { USB_DEVICE(TI_VENDOR_ID, TI_5052_EEPROM_PRODUCT_ID) },
        { USB_DEVICE(TI_VENDOR_ID, TI_5052_FIRMWARE_PRODUCT_ID) },
-       { USB_DEVICE(IBM_VENDOR_ID, IBM_4543_PRODUCT_ID) },
 };
 
 static struct usb_device_id ti_id_table_combined[14+2*TI_EXTRA_VID_PID_COUNT+1] = {
@@ -1658,7 +1657,7 @@ static int ti_do_download(struct usb_device *dev, int pipe,
        u8 cs = 0;
        int done;
        struct ti_firmware_header *header;
-       int status;
+       int status = 0;
        int len;
 
        for (pos = sizeof(struct ti_firmware_header); pos < size; pos++)
index d595aa5586a733003532e6f0a7a95e051e3ce659..bd7581b3a48afd3beb2f3eeef28ca604c8c08842 100644 (file)
@@ -21,6 +21,7 @@
 #include <linux/errno.h>
 #include <linux/init.h>
 #include <linux/slab.h>
+#include <linux/smp_lock.h>
 #include <linux/tty.h>
 #include <linux/tty_driver.h>
 #include <linux/tty_flip.h>
@@ -220,7 +221,8 @@ static int serial_open (struct tty_struct *tty, struct file *filp)
        tty->driver_data = port;
        tty_port_tty_set(&port->port, tty);
 
-       if (port->port.count == 1) {
+       /* If the console is attached, the device is already open */
+       if (port->port.count == 1 && !port->console) {
 
                /* lock this module before we call it
                 * this may fail, which means we must bail out,
@@ -333,6 +335,9 @@ static void serial_close(struct tty_struct *tty, struct file *filp)
 {
        struct usb_serial_port *port = tty->driver_data;
 
+       if (!port)
+               return;
+
        dbg("%s - port %d", __func__, port->number);
 
 
index d41cc0a970f79a147660da239bdc014612396354..773a5cd38c5aa7773f5b7f1837351a8945b3f084 100644 (file)
@@ -118,6 +118,9 @@ static int option_inquiry(struct us_data *us)
 
        result = memcmp(buffer+8, "Option", 6);
 
+       if (result != 0)
+               result = memcmp(buffer+8, "ZCOPTION", 8);
+
        /* Read the CSW */
        usb_stor_bulk_transfer_buf(us,
                        us->recv_bulk_pipe,
index 559f8784acf36e52a47a3ee277f0d24eb47c7c06..9052bcb4f528d206437f9a3e3c4212b211938d12 100644 (file)
@@ -501,7 +501,7 @@ int hwarc_filter_event_WUSB_0100(struct uwb_rc *rc, struct uwb_rceb **header,
        int result = -ENOANO;
        struct uwb_rceb *rceb = *header;
        int event = le16_to_cpu(rceb->wEvent);
-       size_t event_size;
+       ssize_t event_size;
        size_t core_size, offset;
 
        if (rceb->bEventType != UWB_RC_CET_GENERAL)
index cd2035768b47824d3c5b3e80c5b292cd2d7b4d60..86a853b84119d54febd7c895683f42a78235b991 100644 (file)
@@ -326,7 +326,7 @@ int wlp_prepare_tx_frame(struct device *dev, struct wlp *wlp,
        int result = -EINVAL;
        struct ethhdr *eth_hdr = (void *) skb->data;
 
-       if (is_broadcast_ether_addr(eth_hdr->h_dest)) {
+       if (is_multicast_ether_addr(eth_hdr->h_dest)) {
                result = wlp_eda_for_each(&wlp->eda, wlp_wss_send_copy, skb);
                if (result < 0) {
                        if (printk_ratelimit())
index d6d65ef85f541b3cdb49ad45bfaa0430c4cbeba4..3b54b39401781a7b42c076b66cad74eab0ff5259 100644 (file)
@@ -616,6 +616,8 @@ config FB_STI
        select FB_CFB_FILLRECT
        select FB_CFB_COPYAREA
        select FB_CFB_IMAGEBLIT
+       select STI_CONSOLE
+       select VT
        default y
        ---help---
          STI refers to the HP "Standard Text Interface" which is a set of
@@ -1117,12 +1119,13 @@ config FB_CARILLO_RANCH
 
 config FB_INTEL
        tristate "Intel 830M/845G/852GM/855GM/865G/915G/945G/945GM/965G/965GM support (EXPERIMENTAL)"
-       depends on EXPERIMENTAL && FB && PCI && X86 && AGP_INTEL
+       depends on EXPERIMENTAL && FB && PCI && X86 && AGP_INTEL && EMBEDDED
        select FB_MODE_HELPERS
        select FB_CFB_FILLRECT
        select FB_CFB_COPYAREA
        select FB_CFB_IMAGEBLIT
        select FB_BOOT_VESA_SUPPORT if FB_INTEL = y
+       depends on !DRM_I915
        help
          This driver supports the on-board graphics built in to the Intel
           830M/845G/852GM/855GM/865G/915G/915GM/945G/945GM/965G/965GM chipsets.
index fb8163d181abbb5383535b37e1b85a26367d5432..a21efcd10b78792bd75132d19e72cbd56b55e2bf 100644 (file)
@@ -226,9 +226,10 @@ static int clcdfb_set_par(struct fb_info *info)
        clcdfb_enable(fb, regs.cntl);
 
 #ifdef DEBUG
-       printk(KERN_INFO "CLCD: Registers set to\n"
-              KERN_INFO "  %08x %08x %08x %08x\n"
-              KERN_INFO "  %08x %08x %08x %08x\n",
+       printk(KERN_INFO
+              "CLCD: Registers set to\n"
+              "  %08x %08x %08x %08x\n"
+              "  %08x %08x %08x %08x\n",
                readl(fb->regs + CLCD_TIM0), readl(fb->regs + CLCD_TIM1),
                readl(fb->regs + CLCD_TIM2), readl(fb->regs + CLCD_TIM3),
                readl(fb->regs + CLCD_UBAS), readl(fb->regs + CLCD_LBAS),
index 018850c116c646edbeadf5cc6e4fc828e3901eff..8cd279be74e5de975d1e3871f806673e67de3783 100644 (file)
@@ -2405,6 +2405,9 @@ static int do_fb_set_var(struct fb_var_screeninfo *var, int isactive)
        return 0;
 }
 
+/* fbhw->encode_fix() must be called with fb_info->mm_lock held
+ * if it is called after the register_framebuffer() - not a case here
+ */
 static int atafb_get_fix(struct fb_fix_screeninfo *fix, struct fb_info *info)
 {
        struct atafb_par par;
@@ -2414,7 +2417,8 @@ static int atafb_get_fix(struct fb_fix_screeninfo *fix, struct fb_info *info)
        if (err)
                return err;
        memset(fix, 0, sizeof(struct fb_fix_screeninfo));
-       return fbhw->encode_fix(fix, &par);
+       err = fbhw->encode_fix(fix, &par);
+       return err;
 }
 
 static int atafb_get_var(struct fb_var_screeninfo *var, struct fb_info *info)
@@ -2743,7 +2747,9 @@ static int atafb_set_par(struct fb_info *info)
 
        /* Decode wanted screen parameters */
        fbhw->decode_var(&info->var, par);
+       mutex_lock(&info->mm_lock);
        fbhw->encode_fix(&info->fix, par);
+       mutex_unlock(&info->mm_lock);
 
        /* Set new videomode */
        ata_set_par(par);
index 5afd64482f5584fd7c03f0d6267875da6eb3f16f..da05f0801bb754221188d15ddcd070e85b796830 100644 (file)
@@ -261,6 +261,9 @@ static inline void atmel_lcdfb_free_video_memory(struct atmel_lcdfb_info *sinfo)
 /**
  *     atmel_lcdfb_alloc_video_memory - Allocate framebuffer memory
  *     @sinfo: the frame buffer to allocate memory for
+ *     
+ *     This function is called only from the atmel_lcdfb_probe()
+ *     so no locking by fb_info->mm_lock around smem_len setting is needed.
  */
 static int atmel_lcdfb_alloc_video_memory(struct atmel_lcdfb_info *sinfo)
 {
index 7691e73823d398fd76d8cadfdea557cc8a66d605..1f39a62f899be953384320f9bb25da13427c4374 100644 (file)
@@ -187,6 +187,8 @@ struct atyfb_par {
        int mtrr_reg;
 #endif
        u32 mem_cntl;
+       struct crtc saved_crtc;
+       union aty_pll saved_pll;
 };
 
     /*
@@ -217,6 +219,7 @@ struct atyfb_par {
 #define M64F_XL_DLL            0x00080000
 #define M64F_MFB_FORCE_4       0x00100000
 #define M64F_HW_TRIPLE         0x00200000
+#define M64F_XL_MEM            0x00400000
     /*
      *  Register access
      */
index 1207c208a30b32f243a6ab4ec952d811d69fe248..63d3739d43a85bf0e6264a51562f01283bb486ab 100644 (file)
@@ -66,6 +66,8 @@
 #include <linux/spinlock.h>
 #include <linux/wait.h>
 #include <linux/backlight.h>
+#include <linux/reboot.h>
+#include <linux/dmi.h>
 
 #include <asm/io.h>
 #include <linux/uaccess.h>
@@ -249,8 +251,6 @@ static int aty_init(struct fb_info *info);
 static int store_video_par(char *videopar, unsigned char m64_num);
 #endif
 
-static struct crtc saved_crtc;
-static union aty_pll saved_pll;
 static void aty_get_crtc(const struct atyfb_par *par, struct crtc *crtc);
 
 static void aty_set_crtc(const struct atyfb_par *par, const struct crtc *crtc);
@@ -261,6 +261,8 @@ static void set_off_pitch(struct atyfb_par *par, const struct fb_info *info);
 static int read_aty_sense(const struct atyfb_par *par);
 #endif
 
+static DEFINE_MUTEX(reboot_lock);
+static struct fb_info *reboot_info;
 
     /*
      *  Interface used by the world
@@ -361,8 +363,8 @@ static unsigned long phys_guiregbase[FB_MAX] __devinitdata = { 0, };
 #define ATI_CHIP_264GTPRO  (ATI_MODERN_SET | M64F_SDRAM_MAGIC_PLL | M64F_HW_TRIPLE | M64F_FIFO_32 | M64F_RESET_3D)
 #define ATI_CHIP_264LTPRO  (ATI_MODERN_SET | M64F_HW_TRIPLE | M64F_FIFO_32 | M64F_RESET_3D)
 
-#define ATI_CHIP_264XL     (ATI_MODERN_SET | M64F_HW_TRIPLE | M64F_FIFO_32 | M64F_RESET_3D | M64F_XL_DLL | M64F_MFB_FORCE_4)
-#define ATI_CHIP_MOBILITY  (ATI_MODERN_SET | M64F_HW_TRIPLE | M64F_FIFO_32 | M64F_RESET_3D | M64F_XL_DLL | M64F_MFB_FORCE_4 | M64F_MOBIL_BUS)
+#define ATI_CHIP_264XL     (ATI_MODERN_SET | M64F_HW_TRIPLE | M64F_FIFO_32 | M64F_RESET_3D | M64F_XL_DLL | M64F_MFB_FORCE_4 | M64F_XL_MEM)
+#define ATI_CHIP_MOBILITY  (ATI_MODERN_SET | M64F_HW_TRIPLE | M64F_FIFO_32 | M64F_RESET_3D | M64F_XL_DLL | M64F_MFB_FORCE_4 | M64F_XL_MEM | M64F_MOBIL_BUS)
 
 static struct {
        u16 pci_id;
@@ -539,6 +541,7 @@ static char ram_edo[] __devinitdata = "EDO";
 static char ram_sdram[] __devinitdata = "SDRAM (1:1)";
 static char ram_sgram[] __devinitdata = "SGRAM (1:1)";
 static char ram_sdram32[] __devinitdata = "SDRAM (2:1) (32-bit)";
+static char ram_wram[] __devinitdata = "WRAM";
 static char ram_off[] __devinitdata = "OFF";
 #endif /* CONFIG_FB_ATY_CT */
 
@@ -552,6 +555,10 @@ static char *aty_gx_ram[8] __devinitdata = {
 
 #ifdef CONFIG_FB_ATY_CT
 static char *aty_ct_ram[8] __devinitdata = {
+       ram_off, ram_dram, ram_edo, ram_edo,
+       ram_sdram, ram_sgram, ram_wram, ram_resv
+};
+static char *aty_xl_ram[8] __devinitdata = {
        ram_off, ram_dram, ram_edo, ram_edo,
        ram_sdram, ram_sgram, ram_sdram32, ram_resv
 };
@@ -760,6 +767,17 @@ static void aty_set_crtc(const struct atyfb_par *par, const struct crtc *crtc)
 #endif /* CONFIG_FB_ATY_GENERIC_LCD */
 }
 
+static u32 calc_line_length(struct atyfb_par *par, u32 vxres, u32 bpp)
+{
+       u32 line_length = vxres * bpp / 8;
+
+       if (par->ram_type == SGRAM ||
+           (!M64_HAS(XL_MEM) && par->ram_type == WRAM))
+               line_length = (line_length + 63) & ~63;
+
+       return line_length;
+}
+
 static int aty_var_to_crtc(const struct fb_info *info,
        const struct fb_var_screeninfo *var, struct crtc *crtc)
 {
@@ -769,13 +787,14 @@ static int aty_var_to_crtc(const struct fb_info *info,
        u32 h_total, h_disp, h_sync_strt, h_sync_end, h_sync_dly, h_sync_wid, h_sync_pol;
        u32 v_total, v_disp, v_sync_strt, v_sync_end, v_sync_wid, v_sync_pol, c_sync;
        u32 pix_width, dp_pix_width, dp_chain_mask;
+       u32 line_length;
 
        /* input */
-       xres = var->xres;
+       xres = (var->xres + 7) & ~7;
        yres = var->yres;
-       vxres = var->xres_virtual;
+       vxres = (var->xres_virtual + 7) & ~7;
        vyres = var->yres_virtual;
-       xoffset = var->xoffset;
+       xoffset = (var->xoffset + 7) & ~7;
        yoffset = var->yoffset;
        bpp = var->bits_per_pixel;
        if (bpp == 16)
@@ -827,7 +846,9 @@ static int aty_var_to_crtc(const struct fb_info *info,
        } else
                FAIL("invalid bpp");
 
-       if (vxres * vyres * bpp / 8 > info->fix.smem_len)
+       line_length = calc_line_length(par, vxres, bpp);
+
+       if (vyres * line_length > info->fix.smem_len)
                FAIL("not enough video RAM");
 
        h_sync_pol = sync & FB_SYNC_HOR_HIGH_ACT ? 0 : 1;
@@ -969,7 +990,9 @@ static int aty_var_to_crtc(const struct fb_info *info,
        crtc->xoffset = xoffset;
        crtc->yoffset = yoffset;
        crtc->bpp = bpp;
-       crtc->off_pitch = ((yoffset*vxres+xoffset)*bpp/64) | (vxres<<19);
+       crtc->off_pitch =
+               ((yoffset * line_length + xoffset * bpp / 8) / 8) |
+               ((line_length / bpp) << 22);
        crtc->vline_crnt_vline = 0;
 
        crtc->h_tot_disp = h_total | (h_disp<<16);
@@ -1394,7 +1417,9 @@ static int atyfb_set_par(struct fb_info *info)
        }
        aty_st_8(DAC_MASK, 0xff, par);
 
-       info->fix.line_length = var->xres_virtual * var->bits_per_pixel/8;
+       info->fix.line_length = calc_line_length(par, var->xres_virtual,
+                                                var->bits_per_pixel);
+
        info->fix.visual = var->bits_per_pixel <= 8 ?
                FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_DIRECTCOLOR;
 
@@ -1505,10 +1530,12 @@ static void set_off_pitch(struct atyfb_par *par, const struct fb_info *info)
 {
        u32 xoffset = info->var.xoffset;
        u32 yoffset = info->var.yoffset;
-       u32 vxres = par->crtc.vxres;
+       u32 line_length = info->fix.line_length;
        u32 bpp = info->var.bits_per_pixel;
 
-       par->crtc.off_pitch = ((yoffset * vxres + xoffset) * bpp / 64) | (vxres << 19);
+       par->crtc.off_pitch =
+               ((yoffset * line_length + xoffset * bpp / 8) / 8) |
+               ((line_length / bpp) << 22);
 }
 
 
@@ -2201,7 +2228,7 @@ static void __devinit aty_calc_mem_refresh(struct atyfb_par *par, int xclk)
        const int *refresh_tbl;
        int i, size;
 
-       if (IS_XL(par->pci_id) || IS_MOBILITY(par->pci_id)) {
+       if (M64_HAS(XL_MEM)) {
                refresh_tbl = ragexl_tbl;
                size = ARRAY_SIZE(ragexl_tbl);
        } else {
@@ -2335,7 +2362,10 @@ static int __devinit aty_init(struct fb_info *info)
                par->pll_ops = &aty_pll_ct;
                par->bus_type = PCI;
                par->ram_type = (aty_ld_le32(CNFG_STAT0, par) & 0x07);
-               ramname = aty_ct_ram[par->ram_type];
+               if (M64_HAS(XL_MEM))
+                       ramname = aty_xl_ram[par->ram_type];
+               else
+                       ramname = aty_ct_ram[par->ram_type];
                /* for many chips, the mclk is 67 MHz for SDRAM, 63 MHz otherwise */
                if (par->pll_limits.mclk == 67 && par->ram_type < SDRAM)
                        par->pll_limits.mclk = 63;
@@ -2390,9 +2420,9 @@ static int __devinit aty_init(struct fb_info *info)
 #endif /* CONFIG_FB_ATY_CT */
 
        /* save previous video mode */
-       aty_get_crtc(par, &saved_crtc);
+       aty_get_crtc(par, &par->saved_crtc);
        if(par->pll_ops->get_pll)
-               par->pll_ops->get_pll(info, &saved_pll);
+               par->pll_ops->get_pll(info, &par->saved_pll);
 
        par->mem_cntl = aty_ld_le32(MEM_CNTL, par);
        gtb_memsize = M64_HAS(GTB_DSP);
@@ -2667,8 +2697,8 @@ static int __devinit aty_init(struct fb_info *info)
 
 aty_init_exit:
        /* restore video mode */
-       aty_set_crtc(par, &saved_crtc);
-       par->pll_ops->set_pll(info, &saved_pll);
+       aty_set_crtc(par, &par->saved_crtc);
+       par->pll_ops->set_pll(info, &par->saved_pll);
 
 #ifdef CONFIG_MTRR
        if (par->mtrr_reg >= 0) {
@@ -3502,6 +3532,11 @@ static int __devinit atyfb_pci_probe(struct pci_dev *pdev, const struct pci_devi
        par->mmap_map[1].prot_flag = _PAGE_E;
 #endif /* __sparc__ */
 
+       mutex_lock(&reboot_lock);
+       if (!reboot_info)
+               reboot_info = info;
+       mutex_unlock(&reboot_lock);
+
        return 0;
 
 err_release_io:
@@ -3614,8 +3649,8 @@ static void __devexit atyfb_remove(struct fb_info *info)
        struct atyfb_par *par = (struct atyfb_par *) info->par;
 
        /* restore video mode */
-       aty_set_crtc(par, &saved_crtc);
-       par->pll_ops->set_pll(info, &saved_pll);
+       aty_set_crtc(par, &par->saved_crtc);
+       par->pll_ops->set_pll(info, &par->saved_pll);
 
        unregister_framebuffer(info);
 
@@ -3661,6 +3696,11 @@ static void __devexit atyfb_pci_remove(struct pci_dev *pdev)
 {
        struct fb_info *info = pci_get_drvdata(pdev);
 
+       mutex_lock(&reboot_lock);
+       if (reboot_info == info)
+               reboot_info = NULL;
+       mutex_unlock(&reboot_lock);
+
        atyfb_remove(info);
 }
 
@@ -3808,6 +3848,56 @@ static int __init atyfb_setup(char *options)
 }
 #endif  /*  MODULE  */
 
+static int atyfb_reboot_notify(struct notifier_block *nb,
+                              unsigned long code, void *unused)
+{
+       struct atyfb_par *par;
+
+       if (code != SYS_RESTART)
+               return NOTIFY_DONE;
+
+       mutex_lock(&reboot_lock);
+
+       if (!reboot_info)
+               goto out;
+
+       if (!lock_fb_info(reboot_info))
+               goto out;
+
+       par = reboot_info->par;
+
+       /*
+        * HP OmniBook 500's BIOS doesn't like the state of the
+        * hardware after atyfb has been used. Restore the hardware
+        * to the original state to allow successful reboots.
+        */
+       aty_set_crtc(par, &par->saved_crtc);
+       par->pll_ops->set_pll(reboot_info, &par->saved_pll);
+
+       unlock_fb_info(reboot_info);
+ out:
+       mutex_unlock(&reboot_lock);
+
+       return NOTIFY_DONE;
+}
+
+static struct notifier_block atyfb_reboot_notifier = {
+       .notifier_call = atyfb_reboot_notify,
+};
+
+static const struct dmi_system_id atyfb_reboot_ids[] = {
+       {
+               .ident = "HP OmniBook 500",
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "HP OmniBook PC"),
+                       DMI_MATCH(DMI_PRODUCT_VERSION, "HP OmniBook 500 FA"),
+               },
+       },
+
+       { }
+};
+
 static int __init atyfb_init(void)
 {
     int err1 = 1, err2 = 1;
@@ -3826,11 +3916,20 @@ static int __init atyfb_init(void)
     err2 = atyfb_atari_probe();
 #endif
 
-    return (err1 && err2) ? -ENODEV : 0;
+    if (err1 && err2)
+       return -ENODEV;
+
+    if (dmi_check_system(atyfb_reboot_ids))
+       register_reboot_notifier(&atyfb_reboot_notifier);
+
+    return 0;
 }
 
 static void __exit atyfb_exit(void)
 {
+       if (dmi_check_system(atyfb_reboot_ids))
+               unregister_reboot_notifier(&atyfb_reboot_notifier);
+
 #ifdef CONFIG_PCI
        pci_unregister_driver(&atyfb_driver);
 #endif
index 0cc9724e61a268cc8e21acfbd5cd4ff05100a6f6..51fcc0a2c94a9097aea33eff174b1b38969b263d 100644 (file)
@@ -63,14 +63,17 @@ static void reset_GTC_3D_engine(const struct atyfb_par *par)
 void aty_init_engine(struct atyfb_par *par, struct fb_info *info)
 {
        u32 pitch_value;
+       u32 vxres;
 
        /* determine modal information from global mode structure */
-       pitch_value = info->var.xres_virtual;
+       pitch_value = info->fix.line_length / (info->var.bits_per_pixel / 8);
+       vxres = info->var.xres_virtual;
 
        if (info->var.bits_per_pixel == 24) {
                /* In 24 bpp, the engine is in 8 bpp - this requires that all */
                /* horizontal coordinates and widths must be adjusted */
                pitch_value *= 3;
+               vxres *= 3;
        }
 
        /* On GTC (RagePro), we need to reset the 3D engine before */
@@ -133,7 +136,7 @@ void aty_init_engine(struct atyfb_par *par, struct fb_info *info)
        aty_st_le32(SC_LEFT, 0, par);
        aty_st_le32(SC_TOP, 0, par);
        aty_st_le32(SC_BOTTOM, par->crtc.vyres - 1, par);
-       aty_st_le32(SC_RIGHT, pitch_value - 1, par);
+       aty_st_le32(SC_RIGHT, vxres - 1, par);
 
        /* set background color to minimum value (usually BLACK) */
        aty_st_le32(DP_BKGD_CLR, 0, par);
index 1dae7f8f3c6b47c7f4861ff824fff0a4d4dcf8f3..51422fc4f6060ff12b28ff05db0c55ea99613979 100644 (file)
@@ -356,7 +356,7 @@ static int __devinit tdo24m_probe(struct spi_device *spi)
        lcd->power = FB_BLANK_POWERDOWN;
        lcd->mode = MODE_VGA;   /* default to VGA */
 
-       lcd->buf = kmalloc(TDO24M_SPI_BUFF_SIZE, sizeof(GFP_KERNEL));
+       lcd->buf = kmalloc(TDO24M_SPI_BUFF_SIZE, GFP_KERNEL);
        if (lcd->buf == NULL) {
                kfree(lcd);
                return -ENOMEM;
index 7bad24ed04ef5eb2dc8a1e2bec9a56c902e45f7a..108b89e09a80dbdd8c8593f5977a6b8b1a1b7586 100644 (file)
@@ -1,7 +1,7 @@
 /*
  *  Cobalt server LCD frame buffer driver.
  *
- *  Copyright (C) 2008  Yoichi Yuasa <yoichi_yuasa@tripeaks.co.jp>
+ *  Copyright (C) 2008  Yoichi Yuasa <yuasa@linux-mips.org>
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
index f8a09bf8d0cdecb0963116a4fb7a7d3793ed798d..a85c818be9453ecbdf11310b8a77f41435652000 100644 (file)
@@ -16,7 +16,6 @@
 #include <linux/compat.h>
 #include <linux/types.h>
 #include <linux/errno.h>
-#include <linux/smp_lock.h>
 #include <linux/kernel.h>
 #include <linux/major.h>
 #include <linux/slab.h>
@@ -1310,8 +1309,6 @@ static long fb_compat_ioctl(struct file *file, unsigned int cmd,
 
 static int
 fb_mmap(struct file *file, struct vm_area_struct * vma)
-__acquires(&info->lock)
-__releases(&info->lock)
 {
        int fbidx = iminor(file->f_path.dentry->d_inode);
        struct fb_info *info = registered_fb[fbidx];
@@ -1325,16 +1322,14 @@ __releases(&info->lock)
        off = vma->vm_pgoff << PAGE_SHIFT;
        if (!fb)
                return -ENODEV;
+       mutex_lock(&info->mm_lock);
        if (fb->fb_mmap) {
                int res;
-               mutex_lock(&info->lock);
                res = fb->fb_mmap(info, vma);
-               mutex_unlock(&info->lock);
+               mutex_unlock(&info->mm_lock);
                return res;
        }
 
-       mutex_lock(&info->lock);
-
        /* frame buffer memory */
        start = info->fix.smem_start;
        len = PAGE_ALIGN((start & ~PAGE_MASK) + info->fix.smem_len);
@@ -1342,13 +1337,13 @@ __releases(&info->lock)
                /* memory mapped io */
                off -= len;
                if (info->var.accel_flags) {
-                       mutex_unlock(&info->lock);
+                       mutex_unlock(&info->mm_lock);
                        return -EINVAL;
                }
                start = info->fix.mmio_start;
                len = PAGE_ALIGN((start & ~PAGE_MASK) + info->fix.mmio_len);
        }
-       mutex_unlock(&info->lock);
+       mutex_unlock(&info->mm_lock);
        start &= PAGE_MASK;
        if ((vma->vm_end - vma->vm_start + off) > len)
                return -EINVAL;
@@ -1518,6 +1513,7 @@ register_framebuffer(struct fb_info *fb_info)
                        break;
        fb_info->node = i;
        mutex_init(&fb_info->lock);
+       mutex_init(&fb_info->mm_lock);
 
        fb_info->dev = device_create(fb_class, fb_info->device,
                                     MKDEV(FB_MAJOR, i), NULL, "fb%d", i);
index f153c581cbd7bbe99f4558f98e5975b935463263..72d68b3dc478ec4292b6eef69025de3d25a43a52 100644 (file)
@@ -750,24 +750,26 @@ static void update_lcdc(struct fb_info *info)
 static int map_video_memory(struct fb_info *info)
 {
        phys_addr_t phys;
+       u32 smem_len = info->fix.line_length * info->var.yres_virtual;
 
        pr_debug("info->var.xres_virtual = %d\n", info->var.xres_virtual);
        pr_debug("info->var.yres_virtual = %d\n", info->var.yres_virtual);
        pr_debug("info->fix.line_length  = %d\n", info->fix.line_length);
+       pr_debug("MAP_VIDEO_MEMORY: smem_len = %u\n", smem_len);
 
-       info->fix.smem_len = info->fix.line_length * info->var.yres_virtual;
-       pr_debug("MAP_VIDEO_MEMORY: smem_len = %d\n", info->fix.smem_len);
-       info->screen_base = fsl_diu_alloc(info->fix.smem_len, &phys);
+       info->screen_base = fsl_diu_alloc(smem_len, &phys);
        if (info->screen_base == NULL) {
                printk(KERN_ERR "Unable to allocate fb memory\n");
                return -ENOMEM;
        }
+       mutex_lock(&info->mm_lock);
        info->fix.smem_start = (unsigned long) phys;
+       info->fix.smem_len = smem_len;
+       mutex_unlock(&info->mm_lock);
        info->screen_size = info->fix.smem_len;
 
        pr_debug("Allocated fb @ paddr=0x%08lx, size=%d.\n",
-                               info->fix.smem_start,
-               info->fix.smem_len);
+                info->fix.smem_start, info->fix.smem_len);
        pr_debug("screen base %p\n", info->screen_base);
 
        return 0;
@@ -776,9 +778,11 @@ static int map_video_memory(struct fb_info *info)
 static void unmap_video_memory(struct fb_info *info)
 {
        fsl_diu_free(info->screen_base, info->fix.smem_len);
+       mutex_lock(&info->mm_lock);
        info->screen_base = NULL;
        info->fix.smem_start = 0;
        info->fix.smem_len = 0;
+       mutex_unlock(&info->mm_lock);
 }
 
 /*
@@ -1219,12 +1223,6 @@ static int __devinit install_fb(struct fb_info *info)
                return -EINVAL;
        }
 
-       if (fsl_diu_set_par(info)) {
-               printk(KERN_ERR "fb_set_par failed");
-               fb_dealloc_cmap(&info->cmap);
-               return -EINVAL;
-       }
-
        if (register_framebuffer(info) < 0) {
                printk(KERN_ERR "register_framebuffer failed");
                unmap_video_memory(info);
index 020db7fc9153ab1f3483909ccd02f76b9e455900..e7116a6d82d306b51e7b621c1e927fdd156c31ab 100644 (file)
@@ -44,9 +44,6 @@ static struct fb_fix_screeninfo hitfb_fix __initdata = {
        .accel          = FB_ACCEL_NONE,
 };
 
-static u32 pseudo_palette[16];
-static struct fb_info fb_info;
-
 static inline void hitfb_accel_wait(void)
 {
        while (fb_readw(HD64461_GRCFGR) & HD64461_GRCFGR_ACCSTATUS) ;
@@ -331,6 +328,8 @@ static struct fb_ops hitfb_ops = {
 static int __init hitfb_probe(struct platform_device *dev)
 {
        unsigned short lcdclor, ldr3, ldvndr;
+       struct fb_info *info;
+       int ret;
 
        if (fb_get_options("hitfb", NULL))
                return -ENODEV;
@@ -384,32 +383,53 @@ static int __init hitfb_probe(struct platform_device *dev)
                break;
        }
 
-       fb_info.fbops = &hitfb_ops;
-       fb_info.var = hitfb_var;
-       fb_info.fix = hitfb_fix;
-       fb_info.pseudo_palette = pseudo_palette;
-       fb_info.flags = FBINFO_DEFAULT | FBINFO_HWACCEL_YPAN |
+       info = framebuffer_alloc(sizeof(u32) * 16, &dev->dev);
+       if (unlikely(!info))
+               return -ENOMEM;
+
+       info->fbops = &hitfb_ops;
+       info->var = hitfb_var;
+       info->fix = hitfb_fix;
+       info->pseudo_palette = info->par;
+       info->flags = FBINFO_DEFAULT | FBINFO_HWACCEL_YPAN |
                FBINFO_HWACCEL_FILLRECT | FBINFO_HWACCEL_COPYAREA;
 
-       fb_info.screen_base = (void *)hitfb_fix.smem_start;
+       info->screen_base = (void *)hitfb_fix.smem_start;
 
-       fb_alloc_cmap(&fb_info.cmap, 256, 0);
+       ret = fb_alloc_cmap(&info->cmap, 256, 0);
+       if (unlikely(ret < 0))
+               goto err_fb;
 
-       if (register_framebuffer(&fb_info) < 0)
-               return -EINVAL;
+       ret = register_framebuffer(info);
+       if (unlikely(ret < 0))
+               goto err;
+
+       platform_set_drvdata(dev, info);
 
        printk(KERN_INFO "fb%d: %s frame buffer device\n",
-              fb_info.node, fb_info.fix.id);
+              info->node, info->fix.id);
+
        return 0;
+
+err:
+       fb_dealloc_cmap(&info->cmap);
+err_fb:
+       framebuffer_release(info);
+       return ret;
 }
 
 static int __exit hitfb_remove(struct platform_device *dev)
 {
-       return unregister_framebuffer(&fb_info);
+       struct fb_info *info = platform_get_drvdata(dev);
+
+       unregister_framebuffer(info);
+       fb_dealloc_cmap(&info->cmap);
+       framebuffer_release(info);
+
+       return 0;
 }
 
-#ifdef CONFIG_PM
-static int hitfb_suspend(struct platform_device *dev, pm_message_t state)
+static int hitfb_suspend(struct device *dev)
 {
        u16 v;
 
@@ -421,7 +441,7 @@ static int hitfb_suspend(struct platform_device *dev, pm_message_t state)
        return 0;
 }
 
-static int hitfb_resume(struct platform_device *dev)
+static int hitfb_resume(struct device *dev)
 {
        u16 v;
 
@@ -435,17 +455,19 @@ static int hitfb_resume(struct platform_device *dev)
 
        return 0;
 }
-#endif
+
+static struct dev_pm_ops hitfb_dev_pm_ops = {
+       .suspend        = hitfb_suspend,
+       .resume         = hitfb_resume,
+};
 
 static struct platform_driver hitfb_driver = {
        .probe          = hitfb_probe,
        .remove         = __exit_p(hitfb_remove),
-#ifdef CONFIG_PM
-       .suspend        = hitfb_suspend,
-       .resume         = hitfb_resume,
-#endif
        .driver         = {
                .name   = "hitfb",
+               .owner  = THIS_MODULE,
+               .pm     = &hitfb_dev_pm_ops,
        },
 };
 
index 2e940199fc892b40ceac2630019ef3cea9456c61..5743ea25e818814887fada1f82562e553dbfe2c2 100644 (file)
@@ -1090,8 +1090,10 @@ static int encode_fix(struct fb_fix_screeninfo *fix, struct fb_info *info)
        memset(fix, 0, sizeof(struct fb_fix_screeninfo));
 
        strcpy(fix->id, "I810");
+       mutex_lock(&info->mm_lock);
        fix->smem_start = par->fb.physical;
        fix->smem_len = par->fb.size;
+       mutex_unlock(&info->mm_lock);
        fix->type = FB_TYPE_PACKED_PIXELS;
        fix->type_aux = 0;
        fix->xpanstep = 8;
@@ -2058,8 +2060,7 @@ static int __devinit i810fb_init_pci (struct pci_dev *dev,
 
        fb_var_to_videomode(&mode, &info->var);
        fb_add_videomode(&mode, &info->modelist);
-       encode_fix(&info->fix, info); 
-                   
+
        i810fb_init_ringbuffer(info);
        err = register_framebuffer(info);
 
index 0ce3b0a8979805333158d8cd67f44a304ab9f43c..a74e5da17aa074b2454d70e1f30f0b7c2c5223e4 100644 (file)
@@ -454,9 +454,9 @@ static void DAC1064_restore_2(WPMINFO2) {
        dprintk(KERN_DEBUG "DAC1064regs ");
        for (i = 0; i < sizeof(MGA1064_DAC_regs); i++) {
                dprintk("R%02X=%02X ", MGA1064_DAC_regs[i], ACCESS_FBINFO(hw).DACreg[i]);
-               if ((i & 0x7) == 0x7) dprintk("\n" KERN_DEBUG "continuing... ");
+               if ((i & 0x7) == 0x7) dprintk(KERN_DEBUG "continuing... ");
        }
-       dprintk("\n" KERN_DEBUG "DAC1064clk ");
+       dprintk(KERN_DEBUG "DAC1064clk ");
        for (i = 0; i < 6; i++)
                dprintk("C%02X=%02X ", i, ACCESS_FBINFO(hw).DACclk[i]);
        dprintk("\n");
index 13524821e242c7ef0b9f99d11ff31501da995543..4e825112a60173980018acd77f3398cfdb3d10b0 100644 (file)
@@ -651,9 +651,9 @@ static void Ti3026_restore(WPMINFO2) {
        dprintk(KERN_DEBUG "3026DACregs ");
        for (i = 0; i < 21; i++) {
                dprintk("R%02X=%02X ", DACseq[i], hw->DACreg[i]);
-               if ((i & 0x7) == 0x7) dprintk("\n" KERN_DEBUG "continuing... ");
+               if ((i & 0x7) == 0x7) dprintk(KERN_DEBUG "continuing... ");
        }
-       dprintk("\n" KERN_DEBUG "DACclk ");
+       dprintk(KERN_DEBUG "DACclk ");
        for (i = 0; i < 6; i++)
                dprintk("C%02X=%02X ", i, hw->DACclk[i]);
        dprintk("\n");
index 8e7a275df50c79a13c328785a2909d66aae7a0bb..0c1049b308bf3bb433867b0047b1b0afdda65e42 100644 (file)
@@ -724,8 +724,10 @@ static void matroxfb_update_fix(WPMINFO2)
        struct fb_fix_screeninfo *fix = &ACCESS_FBINFO(fbcon).fix;
        DBG(__func__)
 
+       mutex_lock(&ACCESS_FBINFO(fbcon).mm_lock);
        fix->smem_start = ACCESS_FBINFO(video.base) + ACCESS_FBINFO(curr.ydstorg.bytes);
        fix->smem_len = ACCESS_FBINFO(video.len_usable) - ACCESS_FBINFO(curr.ydstorg.bytes);
+       mutex_unlock(&ACCESS_FBINFO(fbcon).mm_lock);
 }
 
 static int matroxfb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
@@ -1874,7 +1876,6 @@ static int initMatrox2(WPMINFO struct board* b){
        }
        matroxfb_init_fix(PMINFO2);
        ACCESS_FBINFO(fbcon.screen_base) = vaddr_va(ACCESS_FBINFO(video.vbase));
-       matroxfb_update_fix(PMINFO2);
        /* Normalize values (namely yres_virtual) */
        matroxfb_check_var(&vesafb_defined, &ACCESS_FBINFO(fbcon));
        /* And put it into "current" var. Do NOT program hardware yet, or we'll not take over
@@ -2081,6 +2082,7 @@ static int matroxfb_probe(struct pci_dev* pdev, const struct pci_device_id* dumm
        spin_lock_init(&ACCESS_FBINFO(lock.accel));
        init_rwsem(&ACCESS_FBINFO(crtc2.lock));
        init_rwsem(&ACCESS_FBINFO(altout.lock));
+       mutex_init(&ACCESS_FBINFO(fbcon).mm_lock);
        ACCESS_FBINFO(irq_flags) = 0;
        init_waitqueue_head(&ACCESS_FBINFO(crtc1.vsync.wait));
        init_waitqueue_head(&ACCESS_FBINFO(crtc2.vsync.wait));
index 7ac4c5f6145d0e0746f3d8233f8f64ed08b05cc6..ebcb5c6b4962bb23cfab791073c9803244efa85f 100644 (file)
@@ -289,7 +289,12 @@ static int matroxfb_dh_release(struct fb_info* info, int user) {
 #undef m2info
 }
 
-static void matroxfb_dh_init_fix(struct matroxfb_dh_fb_info *m2info) {
+/*
+ * This function is called before the register_framebuffer so
+ * no locking is needed.
+ */
+static void matroxfb_dh_init_fix(struct matroxfb_dh_fb_info *m2info)
+{
        struct fb_fix_screeninfo *fix = &m2info->fbcon.fix;
 
        strcpy(fix->id, "MATROX DH");
index b7af5256e887e0522e704a2165311220a5904666..f8778cde218327aec8666b2e758c3763fb9e06a3 100644 (file)
@@ -669,7 +669,7 @@ static uint32_t bpp_to_pixfmt(int bpp)
 }
 
 static int mx3fb_blank(int blank, struct fb_info *fbi);
-static int mx3fb_map_video_memory(struct fb_info *fbi);
+static int mx3fb_map_video_memory(struct fb_info *fbi, unsigned int mem_len);
 static int mx3fb_unmap_video_memory(struct fb_info *fbi);
 
 /**
@@ -742,8 +742,7 @@ static int mx3fb_set_par(struct fb_info *fbi)
                if (fbi->fix.smem_start)
                        mx3fb_unmap_video_memory(fbi);
 
-               fbi->fix.smem_len = mem_len;
-               if (mx3fb_map_video_memory(fbi) < 0) {
+               if (mx3fb_map_video_memory(fbi, mem_len) < 0) {
                        mutex_unlock(&mx3_fbi->mutex);
                        return -ENOMEM;
                }
@@ -1198,6 +1197,7 @@ static int mx3fb_resume(struct platform_device *pdev)
 /**
  * mx3fb_map_video_memory() - allocates the DRAM memory for the frame buffer.
  * @fbi:       framebuffer information pointer
+ * @mem_len:   length of mapped memory
  * @return:    Error code indicating success or failure
  *
  * This buffer is remapped into a non-cached, non-buffered, memory region to
@@ -1205,23 +1205,26 @@ static int mx3fb_resume(struct platform_device *pdev)
  * area is remapped, all virtual memory access to the video memory should occur
  * at the new region.
  */
-static int mx3fb_map_video_memory(struct fb_info *fbi)
+static int mx3fb_map_video_memory(struct fb_info *fbi, unsigned int mem_len)
 {
        int retval = 0;
        dma_addr_t addr;
 
        fbi->screen_base = dma_alloc_writecombine(fbi->device,
-                                                 fbi->fix.smem_len,
+                                                 mem_len,
                                                  &addr, GFP_DMA);
 
        if (!fbi->screen_base) {
                dev_err(fbi->device, "Cannot allocate %u bytes framebuffer memory\n",
-                       fbi->fix.smem_len);
+                       mem_len);
                retval = -EBUSY;
                goto err0;
        }
 
+       mutex_lock(&fbi->mm_lock);
        fbi->fix.smem_start = addr;
+       fbi->fix.smem_len = mem_len;
+       mutex_unlock(&fbi->mm_lock);
 
        dev_dbg(fbi->device, "allocated fb @ p=0x%08x, v=0x%p, size=%d.\n",
                (uint32_t) fbi->fix.smem_start, fbi->screen_base, fbi->fix.smem_len);
@@ -1251,8 +1254,10 @@ static int mx3fb_unmap_video_memory(struct fb_info *fbi)
                              fbi->screen_base, fbi->fix.smem_start);
 
        fbi->screen_base = 0;
+       mutex_lock(&fbi->mm_lock);
        fbi->fix.smem_start = 0;
        fbi->fix.smem_len = 0;
+       mutex_unlock(&fbi->mm_lock);
        return 0;
 }
 
@@ -1360,11 +1365,6 @@ static int init_fb_chan(struct mx3fb_data *mx3fb, struct idmac_channel *ichan)
        init_completion(&mx3fbi->flip_cmpl);
        disable_irq(ichan->eof_irq);
        dev_dbg(mx3fb->dev, "disabling irq %d\n", ichan->eof_irq);
-       ret = mx3fb_set_par(fbi);
-       if (ret < 0)
-               goto esetpar;
-
-       mx3fb_blank(FB_BLANK_UNBLANK, fbi);
 
        dev_info(dev, "registered, using mode %s\n", fb_mode);
 
index 060d72fe57cb1f639861ae24cf10a6ed0babdb40..8862233d57b65c0e9d779c680027339a004f7fd8 100644 (file)
@@ -393,8 +393,10 @@ static void set_fb_fix(struct fb_info *fbi)
 
        rg = &plane->fbdev->mem_desc.region[plane->idx];
        fbi->screen_base        = rg->vaddr;
+       mutex_lock(&fbi->mm_lock);
        fix->smem_start         = rg->paddr;
        fix->smem_len           = rg->size;
+       mutex_unlock(&fbi->mm_lock);
 
        fix->type = FB_TYPE_PACKED_PIXELS;
        bpp = var->bits_per_pixel;
@@ -886,8 +888,10 @@ static int omapfb_setup_mem(struct fb_info *fbi, struct omapfb_mem_info *mi)
                                 * plane memory is dealloce'd, the other
                                 * screen parameters in var / fix are invalid.
                                 */
+                               mutex_lock(&fbi->mm_lock);
                                fbi->fix.smem_start = 0;
                                fbi->fix.smem_len = 0;
+                               mutex_unlock(&fbi->mm_lock);
                        }
                }
        }
@@ -1250,7 +1254,7 @@ static struct fb_ops omapfb_ops = {
 static ssize_t omapfb_show_caps_num(struct device *dev,
                                    struct device_attribute *attr, char *buf)
 {
-       struct omapfb_device *fbdev = (struct omapfb_device *)dev->driver_data;
+       struct omapfb_device *fbdev = dev_get_drvdata(dev);
        int plane;
        size_t size;
        struct omapfb_caps caps;
@@ -1270,7 +1274,7 @@ static ssize_t omapfb_show_caps_num(struct device *dev,
 static ssize_t omapfb_show_caps_text(struct device *dev,
                                     struct device_attribute *attr, char *buf)
 {
-       struct omapfb_device *fbdev = (struct omapfb_device *)dev->driver_data;
+       struct omapfb_device *fbdev = dev_get_drvdata(dev);
        int i;
        struct omapfb_caps caps;
        int plane;
@@ -1317,7 +1321,7 @@ static DEVICE_ATTR(caps_text, 0444, omapfb_show_caps_text, NULL);
 static ssize_t omapfb_show_panel_name(struct device *dev,
                                      struct device_attribute *attr, char *buf)
 {
-       struct omapfb_device *fbdev = (struct omapfb_device *)dev->driver_data;
+       struct omapfb_device *fbdev = dev_get_drvdata(dev);
 
        return snprintf(buf, PAGE_SIZE, "%s\n", fbdev->panel->name);
 }
@@ -1326,7 +1330,7 @@ static ssize_t omapfb_show_bklight_level(struct device *dev,
                                         struct device_attribute *attr,
                                         char *buf)
 {
-       struct omapfb_device *fbdev = (struct omapfb_device *)dev->driver_data;
+       struct omapfb_device *fbdev = dev_get_drvdata(dev);
        int r;
 
        if (fbdev->panel->get_bklight_level) {
@@ -1341,7 +1345,7 @@ static ssize_t omapfb_store_bklight_level(struct device *dev,
                                          struct device_attribute *attr,
                                          const char *buf, size_t size)
 {
-       struct omapfb_device *fbdev = (struct omapfb_device *)dev->driver_data;
+       struct omapfb_device *fbdev = dev_get_drvdata(dev);
        int r;
 
        if (fbdev->panel->set_bklight_level) {
@@ -1360,7 +1364,7 @@ static ssize_t omapfb_store_bklight_level(struct device *dev,
 static ssize_t omapfb_show_bklight_max(struct device *dev,
                                       struct device_attribute *attr, char *buf)
 {
-       struct omapfb_device *fbdev = (struct omapfb_device *)dev->driver_data;
+       struct omapfb_device *fbdev = dev_get_drvdata(dev);
        int r;
 
        if (fbdev->panel->get_bklight_level) {
@@ -1393,7 +1397,7 @@ static struct attribute_group panel_attr_grp = {
 static ssize_t omapfb_show_ctrl_name(struct device *dev,
                                     struct device_attribute *attr, char *buf)
 {
-       struct omapfb_device *fbdev = (struct omapfb_device *)dev->driver_data;
+       struct omapfb_device *fbdev = dev_get_drvdata(dev);
 
        return snprintf(buf, PAGE_SIZE, "%s\n", fbdev->ctrl->name);
 }
index 03b3670130a0d16b81c6f2d6d7d73e0462d91522..bacfabd9ce1653825e14e85a6d702b067f54d9c6 100644 (file)
@@ -141,7 +141,9 @@ static int platinumfb_set_par (struct fb_info *info)
                offset = 0x10;
 
        info->screen_base = pinfo->frame_buffer + init->fb_offset + offset;
+       mutex_lock(&info->mm_lock);
        info->fix.smem_start = (pinfo->frame_buffer_phys) + init->fb_offset + offset;
+       mutex_unlock(&info->mm_lock);
        info->fix.visual = (pinfo->cmode == CMODE_8) ?
                FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_DIRECTCOLOR;
        info->fix.line_length = vmode_attrs[pinfo->vmode-1].hres * (1<<pinfo->cmode)
index 0889d50c3288e127e97fe604bcdb4fa2d52b6224..6506117c134ba136058689157f49d7e725f1818f 100644 (file)
@@ -815,8 +815,10 @@ static int overlayfb_map_video_memory(struct pxafb_layer *ofb)
        ofb->video_mem_phys = virt_to_phys(ofb->video_mem);
        ofb->video_mem_size = size;
 
+       mutex_lock(&ofb->fb.mm_lock);
        ofb->fb.fix.smem_start  = ofb->video_mem_phys;
        ofb->fb.fix.smem_len    = ofb->fb.fix.line_length * var->yres_virtual;
+       mutex_unlock(&ofb->fb.mm_lock);
        ofb->fb.screen_base     = ofb->video_mem;
        return 0;
 }
index 43680e545427f190b432252acb6bfe518219f089..bb63c07e13de5272e1ce5c5bcb2771da14dcc2ab 100644 (file)
@@ -211,23 +211,21 @@ static int s3c_fb_check_var(struct fb_var_screeninfo *var,
 
 /**
  * s3c_fb_calc_pixclk() - calculate the divider to create the pixel clock.
+ * @id: window id.
  * @sfb: The hardware state.
  * @pixclock: The pixel clock wanted, in picoseconds.
  *
  * Given the specified pixel clock, work out the necessary divider to get
  * close to the output frequency.
  */
-static int s3c_fb_calc_pixclk(struct s3c_fb *sfb, unsigned int pixclk)
+static int s3c_fb_calc_pixclk(unsigned char id, struct s3c_fb *sfb, unsigned int pixclk)
 {
+       struct s3c_fb_pd_win *win = sfb->pdata->win[id];
        unsigned long clk = clk_get_rate(sfb->bus_clk);
-       unsigned long long tmp;
        unsigned int result;
 
-       tmp = (unsigned long long)clk;
-       tmp *= pixclk;
-
-       do_div(tmp, 1000000000UL);
-       result = (unsigned int)tmp / 1000;
+       pixclk *= win->win_mode.refresh;
+       result = clk / pixclk;
 
        dev_dbg(sfb->dev, "pixclk=%u, clk=%lu, div=%d (%lu)\n",
                pixclk, clk, result, clk / result);
@@ -267,6 +265,7 @@ static int s3c_fb_set_par(struct fb_info *info)
        struct s3c_fb *sfb = win->parent;
        void __iomem *regs = sfb->regs;
        int win_no = win->index;
+       u32 osdc_data = 0;
        u32 data;
        u32 pagewidth;
        int clkdiv;
@@ -302,7 +301,7 @@ static int s3c_fb_set_par(struct fb_info *info)
        /* use window 0 as the basis for the lcd output timings */
 
        if (win_no == 0) {
-               clkdiv = s3c_fb_calc_pixclk(sfb, var->pixclock);
+               clkdiv = s3c_fb_calc_pixclk(win_no, sfb, var->pixclock);
 
                data = sfb->pdata->vidcon0;
                data &= ~(VIDCON0_CLKVAL_F_MASK | VIDCON0_CLKDIR);
@@ -359,8 +358,6 @@ static int s3c_fb_set_par(struct fb_info *info)
 
        data = var->xres * var->yres;
 
-       u32 osdc_data = 0;
-
        osdc_data = VIDISD14C_ALPHA1_R(0xf) |
                VIDISD14C_ALPHA1_G(0xf) |
                VIDISD14C_ALPHA1_B(0xf);
index 653bdfee30578fa9b6732f286b0c4fb435c5fd05..9f6d6e61f0cc73a91f6ce93c959b61b090f38464 100644 (file)
@@ -120,18 +120,6 @@ static int sh7760_setcolreg (u_int regno,
        return 0;
 }
 
-static void encode_fix(struct fb_fix_screeninfo *fix, struct fb_info *info,
-                      unsigned long stride)
-{
-       memset(fix, 0, sizeof(struct fb_fix_screeninfo));
-       strcpy(fix->id, "sh7760-lcdc");
-
-       fix->smem_start = (unsigned long)info->screen_base;
-       fix->smem_len = info->screen_size;
-
-       fix->line_length = stride;
-}
-
 static int sh7760fb_get_color_info(struct device *dev,
                                   u16 lddfr, int *bpp, int *gray)
 {
@@ -334,7 +322,8 @@ static int sh7760fb_set_par(struct fb_info *info)
 
        iowrite32(ldsarl, par->base + LDSARL);  /* mem for lower half of DSTN */
 
-       encode_fix(&info->fix, info, stride);
+       info->fix.line_length = stride;
+
        sh7760fb_check_var(&info->var, info);
 
        sh7760fb_blank(FB_BLANK_UNBLANK, info); /* panel on! */
@@ -435,6 +424,8 @@ static int sh7760fb_alloc_mem(struct fb_info *info)
 
        info->screen_base = fbmem;
        info->screen_size = vram;
+       info->fix.smem_start = (unsigned long)info->screen_base;
+       info->fix.smem_len = info->screen_size;
 
        return 0;
 }
@@ -520,6 +511,8 @@ static int __devinit sh7760fb_probe(struct platform_device *pdev)
        info->var.transp.length = 0;
        info->var.transp.msb_right = 0;
 
+       strcpy(info->fix.id, "sh7760-lcdc");
+
        /* set the DON2 bit now, before cmap allocation, as it will randomize
         * palette memory.
         */
index f10d2fbeda060275750f3c61fc5dc5f48634f931..8f24564f77b05e9939b964bfd97862f5078a73cf 100644 (file)
@@ -17,6 +17,7 @@
 #include <linux/platform_device.h>
 #include <linux/dma-mapping.h>
 #include <linux/interrupt.h>
+#include <linux/vmalloc.h>
 #include <video/sh_mobile_lcdc.h>
 #include <asm/atomic.h>
 
@@ -30,9 +31,10 @@ struct sh_mobile_lcdc_chan {
        unsigned long enabled; /* ME and SE in LDCNT2R */
        struct sh_mobile_lcdc_chan_cfg cfg;
        u32 pseudo_palette[PALETTE_NR];
-       struct fb_info info;
+       struct fb_info *info;
        dma_addr_t dma_handle;
        struct fb_deferred_io defio;
+       struct scatterlist *sglist;
        unsigned long frame_end;
        wait_queue_head_t frame_end_wait;
 };
@@ -206,16 +208,38 @@ static void sh_mobile_lcdc_clk_on(struct sh_mobile_lcdc_priv *priv) {}
 static void sh_mobile_lcdc_clk_off(struct sh_mobile_lcdc_priv *priv) {}
 #endif
 
+static int sh_mobile_lcdc_sginit(struct fb_info *info,
+                                 struct list_head *pagelist)
+{
+       struct sh_mobile_lcdc_chan *ch = info->par;
+       unsigned int nr_pages_max = info->fix.smem_len >> PAGE_SHIFT;
+       struct page *page;
+       int nr_pages = 0;
+
+       sg_init_table(ch->sglist, nr_pages_max);
+
+       list_for_each_entry(page, pagelist, lru)
+               sg_set_page(&ch->sglist[nr_pages++], page, PAGE_SIZE, 0);
+
+       return nr_pages;
+}
+
 static void sh_mobile_lcdc_deferred_io(struct fb_info *info,
                                       struct list_head *pagelist)
 {
        struct sh_mobile_lcdc_chan *ch = info->par;
+       unsigned int nr_pages;
 
        /* enable clocks before accessing hardware */
        sh_mobile_lcdc_clk_on(ch->lcdc);
 
+       nr_pages = sh_mobile_lcdc_sginit(info, pagelist);
+       dma_map_sg(info->dev, ch->sglist, nr_pages, DMA_TO_DEVICE);
+
        /* trigger panel update */
        lcdc_write_chan(ch, LDSM2R, 1);
+
+       dma_unmap_sg(info->dev, ch->sglist, nr_pages, DMA_TO_DEVICE);
 }
 
 static void sh_mobile_lcdc_deferred_io_touch(struct fb_info *info)
@@ -418,22 +442,22 @@ static int sh_mobile_lcdc_start(struct sh_mobile_lcdc_priv *priv)
                /* set bpp format in PKF[4:0] */
                tmp = lcdc_read_chan(ch, LDDFR);
                tmp &= ~(0x0001001f);
-               tmp |= (priv->ch[k].info.var.bits_per_pixel == 16) ? 3 : 0;
+               tmp |= (ch->info->var.bits_per_pixel == 16) ? 3 : 0;
                lcdc_write_chan(ch, LDDFR, tmp);
 
                /* point out our frame buffer */
-               lcdc_write_chan(ch, LDSA1R, ch->info.fix.smem_start);
+               lcdc_write_chan(ch, LDSA1R, ch->info->fix.smem_start);
 
                /* set line size */
-               lcdc_write_chan(ch, LDMLSR, ch->info.fix.line_length);
+               lcdc_write_chan(ch, LDMLSR, ch->info->fix.line_length);
 
                /* setup deferred io if SYS bus */
                tmp = ch->cfg.sys_bus_cfg.deferred_io_msec;
                if (ch->ldmt1r_value & (1 << 12) && tmp) {
                        ch->defio.deferred_io = sh_mobile_lcdc_deferred_io;
                        ch->defio.delay = msecs_to_jiffies(tmp);
-                       ch->info.fbdefio = &ch->defio;
-                       fb_deferred_io_init(&ch->info);
+                       ch->info->fbdefio = &ch->defio;
+                       fb_deferred_io_init(ch->info);
 
                        /* one-shot mode */
                        lcdc_write_chan(ch, LDSM1R, 1);
@@ -479,12 +503,12 @@ static void sh_mobile_lcdc_stop(struct sh_mobile_lcdc_priv *priv)
                 * flush frame, and wait for frame end interrupt
                 * clean up deferred io and enable clock
                 */
-               if (ch->info.fbdefio) {
+               if (ch->info->fbdefio) {
                        ch->frame_end = 0;
-                       schedule_delayed_work(&ch->info.deferred_work, 0);
+                       schedule_delayed_work(&ch->info->deferred_work, 0);
                        wait_event(ch->frame_end_wait, ch->frame_end);
-                       fb_deferred_io_cleanup(&ch->info);
-                       ch->info.fbdefio = NULL;
+                       fb_deferred_io_cleanup(ch->info);
+                       ch->info->fbdefio = NULL;
                        sh_mobile_lcdc_clk_on(priv);
                }
 
@@ -793,9 +817,16 @@ static int __init sh_mobile_lcdc_probe(struct platform_device *pdev)
        priv->base = ioremap_nocache(res->start, (res->end - res->start) + 1);
 
        for (i = 0; i < j; i++) {
-               info = &priv->ch[i].info;
                cfg = &priv->ch[i].cfg;
 
+               priv->ch[i].info = framebuffer_alloc(0, &pdev->dev);
+               if (!priv->ch[i].info) {
+                       dev_err(&pdev->dev, "unable to allocate fb_info\n");
+                       error = -ENOMEM;
+                       break;
+               }
+
+               info = priv->ch[i].info;
                info->fbops = &sh_mobile_lcdc_ops;
                info->var.xres = info->var.xres_virtual = cfg->lcd_cfg.xres;
                info->var.yres = info->var.yres_virtual = cfg->lcd_cfg.yres;
@@ -846,21 +877,31 @@ static int __init sh_mobile_lcdc_probe(struct platform_device *pdev)
        }
 
        for (i = 0; i < j; i++) {
-               error = register_framebuffer(&priv->ch[i].info);
+               struct sh_mobile_lcdc_chan *ch = priv->ch + i;
+
+               info = ch->info;
+
+               if (info->fbdefio) {
+                       priv->ch->sglist = vmalloc(sizeof(struct scatterlist) *
+                                       info->fix.smem_len >> PAGE_SHIFT);
+                       if (!priv->ch->sglist) {
+                               dev_err(&pdev->dev, "cannot allocate sglist\n");
+                               goto err1;
+                       }
+               }
+
+               error = register_framebuffer(info);
                if (error < 0)
                        goto err1;
-       }
 
-       for (i = 0; i < j; i++) {
-               info = &priv->ch[i].info;
                dev_info(info->dev,
                         "registered %s/%s as %dx%d %dbpp.\n",
                         pdev->name,
-                        (priv->ch[i].cfg.chan == LCDC_CHAN_MAINLCD) ?
+                        (ch->cfg.chan == LCDC_CHAN_MAINLCD) ?
                         "mainlcd" : "sublcd",
-                        (int) priv->ch[i].cfg.lcd_cfg.xres,
-                        (int) priv->ch[i].cfg.lcd_cfg.yres,
-                        priv->ch[i].cfg.bpp);
+                        (int) ch->cfg.lcd_cfg.xres,
+                        (int) ch->cfg.lcd_cfg.yres,
+                        ch->cfg.bpp);
 
                /* deferred io mode: disable clock to save power */
                if (info->fbdefio)
@@ -881,20 +922,24 @@ static int sh_mobile_lcdc_remove(struct platform_device *pdev)
        int i;
 
        for (i = 0; i < ARRAY_SIZE(priv->ch); i++)
-               if (priv->ch[i].info.dev)
-                       unregister_framebuffer(&priv->ch[i].info);
+               if (priv->ch[i].info->dev)
+                       unregister_framebuffer(priv->ch[i].info);
 
        sh_mobile_lcdc_stop(priv);
 
        for (i = 0; i < ARRAY_SIZE(priv->ch); i++) {
-               info = &priv->ch[i].info;
+               info = priv->ch[i].info;
 
-               if (!info->device)
+               if (!info || !info->device)
                        continue;
 
+               if (priv->ch[i].sglist)
+                       vfree(priv->ch[i].sglist);
+
                dma_free_coherent(&pdev->dev, info->fix.smem_len,
                                  info->screen_base, priv->ch[i].dma_handle);
                fb_dealloc_cmap(&info->cmap);
+               framebuffer_release(info);
        }
 
 #ifdef CONFIG_HAVE_CLK
index 7072d19080d584dbaf2f754dd31c177251932de4..4a067f0d0ceb49135dc3ef2c53f728600c6c8f18 100644 (file)
@@ -1847,8 +1847,10 @@ sisfb_get_fix(struct fb_fix_screeninfo *fix, int con, struct fb_info *info)
 
        strcpy(fix->id, ivideo->myid);
 
+       mutex_lock(&info->mm_lock);
        fix->smem_start  = ivideo->video_base + ivideo->video_offset;
        fix->smem_len    = ivideo->sisfb_mem;
+       mutex_unlock(&info->mm_lock);
        fix->type        = FB_TYPE_PACKED_PIXELS;
        fix->type_aux    = 0;
        fix->visual      = (ivideo->video_bpp == 8) ? FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_TRUECOLOR;
@@ -6365,7 +6367,6 @@ error_3:  vfree(ivideo->bios_abase);
                sis_fb_info->fix = ivideo->sisfb_fix;
                sis_fb_info->screen_base = ivideo->video_vbase + ivideo->video_offset;
                sis_fb_info->fbops = &sisfb_ops;
-               sisfb_get_fix(&sis_fb_info->fix, -1, sis_fb_info);
                sis_fb_info->pseudo_palette = ivideo->pseudo_palette;
 
                fb_alloc_cmap(&sis_fb_info->cmap, 256 , 0);
index eb5d73a0670244cee172b1d31aa028a1a86ff8f4..924d79462780c5eb34ee79f5dfa0fb61dec193f8 100644 (file)
@@ -145,7 +145,7 @@ static inline void sm501fb_sync_regs(struct sm501fb_info *info)
 #define SM501_MEMF_ACCEL               (8)
 
 static int sm501_alloc_mem(struct sm501fb_info *inf, struct sm501_mem *mem,
-                          unsigned int why, size_t size)
+                          unsigned int why, size_t size, u32 smem_len)
 {
        struct sm501fb_par *par;
        struct fb_info *fbi;
@@ -172,7 +172,7 @@ static int sm501_alloc_mem(struct sm501fb_info *inf, struct sm501_mem *mem,
                if (ptr > 0)
                        ptr &= ~(PAGE_SIZE - 1);
 
-               if (fbi && ptr < fbi->fix.smem_len)
+               if (fbi && ptr < smem_len)
                        return -ENOMEM;
 
                break;
@@ -197,7 +197,7 @@ static int sm501_alloc_mem(struct sm501fb_info *inf, struct sm501_mem *mem,
 
        case SM501_MEMF_ACCEL:
                fbi = inf->fb[HEAD_CRT];
-               ptr = fbi ? fbi->fix.smem_len : 0;
+               ptr = fbi ? smem_len : 0;
 
                fbi = inf->fb[HEAD_PANEL];
                if (fbi) {
@@ -413,6 +413,7 @@ static int sm501fb_set_par_common(struct fb_info *info,
        unsigned int mem_type;
        unsigned int clock_type;
        unsigned int head_addr;
+       unsigned int smem_len;
 
        dev_dbg(fbi->dev, "%s: %dx%d, bpp = %d, virtual %dx%d\n",
                __func__, var->xres, var->yres, var->bits_per_pixel,
@@ -453,18 +454,20 @@ static int sm501fb_set_par_common(struct fb_info *info,
 
        /* allocate fb memory within 501 */
        info->fix.line_length = (var->xres_virtual * var->bits_per_pixel)/8;
-       info->fix.smem_len    = info->fix.line_length * var->yres_virtual;
+       smem_len = info->fix.line_length * var->yres_virtual;
 
        dev_dbg(fbi->dev, "%s: line length = %u\n", __func__,
                info->fix.line_length);
 
-       if (sm501_alloc_mem(fbi, &par->screen, mem_type,
-                           info->fix.smem_len)) {
+       if (sm501_alloc_mem(fbi, &par->screen, mem_type, smem_len, smem_len)) {
                dev_err(fbi->dev, "no memory available\n");
                return -ENOMEM;
        }
 
+       mutex_lock(&info->mm_lock);
        info->fix.smem_start = fbi->fbmem_res->start + par->screen.sm_addr;
+       info->fix.smem_len   = smem_len;
+       mutex_unlock(&info->mm_lock);
 
        info->screen_base = fbi->fbmem + par->screen.sm_addr;
        info->screen_size = info->fix.smem_len;
@@ -637,7 +640,8 @@ static int sm501fb_set_par_crt(struct fb_info *info)
        if ((control & SM501_DC_CRT_CONTROL_SEL) == 0) {
                /* the head is displaying panel data... */
 
-               sm501_alloc_mem(fbi, &par->screen, SM501_MEMF_CRT, 0);
+               sm501_alloc_mem(fbi, &par->screen, SM501_MEMF_CRT, 0,
+                               info->fix.smem_len);
                goto out_update;
        }
 
@@ -1289,7 +1293,8 @@ static int sm501_init_cursor(struct fb_info *fbi, unsigned int reg_base)
 
        par->cursor_regs = info->regs + reg_base;
 
-       ret = sm501_alloc_mem(info, &par->cursor, SM501_MEMF_CURSOR, 1024);
+       ret = sm501_alloc_mem(info, &par->cursor, SM501_MEMF_CURSOR, 1024,
+                             fbi->fix.smem_len);
        if (ret < 0)
                return ret;
 
@@ -1535,9 +1540,6 @@ static int sm501fb_init_fb(struct fb_info *fb,
        if (ret)
                dev_err(info->dev, "check_var() failed on initial setup?\n");
 
-       /* ensure we've activated our new configuration */
-       (fb->fbops->fb_set_par)(fb);
-
        return 0;
 }
 
@@ -1619,6 +1621,8 @@ static int __devinit sm501fb_start_one(struct sm501fb_info *info,
        if (!fbi)
                return 0;
 
+       mutex_init(&info->fb[head]->mm_lock);
+
        ret = sm501fb_init_fb(info->fb[head], head, drvname);
        if (ret) {
                dev_err(info->dev, "cannot initialise fb %s\n", drvname);
index eec9dcb7f59976f2a9fe337322fb82724a4ed5fe..6120f0c526fe0c7a42c8c27f9f053550ba1c89e8 100644 (file)
@@ -1115,10 +1115,9 @@ static int __init stifb_init_fb(struct sti_struct *sti, int bpp_pref)
                  if the device name contains the string "DX" and tell the
                  user how to reconfigure the card. */
                if (strstr(sti->outptr.dev_name, "DX")) {
-                  printk(KERN_WARNING "WARNING: stifb framebuffer driver does not "
-                       "support '%s' in double-buffer mode.\n"
-                       KERN_WARNING "WARNING: Please disable the double-buffer mode "
-                       "in IPL menu (the PARISC-BIOS).\n",
+                  printk(KERN_WARNING
+"WARNING: stifb framebuffer driver does not support '%s' in double-buffer mode.\n"
+"WARNING: Please disable the double-buffer mode in IPL menu (the PARISC-BIOS).\n",
                        sti->outptr.dev_name);
                   goto out_err0;
                }
index d0674f1e3f10820e95a8e9db42160fe871908498..2376f688ec8b69addc7c4f0439bd62e127d8482b 100644 (file)
@@ -523,6 +523,7 @@ static int w100fb_set_par(struct fb_info *info)
                info->fix.ywrapstep = 0;
                info->fix.line_length = par->xres * BITS_PER_PIXEL / 8;
 
+               mutex_lock(&info->mm_lock);
                if ((par->xres*par->yres*BITS_PER_PIXEL/8) > (MEM_INT_SIZE+1)) {
                        par->extmem_active = 1;
                        info->fix.smem_len = par->mach->mem->size+1;
@@ -530,6 +531,7 @@ static int w100fb_set_par(struct fb_info *info)
                        par->extmem_active = 0;
                        info->fix.smem_len = MEM_INT_SIZE+1;
                }
+               mutex_unlock(&info->mm_lock);
 
                w100fb_activate_var(par);
        }
@@ -746,8 +748,6 @@ int __init w100fb_probe(struct platform_device *pdev)
                goto out;
        }
 
-       w100fb_set_par(info);
-
        if (register_framebuffer(info) < 0) {
                err = -EINVAL;
                goto out;
index 193c8f0e5cc5708a8e1077c0a60bc04c3eaafd2d..bcec78ffc765b67e190d87d5fbf2c35b72e2f0eb 100644 (file)
@@ -669,7 +669,7 @@ static int __init virtio_pci_init(void)
 
        err = pci_register_driver(&virtio_pci_driver);
        if (err)
-               device_unregister(virtio_pci_root);
+               root_device_unregister(virtio_pci_root);
 
        return err;
 }
index f6542211db48ff6a137ca39b74af42822de25f9f..a9efb16253215593635eddcfbd475608232ebdaa 100644 (file)
@@ -13,7 +13,7 @@ config VLYNQ
 
 config VLYNQ_DEBUG
        bool "VLYNQ bus debug"
-       depends on VLYNQ && KERNEL_DEBUG
+       depends on VLYNQ && DEBUG_KERNEL
        help
          Turn on VLYNQ bus debugging.
 
index 7335433b067b300518efbe447b8294725055dce7..f05d2a368367cca553c9da79e0949416ecba5c99 100644 (file)
@@ -76,7 +76,7 @@ struct vlynq_regs {
        u32 int_device[8];
 };
 
-#ifdef VLYNQ_DEBUG
+#ifdef CONFIG_VLYNQ_DEBUG
 static void vlynq_dump_regs(struct vlynq_device *dev)
 {
        int i;
index 1f09d4e4144c23598f3cf7560a28630fa9f6a6d3..59f708efe25f061b0573358d028d317622fe41a7 100644 (file)
@@ -68,6 +68,34 @@ int w1_ds2760_write(struct device *dev, char *buf, int addr, size_t count)
        return w1_ds2760_io(dev, buf, addr, count, 1);
 }
 
+static int w1_ds2760_eeprom_cmd(struct device *dev, int addr, int cmd)
+{
+       struct w1_slave *sl = container_of(dev, struct w1_slave, dev);
+
+       if (!dev)
+               return -EINVAL;
+
+       mutex_lock(&sl->master->mutex);
+
+       if (w1_reset_select_slave(sl) == 0) {
+               w1_write_8(sl->master, cmd);
+               w1_write_8(sl->master, addr);
+       }
+
+       mutex_unlock(&sl->master->mutex);
+       return 0;
+}
+
+int w1_ds2760_store_eeprom(struct device *dev, int addr)
+{
+       return w1_ds2760_eeprom_cmd(dev, addr, W1_DS2760_COPY_DATA);
+}
+
+int w1_ds2760_recall_eeprom(struct device *dev, int addr)
+{
+       return w1_ds2760_eeprom_cmd(dev, addr, W1_DS2760_RECALL_DATA);
+}
+
 static ssize_t w1_ds2760_read_bin(struct kobject *kobj,
                                  struct bin_attribute *bin_attr,
                                  char *buf, loff_t off, size_t count)
@@ -200,6 +228,8 @@ static void __exit w1_ds2760_exit(void)
 
 EXPORT_SYMBOL(w1_ds2760_read);
 EXPORT_SYMBOL(w1_ds2760_write);
+EXPORT_SYMBOL(w1_ds2760_store_eeprom);
+EXPORT_SYMBOL(w1_ds2760_recall_eeprom);
 
 module_init(w1_ds2760_init);
 module_exit(w1_ds2760_exit);
index f1302429cb0273fa4f7e1871e2d5767a2f97d7e1..58e774141568eb11846fab47ae6e9c822993d673 100644 (file)
 
 #define DS2760_PROTECTION_REG          0x00
 #define DS2760_STATUS_REG              0x01
+       #define DS2760_STATUS_IE        (1 << 2)
+       #define DS2760_STATUS_SWEN      (1 << 3)
+       #define DS2760_STATUS_RNAOP     (1 << 4)
+       #define DS2760_STATUS_PMOD      (1 << 5)
 #define DS2760_EEPROM_REG              0x07
 #define DS2760_SPECIAL_FEATURE_REG     0x08
 #define DS2760_VOLTAGE_MSB             0x0c
@@ -38,6 +42,7 @@
 #define DS2760_EEPROM_BLOCK0           0x20
 #define DS2760_ACTIVE_FULL             0x20
 #define DS2760_EEPROM_BLOCK1           0x30
+#define DS2760_STATUS_WRITE_REG                0x31
 #define DS2760_RATED_CAPACITY          0x32
 #define DS2760_CURRENT_OFFSET_BIAS     0x33
 #define DS2760_ACTIVE_EMPTY            0x3b
@@ -46,5 +51,7 @@ extern int w1_ds2760_read(struct device *dev, char *buf, int addr,
                          size_t count);
 extern int w1_ds2760_write(struct device *dev, char *buf, int addr,
                           size_t count);
+extern int w1_ds2760_store_eeprom(struct device *dev, int addr);
+extern int w1_ds2760_recall_eeprom(struct device *dev, int addr);
 
 #endif /* !__w1_ds2760_h__ */
index 5c7011cda6a6a65e1510022c06a8de3b4420a96b..751c003864ad6df86455248e8542e08578f05125 100644 (file)
@@ -161,7 +161,7 @@ static long bcm47xx_wdt_ioctl(struct file *file,
 {
        void __user *argp = (void __user *)arg;
        int __user *p = argp;
-       int new_value, retval = -EINVAL;;
+       int new_value, retval = -EINVAL;
 
        switch (cmd) {
        case WDIOC_GETSUPPORT:
index ee1caae4d33b0683fe7e13501493eb933078b745..016245419fadb17eda3646152ab507ae1057440f 100644 (file)
@@ -38,7 +38,7 @@
 
 static unsigned long oscr_freq;
 static unsigned long sa1100wdt_users;
-static int pre_margin;
+static unsigned int pre_margin;
 static int boot_status;
 
 /*
@@ -84,6 +84,7 @@ static const struct watchdog_info ident = {
        .options        = WDIOF_CARDRESET | WDIOF_SETTIMEOUT
                                | WDIOF_KEEPALIVEPING,
        .identity       = "SA1100/PXA255 Watchdog",
+       .firmware_version       = 1,
 };
 
 static long sa1100dog_ioctl(struct file *file, unsigned int cmd,
@@ -118,7 +119,7 @@ static long sa1100dog_ioctl(struct file *file, unsigned int cmd,
                if (ret)
                        break;
 
-               if (time <= 0 || time > 255) {
+               if (time <= 0 || (oscr_freq * (long long)time >= 0xffffffff)) {
                        ret = -EINVAL;
                        break;
                }
index 916890abffdd3ca9f9010d90b53319db932fce4c..f201accc4e3d908a00ce91ad029177d0c5315f57 100644 (file)
@@ -89,6 +89,11 @@ static void w83627hf_select_wd_register(void)
                c = ((inb_p(WDT_EFDR) & 0xf7) | 0x04); /* select WDT0 */
                outb_p(0x2b, WDT_EFER);
                outb_p(c, WDT_EFDR);    /* set GPIO3 to WDT0 */
+       } else if (c == 0x88) { /* W83627EHF */
+               outb_p(0x2d, WDT_EFER); /* select GPIO5 */
+               c = inb_p(WDT_EFDR) & ~0x01; /* PIN77 -> WDT0# */
+               outb_p(0x2d, WDT_EFER);
+               outb_p(c, WDT_EFDR); /* set GPIO5 to WDT0 */
        }
 
        outb_p(0x07, WDT_EFER); /* point to logical device number reg */
index 883b5f79673a65026f9f129bbe22b79b31bdd652..a6c12dec91a1434c57709b8570f3a3666ae04bc7 100644 (file)
@@ -149,8 +149,10 @@ static void wdt_ctrl(int timeout)
 {
        spin_lock(&io_lock);
 
-       if (w83697ug_select_wd_register() < 0)
+       if (w83697ug_select_wd_register() < 0) {
+               spin_unlock(&io_lock);
                return;
+       }
 
        outb_p(0xF4, WDT_EFER);    /* Select CRF4 */
        outb_p(timeout, WDT_EFDR); /* Write Timeout counter to CRF4 */
index a4fe7a38d9b037e6c2b83eb5e5b735274998f818..3bde56bce63a3228c4f72089263cefe9d5357227 100644 (file)
@@ -218,16 +218,14 @@ static void wdrtas_timer_keepalive(void)
  */
 static int wdrtas_get_temperature(void)
 {
-       long result;
+       int result;
        int temperature = 0;
 
-       result = rtas_call(wdrtas_token_get_sensor_state, 2, 2,
-                          (void *)__pa(&temperature),
-                          WDRTAS_THERMAL_SENSOR, 0);
+       result = rtas_get_sensor(WDRTAS_THERMAL_SENSOR, 0, &temperature);
 
        if (result < 0)
                printk(KERN_WARNING "wdrtas: reading the thermal sensor "
-                      "faild: %li\n", result);
+                      "failed: %i\n", result);
        else
                temperature = ((temperature * 9) / 5) + 32; /* fahrenheit */
 
index 891d2e90753ab6e9dd312b3120ce6904a96058c2..abad71b1632b10dab15c8fb51e2df7554fb4d62c 100644 (file)
@@ -927,9 +927,9 @@ static struct irq_chip xen_dynamic_chip __read_mostly = {
 void __init xen_init_IRQ(void)
 {
        int i;
-       size_t size = nr_cpu_ids * sizeof(struct cpu_evtchn_s);
 
-       cpu_evtchn_mask_p = alloc_bootmem(size);
+       cpu_evtchn_mask_p = kcalloc(nr_cpu_ids, sizeof(struct cpu_evtchn_s),
+                                   GFP_KERNEL);
        BUG_ON(cpu_evtchn_mask_p == NULL);
 
        init_evtchn_cpu_bindings();
index aad92f0a1048428e9c02b010471511edcc15e015..6910a98bd73cefc29cc0e8435dfd0949625d34fd 100644 (file)
@@ -13,6 +13,7 @@
 #include <linux/parser.h>
 #include <linux/mount.h>
 #include <linux/seq_file.h>
+#include <linux/smp_lock.h>
 #include <linux/statfs.h>
 #include "adfs.h"
 #include "dir_f.h"
index 9bd757774c9ed0d154b7f8ec55f93db18f08c9bc..88067f36e5e7bea4c4d51cff5dd0a9e24e79b3ad 100644 (file)
@@ -564,7 +564,7 @@ static struct dentry *afs_lookup(struct inode *dir, struct dentry *dentry,
 static int afs_d_revalidate(struct dentry *dentry, struct nameidata *nd)
 {
        struct afs_vnode *vnode, *dir;
-       struct afs_fid fid;
+       struct afs_fid uninitialized_var(fid);
        struct dentry *parent;
        struct key *key;
        void *dir_version;
index 210acafe4a9b5d1ec4e5d919e474497c22073ba2..3ff8bdd18fb3b90de6829780d65b3d4bc3cbeb51 100644 (file)
@@ -432,7 +432,6 @@ vfs_rejected_lock:
        list_del_init(&fl->fl_u.afs.link);
        if (list_empty(&vnode->granted_locks))
                afs_defer_unlock(vnode, key);
-       spin_unlock(&vnode->lock);
        goto abort_attempt;
 }
 
index c52be53f694628e7a618b6a0405394b582050aca..5ffb570cd3a8e1d962b62d2b43324012741ff888 100644 (file)
@@ -17,7 +17,6 @@
 #include <linux/pagemap.h>
 #include <linux/mount.h>
 #include <linux/namei.h>
-#include <linux/mnt_namespace.h>
 #include "internal.h"
 
 
index ad0514d0115f76356ab2aa6034fab3aa2ea79597..e1ea1c240b6a2caa7e6b5220bc02380db0e2dea5 100644 (file)
@@ -18,6 +18,7 @@
 #include <linux/module.h>
 #include <linux/init.h>
 #include <linux/slab.h>
+#include <linux/smp_lock.h>
 #include <linux/fs.h>
 #include <linux/pagemap.h>
 #include <linux/parser.h>
index 76da12537956cf0635c5615303f8cbb0fb8337a7..d065b2c3273ea03615ae883558100b4962a2ddbb 100644 (file)
--- a/fs/aio.c
+++ b/fs/aio.c
@@ -485,6 +485,8 @@ static inline void really_put_req(struct kioctx *ctx, struct kiocb *req)
 {
        assert_spin_locked(&ctx->ctx_lock);
 
+       if (req->ki_eventfd != NULL)
+               eventfd_ctx_put(req->ki_eventfd);
        if (req->ki_dtor)
                req->ki_dtor(req);
        if (req->ki_iovec != &req->ki_inline_vec)
@@ -509,8 +511,6 @@ static void aio_fput_routine(struct work_struct *data)
                /* Complete the fput(s) */
                if (req->ki_filp != NULL)
                        __fput(req->ki_filp);
-               if (req->ki_eventfd != NULL)
-                       __fput(req->ki_eventfd);
 
                /* Link the iocb into the context's free list */
                spin_lock_irq(&ctx->ctx_lock);
@@ -528,8 +528,6 @@ static void aio_fput_routine(struct work_struct *data)
  */
 static int __aio_put_req(struct kioctx *ctx, struct kiocb *req)
 {
-       int schedule_putreq = 0;
-
        dprintk(KERN_DEBUG "aio_put(%p): f_count=%ld\n",
                req, atomic_long_read(&req->ki_filp->f_count));
 
@@ -549,24 +547,16 @@ static int __aio_put_req(struct kioctx *ctx, struct kiocb *req)
         * we would not be holding the last reference to the file*, so
         * this function will be executed w/out any aio kthread wakeup.
         */
-       if (unlikely(atomic_long_dec_and_test(&req->ki_filp->f_count)))
-               schedule_putreq++;
-       else
-               req->ki_filp = NULL;
-       if (req->ki_eventfd != NULL) {
-               if (unlikely(atomic_long_dec_and_test(&req->ki_eventfd->f_count)))
-                       schedule_putreq++;
-               else
-                       req->ki_eventfd = NULL;
-       }
-       if (unlikely(schedule_putreq)) {
+       if (unlikely(atomic_long_dec_and_test(&req->ki_filp->f_count))) {
                get_ioctx(ctx);
                spin_lock(&fput_lock);
                list_add(&req->ki_list, &fput_head);
                spin_unlock(&fput_lock);
                queue_work(aio_wq, &fput_work);
-       } else
+       } else {
+               req->ki_filp = NULL;
                really_put_req(ctx, req);
+       }
        return 1;
 }
 
@@ -1622,7 +1612,7 @@ static int io_submit_one(struct kioctx *ctx, struct iocb __user *user_iocb,
                 * an eventfd() fd, and will be signaled for each completed
                 * event using the eventfd_signal() function.
                 */
-               req->ki_eventfd = eventfd_fget((int) iocb->aio_resfd);
+               req->ki_eventfd = eventfd_ctx_fdget((int) iocb->aio_resfd);
                if (IS_ERR(req->ki_eventfd)) {
                        ret = PTR_ERR(req->ki_eventfd);
                        req->ki_eventfd = NULL;
index f3da2eb51f56a2c02e579a76517a6547c1ca65e2..00bf8fcb245f13cfd7bab5fcd7bc0fdb92952087 100644 (file)
@@ -19,7 +19,6 @@
 #include <linux/sched.h>
 #include <linux/compat.h>
 #include <linux/syscalls.h>
-#include <linux/smp_lock.h>
 #include <linux/magic.h>
 #include <linux/dcache.h>
 #include <linux/uaccess.h>
index 54bd07d44e6875447ebcbfdc47b12bffb5484784..1e41aadb1068672a1969d6496dce9dd5e930b656 100644 (file)
@@ -8,7 +8,6 @@
 #include <linux/time.h>
 #include <linux/string.h>
 #include <linux/fs.h>
-#include <linux/smp_lock.h>
 #include <linux/buffer_head.h>
 #include <linux/sched.h>
 #include "bfs.h"
index 6a021265f018e5e42717c9b7001b47fe69a744e9..88b9a3ff44e4bc71bcc15029283dd706f2eaa73a 100644 (file)
@@ -11,7 +11,6 @@
 
 #include <linux/fs.h>
 #include <linux/buffer_head.h>
-#include <linux/smp_lock.h>
 #include "bfs.h"
 
 #undef DEBUG
index 9fa212b014a50448534cb8e2deb1ba193c4ed257..b7c1603cd4bd4ded0f70d06dcb8e84546bfdd4ba 100644 (file)
@@ -1522,11 +1522,11 @@ static int fill_note_info(struct elfhdr *elf, int phdrs,
        info->thread = NULL;
 
        psinfo = kmalloc(sizeof(*psinfo), GFP_KERNEL);
-       fill_note(&info->psinfo, "CORE", NT_PRPSINFO, sizeof(*psinfo), psinfo);
-
        if (psinfo == NULL)
                return 0;
 
+       fill_note(&info->psinfo, "CORE", NT_PRPSINFO, sizeof(*psinfo), psinfo);
+
        /*
         * Figure out how many notes we're going to need for each thread.
         */
@@ -1929,7 +1929,10 @@ static int elf_core_dump(long signr, struct pt_regs *regs, struct file *file, un
        elf = kmalloc(sizeof(*elf), GFP_KERNEL);
        if (!elf)
                goto out;
-       
+       /*
+        * The number of segs are recored into ELF header as 16bit value.
+        * Please check DEFAULT_MAX_MAP_COUNT definition when you modify here.
+        */
        segs = current->mm->map_count;
 #ifdef ELF_CORE_EXTRA_PHDRS
        segs += ELF_CORE_EXTRA_PHDRS;
index 31c46a241bac6838de2be1af7a9f452d58b9affb..49a34e7f7306d49af72b6d84fda277b82d01cc01 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * bio-integrity.c - bio data integrity extensions
  *
- * Copyright (C) 2007, 2008 Oracle Corporation
+ * Copyright (C) 2007, 2008, 2009 Oracle Corporation
  * Written by: Martin K. Petersen <martin.petersen@oracle.com>
  *
  * This program is free software; you can redistribute it and/or
 #include <linux/bio.h>
 #include <linux/workqueue.h>
 
-static struct kmem_cache *bio_integrity_slab __read_mostly;
-static mempool_t *bio_integrity_pool;
-static struct bio_set *integrity_bio_set;
+struct integrity_slab {
+       struct kmem_cache *slab;
+       unsigned short nr_vecs;
+       char name[8];
+};
+
+#define IS(x) { .nr_vecs = x, .name = "bip-"__stringify(x) }
+struct integrity_slab bip_slab[BIOVEC_NR_POOLS] __read_mostly = {
+       IS(1), IS(4), IS(16), IS(64), IS(128), IS(BIO_MAX_PAGES),
+};
+#undef IS
+
 static struct workqueue_struct *kintegrityd_wq;
 
+static inline unsigned int vecs_to_idx(unsigned int nr)
+{
+       switch (nr) {
+       case 1:
+               return 0;
+       case 2 ... 4:
+               return 1;
+       case 5 ... 16:
+               return 2;
+       case 17 ... 64:
+               return 3;
+       case 65 ... 128:
+               return 4;
+       case 129 ... BIO_MAX_PAGES:
+               return 5;
+       default:
+               BUG();
+       }
+}
+
+static inline int use_bip_pool(unsigned int idx)
+{
+       if (idx == BIOVEC_NR_POOLS)
+               return 1;
+
+       return 0;
+}
+
 /**
- * bio_integrity_alloc - Allocate integrity payload and attach it to bio
+ * bio_integrity_alloc_bioset - Allocate integrity payload and attach it to bio
  * @bio:       bio to attach integrity metadata to
  * @gfp_mask:  Memory allocation mask
  * @nr_vecs:   Number of integrity metadata scatter-gather elements
+ * @bs:                bio_set to allocate from
  *
  * Description: This function prepares a bio for attaching integrity
  * metadata.  nr_vecs specifies the maximum number of pages containing
  * integrity metadata that can be attached.
  */
-struct bio_integrity_payload *bio_integrity_alloc(struct bio *bio,
-                                                 gfp_t gfp_mask,
-                                                 unsigned int nr_vecs)
+struct bio_integrity_payload *bio_integrity_alloc_bioset(struct bio *bio,
+                                                        gfp_t gfp_mask,
+                                                        unsigned int nr_vecs,
+                                                        struct bio_set *bs)
 {
        struct bio_integrity_payload *bip;
-       struct bio_vec *iv;
-       unsigned long idx;
+       unsigned int idx = vecs_to_idx(nr_vecs);
 
        BUG_ON(bio == NULL);
+       bip = NULL;
 
-       bip = mempool_alloc(bio_integrity_pool, gfp_mask);
-       if (unlikely(bip == NULL)) {
-               printk(KERN_ERR "%s: could not alloc bip\n", __func__);
-               return NULL;
-       }
+       /* Lower order allocations come straight from slab */
+       if (!use_bip_pool(idx))
+               bip = kmem_cache_alloc(bip_slab[idx].slab, gfp_mask);
 
-       memset(bip, 0, sizeof(*bip));
+       /* Use mempool if lower order alloc failed or max vecs were requested */
+       if (bip == NULL) {
+               bip = mempool_alloc(bs->bio_integrity_pool, gfp_mask);
 
-       iv = bvec_alloc_bs(gfp_mask, nr_vecs, &idx, integrity_bio_set);
-       if (unlikely(iv == NULL)) {
-               printk(KERN_ERR "%s: could not alloc bip_vec\n", __func__);
-               mempool_free(bip, bio_integrity_pool);
-               return NULL;
+               if (unlikely(bip == NULL)) {
+                       printk(KERN_ERR "%s: could not alloc bip\n", __func__);
+                       return NULL;
+               }
        }
 
-       bip->bip_pool = idx;
-       bip->bip_vec = iv;
+       memset(bip, 0, sizeof(*bip));
+
+       bip->bip_slab = idx;
        bip->bip_bio = bio;
        bio->bi_integrity = bip;
 
        return bip;
 }
+EXPORT_SYMBOL(bio_integrity_alloc_bioset);
+
+/**
+ * bio_integrity_alloc - Allocate integrity payload and attach it to bio
+ * @bio:       bio to attach integrity metadata to
+ * @gfp_mask:  Memory allocation mask
+ * @nr_vecs:   Number of integrity metadata scatter-gather elements
+ *
+ * Description: This function prepares a bio for attaching integrity
+ * metadata.  nr_vecs specifies the maximum number of pages containing
+ * integrity metadata that can be attached.
+ */
+struct bio_integrity_payload *bio_integrity_alloc(struct bio *bio,
+                                                 gfp_t gfp_mask,
+                                                 unsigned int nr_vecs)
+{
+       return bio_integrity_alloc_bioset(bio, gfp_mask, nr_vecs, fs_bio_set);
+}
 EXPORT_SYMBOL(bio_integrity_alloc);
 
 /**
  * bio_integrity_free - Free bio integrity payload
  * @bio:       bio containing bip to be freed
+ * @bs:                bio_set this bio was allocated from
  *
  * Description: Used to free the integrity portion of a bio. Usually
  * called from bio_free().
  */
-void bio_integrity_free(struct bio *bio)
+void bio_integrity_free(struct bio *bio, struct bio_set *bs)
 {
        struct bio_integrity_payload *bip = bio->bi_integrity;
 
@@ -92,8 +150,10 @@ void bio_integrity_free(struct bio *bio)
            && bip->bip_buf != NULL)
                kfree(bip->bip_buf);
 
-       bvec_free_bs(integrity_bio_set, bip->bip_vec, bip->bip_pool);
-       mempool_free(bip, bio_integrity_pool);
+       if (use_bip_pool(bip->bip_slab))
+               mempool_free(bip, bs->bio_integrity_pool);
+       else
+               kmem_cache_free(bip_slab[bip->bip_slab].slab, bip);
 
        bio->bi_integrity = NULL;
 }
@@ -114,7 +174,7 @@ int bio_integrity_add_page(struct bio *bio, struct page *page,
        struct bio_integrity_payload *bip = bio->bi_integrity;
        struct bio_vec *iv;
 
-       if (bip->bip_vcnt >= bvec_nr_vecs(bip->bip_pool)) {
+       if (bip->bip_vcnt >= bvec_nr_vecs(bip->bip_slab)) {
                printk(KERN_ERR "%s: bip_vec full\n", __func__);
                return 0;
        }
@@ -647,8 +707,8 @@ void bio_integrity_split(struct bio *bio, struct bio_pair *bp, int sectors)
        bp->iv1 = bip->bip_vec[0];
        bp->iv2 = bip->bip_vec[0];
 
-       bp->bip1.bip_vec = &bp->iv1;
-       bp->bip2.bip_vec = &bp->iv2;
+       bp->bip1.bip_vec[0] = bp->iv1;
+       bp->bip2.bip_vec[0] = bp->iv2;
 
        bp->iv1.bv_len = sectors * bi->tuple_size;
        bp->iv2.bv_offset += sectors * bi->tuple_size;
@@ -667,17 +727,19 @@ EXPORT_SYMBOL(bio_integrity_split);
  * @bio:       New bio
  * @bio_src:   Original bio
  * @gfp_mask:  Memory allocation mask
+ * @bs:                bio_set to allocate bip from
  *
  * Description:        Called to allocate a bip when cloning a bio
  */
-int bio_integrity_clone(struct bio *bio, struct bio *bio_src, gfp_t gfp_mask)
+int bio_integrity_clone(struct bio *bio, struct bio *bio_src,
+                       gfp_t gfp_mask, struct bio_set *bs)
 {
        struct bio_integrity_payload *bip_src = bio_src->bi_integrity;
        struct bio_integrity_payload *bip;
 
        BUG_ON(bip_src == NULL);
 
-       bip = bio_integrity_alloc(bio, gfp_mask, bip_src->bip_vcnt);
+       bip = bio_integrity_alloc_bioset(bio, gfp_mask, bip_src->bip_vcnt, bs);
 
        if (bip == NULL)
                return -EIO;
@@ -693,25 +755,43 @@ int bio_integrity_clone(struct bio *bio, struct bio *bio_src, gfp_t gfp_mask)
 }
 EXPORT_SYMBOL(bio_integrity_clone);
 
-static int __init bio_integrity_init(void)
+int bioset_integrity_create(struct bio_set *bs, int pool_size)
 {
-       kintegrityd_wq = create_workqueue("kintegrityd");
+       unsigned int max_slab = vecs_to_idx(BIO_MAX_PAGES);
+
+       bs->bio_integrity_pool =
+               mempool_create_slab_pool(pool_size, bip_slab[max_slab].slab);
 
+       if (!bs->bio_integrity_pool)
+               return -1;
+
+       return 0;
+}
+EXPORT_SYMBOL(bioset_integrity_create);
+
+void bioset_integrity_free(struct bio_set *bs)
+{
+       if (bs->bio_integrity_pool)
+               mempool_destroy(bs->bio_integrity_pool);
+}
+EXPORT_SYMBOL(bioset_integrity_free);
+
+void __init bio_integrity_init(void)
+{
+       unsigned int i;
+
+       kintegrityd_wq = create_workqueue("kintegrityd");
        if (!kintegrityd_wq)
                panic("Failed to create kintegrityd\n");
 
-       bio_integrity_slab = KMEM_CACHE(bio_integrity_payload,
-                                       SLAB_HWCACHE_ALIGN|SLAB_PANIC);
+       for (i = 0 ; i < BIOVEC_NR_POOLS ; i++) {
+               unsigned int size;
 
-       bio_integrity_pool = mempool_create_slab_pool(BIO_POOL_SIZE,
-                                                     bio_integrity_slab);
-       if (!bio_integrity_pool)
-               panic("bio_integrity: can't allocate bip pool\n");
+               size = sizeof(struct bio_integrity_payload)
+                       + bip_slab[i].nr_vecs * sizeof(struct bio_vec);
 
-       integrity_bio_set = bioset_create(BIO_POOL_SIZE, 0);
-       if (!integrity_bio_set)
-               panic("bio_integrity: can't allocate bio_set\n");
-
-       return 0;
+               bip_slab[i].slab =
+                       kmem_cache_create(bip_slab[i].name, size, 0,
+                                         SLAB_HWCACHE_ALIGN|SLAB_PANIC, NULL);
+       }
 }
-subsys_initcall(bio_integrity_init);
index 24c9140435323e4caabbdf00156efd0060d1be55..76738005c8e8af43c3b084a48d4f752e36e2186d 100644 (file)
--- a/fs/bio.c
+++ b/fs/bio.c
@@ -238,7 +238,7 @@ void bio_free(struct bio *bio, struct bio_set *bs)
                bvec_free_bs(bs, bio->bi_io_vec, BIO_POOL_IDX(bio));
 
        if (bio_integrity(bio))
-               bio_integrity_free(bio);
+               bio_integrity_free(bio, bs);
 
        /*
         * If we have front padding, adjust the bio pointer before freeing
@@ -341,7 +341,7 @@ struct bio *bio_alloc(gfp_t gfp_mask, int nr_iovecs)
 static void bio_kmalloc_destructor(struct bio *bio)
 {
        if (bio_integrity(bio))
-               bio_integrity_free(bio);
+               bio_integrity_free(bio, fs_bio_set);
        kfree(bio);
 }
 
@@ -472,7 +472,7 @@ struct bio *bio_clone(struct bio *bio, gfp_t gfp_mask)
        if (bio_integrity(bio)) {
                int ret;
 
-               ret = bio_integrity_clone(b, bio, gfp_mask);
+               ret = bio_integrity_clone(b, bio, gfp_mask, fs_bio_set);
 
                if (ret < 0) {
                        bio_put(b);
@@ -705,14 +705,13 @@ static struct bio_map_data *bio_alloc_map_data(int nr_segs, int iov_count,
 }
 
 static int __bio_copy_iov(struct bio *bio, struct bio_vec *iovecs,
-                         struct sg_iovec *iov, int iov_count, int uncopy,
-                         int do_free_page)
+                         struct sg_iovec *iov, int iov_count,
+                         int to_user, int from_user, int do_free_page)
 {
        int ret = 0, i;
        struct bio_vec *bvec;
        int iov_idx = 0;
        unsigned int iov_off = 0;
-       int read = bio_data_dir(bio) == READ;
 
        __bio_for_each_segment(bvec, bio, i, 0) {
                char *bv_addr = page_address(bvec->bv_page);
@@ -727,13 +726,14 @@ static int __bio_copy_iov(struct bio *bio, struct bio_vec *iovecs,
                        iov_addr = iov[iov_idx].iov_base + iov_off;
 
                        if (!ret) {
-                               if (!read && !uncopy)
-                                       ret = copy_from_user(bv_addr, iov_addr,
-                                                            bytes);
-                               if (read && uncopy)
+                               if (to_user)
                                        ret = copy_to_user(iov_addr, bv_addr,
                                                           bytes);
 
+                               if (from_user)
+                                       ret = copy_from_user(bv_addr, iov_addr,
+                                                            bytes);
+
                                if (ret)
                                        ret = -EFAULT;
                        }
@@ -770,7 +770,8 @@ int bio_uncopy_user(struct bio *bio)
 
        if (!bio_flagged(bio, BIO_NULL_MAPPED))
                ret = __bio_copy_iov(bio, bmd->iovecs, bmd->sgvecs,
-                                    bmd->nr_sgvecs, 1, bmd->is_our_pages);
+                                    bmd->nr_sgvecs, bio_data_dir(bio) == READ,
+                                    0, bmd->is_our_pages);
        bio_free_map_data(bmd);
        bio_put(bio);
        return ret;
@@ -875,8 +876,9 @@ struct bio *bio_copy_user_iov(struct request_queue *q,
        /*
         * success
         */
-       if (!write_to_vm && (!map_data || !map_data->null_mapped)) {
-               ret = __bio_copy_iov(bio, bio->bi_io_vec, iov, iov_count, 0, 0);
+       if ((!write_to_vm && (!map_data || !map_data->null_mapped)) ||
+           (map_data && map_data->from_user)) {
+               ret = __bio_copy_iov(bio, bio->bi_io_vec, iov, iov_count, 0, 1, 0);
                if (ret)
                        goto cleanup;
        }
@@ -1539,6 +1541,7 @@ void bioset_free(struct bio_set *bs)
        if (bs->bio_pool)
                mempool_destroy(bs->bio_pool);
 
+       bioset_integrity_free(bs);
        biovec_free_pools(bs);
        bio_put_slab(bs);
 
@@ -1579,6 +1582,9 @@ struct bio_set *bioset_create(unsigned int pool_size, unsigned int front_pad)
        if (!bs->bio_pool)
                goto bad;
 
+       if (bioset_integrity_create(bs, pool_size))
+               goto bad;
+
        if (!biovec_create_pools(bs, pool_size))
                return bs;
 
@@ -1616,6 +1622,7 @@ static int __init init_bio(void)
        if (!bio_slabs)
                panic("bio: can't allocate bios\n");
 
+       bio_integrity_init();
        biovec_init_slabs();
 
        fs_bio_set = bioset_create(BIO_POOL_SIZE, 0);
index 603972576f0f3b8e704dc8cf8061bc3bfccae51a..f128427b995b108382fde3b3fea6d0582f841666 100644 (file)
 
 #ifdef CONFIG_FS_POSIX_ACL
 
-static void btrfs_update_cached_acl(struct inode *inode,
-                                   struct posix_acl **p_acl,
-                                   struct posix_acl *acl)
-{
-       spin_lock(&inode->i_lock);
-       if (*p_acl && *p_acl != BTRFS_ACL_NOT_CACHED)
-               posix_acl_release(*p_acl);
-       *p_acl = posix_acl_dup(acl);
-       spin_unlock(&inode->i_lock);
-}
-
 static struct posix_acl *btrfs_get_acl(struct inode *inode, int type)
 {
        int size;
        const char *name;
        char *value = NULL;
-       struct posix_acl *acl = NULL, **p_acl;
+       struct posix_acl *acl;
+
+       acl = get_cached_acl(inode, type);
+       if (acl != ACL_NOT_CACHED)
+               return acl;
 
        switch (type) {
        case ACL_TYPE_ACCESS:
                name = POSIX_ACL_XATTR_ACCESS;
-               p_acl = &BTRFS_I(inode)->i_acl;
                break;
        case ACL_TYPE_DEFAULT:
                name = POSIX_ACL_XATTR_DEFAULT;
-               p_acl = &BTRFS_I(inode)->i_default_acl;
                break;
        default:
-               return ERR_PTR(-EINVAL);
+               BUG();
        }
 
-       /* Handle the cached NULL acl case without locking */
-       acl = ACCESS_ONCE(*p_acl);
-       if (!acl)
-               return acl;
-
-       spin_lock(&inode->i_lock);
-       acl = *p_acl;
-       if (acl != BTRFS_ACL_NOT_CACHED)
-               acl = posix_acl_dup(acl);
-       spin_unlock(&inode->i_lock);
-
-       if (acl != BTRFS_ACL_NOT_CACHED)
-               return acl;
-
        size = __btrfs_getxattr(inode, name, "", 0);
        if (size > 0) {
                value = kzalloc(size, GFP_NOFS);
@@ -82,13 +59,13 @@ static struct posix_acl *btrfs_get_acl(struct inode *inode, int type)
                size = __btrfs_getxattr(inode, name, value, size);
                if (size > 0) {
                        acl = posix_acl_from_xattr(value, size);
-                       btrfs_update_cached_acl(inode, p_acl, acl);
+                       set_cached_acl(inode, type, acl);
                }
                kfree(value);
        } else if (size == -ENOENT || size == -ENODATA || size == 0) {
                /* FIXME, who returns -ENOENT?  I think nobody */
                acl = NULL;
-               btrfs_update_cached_acl(inode, p_acl, acl);
+               set_cached_acl(inode, type, acl);
        } else {
                acl = ERR_PTR(-EIO);
        }
@@ -121,7 +98,6 @@ static int btrfs_set_acl(struct inode *inode, struct posix_acl *acl, int type)
 {
        int ret, size = 0;
        const char *name;
-       struct posix_acl **p_acl;
        char *value = NULL;
        mode_t mode;
 
@@ -141,13 +117,11 @@ static int btrfs_set_acl(struct inode *inode, struct posix_acl *acl, int type)
                ret = 0;
                inode->i_mode = mode;
                name = POSIX_ACL_XATTR_ACCESS;
-               p_acl = &BTRFS_I(inode)->i_acl;
                break;
        case ACL_TYPE_DEFAULT:
                if (!S_ISDIR(inode->i_mode))
                        return acl ? -EINVAL : 0;
                name = POSIX_ACL_XATTR_DEFAULT;
-               p_acl = &BTRFS_I(inode)->i_default_acl;
                break;
        default:
                return -EINVAL;
@@ -172,7 +146,7 @@ out:
        kfree(value);
 
        if (!ret)
-               btrfs_update_cached_acl(inode, p_acl, acl);
+               set_cached_acl(inode, type, acl);
 
        return ret;
 }
index 7f88628a1a72e3808c6f96d47bc0ba9e363ade4c..6e4f6c50a120dfcb78eb5f26dc4301936589cd0f 100644 (file)
@@ -299,8 +299,8 @@ int btrfs_start_workers(struct btrfs_workers *workers, int num_workers)
                                           "btrfs-%s-%d", workers->name,
                                           workers->num_workers + i);
                if (IS_ERR(worker->task)) {
-                       kfree(worker);
                        ret = PTR_ERR(worker->task);
+                       kfree(worker);
                        goto fail;
                }
 
index acb4f351758256752066f565c78ebca3d583df5c..ea1ea0af8c0e6cf635c3060a08e1dd648a6fb48f 100644 (file)
@@ -53,10 +53,6 @@ struct btrfs_inode {
        /* used to order data wrt metadata */
        struct btrfs_ordered_inode_tree ordered_tree;
 
-       /* standard acl pointers */
-       struct posix_acl *i_acl;
-       struct posix_acl *i_default_acl;
-
        /* for keeping track of orphaned inodes */
        struct list_head i_orphan;
 
index de1e2fd32080f0c5c4a835460abf514546c7a6bf..9d8ba4d54a37c3f96e9585de46b8e99d701410bc 100644 (file)
@@ -26,7 +26,6 @@
 #include <linux/time.h>
 #include <linux/init.h>
 #include <linux/string.h>
-#include <linux/smp_lock.h>
 #include <linux/backing-dev.h>
 #include <linux/mpage.h>
 #include <linux/swap.h>
index 03441a99ea38ad95aa5b814d99f9a42a4a74ad0d..98a87383871722fbddc36590cae9e60a512ef53a 100644 (file)
@@ -41,8 +41,6 @@ struct btrfs_ordered_sum;
 
 #define BTRFS_MAGIC "_BHRfS_M"
 
-#define BTRFS_ACL_NOT_CACHED    ((void *)-1)
-
 #define BTRFS_MAX_LEVEL 8
 
 #define BTRFS_COMPAT_EXTENT_TREE_V0
@@ -2076,8 +2074,7 @@ static inline int btrfs_insert_empty_item(struct btrfs_trans_handle *trans,
 int btrfs_next_leaf(struct btrfs_root *root, struct btrfs_path *path);
 int btrfs_prev_leaf(struct btrfs_root *root, struct btrfs_path *path);
 int btrfs_leaf_free_space(struct btrfs_root *root, struct extent_buffer *leaf);
-int btrfs_drop_snapshot(struct btrfs_trans_handle *trans, struct btrfs_root
-                       *root);
+int btrfs_drop_snapshot(struct btrfs_root *root, int update_ref);
 int btrfs_drop_subtree(struct btrfs_trans_handle *trans,
                        struct btrfs_root *root,
                        struct extent_buffer *node,
index edc7d208c5ce6032fc7de520f5f4a00739755fec..a5aca3997d426da09c87e33642916284eca135b6 100644 (file)
@@ -990,15 +990,13 @@ static inline int extent_ref_type(u64 parent, u64 owner)
        return type;
 }
 
-static int find_next_key(struct btrfs_path *path, struct btrfs_key *key)
+static int find_next_key(struct btrfs_path *path, int level,
+                        struct btrfs_key *key)
 
 {
-       int level;
-       BUG_ON(!path->keep_locks);
-       for (level = 0; level < BTRFS_MAX_LEVEL; level++) {
+       for (; level < BTRFS_MAX_LEVEL; level++) {
                if (!path->nodes[level])
                        break;
-               btrfs_assert_tree_locked(path->nodes[level]);
                if (path->slots[level] + 1 >=
                    btrfs_header_nritems(path->nodes[level]))
                        continue;
@@ -1158,7 +1156,8 @@ int lookup_inline_extent_backref(struct btrfs_trans_handle *trans,
                 * For simplicity, we just do not add new inline back
                 * ref if there is any kind of item for this block
                 */
-               if (find_next_key(path, &key) == 0 && key.objectid == bytenr &&
+               if (find_next_key(path, 0, &key) == 0 &&
+                   key.objectid == bytenr &&
                    key.type < BTRFS_BLOCK_GROUP_ITEM_KEY) {
                        err = -EAGAIN;
                        goto out;
@@ -2697,7 +2696,7 @@ again:
 
                printk(KERN_ERR "no space left, need %llu, %llu delalloc bytes"
                       ", %llu bytes_used, %llu bytes_reserved, "
-                      "%llu bytes_pinned, %llu bytes_readonly, %llu may use"
+                      "%llu bytes_pinned, %llu bytes_readonly, %llu may use "
                       "%llu total\n", (unsigned long long)bytes,
                       (unsigned long long)data_sinfo->bytes_delalloc,
                       (unsigned long long)data_sinfo->bytes_used,
@@ -4128,6 +4127,7 @@ struct extent_buffer *btrfs_alloc_free_block(struct btrfs_trans_handle *trans,
        return buf;
 }
 
+#if 0
 int btrfs_drop_leaf_ref(struct btrfs_trans_handle *trans,
                        struct btrfs_root *root, struct extent_buffer *leaf)
 {
@@ -4171,8 +4171,6 @@ int btrfs_drop_leaf_ref(struct btrfs_trans_handle *trans,
        return 0;
 }
 
-#if 0
-
 static noinline int cache_drop_leaf_ref(struct btrfs_trans_handle *trans,
                                        struct btrfs_root *root,
                                        struct btrfs_leaf_ref *ref)
@@ -4553,262 +4551,471 @@ out:
 }
 #endif
 
+struct walk_control {
+       u64 refs[BTRFS_MAX_LEVEL];
+       u64 flags[BTRFS_MAX_LEVEL];
+       struct btrfs_key update_progress;
+       int stage;
+       int level;
+       int shared_level;
+       int update_ref;
+       int keep_locks;
+};
+
+#define DROP_REFERENCE 1
+#define UPDATE_BACKREF 2
+
 /*
- * helper function for drop_subtree, this function is similar to
- * walk_down_tree. The main difference is that it checks reference
- * counts while tree blocks are locked.
+ * hepler to process tree block while walking down the tree.
+ *
+ * when wc->stage == DROP_REFERENCE, this function checks
+ * reference count of the block. if the block is shared and
+ * we need update back refs for the subtree rooted at the
+ * block, this function changes wc->stage to UPDATE_BACKREF
+ *
+ * when wc->stage == UPDATE_BACKREF, this function updates
+ * back refs for pointers in the block.
+ *
+ * NOTE: return value 1 means we should stop walking down.
  */
-static noinline int walk_down_tree(struct btrfs_trans_handle *trans,
+static noinline int walk_down_proc(struct btrfs_trans_handle *trans,
                                   struct btrfs_root *root,
-                                  struct btrfs_path *path, int *level)
+                                  struct btrfs_path *path,
+                                  struct walk_control *wc)
 {
-       struct extent_buffer *next;
-       struct extent_buffer *cur;
-       struct extent_buffer *parent;
-       u64 bytenr;
-       u64 ptr_gen;
-       u64 refs;
-       u64 flags;
-       u32 blocksize;
+       int level = wc->level;
+       struct extent_buffer *eb = path->nodes[level];
+       struct btrfs_key key;
+       u64 flag = BTRFS_BLOCK_FLAG_FULL_BACKREF;
        int ret;
 
-       cur = path->nodes[*level];
-       ret = btrfs_lookup_extent_info(trans, root, cur->start, cur->len,
-                                      &refs, &flags);
-       BUG_ON(ret);
-       if (refs > 1)
-               goto out;
+       if (wc->stage == UPDATE_BACKREF &&
+           btrfs_header_owner(eb) != root->root_key.objectid)
+               return 1;
 
-       BUG_ON(!(flags & BTRFS_BLOCK_FLAG_FULL_BACKREF));
+       /*
+        * when reference count of tree block is 1, it won't increase
+        * again. once full backref flag is set, we never clear it.
+        */
+       if ((wc->stage == DROP_REFERENCE && wc->refs[level] != 1) ||
+           (wc->stage == UPDATE_BACKREF && !(wc->flags[level] & flag))) {
+               BUG_ON(!path->locks[level]);
+               ret = btrfs_lookup_extent_info(trans, root,
+                                              eb->start, eb->len,
+                                              &wc->refs[level],
+                                              &wc->flags[level]);
+               BUG_ON(ret);
+               BUG_ON(wc->refs[level] == 0);
+       }
 
-       while (*level >= 0) {
-               cur = path->nodes[*level];
-               if (*level == 0) {
-                       ret = btrfs_drop_leaf_ref(trans, root, cur);
-                       BUG_ON(ret);
-                       clean_tree_block(trans, root, cur);
-                       break;
-               }
-               if (path->slots[*level] >= btrfs_header_nritems(cur)) {
-                       clean_tree_block(trans, root, cur);
-                       break;
+       if (wc->stage == DROP_REFERENCE &&
+           wc->update_ref && wc->refs[level] > 1) {
+               BUG_ON(eb == root->node);
+               BUG_ON(path->slots[level] > 0);
+               if (level == 0)
+                       btrfs_item_key_to_cpu(eb, &key, path->slots[level]);
+               else
+                       btrfs_node_key_to_cpu(eb, &key, path->slots[level]);
+               if (btrfs_header_owner(eb) == root->root_key.objectid &&
+                   btrfs_comp_cpu_keys(&key, &wc->update_progress) >= 0) {
+                       wc->stage = UPDATE_BACKREF;
+                       wc->shared_level = level;
                }
+       }
 
-               bytenr = btrfs_node_blockptr(cur, path->slots[*level]);
-               blocksize = btrfs_level_size(root, *level - 1);
-               ptr_gen = btrfs_node_ptr_generation(cur, path->slots[*level]);
+       if (wc->stage == DROP_REFERENCE) {
+               if (wc->refs[level] > 1)
+                       return 1;
 
-               next = read_tree_block(root, bytenr, blocksize, ptr_gen);
-               btrfs_tree_lock(next);
-               btrfs_set_lock_blocking(next);
+               if (path->locks[level] && !wc->keep_locks) {
+                       btrfs_tree_unlock(eb);
+                       path->locks[level] = 0;
+               }
+               return 0;
+       }
 
-               ret = btrfs_lookup_extent_info(trans, root, bytenr, blocksize,
-                                              &refs, &flags);
+       /* wc->stage == UPDATE_BACKREF */
+       if (!(wc->flags[level] & flag)) {
+               BUG_ON(!path->locks[level]);
+               ret = btrfs_inc_ref(trans, root, eb, 1);
                BUG_ON(ret);
-               if (refs > 1) {
-                       parent = path->nodes[*level];
-                       ret = btrfs_free_extent(trans, root, bytenr,
-                                               blocksize, parent->start,
-                                               btrfs_header_owner(parent),
-                                               *level - 1, 0);
+               ret = btrfs_dec_ref(trans, root, eb, 0);
+               BUG_ON(ret);
+               ret = btrfs_set_disk_extent_flags(trans, root, eb->start,
+                                                 eb->len, flag, 0);
+               BUG_ON(ret);
+               wc->flags[level] |= flag;
+       }
+
+       /*
+        * the block is shared by multiple trees, so it's not good to
+        * keep the tree lock
+        */
+       if (path->locks[level] && level > 0) {
+               btrfs_tree_unlock(eb);
+               path->locks[level] = 0;
+       }
+       return 0;
+}
+
+/*
+ * hepler to process tree block while walking up the tree.
+ *
+ * when wc->stage == DROP_REFERENCE, this function drops
+ * reference count on the block.
+ *
+ * when wc->stage == UPDATE_BACKREF, this function changes
+ * wc->stage back to DROP_REFERENCE if we changed wc->stage
+ * to UPDATE_BACKREF previously while processing the block.
+ *
+ * NOTE: return value 1 means we should stop walking up.
+ */
+static noinline int walk_up_proc(struct btrfs_trans_handle *trans,
+                                struct btrfs_root *root,
+                                struct btrfs_path *path,
+                                struct walk_control *wc)
+{
+       int ret = 0;
+       int level = wc->level;
+       struct extent_buffer *eb = path->nodes[level];
+       u64 parent = 0;
+
+       if (wc->stage == UPDATE_BACKREF) {
+               BUG_ON(wc->shared_level < level);
+               if (level < wc->shared_level)
+                       goto out;
+
+               BUG_ON(wc->refs[level] <= 1);
+               ret = find_next_key(path, level + 1, &wc->update_progress);
+               if (ret > 0)
+                       wc->update_ref = 0;
+
+               wc->stage = DROP_REFERENCE;
+               wc->shared_level = -1;
+               path->slots[level] = 0;
+
+               /*
+                * check reference count again if the block isn't locked.
+                * we should start walking down the tree again if reference
+                * count is one.
+                */
+               if (!path->locks[level]) {
+                       BUG_ON(level == 0);
+                       btrfs_tree_lock(eb);
+                       btrfs_set_lock_blocking(eb);
+                       path->locks[level] = 1;
+
+                       ret = btrfs_lookup_extent_info(trans, root,
+                                                      eb->start, eb->len,
+                                                      &wc->refs[level],
+                                                      &wc->flags[level]);
                        BUG_ON(ret);
-                       path->slots[*level]++;
-                       btrfs_tree_unlock(next);
-                       free_extent_buffer(next);
-                       continue;
+                       BUG_ON(wc->refs[level] == 0);
+                       if (wc->refs[level] == 1) {
+                               btrfs_tree_unlock(eb);
+                               path->locks[level] = 0;
+                               return 1;
+                       }
+               } else {
+                       BUG_ON(level != 0);
                }
+       }
 
-               BUG_ON(!(flags & BTRFS_BLOCK_FLAG_FULL_BACKREF));
+       /* wc->stage == DROP_REFERENCE */
+       BUG_ON(wc->refs[level] > 1 && !path->locks[level]);
 
-               *level = btrfs_header_level(next);
-               path->nodes[*level] = next;
-               path->slots[*level] = 0;
-               path->locks[*level] = 1;
-               cond_resched();
+       if (wc->refs[level] == 1) {
+               if (level == 0) {
+                       if (wc->flags[level] & BTRFS_BLOCK_FLAG_FULL_BACKREF)
+                               ret = btrfs_dec_ref(trans, root, eb, 1);
+                       else
+                               ret = btrfs_dec_ref(trans, root, eb, 0);
+                       BUG_ON(ret);
+               }
+               /* make block locked assertion in clean_tree_block happy */
+               if (!path->locks[level] &&
+                   btrfs_header_generation(eb) == trans->transid) {
+                       btrfs_tree_lock(eb);
+                       btrfs_set_lock_blocking(eb);
+                       path->locks[level] = 1;
+               }
+               clean_tree_block(trans, root, eb);
+       }
+
+       if (eb == root->node) {
+               if (wc->flags[level] & BTRFS_BLOCK_FLAG_FULL_BACKREF)
+                       parent = eb->start;
+               else
+                       BUG_ON(root->root_key.objectid !=
+                              btrfs_header_owner(eb));
+       } else {
+               if (wc->flags[level + 1] & BTRFS_BLOCK_FLAG_FULL_BACKREF)
+                       parent = path->nodes[level + 1]->start;
+               else
+                       BUG_ON(root->root_key.objectid !=
+                              btrfs_header_owner(path->nodes[level + 1]));
        }
-out:
-       if (path->nodes[*level] == root->node)
-               parent = path->nodes[*level];
-       else
-               parent = path->nodes[*level + 1];
-       bytenr = path->nodes[*level]->start;
-       blocksize = path->nodes[*level]->len;
 
-       ret = btrfs_free_extent(trans, root, bytenr, blocksize, parent->start,
-                               btrfs_header_owner(parent), *level, 0);
+       ret = btrfs_free_extent(trans, root, eb->start, eb->len, parent,
+                               root->root_key.objectid, level, 0);
        BUG_ON(ret);
+out:
+       wc->refs[level] = 0;
+       wc->flags[level] = 0;
+       return ret;
+}
+
+static noinline int walk_down_tree(struct btrfs_trans_handle *trans,
+                                  struct btrfs_root *root,
+                                  struct btrfs_path *path,
+                                  struct walk_control *wc)
+{
+       struct extent_buffer *next;
+       struct extent_buffer *cur;
+       u64 bytenr;
+       u64 ptr_gen;
+       u32 blocksize;
+       int level = wc->level;
+       int ret;
+
+       while (level >= 0) {
+               cur = path->nodes[level];
+               BUG_ON(path->slots[level] >= btrfs_header_nritems(cur));
 
-       if (path->locks[*level]) {
-               btrfs_tree_unlock(path->nodes[*level]);
-               path->locks[*level] = 0;
+               ret = walk_down_proc(trans, root, path, wc);
+               if (ret > 0)
+                       break;
+
+               if (level == 0)
+                       break;
+
+               bytenr = btrfs_node_blockptr(cur, path->slots[level]);
+               blocksize = btrfs_level_size(root, level - 1);
+               ptr_gen = btrfs_node_ptr_generation(cur, path->slots[level]);
+
+               next = read_tree_block(root, bytenr, blocksize, ptr_gen);
+               btrfs_tree_lock(next);
+               btrfs_set_lock_blocking(next);
+
+               level--;
+               BUG_ON(level != btrfs_header_level(next));
+               path->nodes[level] = next;
+               path->slots[level] = 0;
+               path->locks[level] = 1;
+               wc->level = level;
        }
-       free_extent_buffer(path->nodes[*level]);
-       path->nodes[*level] = NULL;
-       *level += 1;
-       cond_resched();
        return 0;
 }
 
-/*
- * helper for dropping snapshots.  This walks back up the tree in the path
- * to find the first node higher up where we haven't yet gone through
- * all the slots
- */
 static noinline int walk_up_tree(struct btrfs_trans_handle *trans,
                                 struct btrfs_root *root,
                                 struct btrfs_path *path,
-                                int *level, int max_level)
+                                struct walk_control *wc, int max_level)
 {
-       struct btrfs_root_item *root_item = &root->root_item;
-       int i;
-       int slot;
+       int level = wc->level;
        int ret;
 
-       for (i = *level; i < max_level && path->nodes[i]; i++) {
-               slot = path->slots[i];
-               if (slot + 1 < btrfs_header_nritems(path->nodes[i])) {
-                       /*
-                        * there is more work to do in this level.
-                        * Update the drop_progress marker to reflect
-                        * the work we've done so far, and then bump
-                        * the slot number
-                        */
-                       path->slots[i]++;
-                       WARN_ON(*level == 0);
-                       if (max_level == BTRFS_MAX_LEVEL) {
-                               btrfs_node_key(path->nodes[i],
-                                              &root_item->drop_progress,
-                                              path->slots[i]);
-                               root_item->drop_level = i;
-                       }
-                       *level = i;
+       path->slots[level] = btrfs_header_nritems(path->nodes[level]);
+       while (level < max_level && path->nodes[level]) {
+               wc->level = level;
+               if (path->slots[level] + 1 <
+                   btrfs_header_nritems(path->nodes[level])) {
+                       path->slots[level]++;
                        return 0;
                } else {
-                       struct extent_buffer *parent;
-
-                       /*
-                        * this whole node is done, free our reference
-                        * on it and go up one level
-                        */
-                       if (path->nodes[*level] == root->node)
-                               parent = path->nodes[*level];
-                       else
-                               parent = path->nodes[*level + 1];
+                       ret = walk_up_proc(trans, root, path, wc);
+                       if (ret > 0)
+                               return 0;
 
-                       clean_tree_block(trans, root, path->nodes[i]);
-                       ret = btrfs_free_extent(trans, root,
-                                               path->nodes[i]->start,
-                                               path->nodes[i]->len,
-                                               parent->start,
-                                               btrfs_header_owner(parent),
-                                               *level, 0);
-                       BUG_ON(ret);
-                       if (path->locks[*level]) {
-                               btrfs_tree_unlock(path->nodes[i]);
-                               path->locks[i] = 0;
+                       if (path->locks[level]) {
+                               btrfs_tree_unlock(path->nodes[level]);
+                               path->locks[level] = 0;
                        }
-                       free_extent_buffer(path->nodes[i]);
-                       path->nodes[i] = NULL;
-                       *level = i + 1;
+                       free_extent_buffer(path->nodes[level]);
+                       path->nodes[level] = NULL;
+                       level++;
                }
        }
        return 1;
 }
 
 /*
- * drop the reference count on the tree rooted at 'snap'.  This traverses
- * the tree freeing any blocks that have a ref count of zero after being
- * decremented.
+ * drop a subvolume tree.
+ *
+ * this function traverses the tree freeing any blocks that only
+ * referenced by the tree.
+ *
+ * when a shared tree block is found. this function decreases its
+ * reference count by one. if update_ref is true, this function
+ * also make sure backrefs for the shared block and all lower level
+ * blocks are properly updated.
  */
-int btrfs_drop_snapshot(struct btrfs_trans_handle *trans, struct btrfs_root
-                       *root)
+int btrfs_drop_snapshot(struct btrfs_root *root, int update_ref)
 {
-       int ret = 0;
-       int wret;
-       int level;
        struct btrfs_path *path;
-       int update_count;
+       struct btrfs_trans_handle *trans;
+       struct btrfs_root *tree_root = root->fs_info->tree_root;
        struct btrfs_root_item *root_item = &root->root_item;
+       struct walk_control *wc;
+       struct btrfs_key key;
+       int err = 0;
+       int ret;
+       int level;
 
        path = btrfs_alloc_path();
        BUG_ON(!path);
 
-       level = btrfs_header_level(root->node);
+       wc = kzalloc(sizeof(*wc), GFP_NOFS);
+       BUG_ON(!wc);
+
+       trans = btrfs_start_transaction(tree_root, 1);
+
        if (btrfs_disk_key_objectid(&root_item->drop_progress) == 0) {
+               level = btrfs_header_level(root->node);
                path->nodes[level] = btrfs_lock_root_node(root);
                btrfs_set_lock_blocking(path->nodes[level]);
                path->slots[level] = 0;
                path->locks[level] = 1;
+               memset(&wc->update_progress, 0,
+                      sizeof(wc->update_progress));
        } else {
-               struct btrfs_key key;
-               struct btrfs_disk_key found_key;
-               struct extent_buffer *node;
-
                btrfs_disk_key_to_cpu(&key, &root_item->drop_progress);
+               memcpy(&wc->update_progress, &key,
+                      sizeof(wc->update_progress));
+
                level = root_item->drop_level;
+               BUG_ON(level == 0);
                path->lowest_level = level;
-               wret = btrfs_search_slot(NULL, root, &key, path, 0, 0);
-               if (wret < 0) {
-                       ret = wret;
+               ret = btrfs_search_slot(NULL, root, &key, path, 0, 0);
+               path->lowest_level = 0;
+               if (ret < 0) {
+                       err = ret;
                        goto out;
                }
-               node = path->nodes[level];
-               btrfs_node_key(node, &found_key, path->slots[level]);
-               WARN_ON(memcmp(&found_key, &root_item->drop_progress,
-                              sizeof(found_key)));
+               btrfs_node_key_to_cpu(path->nodes[level], &key,
+                                     path->slots[level]);
+               WARN_ON(memcmp(&key, &wc->update_progress, sizeof(key)));
+
                /*
                 * unlock our path, this is safe because only this
                 * function is allowed to delete this snapshot
                 */
                btrfs_unlock_up_safe(path, 0);
+
+               level = btrfs_header_level(root->node);
+               while (1) {
+                       btrfs_tree_lock(path->nodes[level]);
+                       btrfs_set_lock_blocking(path->nodes[level]);
+
+                       ret = btrfs_lookup_extent_info(trans, root,
+                                               path->nodes[level]->start,
+                                               path->nodes[level]->len,
+                                               &wc->refs[level],
+                                               &wc->flags[level]);
+                       BUG_ON(ret);
+                       BUG_ON(wc->refs[level] == 0);
+
+                       if (level == root_item->drop_level)
+                               break;
+
+                       btrfs_tree_unlock(path->nodes[level]);
+                       WARN_ON(wc->refs[level] != 1);
+                       level--;
+               }
        }
+
+       wc->level = level;
+       wc->shared_level = -1;
+       wc->stage = DROP_REFERENCE;
+       wc->update_ref = update_ref;
+       wc->keep_locks = 0;
+
        while (1) {
-               unsigned long update;
-               wret = walk_down_tree(trans, root, path, &level);
-               if (wret > 0)
+               ret = walk_down_tree(trans, root, path, wc);
+               if (ret < 0) {
+                       err = ret;
                        break;
-               if (wret < 0)
-                       ret = wret;
+               }
 
-               wret = walk_up_tree(trans, root, path, &level,
-                                   BTRFS_MAX_LEVEL);
-               if (wret > 0)
+               ret = walk_up_tree(trans, root, path, wc, BTRFS_MAX_LEVEL);
+               if (ret < 0) {
+                       err = ret;
                        break;
-               if (wret < 0)
-                       ret = wret;
-               if (trans->transaction->in_commit ||
-                   trans->transaction->delayed_refs.flushing) {
-                       ret = -EAGAIN;
+               }
+
+               if (ret > 0) {
+                       BUG_ON(wc->stage != DROP_REFERENCE);
                        break;
                }
-               for (update_count = 0; update_count < 16; update_count++) {
+
+               if (wc->stage == DROP_REFERENCE) {
+                       level = wc->level;
+                       btrfs_node_key(path->nodes[level],
+                                      &root_item->drop_progress,
+                                      path->slots[level]);
+                       root_item->drop_level = level;
+               }
+
+               BUG_ON(wc->level == 0);
+               if (trans->transaction->in_commit ||
+                   trans->transaction->delayed_refs.flushing) {
+                       ret = btrfs_update_root(trans, tree_root,
+                                               &root->root_key,
+                                               root_item);
+                       BUG_ON(ret);
+
+                       btrfs_end_transaction(trans, tree_root);
+                       trans = btrfs_start_transaction(tree_root, 1);
+               } else {
+                       unsigned long update;
                        update = trans->delayed_ref_updates;
                        trans->delayed_ref_updates = 0;
                        if (update)
-                               btrfs_run_delayed_refs(trans, root, update);
-                       else
-                               break;
+                               btrfs_run_delayed_refs(trans, tree_root,
+                                                      update);
                }
        }
+       btrfs_release_path(root, path);
+       BUG_ON(err);
+
+       ret = btrfs_del_root(trans, tree_root, &root->root_key);
+       BUG_ON(ret);
+
+       free_extent_buffer(root->node);
+       free_extent_buffer(root->commit_root);
+       kfree(root);
 out:
+       btrfs_end_transaction(trans, tree_root);
+       kfree(wc);
        btrfs_free_path(path);
-       return ret;
+       return err;
 }
 
+/*
+ * drop subtree rooted at tree block 'node'.
+ *
+ * NOTE: this function will unlock and release tree block 'node'
+ */
 int btrfs_drop_subtree(struct btrfs_trans_handle *trans,
                        struct btrfs_root *root,
                        struct extent_buffer *node,
                        struct extent_buffer *parent)
 {
        struct btrfs_path *path;
+       struct walk_control *wc;
        int level;
        int parent_level;
        int ret = 0;
        int wret;
 
+       BUG_ON(root->root_key.objectid != BTRFS_TREE_RELOC_OBJECTID);
+
        path = btrfs_alloc_path();
        BUG_ON(!path);
 
+       wc = kzalloc(sizeof(*wc), GFP_NOFS);
+       BUG_ON(!wc);
+
        btrfs_assert_tree_locked(parent);
        parent_level = btrfs_header_level(parent);
        extent_buffer_get(parent);
@@ -4817,24 +5024,33 @@ int btrfs_drop_subtree(struct btrfs_trans_handle *trans,
 
        btrfs_assert_tree_locked(node);
        level = btrfs_header_level(node);
-       extent_buffer_get(node);
        path->nodes[level] = node;
        path->slots[level] = 0;
+       path->locks[level] = 1;
+
+       wc->refs[parent_level] = 1;
+       wc->flags[parent_level] = BTRFS_BLOCK_FLAG_FULL_BACKREF;
+       wc->level = level;
+       wc->shared_level = -1;
+       wc->stage = DROP_REFERENCE;
+       wc->update_ref = 0;
+       wc->keep_locks = 1;
 
        while (1) {
-               wret = walk_down_tree(trans, root, path, &level);
-               if (wret < 0)
+               wret = walk_down_tree(trans, root, path, wc);
+               if (wret < 0) {
                        ret = wret;
-               if (wret != 0)
                        break;
+               }
 
-               wret = walk_up_tree(trans, root, path, &level, parent_level);
+               wret = walk_up_tree(trans, root, path, wc, parent_level);
                if (wret < 0)
                        ret = wret;
                if (wret != 0)
                        break;
        }
 
+       kfree(wc);
        btrfs_free_path(path);
        return ret;
 }
index 126477eaecf56f074a03581c17079d6b985caa81..4b833972273a75218eb775cf8caf64dc1be80ed7 100644 (file)
@@ -22,7 +22,6 @@
 #include <linux/time.h>
 #include <linux/init.h>
 #include <linux/string.h>
-#include <linux/smp_lock.h>
 #include <linux/backing-dev.h>
 #include <linux/mpage.h>
 #include <linux/swap.h>
@@ -151,7 +150,10 @@ static noinline int dirty_and_release_pages(struct btrfs_trans_handle *trans,
        }
        if (end_pos > isize) {
                i_size_write(inode, end_pos);
-               btrfs_update_inode(trans, root, inode);
+               /* we've only changed i_size in ram, and we haven't updated
+                * the disk i_size.  There is no need to log the inode
+                * at this time.
+                */
        }
        err = btrfs_end_transaction(trans, root);
 out_unlock:
index 8612b3a098111a818f54b3637d1af7487a6c2707..791eab19e330b46f93086ac92b7f1b150b5e1513 100644 (file)
@@ -26,7 +26,6 @@
 #include <linux/time.h>
 #include <linux/init.h>
 #include <linux/string.h>
-#include <linux/smp_lock.h>
 #include <linux/backing-dev.h>
 #include <linux/mpage.h>
 #include <linux/swap.h>
@@ -2122,10 +2121,8 @@ static void btrfs_read_locked_inode(struct inode *inode)
         * any xattrs or acls
         */
        maybe_acls = acls_after_inode_item(leaf, path->slots[0], inode->i_ino);
-       if (!maybe_acls) {
-               BTRFS_I(inode)->i_acl = NULL;
-               BTRFS_I(inode)->i_default_acl = NULL;
-       }
+       if (!maybe_acls)
+               cache_no_acl(inode);
 
        BTRFS_I(inode)->block_group = btrfs_find_block_group(root, 0,
                                                alloc_group_block, 0);
@@ -3141,9 +3138,6 @@ static noinline void init_btrfs_i(struct inode *inode)
 {
        struct btrfs_inode *bi = BTRFS_I(inode);
 
-       bi->i_acl = BTRFS_ACL_NOT_CACHED;
-       bi->i_default_acl = BTRFS_ACL_NOT_CACHED;
-
        bi->generation = 0;
        bi->sequence = 0;
        bi->last_trans = 0;
@@ -3585,12 +3579,6 @@ static struct inode *btrfs_new_inode(struct btrfs_trans_handle *trans,
                owner = 1;
        BTRFS_I(inode)->block_group =
                        btrfs_find_block_group(root, 0, alloc_hint, owner);
-       if ((mode & S_IFREG)) {
-               if (btrfs_test_opt(root, NODATASUM))
-                       BTRFS_I(inode)->flags |= BTRFS_INODE_NODATASUM;
-               if (btrfs_test_opt(root, NODATACOW))
-                       BTRFS_I(inode)->flags |= BTRFS_INODE_NODATACOW;
-       }
 
        key[0].objectid = objectid;
        btrfs_set_key_type(&key[0], BTRFS_INODE_ITEM_KEY);
@@ -3645,6 +3633,13 @@ static struct inode *btrfs_new_inode(struct btrfs_trans_handle *trans,
 
        btrfs_inherit_iflags(inode, dir);
 
+       if ((mode & S_IFREG)) {
+               if (btrfs_test_opt(root, NODATASUM))
+                       BTRFS_I(inode)->flags |= BTRFS_INODE_NODATASUM;
+               if (btrfs_test_opt(root, NODATACOW))
+                       BTRFS_I(inode)->flags |= BTRFS_INODE_NODATACOW;
+       }
+
        insert_inode_hash(inode);
        inode_tree_add(inode);
        return inode;
@@ -4640,8 +4635,6 @@ struct inode *btrfs_alloc_inode(struct super_block *sb)
        ei->last_trans = 0;
        ei->logged_trans = 0;
        btrfs_ordered_inode_tree_init(&ei->ordered_tree);
-       ei->i_acl = BTRFS_ACL_NOT_CACHED;
-       ei->i_default_acl = BTRFS_ACL_NOT_CACHED;
        INIT_LIST_HEAD(&ei->i_orphan);
        INIT_LIST_HEAD(&ei->ordered_operations);
        return &ei->vfs_inode;
@@ -4655,13 +4648,6 @@ void btrfs_destroy_inode(struct inode *inode)
        WARN_ON(!list_empty(&inode->i_dentry));
        WARN_ON(inode->i_data.nrpages);
 
-       if (BTRFS_I(inode)->i_acl &&
-           BTRFS_I(inode)->i_acl != BTRFS_ACL_NOT_CACHED)
-               posix_acl_release(BTRFS_I(inode)->i_acl);
-       if (BTRFS_I(inode)->i_default_acl &&
-           BTRFS_I(inode)->i_default_acl != BTRFS_ACL_NOT_CACHED)
-               posix_acl_release(BTRFS_I(inode)->i_default_acl);
-
        /*
         * Make sure we're properly removed from the ordered operation
         * lists.
@@ -5096,6 +5082,7 @@ static long btrfs_fallocate(struct inode *inode, int mode,
        u64 mask = BTRFS_I(inode)->root->sectorsize - 1;
        struct extent_map *em;
        struct btrfs_trans_handle *trans;
+       struct btrfs_root *root;
        int ret;
 
        alloc_start = offset & ~mask;
@@ -5114,6 +5101,13 @@ static long btrfs_fallocate(struct inode *inode, int mode,
                        goto out;
        }
 
+       root = BTRFS_I(inode)->root;
+
+       ret = btrfs_check_data_free_space(root, inode,
+                                         alloc_end - alloc_start);
+       if (ret)
+               goto out;
+
        locked_end = alloc_end - 1;
        while (1) {
                struct btrfs_ordered_extent *ordered;
@@ -5121,7 +5115,7 @@ static long btrfs_fallocate(struct inode *inode, int mode,
                trans = btrfs_start_transaction(BTRFS_I(inode)->root, 1);
                if (!trans) {
                        ret = -EIO;
-                       goto out;
+                       goto out_free;
                }
 
                /* the extent lock is ordered inside the running
@@ -5182,6 +5176,8 @@ static long btrfs_fallocate(struct inode *inode, int mode,
                      GFP_NOFS);
 
        btrfs_end_transaction(trans, BTRFS_I(inode)->root);
+out_free:
+       btrfs_free_reserved_data_space(root, inode, alloc_end - alloc_start);
 out:
        mutex_unlock(&inode->i_mutex);
        return ret;
index eff18f5b53620f20a392f9c57a80c8897c61d317..bd88f25889f7c5daf94bf0aec8645041bfb2ce60 100644 (file)
@@ -27,7 +27,6 @@
 #include <linux/time.h>
 #include <linux/init.h>
 #include <linux/string.h>
-#include <linux/smp_lock.h>
 #include <linux/backing-dev.h>
 #include <linux/mount.h>
 #include <linux/mpage.h>
@@ -1028,7 +1027,8 @@ static long btrfs_ioctl_clone(struct file *file, unsigned long srcfd,
                                                struct btrfs_file_extent_item);
                        comp = btrfs_file_extent_compression(leaf, extent);
                        type = btrfs_file_extent_type(leaf, extent);
-                       if (type == BTRFS_FILE_EXTENT_REG) {
+                       if (type == BTRFS_FILE_EXTENT_REG ||
+                           type == BTRFS_FILE_EXTENT_PREALLOC) {
                                disko = btrfs_file_extent_disk_bytenr(leaf,
                                                                      extent);
                                diskl = btrfs_file_extent_disk_num_bytes(leaf,
@@ -1051,7 +1051,8 @@ static long btrfs_ioctl_clone(struct file *file, unsigned long srcfd,
                        new_key.objectid = inode->i_ino;
                        new_key.offset = key.offset + destoff - off;
 
-                       if (type == BTRFS_FILE_EXTENT_REG) {
+                       if (type == BTRFS_FILE_EXTENT_REG ||
+                           type == BTRFS_FILE_EXTENT_PREALLOC) {
                                ret = btrfs_insert_empty_item(trans, root, path,
                                                              &new_key, size);
                                if (ret)
index b23dc209ae103192bf4eea8ab6ca70f27adda11e..008397934778d457f7d90c3fbd03955fab230639 100644 (file)
@@ -1788,7 +1788,7 @@ static void merge_func(struct btrfs_work *work)
                btrfs_end_transaction(trans, root);
        }
 
-       btrfs_drop_dead_root(reloc_root);
+       btrfs_drop_snapshot(reloc_root, 0);
 
        if (atomic_dec_and_test(async->num_pending))
                complete(async->done);
@@ -2075,9 +2075,6 @@ static int do_relocation(struct btrfs_trans_handle *trans,
 
                        ret = btrfs_drop_subtree(trans, root, eb, upper->eb);
                        BUG_ON(ret);
-
-                       btrfs_tree_unlock(eb);
-                       free_extent_buffer(eb);
                }
                if (!lowest) {
                        btrfs_tree_unlock(upper->eb);
index 9f179d4832d5c90e6270c732628b4e1998a28013..6d6d06cb6dfce1e0bf950ca6d0175e9993f53010 100644 (file)
@@ -26,7 +26,6 @@
 #include <linux/init.h>
 #include <linux/seq_file.h>
 #include <linux/string.h>
-#include <linux/smp_lock.h>
 #include <linux/backing-dev.h>
 #include <linux/mount.h>
 #include <linux/mpage.h>
index 4e83457ea253e798ccfc8cb1d493ad7e48daa2bd..2dbf1c1f56ee41b73068c54ee7c345a969b7f38e 100644 (file)
@@ -593,6 +593,7 @@ int btrfs_defrag_root(struct btrfs_root *root, int cacheonly)
        return 0;
 }
 
+#if 0
 /*
  * when dropping snapshots, we generate a ton of delayed refs, and it makes
  * sense not to join the transaction while it is trying to flush the current
@@ -681,6 +682,7 @@ int btrfs_drop_dead_root(struct btrfs_root *root)
        btrfs_btree_balance_dirty(tree_root, nr);
        return ret;
 }
+#endif
 
 /*
  * new snapshots need to be created at a very specific time in the
@@ -1081,7 +1083,7 @@ int btrfs_clean_old_snapshots(struct btrfs_root *root)
        while (!list_empty(&list)) {
                root = list_entry(list.next, struct btrfs_root, root_list);
                list_del_init(&root->root_list);
-               btrfs_drop_dead_root(root);
+               btrfs_drop_snapshot(root, 0);
        }
        return 0;
 }
index b7c9d5187a756e019bc88c2bcbf0ed3f9d5844f7..a173551e19d79da5ae6132be9eaa24522abd4580 100644 (file)
@@ -13,7 +13,6 @@
 #include <linux/major.h>
 #include <linux/errno.h>
 #include <linux/module.h>
-#include <linux/smp_lock.h>
 #include <linux/seq_file.h>
 
 #include <linux/kobject.h>
index b48689839428805efd6175eacd0a7396068cdafe..92888aa907492e813be7ea7f6c9567f2fdd32d93 100644 (file)
@@ -5,7 +5,11 @@ client generated ones by default (mount option "serverino" turned
 on by default if server supports it).  Add forceuid and forcegid
 mount options (so that when negotiating unix extensions specifying
 which uid mounted does not immediately force the server's reported
-uids to be overridden).
+uids to be overridden).  Add support for scope mount parm. Improve
+hard link detection to use same inode for both.  Do not set
+read-only dos attribute on directories (for chmod) since Windows
+explorer special cases this attribute bit for directories for
+a different purpose.
 
 Version 1.58
 ------------
index 1b09f167006160ad911211a83bd1a8a53f51db82..20692fbfdb244ffb3d5b7acc5e5d84da00d3f7ba 100644 (file)
@@ -49,6 +49,7 @@
 #define ASN1_OJI       6       /* Object Identifier  */
 #define ASN1_OJD       7       /* Object Description */
 #define ASN1_EXT       8       /* External */
+#define ASN1_ENUM      10      /* Enumerated */
 #define ASN1_SEQ       16      /* Sequence */
 #define ASN1_SET       17      /* Set */
 #define ASN1_NUMSTR    18      /* Numerical String */
 #define SPNEGO_OID_LEN 7
 #define NTLMSSP_OID_LEN  10
 #define KRB5_OID_LEN  7
+#define KRB5U2U_OID_LEN  8
 #define MSKRB5_OID_LEN  7
 static unsigned long SPNEGO_OID[7] = { 1, 3, 6, 1, 5, 5, 2 };
 static unsigned long NTLMSSP_OID[10] = { 1, 3, 6, 1, 4, 1, 311, 2, 2, 10 };
 static unsigned long KRB5_OID[7] = { 1, 2, 840, 113554, 1, 2, 2 };
+static unsigned long KRB5U2U_OID[8] = { 1, 2, 840, 113554, 1, 2, 2, 3 };
 static unsigned long MSKRB5_OID[7] = { 1, 2, 840, 48018, 1, 2, 2 };
 
 /*
@@ -122,6 +125,28 @@ asn1_octet_decode(struct asn1_ctx *ctx, unsigned char *ch)
        return 1;
 }
 
+#if 0 /* will be needed later by spnego decoding/encoding of ntlmssp */
+static unsigned char
+asn1_enum_decode(struct asn1_ctx *ctx, __le32 *val)
+{
+       unsigned char ch;
+
+       if (ctx->pointer >= ctx->end) {
+               ctx->error = ASN1_ERR_DEC_EMPTY;
+               return 0;
+       }
+
+       ch = *(ctx->pointer)++; /* ch has 0xa, ptr points to lenght octet */
+       if ((ch) == ASN1_ENUM)  /* if ch value is ENUM, 0xa */
+               *val = *(++(ctx->pointer)); /* value has enum value */
+       else
+               return 0;
+
+       ctx->pointer++;
+       return 1;
+}
+#endif
+
 static unsigned char
 asn1_tag_decode(struct asn1_ctx *ctx, unsigned int *tag)
 {
@@ -476,10 +501,9 @@ decode_negTokenInit(unsigned char *security_blob, int length,
        unsigned int cls, con, tag, oidlen, rc;
        bool use_ntlmssp = false;
        bool use_kerberos = false;
+       bool use_kerberosu2u = false;
        bool use_mskerberos = false;
 
-       *secType = NTLM; /* BB eventually make Kerberos or NLTMSSP the default*/
-
        /* cifs_dump_mem(" Received SecBlob ", security_blob, length); */
 
        asn1_open(&ctx, security_blob, length);
@@ -515,6 +539,7 @@ decode_negTokenInit(unsigned char *security_blob, int length,
                return 0;
        }
 
+       /* SPNEGO */
        if (asn1_header_decode(&ctx, &end, &cls, &con, &tag) == 0) {
                cFYI(1, ("Error decoding negTokenInit"));
                return 0;
@@ -526,6 +551,7 @@ decode_negTokenInit(unsigned char *security_blob, int length,
                return 0;
        }
 
+       /* negTokenInit */
        if (asn1_header_decode(&ctx, &end, &cls, &con, &tag) == 0) {
                cFYI(1, ("Error decoding negTokenInit"));
                return 0;
@@ -537,6 +563,7 @@ decode_negTokenInit(unsigned char *security_blob, int length,
                return 0;
        }
 
+       /* sequence */
        if (asn1_header_decode(&ctx, &end, &cls, &con, &tag) == 0) {
                cFYI(1, ("Error decoding 2nd part of negTokenInit"));
                return 0;
@@ -548,6 +575,7 @@ decode_negTokenInit(unsigned char *security_blob, int length,
                return 0;
        }
 
+       /* sequence of */
        if (asn1_header_decode
            (&ctx, &sequence_end, &cls, &con, &tag) == 0) {
                cFYI(1, ("Error decoding 2nd part of negTokenInit"));
@@ -560,6 +588,7 @@ decode_negTokenInit(unsigned char *security_blob, int length,
                return 0;
        }
 
+       /* list of security mechanisms */
        while (!asn1_eoc_decode(&ctx, sequence_end)) {
                rc = asn1_header_decode(&ctx, &end, &cls, &con, &tag);
                if (!rc) {
@@ -576,11 +605,15 @@ decode_negTokenInit(unsigned char *security_blob, int length,
 
                                if (compare_oid(oid, oidlen, MSKRB5_OID,
                                                MSKRB5_OID_LEN) &&
-                                               !use_kerberos)
+                                               !use_mskerberos)
                                        use_mskerberos = true;
+                               else if (compare_oid(oid, oidlen, KRB5U2U_OID,
+                                                    KRB5U2U_OID_LEN) &&
+                                                    !use_kerberosu2u)
+                                       use_kerberosu2u = true;
                                else if (compare_oid(oid, oidlen, KRB5_OID,
                                                     KRB5_OID_LEN) &&
-                                                    !use_mskerberos)
+                                                    !use_kerberos)
                                        use_kerberos = true;
                                else if (compare_oid(oid, oidlen, NTLMSSP_OID,
                                                     NTLMSSP_OID_LEN))
@@ -593,7 +626,12 @@ decode_negTokenInit(unsigned char *security_blob, int length,
                }
        }
 
+       /* mechlistMIC */
        if (asn1_header_decode(&ctx, &end, &cls, &con, &tag) == 0) {
+               /* Check if we have reached the end of the blob, but with
+                  no mechListMic (e.g. NTLMSSP instead of KRB5) */
+               if (ctx.error == ASN1_ERR_DEC_EMPTY)
+                       goto decode_negtoken_exit;
                cFYI(1, ("Error decoding last part negTokenInit exit3"));
                return 0;
        } else if ((cls != ASN1_CTX) || (con != ASN1_CON)) {
@@ -602,6 +640,8 @@ decode_negTokenInit(unsigned char *security_blob, int length,
                         cls, con, tag, end, *end));
                return 0;
        }
+
+       /* sequence */
        if (asn1_header_decode(&ctx, &end, &cls, &con, &tag) == 0) {
                cFYI(1, ("Error decoding last part negTokenInit exit5"));
                return 0;
@@ -611,6 +651,7 @@ decode_negTokenInit(unsigned char *security_blob, int length,
                        cls, con, tag, end, *end));
        }
 
+       /* sequence of */
        if (asn1_header_decode(&ctx, &end, &cls, &con, &tag) == 0) {
                cFYI(1, ("Error decoding last part negTokenInit exit 7"));
                return 0;
@@ -619,6 +660,8 @@ decode_negTokenInit(unsigned char *security_blob, int length,
                         cls, con, tag, end, *end));
                return 0;
        }
+
+       /* general string */
        if (asn1_header_decode(&ctx, &end, &cls, &con, &tag) == 0) {
                cFYI(1, ("Error decoding last part negTokenInit exit9"));
                return 0;
@@ -630,13 +673,13 @@ decode_negTokenInit(unsigned char *security_blob, int length,
        }
        cFYI(1, ("Need to call asn1_octets_decode() function for %s",
                 ctx.pointer)); /* is this UTF-8 or ASCII? */
-
+decode_negtoken_exit:
        if (use_kerberos)
                *secType = Kerberos;
        else if (use_mskerberos)
                *secType = MSKerberos;
        else if (use_ntlmssp)
-               *secType = NTLMSSP;
+               *secType = RawNTLMSSP;
 
        return 1;
 }
index 4a4581cb2b5e3442e1cc0da0f0a7cd2f6de930bd..051caecf7d677ebb621ba825e7b23962aef957bb 100644 (file)
@@ -86,6 +86,9 @@ struct key_type cifs_spnego_key_type = {
 /* strlen of ";user=" */
 #define USER_KEY_LEN           6
 
+/* strlen of ";pid=0x" */
+#define PID_KEY_LEN            7
+
 /* get a key struct with a SPNEGO security blob, suitable for session setup */
 struct key *
 cifs_get_spnego_key(struct cifsSesInfo *sesInfo)
@@ -103,7 +106,8 @@ cifs_get_spnego_key(struct cifsSesInfo *sesInfo)
                   IP_KEY_LEN + INET6_ADDRSTRLEN +
                   MAX_MECH_STR_LEN +
                   UID_KEY_LEN + (sizeof(uid_t) * 2) +
-                  USER_KEY_LEN + strlen(sesInfo->userName) + 1;
+                  USER_KEY_LEN + strlen(sesInfo->userName) +
+                  PID_KEY_LEN + (sizeof(pid_t) * 2) + 1;
 
        spnego_key = ERR_PTR(-ENOMEM);
        description = kzalloc(desc_len, GFP_KERNEL);
@@ -141,6 +145,9 @@ cifs_get_spnego_key(struct cifsSesInfo *sesInfo)
        dp = description + strlen(description);
        sprintf(dp, ";user=%s", sesInfo->userName);
 
+       dp = description + strlen(description);
+       sprintf(dp, ";pid=0x%x", current->pid);
+
        cFYI(1, ("key description = %s", description));
        spnego_key = request_key(&cifs_spnego_key_type, description, "");
 
index 1403b5d86a739d67725e0dc94db1bec593e5ddab..6941c22398a6ac4097528add80d3ebcbcad2bbc2 100644 (file)
@@ -327,7 +327,7 @@ static void dump_ace(struct cifs_ace *pace, char *end_of_acl)
 
 static void parse_dacl(struct cifs_acl *pdacl, char *end_of_acl,
                       struct cifs_sid *pownersid, struct cifs_sid *pgrpsid,
-                      struct inode *inode)
+                      struct cifs_fattr *fattr)
 {
        int i;
        int num_aces = 0;
@@ -340,7 +340,7 @@ static void parse_dacl(struct cifs_acl *pdacl, char *end_of_acl,
        if (!pdacl) {
                /* no DACL in the security descriptor, set
                   all the permissions for user/group/other */
-               inode->i_mode |= S_IRWXUGO;
+               fattr->cf_mode |= S_IRWXUGO;
                return;
        }
 
@@ -357,7 +357,7 @@ static void parse_dacl(struct cifs_acl *pdacl, char *end_of_acl,
        /* reset rwx permissions for user/group/other.
           Also, if num_aces is 0 i.e. DACL has no ACEs,
           user/group/other have no permissions */
-       inode->i_mode &= ~(S_IRWXUGO);
+       fattr->cf_mode &= ~(S_IRWXUGO);
 
        acl_base = (char *)pdacl;
        acl_size = sizeof(struct cifs_acl);
@@ -379,17 +379,17 @@ static void parse_dacl(struct cifs_acl *pdacl, char *end_of_acl,
                        if (compare_sids(&(ppace[i]->sid), pownersid))
                                access_flags_to_mode(ppace[i]->access_req,
                                                     ppace[i]->type,
-                                                    &(inode->i_mode),
+                                                    &fattr->cf_mode,
                                                     &user_mask);
                        if (compare_sids(&(ppace[i]->sid), pgrpsid))
                                access_flags_to_mode(ppace[i]->access_req,
                                                     ppace[i]->type,
-                                                    &(inode->i_mode),
+                                                    &fattr->cf_mode,
                                                     &group_mask);
                        if (compare_sids(&(ppace[i]->sid), &sid_everyone))
                                access_flags_to_mode(ppace[i]->access_req,
                                                     ppace[i]->type,
-                                                    &(inode->i_mode),
+                                                    &fattr->cf_mode,
                                                     &other_mask);
 
 /*                     memcpy((void *)(&(cifscred->aces[i])),
@@ -464,7 +464,7 @@ static int parse_sid(struct cifs_sid *psid, char *end_of_acl)
 
 /* Convert CIFS ACL to POSIX form */
 static int parse_sec_desc(struct cifs_ntsd *pntsd, int acl_len,
-                         struct inode *inode)
+                         struct cifs_fattr *fattr)
 {
        int rc;
        struct cifs_sid *owner_sid_ptr, *group_sid_ptr;
@@ -472,7 +472,7 @@ static int parse_sec_desc(struct cifs_ntsd *pntsd, int acl_len,
        char *end_of_acl = ((char *)pntsd) + acl_len;
        __u32 dacloffset;
 
-       if ((inode == NULL) || (pntsd == NULL))
+       if (pntsd == NULL)
                return -EIO;
 
        owner_sid_ptr = (struct cifs_sid *)((char *)pntsd +
@@ -497,7 +497,7 @@ static int parse_sec_desc(struct cifs_ntsd *pntsd, int acl_len,
 
        if (dacloffset)
                parse_dacl(dacl_ptr, end_of_acl, owner_sid_ptr,
-                          group_sid_ptr, inode);
+                          group_sid_ptr, fattr);
        else
                cFYI(1, ("no ACL")); /* BB grant all or default perms? */
 
@@ -508,7 +508,6 @@ static int parse_sec_desc(struct cifs_ntsd *pntsd, int acl_len,
        memcpy((void *)(&(cifscred->gsid)), (void *)group_sid_ptr,
                        sizeof(struct cifs_sid)); */
 
-
        return 0;
 }
 
@@ -671,8 +670,9 @@ static int set_cifs_acl(struct cifs_ntsd *pnntsd, __u32 acllen,
 }
 
 /* Translate the CIFS ACL (simlar to NTFS ACL) for a file into mode bits */
-void acl_to_uid_mode(struct cifs_sb_info *cifs_sb, struct inode *inode,
-                    const char *path, const __u16 *pfid)
+void
+cifs_acl_to_fattr(struct cifs_sb_info *cifs_sb, struct cifs_fattr *fattr,
+                 struct inode *inode, const char *path, const __u16 *pfid)
 {
        struct cifs_ntsd *pntsd = NULL;
        u32 acllen = 0;
@@ -687,7 +687,7 @@ void acl_to_uid_mode(struct cifs_sb_info *cifs_sb, struct inode *inode,
 
        /* if we can retrieve the ACL, now parse Access Control Entries, ACEs */
        if (pntsd)
-               rc = parse_sec_desc(pntsd, acllen, inode);
+               rc = parse_sec_desc(pntsd, acllen, fattr);
        if (rc)
                cFYI(1, ("parse sec desc failed rc = %d", rc));
 
index 0d92114195ab6adb4e74acaba8d3380f94123356..44f30504b82d1bbe511da6d4def1342067359deb 100644 (file)
@@ -308,7 +308,6 @@ cifs_alloc_inode(struct super_block *sb)
        if (!cifs_inode)
                return NULL;
        cifs_inode->cifsAttrs = 0x20;   /* default */
-       atomic_set(&cifs_inode->inUse, 0);
        cifs_inode->time = 0;
        cifs_inode->write_behind_rc = 0;
        /* Until the file is open and we have gotten oplock
@@ -333,6 +332,27 @@ cifs_destroy_inode(struct inode *inode)
        kmem_cache_free(cifs_inode_cachep, CIFS_I(inode));
 }
 
+static void
+cifs_show_address(struct seq_file *s, struct TCP_Server_Info *server)
+{
+       seq_printf(s, ",addr=");
+
+       switch (server->addr.sockAddr.sin_family) {
+       case AF_INET:
+               seq_printf(s, "%pI4", &server->addr.sockAddr.sin_addr.s_addr);
+               break;
+       case AF_INET6:
+               seq_printf(s, "%pI6",
+                          &server->addr.sockAddr6.sin6_addr.s6_addr);
+               if (server->addr.sockAddr6.sin6_scope_id)
+                       seq_printf(s, "%%%u",
+                                  server->addr.sockAddr6.sin6_scope_id);
+               break;
+       default:
+               seq_printf(s, "(unknown)");
+       }
+}
+
 /*
  * cifs_show_options() is for displaying mount options in /proc/mounts.
  * Not all settable options are displayed but most of the important
@@ -343,83 +363,64 @@ cifs_show_options(struct seq_file *s, struct vfsmount *m)
 {
        struct cifs_sb_info *cifs_sb;
        struct cifsTconInfo *tcon;
-       struct TCP_Server_Info *server;
 
        cifs_sb = CIFS_SB(m->mnt_sb);
+       tcon = cifs_sb->tcon;
 
-       if (cifs_sb) {
-               tcon = cifs_sb->tcon;
-               if (tcon) {
-                       seq_printf(s, ",unc=%s", cifs_sb->tcon->treeName);
-                       if (tcon->ses) {
-                               if (tcon->ses->userName)
-                                       seq_printf(s, ",username=%s",
-                                          tcon->ses->userName);
-                               if (tcon->ses->domainName)
-                                       seq_printf(s, ",domain=%s",
-                                          tcon->ses->domainName);
-                               server = tcon->ses->server;
-                               if (server) {
-                                       seq_printf(s, ",addr=");
-                                       switch (server->addr.sockAddr6.
-                                               sin6_family) {
-                                       case AF_INET6:
-                                               seq_printf(s, "%pI6",
-                                                          &server->addr.sockAddr6.sin6_addr);
-                                               break;
-                                       case AF_INET:
-                                               seq_printf(s, "%pI4",
-                                                          &server->addr.sockAddr.sin_addr.s_addr);
-                                               break;
-                                       }
-                               }
-                       }
-                       if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_OVERR_UID) ||
-                          !(tcon->unix_ext))
-                               seq_printf(s, ",uid=%d", cifs_sb->mnt_uid);
-                       if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_OVERR_GID) ||
-                          !(tcon->unix_ext))
-                               seq_printf(s, ",gid=%d", cifs_sb->mnt_gid);
-                       if (!tcon->unix_ext) {
-                               seq_printf(s, ",file_mode=0%o,dir_mode=0%o",
+       seq_printf(s, ",unc=%s", cifs_sb->tcon->treeName);
+       if (tcon->ses->userName)
+               seq_printf(s, ",username=%s", tcon->ses->userName);
+       if (tcon->ses->domainName)
+               seq_printf(s, ",domain=%s", tcon->ses->domainName);
+
+       seq_printf(s, ",uid=%d", cifs_sb->mnt_uid);
+       if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_OVERR_UID)
+               seq_printf(s, ",forceuid");
+
+       seq_printf(s, ",gid=%d", cifs_sb->mnt_gid);
+       if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_OVERR_GID)
+               seq_printf(s, ",forcegid");
+
+       cifs_show_address(s, tcon->ses->server);
+
+       if (!tcon->unix_ext)
+               seq_printf(s, ",file_mode=0%o,dir_mode=0%o",
                                           cifs_sb->mnt_file_mode,
                                           cifs_sb->mnt_dir_mode);
-                       }
-                       if (tcon->seal)
-                               seq_printf(s, ",seal");
-                       if (tcon->nocase)
-                               seq_printf(s, ",nocase");
-                       if (tcon->retry)
-                               seq_printf(s, ",hard");
-               }
-               if (cifs_sb->prepath)
-                       seq_printf(s, ",prepath=%s", cifs_sb->prepath);
-               if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_POSIX_PATHS)
-                       seq_printf(s, ",posixpaths");
-               if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID)
-                       seq_printf(s, ",setuids");
-               if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM)
-                       seq_printf(s, ",serverino");
-               if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DIRECT_IO)
-                       seq_printf(s, ",directio");
-               if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_XATTR)
-                       seq_printf(s, ",nouser_xattr");
-               if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR)
-                       seq_printf(s, ",mapchars");
-               if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL)
-                       seq_printf(s, ",sfu");
-               if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_BRL)
-                       seq_printf(s, ",nobrl");
-               if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_CIFS_ACL)
-                       seq_printf(s, ",cifsacl");
-               if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DYNPERM)
-                       seq_printf(s, ",dynperm");
-               if (m->mnt_sb->s_flags & MS_POSIXACL)
-                       seq_printf(s, ",acl");
-
-               seq_printf(s, ",rsize=%d", cifs_sb->rsize);
-               seq_printf(s, ",wsize=%d", cifs_sb->wsize);
-       }
+       if (tcon->seal)
+               seq_printf(s, ",seal");
+       if (tcon->nocase)
+               seq_printf(s, ",nocase");
+       if (tcon->retry)
+               seq_printf(s, ",hard");
+       if (cifs_sb->prepath)
+               seq_printf(s, ",prepath=%s", cifs_sb->prepath);
+       if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_POSIX_PATHS)
+               seq_printf(s, ",posixpaths");
+       if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID)
+               seq_printf(s, ",setuids");
+       if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM)
+               seq_printf(s, ",serverino");
+       if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DIRECT_IO)
+               seq_printf(s, ",directio");
+       if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_XATTR)
+               seq_printf(s, ",nouser_xattr");
+       if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR)
+               seq_printf(s, ",mapchars");
+       if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL)
+               seq_printf(s, ",sfu");
+       if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_BRL)
+               seq_printf(s, ",nobrl");
+       if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_CIFS_ACL)
+               seq_printf(s, ",cifsacl");
+       if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DYNPERM)
+               seq_printf(s, ",dynperm");
+       if (m->mnt_sb->s_flags & MS_POSIXACL)
+               seq_printf(s, ",acl");
+
+       seq_printf(s, ",rsize=%d", cifs_sb->rsize);
+       seq_printf(s, ",wsize=%d", cifs_sb->wsize);
+
        return 0;
 }
 
@@ -535,9 +536,14 @@ static void cifs_umount_begin(struct super_block *sb)
        if (tcon == NULL)
                return;
 
-       lock_kernel();
        read_lock(&cifs_tcp_ses_lock);
-       if (tcon->tc_count == 1)
+       if ((tcon->tc_count > 1) || (tcon->tidStatus == CifsExiting)) {
+               /* we have other mounts to same share or we have
+                  already tried to force umount this and woken up
+                  all waiting network requests, nothing to do */
+               read_unlock(&cifs_tcp_ses_lock);
+               return;
+       } else if (tcon->tc_count == 1)
                tcon->tidStatus = CifsExiting;
        read_unlock(&cifs_tcp_ses_lock);
 
@@ -552,9 +558,7 @@ static void cifs_umount_begin(struct super_block *sb)
                wake_up_all(&tcon->ses->server->response_q);
                msleep(1);
        }
-/* BB FIXME - finish add checks for tidStatus BB */
 
-       unlock_kernel();
        return;
 }
 
index 9570a0e8023f4258941d1f4cdc0e8141188a622d..6c170948300d9be5cc6d8cc47eac8d73053bf390 100644 (file)
 
 #define ROOT_I 2
 
+/*
+ * ino_t is 32-bits on 32-bit arch. We have to squash the 64-bit value down
+ * so that it will fit.
+ */
+static inline ino_t
+cifs_uniqueid_to_ino_t(u64 fileid)
+{
+       ino_t ino = (ino_t) fileid;
+       if (sizeof(ino_t) < sizeof(u64))
+               ino ^= fileid >> (sizeof(u64)-sizeof(ino_t)) * 8;
+       return ino;
+}
+
 extern struct file_system_type cifs_fs_type;
 extern const struct address_space_operations cifs_addr_ops;
 extern const struct address_space_operations cifs_addr_ops_smallbuf;
@@ -100,5 +113,5 @@ extern long cifs_ioctl(struct file *filep, unsigned int cmd, unsigned long arg);
 extern const struct export_operations cifs_export_ops;
 #endif /* EXPERIMENTAL */
 
-#define CIFS_VERSION   "1.59"
+#define CIFS_VERSION   "1.60"
 #endif                         /* _CIFSFS_H */
index a61ab772c6f633dde7ac0e5628214b0bc8c4268f..63f6cdfa56387b355f0fa8f5b7ff0ae7a00c9ab0 100644 (file)
@@ -83,7 +83,7 @@ enum securityEnum {
        NTLM,                   /* Legacy NTLM012 auth with NTLM hash */
        NTLMv2,                 /* Legacy NTLM auth with NTLMv2 hash */
        RawNTLMSSP,             /* NTLMSSP without SPNEGO, NTLMv2 hash */
-       NTLMSSP,                /* NTLMSSP via SPNEGO, NTLMv2 hash */
+/*     NTLMSSP, */ /* can use rawNTLMSSP instead of NTLMSSP via SPNEGO */
        Kerberos,               /* Kerberos via SPNEGO */
        MSKerberos,             /* MS Kerberos via SPNEGO */
 };
@@ -364,13 +364,13 @@ struct cifsInodeInfo {
        struct list_head openFileList;
        int write_behind_rc;
        __u32 cifsAttrs; /* e.g. DOS archive bit, sparse, compressed, system */
-       atomic_t inUse;  /* num concurrent users (local openers cifs) of file*/
        unsigned long time;     /* jiffies of last update/check of inode */
        bool clientCanCacheRead:1;      /* read oplock */
        bool clientCanCacheAll:1;       /* read and writebehind oplock */
        bool oplockPending:1;
        bool delete_pending:1;          /* DELETE_ON_CLOSE is set */
        u64  server_eof;                /* current file size on server */
+       u64  uniqueid;                  /* server inode number */
        struct inode vfs_inode;
 };
 
@@ -472,6 +472,32 @@ struct dfs_info3_param {
        char *node_name;
 };
 
+/*
+ * common struct for holding inode info when searching for or updating an
+ * inode with new info
+ */
+
+#define CIFS_FATTR_DFS_REFERRAL                0x1
+#define CIFS_FATTR_DELETE_PENDING      0x2
+#define CIFS_FATTR_NEED_REVAL          0x4
+
+struct cifs_fattr {
+       u32             cf_flags;
+       u32             cf_cifsattrs;
+       u64             cf_uniqueid;
+       u64             cf_eof;
+       u64             cf_bytes;
+       uid_t           cf_uid;
+       gid_t           cf_gid;
+       umode_t         cf_mode;
+       dev_t           cf_rdev;
+       unsigned int    cf_nlink;
+       unsigned int    cf_dtype;
+       struct timespec cf_atime;
+       struct timespec cf_mtime;
+       struct timespec cf_ctime;
+};
+
 static inline void free_dfs_info_param(struct dfs_info3_param *param)
 {
        if (param) {
index a785f69dbc9feecd616eba56dfaa47e8ab74b392..2d07f890a842f1fac459c39d2d53044a9c19df91 100644 (file)
@@ -2328,19 +2328,7 @@ struct file_attrib_tag {
 typedef struct {
        __le32 NextEntryOffset;
        __u32 ResumeKey; /* as with FileIndex - no need to convert */
-       __le64 EndOfFile;
-       __le64 NumOfBytes;
-       __le64 LastStatusChange; /*SNIA specs DCE time for the 3 time fields */
-       __le64 LastAccessTime;
-       __le64 LastModificationTime;
-       __le64 Uid;
-       __le64 Gid;
-       __le32 Type;
-       __le64 DevMajor;
-       __le64 DevMinor;
-       __le64 UniqueId;
-       __le64 Permissions;
-       __le64 Nlinks;
+       FILE_UNIX_BASIC_INFO basic;
        char FileName[1];
 } __attribute__((packed)) FILE_UNIX_INFO; /* level 0x202 */
 
index f9452329bcce5b02929c5090a79220170d329813..da8fbf565991906320359743d0860ee0d026b812 100644 (file)
@@ -74,7 +74,7 @@ extern unsigned int smbCalcSize(struct smb_hdr *ptr);
 extern unsigned int smbCalcSize_LE(struct smb_hdr *ptr);
 extern int decode_negTokenInit(unsigned char *security_blob, int length,
                        enum securityEnum *secType);
-extern int cifs_inet_pton(const int, const char *source, void *dst);
+extern int cifs_convert_address(char *src, void *dst);
 extern int map_smb_to_linux_error(struct smb_hdr *smb, int logErr);
 extern void header_assemble(struct smb_hdr *, char /* command */ ,
                            const struct cifsTconInfo *, int /* length of
@@ -98,9 +98,13 @@ extern struct timespec cnvrtDosUnixTm(__le16 le_date, __le16 le_time,
 extern int cifs_posix_open(char *full_path, struct inode **pinode,
                           struct super_block *sb, int mode, int oflags,
                           int *poplock, __u16 *pnetfid, int xid);
-extern void posix_fill_in_inode(struct inode *tmp_inode,
-                               FILE_UNIX_BASIC_INFO *pData, int isNewInode);
-extern struct inode *cifs_new_inode(struct super_block *sb, __u64 *inum);
+extern void cifs_unix_basic_to_fattr(struct cifs_fattr *fattr,
+                                    FILE_UNIX_BASIC_INFO *info,
+                                    struct cifs_sb_info *cifs_sb);
+extern void cifs_fattr_to_inode(struct inode *inode, struct cifs_fattr *fattr);
+extern struct inode *cifs_iget(struct super_block *sb,
+                              struct cifs_fattr *fattr);
+
 extern int cifs_get_inode_info(struct inode **pinode,
                        const unsigned char *search_path,
                        FILE_ALL_INFO *pfile_info,
@@ -108,8 +112,9 @@ extern int cifs_get_inode_info(struct inode **pinode,
 extern int cifs_get_inode_info_unix(struct inode **pinode,
                        const unsigned char *search_path,
                        struct super_block *sb, int xid);
-extern void acl_to_uid_mode(struct cifs_sb_info *cifs_sb, struct inode *inode,
-                           const char *path, const __u16 *pfid);
+extern void cifs_acl_to_fattr(struct cifs_sb_info *cifs_sb,
+                             struct cifs_fattr *fattr, struct inode *inode,
+                             const char *path, const __u16 *pfid);
 extern int mode_to_acl(struct inode *inode, const char *path, __u64);
 
 extern int cifs_mount(struct super_block *, struct cifs_sb_info *, char *,
@@ -215,7 +220,11 @@ struct cifs_unix_set_info_args {
        dev_t   device;
 };
 
-extern int CIFSSMBUnixSetInfo(const int xid, struct cifsTconInfo *pTcon,
+extern int CIFSSMBUnixSetFileInfo(const int xid, struct cifsTconInfo *tcon,
+                                 const struct cifs_unix_set_info_args *args,
+                                 u16 fid, u32 pid_of_opener);
+
+extern int CIFSSMBUnixSetPathInfo(const int xid, struct cifsTconInfo *pTcon,
                        char *fileName,
                        const struct cifs_unix_set_info_args *args,
                        const struct nls_table *nls_codepage,
index b84c61d5bca419d2ea221484636508f1ddaceaa1..922f5fe2084c902b75d58b42edb85af920bfc6d9 100644 (file)
@@ -594,7 +594,7 @@ CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses)
        else if (secFlags & CIFSSEC_MAY_KRB5)
                server->secType = Kerberos;
        else if (secFlags & CIFSSEC_MAY_NTLMSSP)
-               server->secType = NTLMSSP;
+               server->secType = RawNTLMSSP;
        else if (secFlags & CIFSSEC_MAY_LANMAN)
                server->secType = LANMAN;
 /* #ifdef CONFIG_CIFS_EXPERIMENTAL
@@ -729,7 +729,7 @@ CIFSSMBTDis(const int xid, struct cifsTconInfo *tcon)
         * the tcon is no longer on the list, so no need to take lock before
         * checking this.
         */
-       if (tcon->need_reconnect)
+       if ((tcon->need_reconnect) || (tcon->ses->need_reconnect))
                return 0;
 
        rc = small_smb_init(SMB_COM_TREE_DISCONNECT, 0, tcon,
@@ -5074,10 +5074,114 @@ SetAttrLgcyRetry:
 }
 #endif /* temporarily unneeded SetAttr legacy function */
 
+static void
+cifs_fill_unix_set_info(FILE_UNIX_BASIC_INFO *data_offset,
+                       const struct cifs_unix_set_info_args *args)
+{
+       u64 mode = args->mode;
+
+       /*
+        * Samba server ignores set of file size to zero due to bugs in some
+        * older clients, but we should be precise - we use SetFileSize to
+        * set file size and do not want to truncate file size to zero
+        * accidently as happened on one Samba server beta by putting
+        * zero instead of -1 here
+        */
+       data_offset->EndOfFile = cpu_to_le64(NO_CHANGE_64);
+       data_offset->NumOfBytes = cpu_to_le64(NO_CHANGE_64);
+       data_offset->LastStatusChange = cpu_to_le64(args->ctime);
+       data_offset->LastAccessTime = cpu_to_le64(args->atime);
+       data_offset->LastModificationTime = cpu_to_le64(args->mtime);
+       data_offset->Uid = cpu_to_le64(args->uid);
+       data_offset->Gid = cpu_to_le64(args->gid);
+       /* better to leave device as zero when it is  */
+       data_offset->DevMajor = cpu_to_le64(MAJOR(args->device));
+       data_offset->DevMinor = cpu_to_le64(MINOR(args->device));
+       data_offset->Permissions = cpu_to_le64(mode);
+
+       if (S_ISREG(mode))
+               data_offset->Type = cpu_to_le32(UNIX_FILE);
+       else if (S_ISDIR(mode))
+               data_offset->Type = cpu_to_le32(UNIX_DIR);
+       else if (S_ISLNK(mode))
+               data_offset->Type = cpu_to_le32(UNIX_SYMLINK);
+       else if (S_ISCHR(mode))
+               data_offset->Type = cpu_to_le32(UNIX_CHARDEV);
+       else if (S_ISBLK(mode))
+               data_offset->Type = cpu_to_le32(UNIX_BLOCKDEV);
+       else if (S_ISFIFO(mode))
+               data_offset->Type = cpu_to_le32(UNIX_FIFO);
+       else if (S_ISSOCK(mode))
+               data_offset->Type = cpu_to_le32(UNIX_SOCKET);
+}
+
 int
-CIFSSMBUnixSetInfo(const int xid, struct cifsTconInfo *tcon, char *fileName,
-                  const struct cifs_unix_set_info_args *args,
-                  const struct nls_table *nls_codepage, int remap)
+CIFSSMBUnixSetFileInfo(const int xid, struct cifsTconInfo *tcon,
+                      const struct cifs_unix_set_info_args *args,
+                      u16 fid, u32 pid_of_opener)
+{
+       struct smb_com_transaction2_sfi_req *pSMB  = NULL;
+       FILE_UNIX_BASIC_INFO *data_offset;
+       int rc = 0;
+       u16 params, param_offset, offset, byte_count, count;
+
+       cFYI(1, ("Set Unix Info (via SetFileInfo)"));
+       rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
+
+       if (rc)
+               return rc;
+
+       pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
+       pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
+
+       params = 6;
+       pSMB->MaxSetupCount = 0;
+       pSMB->Reserved = 0;
+       pSMB->Flags = 0;
+       pSMB->Timeout = 0;
+       pSMB->Reserved2 = 0;
+       param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
+       offset = param_offset + params;
+
+       data_offset = (FILE_UNIX_BASIC_INFO *)
+                               ((char *)(&pSMB->hdr.Protocol) + offset);
+       count = sizeof(FILE_UNIX_BASIC_INFO);
+
+       pSMB->MaxParameterCount = cpu_to_le16(2);
+       /* BB find max SMB PDU from sess */
+       pSMB->MaxDataCount = cpu_to_le16(1000);
+       pSMB->SetupCount = 1;
+       pSMB->Reserved3 = 0;
+       pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
+       byte_count = 3 /* pad */  + params + count;
+       pSMB->DataCount = cpu_to_le16(count);
+       pSMB->ParameterCount = cpu_to_le16(params);
+       pSMB->TotalDataCount = pSMB->DataCount;
+       pSMB->TotalParameterCount = pSMB->ParameterCount;
+       pSMB->ParameterOffset = cpu_to_le16(param_offset);
+       pSMB->DataOffset = cpu_to_le16(offset);
+       pSMB->Fid = fid;
+       pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_BASIC);
+       pSMB->Reserved4 = 0;
+       pSMB->hdr.smb_buf_length += byte_count;
+       pSMB->ByteCount = cpu_to_le16(byte_count);
+
+       cifs_fill_unix_set_info(data_offset, args);
+
+       rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
+       if (rc)
+               cFYI(1, ("Send error in Set Time (SetFileInfo) = %d", rc));
+
+       /* Note: On -EAGAIN error only caller can retry on handle based calls
+               since file handle passed in no longer valid */
+
+       return rc;
+}
+
+int
+CIFSSMBUnixSetPathInfo(const int xid, struct cifsTconInfo *tcon, char *fileName,
+                      const struct cifs_unix_set_info_args *args,
+                      const struct nls_table *nls_codepage, int remap)
 {
        TRANSACTION2_SPI_REQ *pSMB = NULL;
        TRANSACTION2_SPI_RSP *pSMBr = NULL;
@@ -5086,7 +5190,6 @@ CIFSSMBUnixSetInfo(const int xid, struct cifsTconInfo *tcon, char *fileName,
        int bytes_returned = 0;
        FILE_UNIX_BASIC_INFO *data_offset;
        __u16 params, param_offset, offset, count, byte_count;
-       __u64 mode = args->mode;
 
        cFYI(1, ("In SetUID/GID/Mode"));
 setPermsRetry:
@@ -5137,38 +5240,8 @@ setPermsRetry:
        pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_BASIC);
        pSMB->Reserved4 = 0;
        pSMB->hdr.smb_buf_length += byte_count;
-       /* Samba server ignores set of file size to zero due to bugs in some
-       older clients, but we should be precise - we use SetFileSize to
-       set file size and do not want to truncate file size to zero
-       accidently as happened on one Samba server beta by putting
-       zero instead of -1 here */
-       data_offset->EndOfFile = cpu_to_le64(NO_CHANGE_64);
-       data_offset->NumOfBytes = cpu_to_le64(NO_CHANGE_64);
-       data_offset->LastStatusChange = cpu_to_le64(args->ctime);
-       data_offset->LastAccessTime = cpu_to_le64(args->atime);
-       data_offset->LastModificationTime = cpu_to_le64(args->mtime);
-       data_offset->Uid = cpu_to_le64(args->uid);
-       data_offset->Gid = cpu_to_le64(args->gid);
-       /* better to leave device as zero when it is  */
-       data_offset->DevMajor = cpu_to_le64(MAJOR(args->device));
-       data_offset->DevMinor = cpu_to_le64(MINOR(args->device));
-       data_offset->Permissions = cpu_to_le64(mode);
-
-       if (S_ISREG(mode))
-               data_offset->Type = cpu_to_le32(UNIX_FILE);
-       else if (S_ISDIR(mode))
-               data_offset->Type = cpu_to_le32(UNIX_DIR);
-       else if (S_ISLNK(mode))
-               data_offset->Type = cpu_to_le32(UNIX_SYMLINK);
-       else if (S_ISCHR(mode))
-               data_offset->Type = cpu_to_le32(UNIX_CHARDEV);
-       else if (S_ISBLK(mode))
-               data_offset->Type = cpu_to_le32(UNIX_BLOCKDEV);
-       else if (S_ISFIFO(mode))
-               data_offset->Type = cpu_to_le32(UNIX_FIFO);
-       else if (S_ISSOCK(mode))
-               data_offset->Type = cpu_to_le32(UNIX_SOCKET);
 
+       cifs_fill_unix_set_info(data_offset, args);
 
        pSMB->ByteCount = cpu_to_le16(byte_count);
        rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
index 97f4311b9a8ea2f40325ac2fda8a2929153402eb..e16d7592116ad7dbedd557d8df37497d6370155c 100644 (file)
@@ -70,7 +70,6 @@ struct smb_vol {
        mode_t file_mode;
        mode_t dir_mode;
        unsigned secFlg;
-       bool rw:1;
        bool retry:1;
        bool intr:1;
        bool setuids:1;
@@ -832,7 +831,6 @@ cifs_parse_mount_options(char *options, const char *devname,
        vol->dir_mode = vol->file_mode = S_IRUGO | S_IXUGO | S_IWUSR;
 
        /* vol->retry default is 0 (i.e. "soft" limited retry not hard retry) */
-       vol->rw = true;
        /* default is always to request posix paths. */
        vol->posix_paths = 1;
        /* default to using server inode numbers where available */
@@ -1199,7 +1197,9 @@ cifs_parse_mount_options(char *options, const char *devname,
                } else if (strnicmp(data, "guest", 5) == 0) {
                        /* ignore */
                } else if (strnicmp(data, "rw", 2) == 0) {
-                       vol->rw = true;
+                       /* ignore */
+               } else if (strnicmp(data, "ro", 2) == 0) {
+                       /* ignore */
                } else if (strnicmp(data, "noblocksend", 11) == 0) {
                        vol->noblocksnd = 1;
                } else if (strnicmp(data, "noautotune", 10) == 0) {
@@ -1218,8 +1218,6 @@ cifs_parse_mount_options(char *options, const char *devname,
                            parse these options again and set anything and it
                            is ok to just ignore them */
                        continue;
-               } else if (strnicmp(data, "ro", 2) == 0) {
-                       vol->rw = false;
                } else if (strnicmp(data, "hard", 4) == 0) {
                        vol->retry = 1;
                } else if (strnicmp(data, "soft", 4) == 0) {
@@ -1386,8 +1384,10 @@ cifs_find_tcp_session(struct sockaddr_storage *addr)
                     server->addr.sockAddr.sin_addr.s_addr))
                        continue;
                else if (addr->ss_family == AF_INET6 &&
-                        !ipv6_addr_equal(&server->addr.sockAddr6.sin6_addr,
-                                         &addr6->sin6_addr))
+                        (!ipv6_addr_equal(&server->addr.sockAddr6.sin6_addr,
+                                          &addr6->sin6_addr) ||
+                         server->addr.sockAddr6.sin6_scope_id !=
+                                          addr6->sin6_scope_id))
                        continue;
 
                ++server->srv_count;
@@ -1433,28 +1433,15 @@ cifs_get_tcp_session(struct smb_vol *volume_info)
 
        memset(&addr, 0, sizeof(struct sockaddr_storage));
 
-       if (volume_info->UNCip && volume_info->UNC) {
-               rc = cifs_inet_pton(AF_INET, volume_info->UNCip,
-                                   &sin_server->sin_addr.s_addr);
-
-               if (rc <= 0) {
-                       /* not ipv4 address, try ipv6 */
-                       rc = cifs_inet_pton(AF_INET6, volume_info->UNCip,
-                                           &sin_server6->sin6_addr.in6_u);
-                       if (rc > 0)
-                               addr.ss_family = AF_INET6;
-               } else {
-                       addr.ss_family = AF_INET;
-               }
+       cFYI(1, ("UNC: %s ip: %s", volume_info->UNC, volume_info->UNCip));
 
-               if (rc <= 0) {
+       if (volume_info->UNCip && volume_info->UNC) {
+               rc = cifs_convert_address(volume_info->UNCip, &addr);
+               if (!rc) {
                        /* we failed translating address */
                        rc = -EINVAL;
                        goto out_err;
                }
-
-               cFYI(1, ("UNC: %s ip: %s", volume_info->UNC,
-                        volume_info->UNCip));
        } else if (volume_info->UNCip) {
                /* BB using ip addr as tcp_ses name to connect to the
                   DFS root below */
@@ -1513,14 +1500,14 @@ cifs_get_tcp_session(struct smb_vol *volume_info)
                cFYI(1, ("attempting ipv6 connect"));
                /* BB should we allow ipv6 on port 139? */
                /* other OS never observed in Wild doing 139 with v6 */
+               sin_server6->sin6_port = htons(volume_info->port);
                memcpy(&tcp_ses->addr.sockAddr6, sin_server6,
                        sizeof(struct sockaddr_in6));
-               sin_server6->sin6_port = htons(volume_info->port);
                rc = ipv6_connect(tcp_ses);
        } else {
+               sin_server->sin_port = htons(volume_info->port);
                memcpy(&tcp_ses->addr.sockAddr, sin_server,
                        sizeof(struct sockaddr_in));
-               sin_server->sin_port = htons(volume_info->port);
                rc = ipv4_connect(tcp_ses);
        }
        if (rc < 0) {
index 3758965d73d56c8b281a3ea055b2eb27eed3892d..4326ffd90fa91b92086ab993bcfe7631396c7cf4 100644 (file)
@@ -188,6 +188,7 @@ int cifs_posix_open(char *full_path, struct inode **pinode,
        FILE_UNIX_BASIC_INFO *presp_data;
        __u32 posix_flags = 0;
        struct cifs_sb_info *cifs_sb = CIFS_SB(sb);
+       struct cifs_fattr fattr;
 
        cFYI(1, ("posix open %s", full_path));
 
@@ -236,22 +237,21 @@ int cifs_posix_open(char *full_path, struct inode **pinode,
        if (presp_data->Type == cpu_to_le32(-1))
                goto posix_open_ret; /* open ok, caller does qpathinfo */
 
-       /* get new inode and set it up */
        if (!pinode)
                goto posix_open_ret; /* caller does not need info */
 
+       cifs_unix_basic_to_fattr(&fattr, presp_data, cifs_sb);
+
+       /* get new inode and set it up */
        if (*pinode == NULL) {
-               __u64 unique_id = le64_to_cpu(presp_data->UniqueId);
-               *pinode = cifs_new_inode(sb, &unique_id);
+               *pinode = cifs_iget(sb, &fattr);
+               if (!*pinode) {
+                       rc = -ENOMEM;
+                       goto posix_open_ret;
+               }
+       } else {
+               cifs_fattr_to_inode(*pinode, &fattr);
        }
-       /* else an inode was passed in. Update its info, don't create one */
-
-       /* We do not need to close the file if new_inode fails since
-          the caller will retry qpathinfo as long as inode is null */
-       if (*pinode == NULL)
-               goto posix_open_ret;
-
-       posix_fill_in_inode(*pinode, presp_data, 1);
 
        cifs_fill_fileinfo(*pinode, *pnetfid, cifs_sb->tcon, write_only);
 
@@ -307,8 +307,9 @@ cifs_create(struct inode *inode, struct dentry *direntry, int mode,
 
        full_path = build_path_from_dentry(direntry);
        if (full_path == NULL) {
+               rc = -ENOMEM;
                FreeXid(xid);
-               return -ENOMEM;
+               return rc;
        }
 
        if (oplockEnabled)
@@ -424,9 +425,10 @@ cifs_create(struct inode *inode, struct dentry *direntry, int mode,
                        args.uid = NO_CHANGE_64;
                        args.gid = NO_CHANGE_64;
                }
-               CIFSSMBUnixSetInfo(xid, tcon, full_path, &args,
-                       cifs_sb->local_nls,
-                       cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
+               CIFSSMBUnixSetPathInfo(xid, tcon, full_path, &args,
+                                       cifs_sb->local_nls,
+                                       cifs_sb->mnt_cifs_flags &
+                                               CIFS_MOUNT_MAP_SPECIAL_CHR);
        } else {
                /* BB implement mode setting via Windows security
                   descriptors e.g. */
@@ -514,10 +516,10 @@ int cifs_mknod(struct inode *inode, struct dentry *direntry, int mode,
                        args.uid = NO_CHANGE_64;
                        args.gid = NO_CHANGE_64;
                }
-               rc = CIFSSMBUnixSetInfo(xid, pTcon, full_path,
-                       &args, cifs_sb->local_nls,
-                       cifs_sb->mnt_cifs_flags &
-                               CIFS_MOUNT_MAP_SPECIAL_CHR);
+               rc = CIFSSMBUnixSetPathInfo(xid, pTcon, full_path, &args,
+                                           cifs_sb->local_nls,
+                                           cifs_sb->mnt_cifs_flags &
+                                               CIFS_MOUNT_MAP_SPECIAL_CHR);
 
                if (!rc) {
                        rc = cifs_get_inode_info_unix(&newinode, full_path,
@@ -540,8 +542,9 @@ int cifs_mknod(struct inode *inode, struct dentry *direntry, int mode,
                        buf = kmalloc(sizeof(FILE_ALL_INFO), GFP_KERNEL);
                        if (buf == NULL) {
                                kfree(full_path);
+                               rc = -ENOMEM;
                                FreeXid(xid);
-                               return -ENOMEM;
+                               return rc;
                        }
 
                        rc = CIFSSMBOpen(xid, pTcon, full_path,
@@ -641,6 +644,15 @@ cifs_lookup(struct inode *parent_dir_inode, struct dentry *direntry,
                        }
        }
 
+       /*
+        * O_EXCL: optimize away the lookup, but don't hash the dentry. Let
+        * the VFS handle the create.
+        */
+       if (nd->flags & LOOKUP_EXCL) {
+               d_instantiate(direntry, NULL);
+               return 0;
+       }
+
        /* can not grab the rename sem here since it would
        deadlock in the cases (beginning of sys_rename itself)
        in which we already have the sb rename sem */
index df4a306f697efc9c5772d52ae88045095b28e077..87948147d7ece68d64e7218c8331624410ac2196 100644 (file)
  *             0 - name is not IP
  */
 static int
-is_ip(const char *name)
+is_ip(char *name)
 {
-       int rc;
-       struct sockaddr_in sin_server;
-       struct sockaddr_in6 sin_server6;
-
-       rc = cifs_inet_pton(AF_INET, name,
-                       &sin_server.sin_addr.s_addr);
-
-       if (rc <= 0) {
-               /* not ipv4 address, try ipv6 */
-               rc = cifs_inet_pton(AF_INET6, name,
-                               &sin_server6.sin6_addr.in6_u);
-               if (rc > 0)
-                       return 1;
-       } else {
-               return 1;
-       }
-       /* we failed translating address */
-       return 0;
+       struct sockaddr_storage ss;
+
+       return cifs_convert_address(name, &ss);
 }
 
 static int
@@ -72,7 +57,7 @@ dns_resolver_instantiate(struct key *key, const void *data,
        ip[datalen] = '\0';
 
        /* make sure this looks like an address */
-       if (!is_ip((const char *) ip)) {
+       if (!is_ip(ip)) {
                kfree(ip);
                return -EINVAL;
        }
index 06866841b97f1b9993ea3dd577f3f4478d06880e..c34b7f8a217b383b1f8505822f00052276779833 100644 (file)
@@ -300,14 +300,16 @@ int cifs_open(struct inode *inode, struct file *file)
        pCifsInode = CIFS_I(file->f_path.dentry->d_inode);
        pCifsFile = cifs_fill_filedata(file);
        if (pCifsFile) {
+               rc = 0;
                FreeXid(xid);
-               return 0;
+               return rc;
        }
 
        full_path = build_path_from_dentry(file->f_path.dentry);
        if (full_path == NULL) {
+               rc = -ENOMEM;
                FreeXid(xid);
-               return -ENOMEM;
+               return rc;
        }
 
        cFYI(1, ("inode = 0x%p file flags are 0x%x for %s",
@@ -446,9 +448,9 @@ int cifs_open(struct inode *inode, struct file *file)
                                .mtime  = NO_CHANGE_64,
                                .device = 0,
                        };
-                       CIFSSMBUnixSetInfo(xid, tcon, full_path, &args,
-                                           cifs_sb->local_nls,
-                                           cifs_sb->mnt_cifs_flags &
+                       CIFSSMBUnixSetPathInfo(xid, tcon, full_path, &args,
+                                              cifs_sb->local_nls,
+                                              cifs_sb->mnt_cifs_flags &
                                                CIFS_MOUNT_MAP_SPECIAL_CHR);
                }
        }
@@ -491,11 +493,12 @@ static int cifs_reopen_file(struct file *file, bool can_flush)
                return -EBADF;
 
        xid = GetXid();
-       mutex_unlock(&pCifsFile->fh_mutex);
+       mutex_lock(&pCifsFile->fh_mutex);
        if (!pCifsFile->invalidHandle) {
-               mutex_lock(&pCifsFile->fh_mutex);
+               mutex_unlock(&pCifsFile->fh_mutex);
+               rc = 0;
                FreeXid(xid);
-               return 0;
+               return rc;
        }
 
        if (file->f_path.dentry == NULL) {
@@ -524,7 +527,7 @@ static int cifs_reopen_file(struct file *file, bool can_flush)
        if (full_path == NULL) {
                rc = -ENOMEM;
 reopen_error_exit:
-               mutex_lock(&pCifsFile->fh_mutex);
+               mutex_unlock(&pCifsFile->fh_mutex);
                FreeXid(xid);
                return rc;
        }
@@ -566,14 +569,14 @@ reopen_error_exit:
                         cifs_sb->local_nls, cifs_sb->mnt_cifs_flags &
                                CIFS_MOUNT_MAP_SPECIAL_CHR);
        if (rc) {
-               mutex_lock(&pCifsFile->fh_mutex);
+               mutex_unlock(&pCifsFile->fh_mutex);
                cFYI(1, ("cifs_open returned 0x%x", rc));
                cFYI(1, ("oplock: %d", oplock));
        } else {
 reopen_success:
                pCifsFile->netfid = netfid;
                pCifsFile->invalidHandle = false;
-               mutex_lock(&pCifsFile->fh_mutex);
+               mutex_unlock(&pCifsFile->fh_mutex);
                pCifsInode = CIFS_I(inode);
                if (pCifsInode) {
                        if (can_flush) {
@@ -845,8 +848,9 @@ int cifs_lock(struct file *file, int cmd, struct file_lock *pfLock)
        tcon = cifs_sb->tcon;
 
        if (file->private_data == NULL) {
+               rc = -EBADF;
                FreeXid(xid);
-               return -EBADF;
+               return rc;
        }
        netfid = ((struct cifsFileInfo *)file->private_data)->netfid;
 
@@ -1805,8 +1809,9 @@ ssize_t cifs_user_read(struct file *file, char __user *read_data,
        pTcon = cifs_sb->tcon;
 
        if (file->private_data == NULL) {
+               rc = -EBADF;
                FreeXid(xid);
-               return -EBADF;
+               return rc;
        }
        open_file = (struct cifsFileInfo *)file->private_data;
 
@@ -1885,8 +1890,9 @@ static ssize_t cifs_read(struct file *file, char *read_data, size_t read_size,
        pTcon = cifs_sb->tcon;
 
        if (file->private_data == NULL) {
+               rc = -EBADF;
                FreeXid(xid);
-               return -EBADF;
+               return rc;
        }
        open_file = (struct cifsFileInfo *)file->private_data;
 
@@ -2019,8 +2025,9 @@ static int cifs_readpages(struct file *file, struct address_space *mapping,
 
        xid = GetXid();
        if (file->private_data == NULL) {
+               rc = -EBADF;
                FreeXid(xid);
-               return -EBADF;
+               return rc;
        }
        open_file = (struct cifsFileInfo *)file->private_data;
        cifs_sb = CIFS_SB(file->f_path.dentry->d_sb);
@@ -2185,8 +2192,9 @@ static int cifs_readpage(struct file *file, struct page *page)
        xid = GetXid();
 
        if (file->private_data == NULL) {
+               rc = -EBADF;
                FreeXid(xid);
-               return -EBADF;
+               return rc;
        }
 
        cFYI(1, ("readpage %p at offset %d 0x%x\n",
index fad882b075ba50358b113e58808b9845f6baca4c..18afe57b24611748e35377e95de5130c53a5a625 100644 (file)
@@ -77,239 +77,202 @@ static void cifs_set_ops(struct inode *inode, const bool is_dfs_referral)
        }
 }
 
-static void cifs_unix_info_to_inode(struct inode *inode,
-               FILE_UNIX_BASIC_INFO *info, int force_uid_gid)
+/* populate an inode with info from a cifs_fattr struct */
+void
+cifs_fattr_to_inode(struct inode *inode, struct cifs_fattr *fattr)
 {
+       struct cifsInodeInfo *cifs_i = CIFS_I(inode);
        struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
-       struct cifsInodeInfo *cifsInfo = CIFS_I(inode);
-       __u64 num_of_bytes = le64_to_cpu(info->NumOfBytes);
-       __u64 end_of_file = le64_to_cpu(info->EndOfFile);
+       unsigned long oldtime = cifs_i->time;
+
+       inode->i_atime = fattr->cf_atime;
+       inode->i_mtime = fattr->cf_mtime;
+       inode->i_ctime = fattr->cf_ctime;
+       inode->i_rdev = fattr->cf_rdev;
+       inode->i_nlink = fattr->cf_nlink;
+       inode->i_uid = fattr->cf_uid;
+       inode->i_gid = fattr->cf_gid;
+
+       /* if dynperm is set, don't clobber existing mode */
+       if (inode->i_state & I_NEW ||
+           !(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DYNPERM))
+               inode->i_mode = fattr->cf_mode;
+
+       cifs_i->cifsAttrs = fattr->cf_cifsattrs;
+       cifs_i->uniqueid = fattr->cf_uniqueid;
+
+       if (fattr->cf_flags & CIFS_FATTR_NEED_REVAL)
+               cifs_i->time = 0;
+       else
+               cifs_i->time = jiffies;
+
+       cFYI(1, ("inode 0x%p old_time=%ld new_time=%ld", inode,
+                oldtime, cifs_i->time));
 
-       inode->i_atime = cifs_NTtimeToUnix(info->LastAccessTime);
-       inode->i_mtime =
-               cifs_NTtimeToUnix(info->LastModificationTime);
-       inode->i_ctime = cifs_NTtimeToUnix(info->LastStatusChange);
-       inode->i_mode = le64_to_cpu(info->Permissions);
+       cifs_i->delete_pending = fattr->cf_flags & CIFS_FATTR_DELETE_PENDING;
+
+       /*
+        * Can't safely change the file size here if the client is writing to
+        * it due to potential races.
+        */
+       spin_lock(&inode->i_lock);
+       if (is_size_safe_to_change(cifs_i, fattr->cf_eof)) {
+               i_size_write(inode, fattr->cf_eof);
+
+               /*
+                * i_blocks is not related to (i_size / i_blksize),
+                * but instead 512 byte (2**9) size is required for
+                * calculating num blocks.
+                */
+               inode->i_blocks = (512 - 1 + fattr->cf_bytes) >> 9;
+       }
+       spin_unlock(&inode->i_lock);
+
+       cifs_set_ops(inode, fattr->cf_flags & CIFS_FATTR_DFS_REFERRAL);
+}
+
+/* Fill a cifs_fattr struct with info from FILE_UNIX_BASIC_INFO. */
+void
+cifs_unix_basic_to_fattr(struct cifs_fattr *fattr, FILE_UNIX_BASIC_INFO *info,
+                        struct cifs_sb_info *cifs_sb)
+{
+       memset(fattr, 0, sizeof(*fattr));
+       fattr->cf_uniqueid = le64_to_cpu(info->UniqueId);
+       fattr->cf_bytes = le64_to_cpu(info->NumOfBytes);
+       fattr->cf_eof = le64_to_cpu(info->EndOfFile);
+
+       fattr->cf_atime = cifs_NTtimeToUnix(info->LastAccessTime);
+       fattr->cf_mtime = cifs_NTtimeToUnix(info->LastModificationTime);
+       fattr->cf_ctime = cifs_NTtimeToUnix(info->LastStatusChange);
+       fattr->cf_mode = le64_to_cpu(info->Permissions);
 
        /*
         * Since we set the inode type below we need to mask off
         * to avoid strange results if bits set above.
         */
-       inode->i_mode &= ~S_IFMT;
+       fattr->cf_mode &= ~S_IFMT;
        switch (le32_to_cpu(info->Type)) {
        case UNIX_FILE:
-               inode->i_mode |= S_IFREG;
+               fattr->cf_mode |= S_IFREG;
+               fattr->cf_dtype = DT_REG;
                break;
        case UNIX_SYMLINK:
-               inode->i_mode |= S_IFLNK;
+               fattr->cf_mode |= S_IFLNK;
+               fattr->cf_dtype = DT_LNK;
                break;
        case UNIX_DIR:
-               inode->i_mode |= S_IFDIR;
+               fattr->cf_mode |= S_IFDIR;
+               fattr->cf_dtype = DT_DIR;
                break;
        case UNIX_CHARDEV:
-               inode->i_mode |= S_IFCHR;
-               inode->i_rdev = MKDEV(le64_to_cpu(info->DevMajor),
-                                     le64_to_cpu(info->DevMinor) & MINORMASK);
+               fattr->cf_mode |= S_IFCHR;
+               fattr->cf_dtype = DT_CHR;
+               fattr->cf_rdev = MKDEV(le64_to_cpu(info->DevMajor),
+                                      le64_to_cpu(info->DevMinor) & MINORMASK);
                break;
        case UNIX_BLOCKDEV:
-               inode->i_mode |= S_IFBLK;
-               inode->i_rdev = MKDEV(le64_to_cpu(info->DevMajor),
-                                     le64_to_cpu(info->DevMinor) & MINORMASK);
+               fattr->cf_mode |= S_IFBLK;
+               fattr->cf_dtype = DT_BLK;
+               fattr->cf_rdev = MKDEV(le64_to_cpu(info->DevMajor),
+                                      le64_to_cpu(info->DevMinor) & MINORMASK);
                break;
        case UNIX_FIFO:
-               inode->i_mode |= S_IFIFO;
+               fattr->cf_mode |= S_IFIFO;
+               fattr->cf_dtype = DT_FIFO;
                break;
        case UNIX_SOCKET:
-               inode->i_mode |= S_IFSOCK;
+               fattr->cf_mode |= S_IFSOCK;
+               fattr->cf_dtype = DT_SOCK;
                break;
        default:
                /* safest to call it a file if we do not know */
-               inode->i_mode |= S_IFREG;
+               fattr->cf_mode |= S_IFREG;
+               fattr->cf_dtype = DT_REG;
                cFYI(1, ("unknown type %d", le32_to_cpu(info->Type)));
                break;
        }
 
-       if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_OVERR_UID) &&
-           !force_uid_gid)
-               inode->i_uid = cifs_sb->mnt_uid;
+       if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_OVERR_UID)
+               fattr->cf_uid = cifs_sb->mnt_uid;
        else
-               inode->i_uid = le64_to_cpu(info->Uid);
+               fattr->cf_uid = le64_to_cpu(info->Uid);
 
-       if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_OVERR_GID) &&
-           !force_uid_gid)
-               inode->i_gid = cifs_sb->mnt_gid;
+       if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_OVERR_GID)
+               fattr->cf_gid = cifs_sb->mnt_gid;
        else
-               inode->i_gid = le64_to_cpu(info->Gid);
-
-       inode->i_nlink = le64_to_cpu(info->Nlinks);
-
-       cifsInfo->server_eof = end_of_file;
-       spin_lock(&inode->i_lock);
-       if (is_size_safe_to_change(cifsInfo, end_of_file)) {
-               /*
-                * We can not safely change the file size here if the client
-                * is writing to it due to potential races.
-                */
-               i_size_write(inode, end_of_file);
+               fattr->cf_gid = le64_to_cpu(info->Gid);
 
-               /*
-                * i_blocks is not related to (i_size / i_blksize),
-                * but instead 512 byte (2**9) size is required for
-                * calculating num blocks.
-                */
-               inode->i_blocks = (512 - 1 + num_of_bytes) >> 9;
-       }
-       spin_unlock(&inode->i_lock);
+       fattr->cf_nlink = le64_to_cpu(info->Nlinks);
 }
 
-
 /*
- *     Needed to setup inode data for the directory which is the
- *     junction to the new submount (ie to setup the fake directory
- *      which represents a DFS referral)
- */
-static void fill_fake_finddataunix(FILE_UNIX_BASIC_INFO *pfnd_dat,
-                              struct super_block *sb)
-{
-       struct inode *pinode = NULL;
-
-       memset(pfnd_dat, 0, sizeof(FILE_UNIX_BASIC_INFO));
-
-/*     __le64 pfnd_dat->EndOfFile = cpu_to_le64(0);
-       __le64 pfnd_dat->NumOfBytes = cpu_to_le64(0);
-       __u64 UniqueId = 0;  */
-       pfnd_dat->LastStatusChange =
-               cpu_to_le64(cifs_UnixTimeToNT(CURRENT_TIME));
-       pfnd_dat->LastAccessTime =
-               cpu_to_le64(cifs_UnixTimeToNT(CURRENT_TIME));
-       pfnd_dat->LastModificationTime =
-               cpu_to_le64(cifs_UnixTimeToNT(CURRENT_TIME));
-       pfnd_dat->Type = cpu_to_le32(UNIX_DIR);
-       pfnd_dat->Permissions = cpu_to_le64(S_IXUGO | S_IRWXU);
-       pfnd_dat->Nlinks = cpu_to_le64(2);
-       if (sb->s_root)
-               pinode = sb->s_root->d_inode;
-       if (pinode == NULL)
-               return;
-
-       /* fill in default values for the remaining based on root
-          inode since we can not query the server for this inode info */
-       pfnd_dat->DevMajor = cpu_to_le64(MAJOR(pinode->i_rdev));
-       pfnd_dat->DevMinor = cpu_to_le64(MINOR(pinode->i_rdev));
-       pfnd_dat->Uid = cpu_to_le64(pinode->i_uid);
-       pfnd_dat->Gid = cpu_to_le64(pinode->i_gid);
-}
-
-/**
- * cifs_new inode - create new inode, initialize, and hash it
- * @sb - pointer to superblock
- * @inum - if valid pointer and serverino is enabled, replace i_ino with val
- *
- * Create a new inode, initialize it for CIFS and hash it. Returns the new
- * inode or NULL if one couldn't be allocated.
+ * Fill a cifs_fattr struct with fake inode info.
  *
- * If the share isn't mounted with "serverino" or inum is a NULL pointer then
- * we'll just use the inode number assigned by new_inode(). Note that this can
- * mean i_ino collisions since the i_ino assigned by new_inode is not
- * guaranteed to be unique.
+ * Needed to setup cifs_fattr data for the directory which is the
+ * junction to the new submount (ie to setup the fake directory
+ * which represents a DFS referral).
  */
-struct inode *
-cifs_new_inode(struct super_block *sb, __u64 *inum)
+void
+cifs_create_dfs_fattr(struct cifs_fattr *fattr, struct super_block *sb)
 {
-       struct inode *inode;
-
-       inode = new_inode(sb);
-       if (inode == NULL)
-               return NULL;
-
-       /*
-        * BB: Is i_ino == 0 legal? Here, we assume that it is. If it isn't we
-        *     stop passing inum as ptr. Are there sanity checks we can use to
-        *     ensure that the server is really filling in that field? Also,
-        *     if serverino is disabled, perhaps we should be using iunique()?
-        */
-       if (inum && (CIFS_SB(sb)->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM))
-               inode->i_ino = (unsigned long) *inum;
-
-       /*
-        * must set this here instead of cifs_alloc_inode since VFS will
-        * clobber i_flags
-        */
-       if (sb->s_flags & MS_NOATIME)
-               inode->i_flags |= S_NOATIME | S_NOCMTIME;
-
-       insert_inode_hash(inode);
+       struct cifs_sb_info *cifs_sb = CIFS_SB(sb);
 
-       return inode;
+       cFYI(1, ("creating fake fattr for DFS referral"));
+
+       memset(fattr, 0, sizeof(*fattr));
+       fattr->cf_mode = S_IFDIR | S_IXUGO | S_IRWXU;
+       fattr->cf_uid = cifs_sb->mnt_uid;
+       fattr->cf_gid = cifs_sb->mnt_gid;
+       fattr->cf_atime = CURRENT_TIME;
+       fattr->cf_ctime = CURRENT_TIME;
+       fattr->cf_mtime = CURRENT_TIME;
+       fattr->cf_nlink = 2;
+       fattr->cf_flags |= CIFS_FATTR_DFS_REFERRAL;
 }
 
 int cifs_get_inode_info_unix(struct inode **pinode,
-       const unsigned char *full_path, struct super_block *sb, int xid)
+                            const unsigned char *full_path,
+                            struct super_block *sb, int xid)
 {
-       int rc = 0;
+       int rc;
        FILE_UNIX_BASIC_INFO find_data;
-       struct cifsTconInfo *pTcon;
-       struct inode *inode;
+       struct cifs_fattr fattr;
+       struct cifsTconInfo *tcon;
        struct cifs_sb_info *cifs_sb = CIFS_SB(sb);
-       bool is_dfs_referral = false;
-       struct cifsInodeInfo *cifsInfo;
-       __u64 num_of_bytes;
-       __u64 end_of_file;
 
-       pTcon = cifs_sb->tcon;
+       tcon = cifs_sb->tcon;
        cFYI(1, ("Getting info on %s", full_path));
 
        /* could have done a find first instead but this returns more info */
-       rc = CIFSSMBUnixQPathInfo(xid, pTcon, full_path, &find_data,
+       rc = CIFSSMBUnixQPathInfo(xid, tcon, full_path, &find_data,
                                  cifs_sb->local_nls, cifs_sb->mnt_cifs_flags &
                                        CIFS_MOUNT_MAP_SPECIAL_CHR);
-       if (rc == -EREMOTE && !is_dfs_referral) {
-               is_dfs_referral = true;
-               cFYI(DBG2, ("DFS ref"));
-               /* for DFS, server does not give us real inode data */
-               fill_fake_finddataunix(&find_data, sb);
-               rc = 0;
-       } else if (rc)
-               goto cgiiu_exit;
 
-       num_of_bytes = le64_to_cpu(find_data.NumOfBytes);
-       end_of_file = le64_to_cpu(find_data.EndOfFile);
+       if (!rc) {
+               cifs_unix_basic_to_fattr(&fattr, &find_data, cifs_sb);
+       } else if (rc == -EREMOTE) {
+               cifs_create_dfs_fattr(&fattr, sb);
+               rc = 0;
+       } else {
+               return rc;
+       }
 
-       /* get new inode */
        if (*pinode == NULL) {
-               __u64 unique_id = le64_to_cpu(find_data.UniqueId);
-               *pinode = cifs_new_inode(sb, &unique_id);
-               if (*pinode == NULL) {
+               /* get new inode */
+               *pinode = cifs_iget(sb, &fattr);
+               if (!*pinode)
                        rc = -ENOMEM;
-                       goto cgiiu_exit;
-               }
+       } else {
+               /* we already have inode, update it */
+               cifs_fattr_to_inode(*pinode, &fattr);
        }
 
-       inode = *pinode;
-       cifsInfo = CIFS_I(inode);
-
-       cFYI(1, ("Old time %ld", cifsInfo->time));
-       cifsInfo->time = jiffies;
-       cFYI(1, ("New time %ld", cifsInfo->time));
-       /* this is ok to set on every inode revalidate */
-       atomic_set(&cifsInfo->inUse, 1);
-
-       cifs_unix_info_to_inode(inode, &find_data, 0);
-
-       if (num_of_bytes < end_of_file)
-               cFYI(1, ("allocation size less than end of file"));
-       cFYI(1, ("Size %ld and blocks %llu",
-               (unsigned long) inode->i_size,
-               (unsigned long long)inode->i_blocks));
-
-       cifs_set_ops(inode, is_dfs_referral);
-cgiiu_exit:
        return rc;
 }
 
-static int decode_sfu_inode(struct inode *inode, __u64 size,
-                           const unsigned char *path,
-                           struct cifs_sb_info *cifs_sb, int xid)
+static int
+cifs_sfu_type(struct cifs_fattr *fattr, const unsigned char *path,
+             struct cifs_sb_info *cifs_sb, int xid)
 {
        int rc;
        int oplock = 0;
@@ -321,10 +284,15 @@ static int decode_sfu_inode(struct inode *inode, __u64 size,
 
        pbuf = buf;
 
-       if (size == 0) {
-               inode->i_mode |= S_IFIFO;
+       fattr->cf_mode &= ~S_IFMT;
+
+       if (fattr->cf_eof == 0) {
+               fattr->cf_mode |= S_IFIFO;
+               fattr->cf_dtype = DT_FIFO;
                return 0;
-       } else if (size < 8) {
+       } else if (fattr->cf_eof < 8) {
+               fattr->cf_mode |= S_IFREG;
+               fattr->cf_dtype = DT_REG;
                return -EINVAL;  /* EOPNOTSUPP? */
        }
 
@@ -336,42 +304,46 @@ static int decode_sfu_inode(struct inode *inode, __u64 size,
        if (rc == 0) {
                int buf_type = CIFS_NO_BUFFER;
                        /* Read header */
-               rc = CIFSSMBRead(xid, pTcon,
-                                netfid,
+               rc = CIFSSMBRead(xid, pTcon, netfid,
                                 24 /* length */, 0 /* offset */,
                                 &bytes_read, &pbuf, &buf_type);
                if ((rc == 0) && (bytes_read >= 8)) {
                        if (memcmp("IntxBLK", pbuf, 8) == 0) {
                                cFYI(1, ("Block device"));
-                               inode->i_mode |= S_IFBLK;
+                               fattr->cf_mode |= S_IFBLK;
+                               fattr->cf_dtype = DT_BLK;
                                if (bytes_read == 24) {
                                        /* we have enough to decode dev num */
                                        __u64 mjr; /* major */
                                        __u64 mnr; /* minor */
                                        mjr = le64_to_cpu(*(__le64 *)(pbuf+8));
                                        mnr = le64_to_cpu(*(__le64 *)(pbuf+16));
-                                       inode->i_rdev = MKDEV(mjr, mnr);
+                                       fattr->cf_rdev = MKDEV(mjr, mnr);
                                }
                        } else if (memcmp("IntxCHR", pbuf, 8) == 0) {
                                cFYI(1, ("Char device"));
-                               inode->i_mode |= S_IFCHR;
+                               fattr->cf_mode |= S_IFCHR;
+                               fattr->cf_dtype = DT_CHR;
                                if (bytes_read == 24) {
                                        /* we have enough to decode dev num */
                                        __u64 mjr; /* major */
                                        __u64 mnr; /* minor */
                                        mjr = le64_to_cpu(*(__le64 *)(pbuf+8));
                                        mnr = le64_to_cpu(*(__le64 *)(pbuf+16));
-                                       inode->i_rdev = MKDEV(mjr, mnr);
+                                       fattr->cf_rdev = MKDEV(mjr, mnr);
                                }
                        } else if (memcmp("IntxLNK", pbuf, 7) == 0) {
                                cFYI(1, ("Symlink"));
-                               inode->i_mode |= S_IFLNK;
+                               fattr->cf_mode |= S_IFLNK;
+                               fattr->cf_dtype = DT_LNK;
                        } else {
-                               inode->i_mode |= S_IFREG; /* file? */
+                               fattr->cf_mode |= S_IFREG; /* file? */
+                               fattr->cf_dtype = DT_REG;
                                rc = -EOPNOTSUPP;
                        }
                } else {
-                       inode->i_mode |= S_IFREG; /* then it is a file */
+                       fattr->cf_mode |= S_IFREG; /* then it is a file */
+                       fattr->cf_dtype = DT_REG;
                        rc = -EOPNOTSUPP; /* or some unknown SFU type */
                }
                CIFSSMBClose(xid, pTcon, netfid);
@@ -381,9 +353,13 @@ static int decode_sfu_inode(struct inode *inode, __u64 size,
 
 #define SFBITS_MASK (S_ISVTX | S_ISGID | S_ISUID)  /* SETFILEBITS valid bits */
 
-static int get_sfu_mode(struct inode *inode,
-                       const unsigned char *path,
-                       struct cifs_sb_info *cifs_sb, int xid)
+/*
+ * Fetch mode bits as provided by SFU.
+ *
+ * FIXME: Doesn't this clobber the type bit we got from cifs_sfu_type ?
+ */
+static int cifs_sfu_mode(struct cifs_fattr *fattr, const unsigned char *path,
+                        struct cifs_sb_info *cifs_sb, int xid)
 {
 #ifdef CONFIG_CIFS_XATTR
        ssize_t rc;
@@ -391,68 +367,80 @@ static int get_sfu_mode(struct inode *inode,
        __u32 mode;
 
        rc = CIFSSMBQueryEA(xid, cifs_sb->tcon, path, "SETFILEBITS",
-                       ea_value, 4 /* size of buf */, cifs_sb->local_nls,
-               cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
+                           ea_value, 4 /* size of buf */, cifs_sb->local_nls,
+                           cifs_sb->mnt_cifs_flags &
+                               CIFS_MOUNT_MAP_SPECIAL_CHR);
        if (rc < 0)
                return (int)rc;
        else if (rc > 3) {
                mode = le32_to_cpu(*((__le32 *)ea_value));
-               inode->i_mode &= ~SFBITS_MASK;
-               cFYI(1, ("special bits 0%o org mode 0%o", mode, inode->i_mode));
-               inode->i_mode = (mode &  SFBITS_MASK) | inode->i_mode;
+               fattr->cf_mode &= ~SFBITS_MASK;
+               cFYI(1, ("special bits 0%o org mode 0%o", mode,
+                        fattr->cf_mode));
+               fattr->cf_mode = (mode & SFBITS_MASK) | fattr->cf_mode;
                cFYI(1, ("special mode bits 0%o", mode));
-               return 0;
-       } else {
-               return 0;
        }
+
+       return 0;
 #else
        return -EOPNOTSUPP;
 #endif
 }
 
-/*
- *     Needed to setup inode data for the directory which is the
- *     junction to the new submount (ie to setup the fake directory
- *      which represents a DFS referral)
- */
-static void fill_fake_finddata(FILE_ALL_INFO *pfnd_dat,
-                              struct super_block *sb)
+/* Fill a cifs_fattr struct with info from FILE_ALL_INFO */
+void
+cifs_all_info_to_fattr(struct cifs_fattr *fattr, FILE_ALL_INFO *info,
+                      struct cifs_sb_info *cifs_sb, bool adjust_tz)
 {
-       memset(pfnd_dat, 0, sizeof(FILE_ALL_INFO));
-
-/*     __le64 pfnd_dat->AllocationSize = cpu_to_le64(0);
-       __le64 pfnd_dat->EndOfFile = cpu_to_le64(0);
-       __u8 pfnd_dat->DeletePending = 0;
-       __u8 pfnd_data->Directory = 0;
-       __le32 pfnd_dat->EASize = 0;
-       __u64 pfnd_dat->IndexNumber = 0;
-       __u64 pfnd_dat->IndexNumber1 = 0;  */
-       pfnd_dat->CreationTime =
-               cpu_to_le64(cifs_UnixTimeToNT(CURRENT_TIME));
-       pfnd_dat->LastAccessTime =
-               cpu_to_le64(cifs_UnixTimeToNT(CURRENT_TIME));
-       pfnd_dat->LastWriteTime =
-               cpu_to_le64(cifs_UnixTimeToNT(CURRENT_TIME));
-       pfnd_dat->ChangeTime =
-               cpu_to_le64(cifs_UnixTimeToNT(CURRENT_TIME));
-       pfnd_dat->Attributes = cpu_to_le32(ATTR_DIRECTORY);
-       pfnd_dat->NumberOfLinks = cpu_to_le32(2);
+       memset(fattr, 0, sizeof(*fattr));
+       fattr->cf_cifsattrs = le32_to_cpu(info->Attributes);
+       if (info->DeletePending)
+               fattr->cf_flags |= CIFS_FATTR_DELETE_PENDING;
+
+       if (info->LastAccessTime)
+               fattr->cf_atime = cifs_NTtimeToUnix(info->LastAccessTime);
+       else
+               fattr->cf_atime = CURRENT_TIME;
+
+       fattr->cf_ctime = cifs_NTtimeToUnix(info->ChangeTime);
+       fattr->cf_mtime = cifs_NTtimeToUnix(info->LastWriteTime);
+
+       if (adjust_tz) {
+               fattr->cf_ctime.tv_sec += cifs_sb->tcon->ses->server->timeAdj;
+               fattr->cf_mtime.tv_sec += cifs_sb->tcon->ses->server->timeAdj;
+       }
+
+       fattr->cf_eof = le64_to_cpu(info->EndOfFile);
+       fattr->cf_bytes = le64_to_cpu(info->AllocationSize);
+
+       if (fattr->cf_cifsattrs & ATTR_DIRECTORY) {
+               fattr->cf_mode = S_IFDIR | cifs_sb->mnt_dir_mode;
+               fattr->cf_dtype = DT_DIR;
+       } else {
+               fattr->cf_mode = S_IFREG | cifs_sb->mnt_file_mode;
+               fattr->cf_dtype = DT_REG;
+
+               /* clear write bits if ATTR_READONLY is set */
+               if (fattr->cf_cifsattrs & ATTR_READONLY)
+                       fattr->cf_mode &= ~(S_IWUGO);
+       }
+
+       fattr->cf_nlink = le32_to_cpu(info->NumberOfLinks);
+
+       fattr->cf_uid = cifs_sb->mnt_uid;
+       fattr->cf_gid = cifs_sb->mnt_gid;
 }
 
 int cifs_get_inode_info(struct inode **pinode,
        const unsigned char *full_path, FILE_ALL_INFO *pfindData,
        struct super_block *sb, int xid, const __u16 *pfid)
 {
-       int rc = 0;
-       __u32 attr;
-       struct cifsInodeInfo *cifsInfo;
+       int rc = 0, tmprc;
        struct cifsTconInfo *pTcon;
-       struct inode *inode;
        struct cifs_sb_info *cifs_sb = CIFS_SB(sb);
        char *buf = NULL;
        bool adjustTZ = false;
-       bool is_dfs_referral = false;
-       umode_t default_mode;
+       struct cifs_fattr fattr;
 
        pTcon = cifs_sb->tcon;
        cFYI(1, ("Getting info on %s", full_path));
@@ -487,163 +475,82 @@ int cifs_get_inode_info(struct inode **pinode,
                        adjustTZ = true;
                }
        }
-       /* dump_mem("\nQPathInfo return data",&findData, sizeof(findData)); */
-       if (rc == -EREMOTE) {
-               is_dfs_referral = true;
-               fill_fake_finddata(pfindData, sb);
+
+       if (!rc) {
+               cifs_all_info_to_fattr(&fattr, (FILE_ALL_INFO *) pfindData,
+                                      cifs_sb, adjustTZ);
+       } else if (rc == -EREMOTE) {
+               cifs_create_dfs_fattr(&fattr, sb);
                rc = 0;
-       } else if (rc)
+       } else {
                goto cgii_exit;
+       }
 
-       attr = le32_to_cpu(pfindData->Attributes);
-
-       /* get new inode */
+       /*
+        * If an inode wasn't passed in, then get the inode number
+        *
+        * Is an i_ino of zero legal? Can we use that to check if the server
+        * supports returning inode numbers?  Are there other sanity checks we
+        * can use to ensure that the server is really filling in that field?
+        *
+        * We can not use the IndexNumber field by default from Windows or
+        * Samba (in ALL_INFO buf) but we can request it explicitly. The SNIA
+        * CIFS spec claims that this value is unique within the scope of a
+        * share, and the windows docs hint that it's actually unique
+        * per-machine.
+        *
+        * There may be higher info levels that work but are there Windows
+        * server or network appliances for which IndexNumber field is not
+        * guaranteed unique?
+        */
        if (*pinode == NULL) {
-               __u64 inode_num;
-               __u64 *pinum = &inode_num;
-
-               /* Is an i_ino of zero legal? Can we use that to check
-                  if the server supports returning inode numbers?  Are
-                  there other sanity checks we can use to ensure that
-                  the server is really filling in that field? */
-
-               /* We can not use the IndexNumber field by default from
-                  Windows or Samba (in ALL_INFO buf) but we can request
-                  it explicitly.  It may not be unique presumably if
-                  the server has multiple devices mounted under one share */
-
-               /* There may be higher info levels that work but are
-                  there Windows server or network appliances for which
-                  IndexNumber field is not guaranteed unique? */
-
                if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM) {
                        int rc1 = 0;
 
                        rc1 = CIFSGetSrvInodeNumber(xid, pTcon,
-                                       full_path, pinum,
+                                       full_path, &fattr.cf_uniqueid,
                                        cifs_sb->local_nls,
                                        cifs_sb->mnt_cifs_flags &
                                                CIFS_MOUNT_MAP_SPECIAL_CHR);
                        if (rc1) {
-                               cFYI(1, ("GetSrvInodeNum rc %d", rc1));
-                               pinum = NULL;
                                /* BB EOPNOSUPP disable SERVER_INUM? */
+                               cFYI(1, ("GetSrvInodeNum rc %d", rc1));
+                               fattr.cf_uniqueid = iunique(sb, ROOT_I);
                        }
                } else {
-                       pinum = NULL;
+                       fattr.cf_uniqueid = iunique(sb, ROOT_I);
                }
-
-               *pinode = cifs_new_inode(sb, pinum);
-               if (*pinode == NULL) {
-                       rc = -ENOMEM;
-                       goto cgii_exit;
-               }
-       }
-       inode = *pinode;
-       cifsInfo = CIFS_I(inode);
-       cifsInfo->cifsAttrs = attr;
-       cifsInfo->delete_pending = pfindData->DeletePending ? true : false;
-       cFYI(1, ("Old time %ld", cifsInfo->time));
-       cifsInfo->time = jiffies;
-       cFYI(1, ("New time %ld", cifsInfo->time));
-
-       /* blksize needs to be multiple of two. So safer to default to
-       blksize and blkbits set in superblock so 2**blkbits and blksize
-       will match rather than setting to:
-       (pTcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE) & 0xFFFFFE00;*/
-
-       /* Linux can not store file creation time so ignore it */
-       if (pfindData->LastAccessTime)
-               inode->i_atime = cifs_NTtimeToUnix(pfindData->LastAccessTime);
-       else /* do not need to use current_fs_time - time not stored */
-               inode->i_atime = CURRENT_TIME;
-       inode->i_mtime = cifs_NTtimeToUnix(pfindData->LastWriteTime);
-       inode->i_ctime = cifs_NTtimeToUnix(pfindData->ChangeTime);
-       cFYI(DBG2, ("Attributes came in as 0x%x", attr));
-       if (adjustTZ && (pTcon->ses) && (pTcon->ses->server)) {
-               inode->i_ctime.tv_sec += pTcon->ses->server->timeAdj;
-               inode->i_mtime.tv_sec += pTcon->ses->server->timeAdj;
-       }
-
-       /* get default inode mode */
-       if (attr & ATTR_DIRECTORY)
-               default_mode = cifs_sb->mnt_dir_mode;
-       else
-               default_mode = cifs_sb->mnt_file_mode;
-
-       /* set permission bits */
-       if (atomic_read(&cifsInfo->inUse) == 0 ||
-           (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DYNPERM) == 0)
-               inode->i_mode = default_mode;
-       else {
-               /* just reenable write bits if !ATTR_READONLY */
-               if ((inode->i_mode & S_IWUGO) == 0 &&
-                   (attr & ATTR_READONLY) == 0)
-                       inode->i_mode |= (S_IWUGO & default_mode);
-
-               inode->i_mode &= ~S_IFMT;
-       }
-       /* clear write bits if ATTR_READONLY is set */
-       if (attr & ATTR_READONLY)
-               inode->i_mode &= ~S_IWUGO;
-
-       /* set inode type */
-       if ((attr & ATTR_SYSTEM) &&
-           (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL)) {
-               /* no need to fix endianness on 0 */
-               if (pfindData->EndOfFile == 0)
-                       inode->i_mode |= S_IFIFO;
-               else if (decode_sfu_inode(inode,
-                               le64_to_cpu(pfindData->EndOfFile),
-                               full_path, cifs_sb, xid))
-                       cFYI(1, ("unknown SFU file type\n"));
        } else {
-               if (attr & ATTR_DIRECTORY)
-                       inode->i_mode |= S_IFDIR;
-               else
-                       inode->i_mode |= S_IFREG;
+               fattr.cf_uniqueid = CIFS_I(*pinode)->uniqueid;
        }
 
-       cifsInfo->server_eof = le64_to_cpu(pfindData->EndOfFile);
-       spin_lock(&inode->i_lock);
-       if (is_size_safe_to_change(cifsInfo, cifsInfo->server_eof)) {
-               /* can not safely shrink the file size here if the
-                  client is writing to it due to potential races */
-               i_size_write(inode, cifsInfo->server_eof);
-
-               /* 512 bytes (2**9) is the fake blocksize that must be
-                  used for this calculation */
-               inode->i_blocks = (512 - 1 + le64_to_cpu(
-                                  pfindData->AllocationSize)) >> 9;
+       /* query for SFU type info if supported and needed */
+       if (fattr.cf_cifsattrs & ATTR_SYSTEM &&
+           cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL) {
+               tmprc = cifs_sfu_type(&fattr, full_path, cifs_sb, xid);
+               if (tmprc)
+                       cFYI(1, ("cifs_sfu_type failed: %d", tmprc));
        }
-       spin_unlock(&inode->i_lock);
-
-       inode->i_nlink = le32_to_cpu(pfindData->NumberOfLinks);
 
-       /* BB fill in uid and gid here? with help from winbind?
-          or retrieve from NTFS stream extended attribute */
 #ifdef CONFIG_CIFS_EXPERIMENTAL
        /* fill in 0777 bits from ACL */
        if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_CIFS_ACL) {
                cFYI(1, ("Getting mode bits from ACL"));
-               acl_to_uid_mode(cifs_sb, inode, full_path, pfid);
+               cifs_acl_to_fattr(cifs_sb, &fattr, *pinode, full_path, pfid);
        }
 #endif
-       if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL) {
-               /* fill in remaining high mode bits e.g. SUID, VTX */
-               get_sfu_mode(inode, full_path, cifs_sb, xid);
-       } else if (atomic_read(&cifsInfo->inUse) == 0) {
-               inode->i_uid = cifs_sb->mnt_uid;
-               inode->i_gid = cifs_sb->mnt_gid;
-               /* set so we do not keep refreshing these fields with
-                  bad data after user has changed them in memory */
-               atomic_set(&cifsInfo->inUse, 1);
-       }
-
-       cifs_set_ops(inode, is_dfs_referral);
-
 
+       /* fill in remaining high mode bits e.g. SUID, VTX */
+       if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL)
+               cifs_sfu_mode(&fattr, full_path, cifs_sb, xid);
 
+       if (!*pinode) {
+               *pinode = cifs_iget(sb, &fattr);
+               if (!*pinode)
+                       rc = -ENOMEM;
+       } else {
+               cifs_fattr_to_inode(*pinode, &fattr);
+       }
 
 cgii_exit:
        kfree(buf);
@@ -695,33 +602,78 @@ char *cifs_build_path_to_root(struct cifs_sb_info *cifs_sb)
        return full_path;
 }
 
+static int
+cifs_find_inode(struct inode *inode, void *opaque)
+{
+       struct cifs_fattr *fattr = (struct cifs_fattr *) opaque;
+
+       if (CIFS_I(inode)->uniqueid != fattr->cf_uniqueid)
+               return 0;
+
+       return 1;
+}
+
+static int
+cifs_init_inode(struct inode *inode, void *opaque)
+{
+       struct cifs_fattr *fattr = (struct cifs_fattr *) opaque;
+
+       CIFS_I(inode)->uniqueid = fattr->cf_uniqueid;
+       return 0;
+}
+
+/* Given fattrs, get a corresponding inode */
+struct inode *
+cifs_iget(struct super_block *sb, struct cifs_fattr *fattr)
+{
+       unsigned long hash;
+       struct inode *inode;
+
+       cFYI(1, ("looking for uniqueid=%llu", fattr->cf_uniqueid));
+
+       /* hash down to 32-bits on 32-bit arch */
+       hash = cifs_uniqueid_to_ino_t(fattr->cf_uniqueid);
+
+       inode = iget5_locked(sb, hash, cifs_find_inode, cifs_init_inode, fattr);
+
+       /* we have fattrs in hand, update the inode */
+       if (inode) {
+               cifs_fattr_to_inode(inode, fattr);
+               if (sb->s_flags & MS_NOATIME)
+                       inode->i_flags |= S_NOATIME | S_NOCMTIME;
+               if (inode->i_state & I_NEW) {
+                       inode->i_ino = hash;
+                       unlock_new_inode(inode);
+               }
+       }
+
+       return inode;
+}
+
 /* gets root inode */
 struct inode *cifs_root_iget(struct super_block *sb, unsigned long ino)
 {
        int xid;
        struct cifs_sb_info *cifs_sb;
-       struct inode *inode;
+       struct inode *inode = NULL;
        long rc;
        char *full_path;
 
-       inode = iget_locked(sb, ino);
-       if (!inode)
-               return ERR_PTR(-ENOMEM);
-       if (!(inode->i_state & I_NEW))
-               return inode;
-
-       cifs_sb = CIFS_SB(inode->i_sb);
+       cifs_sb = CIFS_SB(sb);
        full_path = cifs_build_path_to_root(cifs_sb);
        if (full_path == NULL)
                return ERR_PTR(-ENOMEM);
 
        xid = GetXid();
        if (cifs_sb->tcon->unix_ext)
-               rc = cifs_get_inode_info_unix(&inode, full_path, inode->i_sb,
-                                               xid);
+               rc = cifs_get_inode_info_unix(&inode, full_path, sb, xid);
        else
-               rc = cifs_get_inode_info(&inode, full_path, NULL, inode->i_sb,
+               rc = cifs_get_inode_info(&inode, full_path, NULL, sb,
                                                xid, NULL);
+
+       if (!inode)
+               return ERR_PTR(-ENOMEM);
+
        if (rc && cifs_sb->tcon->ipc) {
                cFYI(1, ("ipc connection - fake read inode"));
                inode->i_mode |= S_IFDIR;
@@ -737,7 +689,6 @@ struct inode *cifs_root_iget(struct super_block *sb, unsigned long ino)
                return ERR_PTR(rc);
        }
 
-       unlock_new_inode(inode);
 
        kfree(full_path);
        /* can not call macro FreeXid here since in a void func
@@ -988,8 +939,9 @@ int cifs_unlink(struct inode *dir, struct dentry *dentry)
         * sb->s_vfs_rename_mutex here */
        full_path = build_path_from_dentry(dentry);
        if (full_path == NULL) {
+               rc = -ENOMEM;
                FreeXid(xid);
-               return -ENOMEM;
+               return rc;
        }
 
        if ((tcon->ses->capabilities & CAP_UNIX) &&
@@ -1062,44 +1014,6 @@ out_reval:
        return rc;
 }
 
-void posix_fill_in_inode(struct inode *tmp_inode,
-       FILE_UNIX_BASIC_INFO *pData, int isNewInode)
-{
-       struct cifsInodeInfo *cifsInfo = CIFS_I(tmp_inode);
-       loff_t local_size;
-       struct timespec local_mtime;
-
-       cifsInfo->time = jiffies;
-       atomic_inc(&cifsInfo->inUse);
-
-       /* save mtime and size */
-       local_mtime = tmp_inode->i_mtime;
-       local_size  = tmp_inode->i_size;
-
-       cifs_unix_info_to_inode(tmp_inode, pData, 1);
-       cifs_set_ops(tmp_inode, false);
-
-       if (!S_ISREG(tmp_inode->i_mode))
-               return;
-
-       /*
-        * No sense invalidating pages for new inode
-        * since we we have not started caching
-        * readahead file data yet.
-        */
-       if (isNewInode)
-               return;
-
-       if (timespec_equal(&tmp_inode->i_mtime, &local_mtime) &&
-               (local_size == tmp_inode->i_size)) {
-               cFYI(1, ("inode exists but unchanged"));
-       } else {
-               /* file may have changed on server */
-               cFYI(1, ("invalidate inode, readdir detected change"));
-               invalidate_remote_inode(tmp_inode);
-       }
-}
-
 int cifs_mkdir(struct inode *inode, struct dentry *direntry, int mode)
 {
        int rc = 0, tmprc;
@@ -1108,6 +1022,7 @@ int cifs_mkdir(struct inode *inode, struct dentry *direntry, int mode)
        struct cifsTconInfo *pTcon;
        char *full_path = NULL;
        struct inode *newinode = NULL;
+       struct cifs_fattr fattr;
 
        cFYI(1, ("In cifs_mkdir, mode = 0x%x inode = 0x%p", mode, inode));
 
@@ -1118,8 +1033,9 @@ int cifs_mkdir(struct inode *inode, struct dentry *direntry, int mode)
 
        full_path = build_path_from_dentry(direntry);
        if (full_path == NULL) {
+               rc = -ENOMEM;
                FreeXid(xid);
-               return -ENOMEM;
+               return rc;
        }
 
        if ((pTcon->ses->capabilities & CAP_UNIX) &&
@@ -1146,7 +1062,6 @@ int cifs_mkdir(struct inode *inode, struct dentry *direntry, int mode)
                        cFYI(1, ("posix mkdir returned 0x%x", rc));
                        d_drop(direntry);
                } else {
-                       __u64 unique_id;
                        if (pInfo->Type == cpu_to_le32(-1)) {
                                /* no return info, go query for it */
                                kfree(pInfo);
@@ -1160,20 +1075,15 @@ int cifs_mkdir(struct inode *inode, struct dentry *direntry, int mode)
                        else
                                direntry->d_op = &cifs_dentry_ops;
 
-                       unique_id = le64_to_cpu(pInfo->UniqueId);
-                       newinode = cifs_new_inode(inode->i_sb, &unique_id);
-                       if (newinode == NULL) {
+                       cifs_unix_basic_to_fattr(&fattr, pInfo, cifs_sb);
+                       newinode = cifs_iget(inode->i_sb, &fattr);
+                       if (!newinode) {
                                kfree(pInfo);
                                goto mkdir_get_info;
                        }
 
-                       newinode->i_nlink = 2;
                        d_instantiate(direntry, newinode);
 
-                       /* we already checked in POSIXCreate whether
-                          frame was long enough */
-                       posix_fill_in_inode(direntry->d_inode,
-                                       pInfo, 1 /* NewInode */);
 #ifdef CONFIG_CIFS_DEBUG2
                        cFYI(1, ("instantiated dentry %p %s to inode %p",
                                direntry, direntry->d_name.name, newinode));
@@ -1236,10 +1146,10 @@ mkdir_get_info:
                                args.uid = NO_CHANGE_64;
                                args.gid = NO_CHANGE_64;
                        }
-                       CIFSSMBUnixSetInfo(xid, pTcon, full_path, &args,
-                                           cifs_sb->local_nls,
-                                           cifs_sb->mnt_cifs_flags &
-                                           CIFS_MOUNT_MAP_SPECIAL_CHR);
+                       CIFSSMBUnixSetPathInfo(xid, pTcon, full_path, &args,
+                                              cifs_sb->local_nls,
+                                              cifs_sb->mnt_cifs_flags &
+                                               CIFS_MOUNT_MAP_SPECIAL_CHR);
                } else {
                        if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_CIFS_ACL) &&
                            (mode & S_IWUGO) == 0) {
@@ -1303,8 +1213,9 @@ int cifs_rmdir(struct inode *inode, struct dentry *direntry)
 
        full_path = build_path_from_dentry(direntry);
        if (full_path == NULL) {
+               rc = -ENOMEM;
                FreeXid(xid);
-               return -ENOMEM;
+               return rc;
        }
 
        rc = CIFSSMBRmDir(xid, pTcon, full_path, cifs_sb->local_nls,
@@ -1508,8 +1419,9 @@ int cifs_revalidate(struct dentry *direntry)
           since that would deadlock */
        full_path = build_path_from_dentry(direntry);
        if (full_path == NULL) {
+               rc = -ENOMEM;
                FreeXid(xid);
-               return -ENOMEM;
+               return rc;
        }
        cFYI(1, ("Revalidate: %s inode 0x%p count %d dentry: 0x%p d_time %ld "
                 "jiffies %ld", full_path, direntry->d_inode,
@@ -1618,6 +1530,7 @@ int cifs_getattr(struct vfsmount *mnt, struct dentry *dentry,
        if (!err) {
                generic_fillattr(dentry->d_inode, stat);
                stat->blksize = CIFS_MAX_MSGSIZE;
+               stat->ino = CIFS_I(dentry->d_inode)->uniqueid;
        }
        return err;
 }
@@ -1782,6 +1695,7 @@ cifs_setattr_unix(struct dentry *direntry, struct iattr *attrs)
        struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
        struct cifsTconInfo *pTcon = cifs_sb->tcon;
        struct cifs_unix_set_info_args *args = NULL;
+       struct cifsFileInfo *open_file;
 
        cFYI(1, ("setattr_unix on file %s attrs->ia_valid=0x%x",
                 direntry->d_name.name, attrs->ia_valid));
@@ -1868,10 +1782,18 @@ cifs_setattr_unix(struct dentry *direntry, struct iattr *attrs)
                args->ctime = NO_CHANGE_64;
 
        args->device = 0;
-       rc = CIFSSMBUnixSetInfo(xid, pTcon, full_path, args,
-                               cifs_sb->local_nls,
-                               cifs_sb->mnt_cifs_flags &
-                               CIFS_MOUNT_MAP_SPECIAL_CHR);
+       open_file = find_writable_file(cifsInode);
+       if (open_file) {
+               u16 nfid = open_file->netfid;
+               u32 npid = open_file->pid;
+               rc = CIFSSMBUnixSetFileInfo(xid, pTcon, args, nfid, npid);
+               atomic_dec(&open_file->wrtPending);
+       } else {
+               rc = CIFSSMBUnixSetPathInfo(xid, pTcon, full_path, args,
+                                   cifs_sb->local_nls,
+                                   cifs_sb->mnt_cifs_flags &
+                                       CIFS_MOUNT_MAP_SPECIAL_CHR);
+       }
 
        if (!rc)
                rc = inode_setattr(inode, attrs);
@@ -1911,8 +1833,9 @@ cifs_setattr_nounix(struct dentry *direntry, struct iattr *attrs)
 
        full_path = build_path_from_dentry(direntry);
        if (full_path == NULL) {
+               rc = -ENOMEM;
                FreeXid(xid);
-               return -ENOMEM;
+               return rc;
        }
 
        /*
index cd83c53fcbb546f72253dd0306430319db073f6e..fc1e0487eaee3c5a2b0c4fba34e4c532e930e06b 100644 (file)
@@ -172,8 +172,9 @@ cifs_symlink(struct inode *inode, struct dentry *direntry, const char *symname)
        full_path = build_path_from_dentry(direntry);
 
        if (full_path == NULL) {
+               rc = -ENOMEM;
                FreeXid(xid);
-               return -ENOMEM;
+               return rc;
        }
 
        cFYI(1, ("Full path: %s", full_path));
index 32d6baa0a54fa907963d976c56d75c09d301e055..bd6d6895730d885442f5715e7d4c4e3e693ce333 100644 (file)
@@ -133,10 +133,12 @@ static const struct smb_to_posix_error mapping_table_ERRHRD[] = {
        {0, 0}
 };
 
-/* Convert string containing dotted ip address to binary form */
-/* returns 0 if invalid address */
-
-int
+/*
+ * Convert a string containing text IPv4 or IPv6 address to binary form.
+ *
+ * Returns 0 on failure.
+ */
+static int
 cifs_inet_pton(const int address_family, const char *cp, void *dst)
 {
        int ret = 0;
@@ -153,6 +155,52 @@ cifs_inet_pton(const int address_family, const char *cp, void *dst)
        return ret;
 }
 
+/*
+ * Try to convert a string to an IPv4 address and then attempt to convert
+ * it to an IPv6 address if that fails. Set the family field if either
+ * succeeds. If it's an IPv6 address and it has a '%' sign in it, try to
+ * treat the part following it as a numeric sin6_scope_id.
+ *
+ * Returns 0 on failure.
+ */
+int
+cifs_convert_address(char *src, void *dst)
+{
+       int rc;
+       char *pct, *endp;
+       struct sockaddr_in *s4 = (struct sockaddr_in *) dst;
+       struct sockaddr_in6 *s6 = (struct sockaddr_in6 *) dst;
+
+       /* IPv4 address */
+       if (cifs_inet_pton(AF_INET, src, &s4->sin_addr.s_addr)) {
+               s4->sin_family = AF_INET;
+               return 1;
+       }
+
+       /* temporarily terminate string */
+       pct = strchr(src, '%');
+       if (pct)
+               *pct = '\0';
+
+       rc = cifs_inet_pton(AF_INET6, src, &s6->sin6_addr.s6_addr);
+
+       /* repair temp termination (if any) and make pct point to scopeid */
+       if (pct)
+               *pct++ = '%';
+
+       if (!rc)
+               return rc;
+
+       s6->sin6_family = AF_INET6;
+       if (pct) {
+               s6->sin6_scope_id = (u32) simple_strtoul(pct, &endp, 0);
+               if (!*pct || *endp)
+                       return 0;
+       }
+
+       return rc;
+}
+
 /*****************************************************************************
 convert a NT status code to a dos class/code
  *****************************************************************************/
index 86d0055dc529906df58a3dfddbc4b5601af08d0f..f823a4a208a71b049499cfb4e3a5bf3191370a58 100644 (file)
@@ -63,374 +63,123 @@ static inline void dump_cifs_file_struct(struct file *file, char *label)
 }
 #endif /* DEBUG2 */
 
-/* Returns 1 if new inode created, 2 if both dentry and inode were */
-/* Might check in the future if inode number changed so we can rehash inode */
-static int
-construct_dentry(struct qstr *qstring, struct file *file,
-                struct inode **ptmp_inode, struct dentry **pnew_dentry,
-                __u64 *inum)
+/*
+ * Find the dentry that matches "name". If there isn't one, create one. If it's
+ * a negative dentry or the uniqueid changed, then drop it and recreate it.
+ */
+static struct dentry *
+cifs_readdir_lookup(struct dentry *parent, struct qstr *name,
+                   struct cifs_fattr *fattr)
 {
-       struct dentry *tmp_dentry = NULL;
-       struct super_block *sb = file->f_path.dentry->d_sb;
-       int rc = 0;
+       struct dentry *dentry, *alias;
+       struct inode *inode;
+       struct super_block *sb = parent->d_inode->i_sb;
+
+       cFYI(1, ("For %s", name->name));
+
+       dentry = d_lookup(parent, name);
+       if (dentry) {
+               /* FIXME: check for inode number changes? */
+               if (dentry->d_inode != NULL)
+                       return dentry;
+               d_drop(dentry);
+               dput(dentry);
+       }
 
-       cFYI(1, ("For %s", qstring->name));
-
-       qstring->hash = full_name_hash(qstring->name, qstring->len);
-       tmp_dentry = d_lookup(file->f_path.dentry, qstring);
-       if (tmp_dentry) {
-               /* BB: overwrite old name? i.e. tmp_dentry->d_name and
-                * tmp_dentry->d_name.len??
-                */
-               cFYI(0, ("existing dentry with inode 0x%p",
-                        tmp_dentry->d_inode));
-               *ptmp_inode = tmp_dentry->d_inode;
-               if (*ptmp_inode == NULL) {
-                       *ptmp_inode = cifs_new_inode(sb, inum);
-                       if (*ptmp_inode == NULL)
-                               return rc;
-                       rc = 1;
-               }
-       } else {
-               tmp_dentry = d_alloc(file->f_path.dentry, qstring);
-               if (tmp_dentry == NULL) {
-                       cERROR(1, ("Failed allocating dentry"));
-                       *ptmp_inode = NULL;
-                       return rc;
-               }
+       dentry = d_alloc(parent, name);
+       if (dentry == NULL)
+               return NULL;
 
-               if (CIFS_SB(sb)->tcon->nocase)
-                       tmp_dentry->d_op = &cifs_ci_dentry_ops;
-               else
-                       tmp_dentry->d_op = &cifs_dentry_ops;
+       inode = cifs_iget(sb, fattr);
+       if (!inode) {
+               dput(dentry);
+               return NULL;
+       }
 
-               *ptmp_inode = cifs_new_inode(sb, inum);
-               if (*ptmp_inode == NULL)
-                       return rc;
-               rc = 2;
+       if (CIFS_SB(sb)->tcon->nocase)
+               dentry->d_op = &cifs_ci_dentry_ops;
+       else
+               dentry->d_op = &cifs_dentry_ops;
+
+       alias = d_materialise_unique(dentry, inode);
+       if (alias != NULL) {
+               dput(dentry);
+               if (IS_ERR(alias))
+                       return NULL;
+               dentry = alias;
        }
 
-       tmp_dentry->d_time = jiffies;
-       *pnew_dentry = tmp_dentry;
-       return rc;
+       return dentry;
 }
 
-static void fill_in_inode(struct inode *tmp_inode, int new_buf_type,
-                         char *buf, unsigned int *pobject_type, int isNewInode)
+static void
+cifs_fill_common_info(struct cifs_fattr *fattr, struct cifs_sb_info *cifs_sb)
 {
-       loff_t local_size;
-       struct timespec local_mtime;
-
-       struct cifsInodeInfo *cifsInfo = CIFS_I(tmp_inode);
-       struct cifs_sb_info *cifs_sb = CIFS_SB(tmp_inode->i_sb);
-       __u32 attr;
-       __u64 allocation_size;
-       __u64 end_of_file;
-       umode_t default_mode;
-
-       /* save mtime and size */
-       local_mtime = tmp_inode->i_mtime;
-       local_size  = tmp_inode->i_size;
-
-       if (new_buf_type) {
-               FILE_DIRECTORY_INFO *pfindData = (FILE_DIRECTORY_INFO *)buf;
-
-               attr = le32_to_cpu(pfindData->ExtFileAttributes);
-               allocation_size = le64_to_cpu(pfindData->AllocationSize);
-               end_of_file = le64_to_cpu(pfindData->EndOfFile);
-               tmp_inode->i_atime =
-                       cifs_NTtimeToUnix(pfindData->LastAccessTime);
-               tmp_inode->i_mtime =
-                       cifs_NTtimeToUnix(pfindData->LastWriteTime);
-               tmp_inode->i_ctime =
-                       cifs_NTtimeToUnix(pfindData->ChangeTime);
-       } else { /* legacy, OS2 and DOS style */
-               int offset = cifs_sb->tcon->ses->server->timeAdj;
-               FIND_FILE_STANDARD_INFO *pfindData =
-                       (FIND_FILE_STANDARD_INFO *)buf;
-
-               tmp_inode->i_mtime = cnvrtDosUnixTm(pfindData->LastWriteDate,
-                                                   pfindData->LastWriteTime,
-                                                   offset);
-               tmp_inode->i_atime = cnvrtDosUnixTm(pfindData->LastAccessDate,
-                                                   pfindData->LastAccessTime,
-                                                   offset);
-               tmp_inode->i_ctime = cnvrtDosUnixTm(pfindData->LastWriteDate,
-                                                   pfindData->LastWriteTime,
-                                                   offset);
-               attr = le16_to_cpu(pfindData->Attributes);
-               allocation_size = le32_to_cpu(pfindData->AllocationSize);
-               end_of_file = le32_to_cpu(pfindData->DataSize);
-       }
+       fattr->cf_uid = cifs_sb->mnt_uid;
+       fattr->cf_gid = cifs_sb->mnt_gid;
 
-       /* Linux can not store file creation time unfortunately so ignore it */
-
-       cifsInfo->cifsAttrs = attr;
-#ifdef CONFIG_CIFS_EXPERIMENTAL
-       if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_CIFS_ACL) {
-               /* get more accurate mode via ACL - so force inode refresh */
-               cifsInfo->time = 0;
-       } else
-#endif /* CONFIG_CIFS_EXPERIMENTAL */
-               cifsInfo->time = jiffies;
-
-       /* treat dos attribute of read-only as read-only mode bit e.g. 555? */
-       /* 2767 perms - indicate mandatory locking */
-               /* BB fill in uid and gid here? with help from winbind?
-                  or retrieve from NTFS stream extended attribute */
-       if (atomic_read(&cifsInfo->inUse) == 0) {
-               tmp_inode->i_uid = cifs_sb->mnt_uid;
-               tmp_inode->i_gid = cifs_sb->mnt_gid;
-       }
-
-       if (attr & ATTR_DIRECTORY)
-               default_mode = cifs_sb->mnt_dir_mode;
-       else
-               default_mode = cifs_sb->mnt_file_mode;
-
-       /* set initial permissions */
-       if ((atomic_read(&cifsInfo->inUse) == 0) ||
-           (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DYNPERM) == 0)
-               tmp_inode->i_mode = default_mode;
-       else {
-               /* just reenable write bits if !ATTR_READONLY */
-               if ((tmp_inode->i_mode & S_IWUGO) == 0 &&
-                   (attr & ATTR_READONLY) == 0)
-                       tmp_inode->i_mode |= (S_IWUGO & default_mode);
-
-               tmp_inode->i_mode &= ~S_IFMT;
+       if (fattr->cf_cifsattrs & ATTR_DIRECTORY) {
+               fattr->cf_mode = S_IFDIR | cifs_sb->mnt_dir_mode;
+               fattr->cf_dtype = DT_DIR;
+       } else {
+               fattr->cf_mode = S_IFREG | cifs_sb->mnt_file_mode;
+               fattr->cf_dtype = DT_REG;
        }
 
-       /* clear write bits if ATTR_READONLY is set */
-       if (attr & ATTR_READONLY)
-               tmp_inode->i_mode &= ~S_IWUGO;
+       if (fattr->cf_cifsattrs & ATTR_READONLY)
+               fattr->cf_mode &= ~S_IWUGO;
 
-       /* set inode type */
-       if ((attr & ATTR_SYSTEM) &&
-           (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL)) {
-               if (end_of_file == 0)  {
-                       tmp_inode->i_mode |= S_IFIFO;
-                       *pobject_type = DT_FIFO;
+       if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL &&
+           fattr->cf_cifsattrs & ATTR_SYSTEM) {
+               if (fattr->cf_eof == 0)  {
+                       fattr->cf_mode &= ~S_IFMT;
+                       fattr->cf_mode |= S_IFIFO;
+                       fattr->cf_dtype = DT_FIFO;
                } else {
                        /*
-                        * trying to get the type can be slow, so just call
-                        * this a regular file for now, and mark for reval
+                        * trying to get the type and mode via SFU can be slow,
+                        * so just call those regular files for now, and mark
+                        * for reval
                         */
-                       tmp_inode->i_mode |= S_IFREG;
-                       *pobject_type = DT_REG;
-                       cifsInfo->time = 0;
-               }
-       } else {
-               if (attr & ATTR_DIRECTORY) {
-                       tmp_inode->i_mode |= S_IFDIR;
-                       *pobject_type = DT_DIR;
-               } else {
-                       tmp_inode->i_mode |= S_IFREG;
-                       *pobject_type = DT_REG;
+                       fattr->cf_flags |= CIFS_FATTR_NEED_REVAL;
                }
        }
+}
 
-       /* can not fill in nlink here as in qpathinfo version and Unx search */
-       if (atomic_read(&cifsInfo->inUse) == 0)
-               atomic_set(&cifsInfo->inUse, 1);
-
-       cifsInfo->server_eof = end_of_file;
-       spin_lock(&tmp_inode->i_lock);
-       if (is_size_safe_to_change(cifsInfo, end_of_file)) {
-               /* can not safely change the file size here if the
-               client is writing to it due to potential races */
-               i_size_write(tmp_inode, end_of_file);
-
-       /* 512 bytes (2**9) is the fake blocksize that must be used */
-       /* for this calculation, even though the reported blocksize is larger */
-               tmp_inode->i_blocks = (512 - 1 + allocation_size) >> 9;
-       }
-       spin_unlock(&tmp_inode->i_lock);
-
-       if (allocation_size < end_of_file)
-               cFYI(1, ("May be sparse file, allocation less than file size"));
-       cFYI(1, ("File Size %ld and blocks %llu",
-               (unsigned long)tmp_inode->i_size,
-               (unsigned long long)tmp_inode->i_blocks));
-       if (S_ISREG(tmp_inode->i_mode)) {
-               cFYI(1, ("File inode"));
-               tmp_inode->i_op = &cifs_file_inode_ops;
-               if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DIRECT_IO) {
-                       if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_BRL)
-                               tmp_inode->i_fop = &cifs_file_direct_nobrl_ops;
-                       else
-                               tmp_inode->i_fop = &cifs_file_direct_ops;
-               } else if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_BRL)
-                       tmp_inode->i_fop = &cifs_file_nobrl_ops;
-               else
-                       tmp_inode->i_fop = &cifs_file_ops;
-
-               if ((cifs_sb->tcon) && (cifs_sb->tcon->ses) &&
-                  (cifs_sb->tcon->ses->server->maxBuf <
-                       PAGE_CACHE_SIZE + MAX_CIFS_HDR_SIZE))
-                       tmp_inode->i_data.a_ops = &cifs_addr_ops_smallbuf;
-               else
-                       tmp_inode->i_data.a_ops = &cifs_addr_ops;
-
-               if (isNewInode)
-                       return; /* No sense invalidating pages for new inode
-                                  since have not started caching readahead file
-                                  data yet */
-
-               if (timespec_equal(&tmp_inode->i_mtime, &local_mtime) &&
-                       (local_size == tmp_inode->i_size)) {
-                       cFYI(1, ("inode exists but unchanged"));
-               } else {
-                       /* file may have changed on server */
-                       cFYI(1, ("invalidate inode, readdir detected change"));
-                       invalidate_remote_inode(tmp_inode);
-               }
-       } else if (S_ISDIR(tmp_inode->i_mode)) {
-               cFYI(1, ("Directory inode"));
-               tmp_inode->i_op = &cifs_dir_inode_ops;
-               tmp_inode->i_fop = &cifs_dir_ops;
-       } else if (S_ISLNK(tmp_inode->i_mode)) {
-               cFYI(1, ("Symbolic Link inode"));
-               tmp_inode->i_op = &cifs_symlink_inode_ops;
-       } else {
-               cFYI(1, ("Init special inode"));
-               init_special_inode(tmp_inode, tmp_inode->i_mode,
-                                  tmp_inode->i_rdev);
-       }
+void
+cifs_dir_info_to_fattr(struct cifs_fattr *fattr, FILE_DIRECTORY_INFO *info,
+                      struct cifs_sb_info *cifs_sb)
+{
+       memset(fattr, 0, sizeof(*fattr));
+       fattr->cf_cifsattrs = le32_to_cpu(info->ExtFileAttributes);
+       fattr->cf_eof = le64_to_cpu(info->EndOfFile);
+       fattr->cf_bytes = le64_to_cpu(info->AllocationSize);
+       fattr->cf_atime = cifs_NTtimeToUnix(info->LastAccessTime);
+       fattr->cf_ctime = cifs_NTtimeToUnix(info->ChangeTime);
+       fattr->cf_mtime = cifs_NTtimeToUnix(info->LastWriteTime);
+
+       cifs_fill_common_info(fattr, cifs_sb);
 }
 
-static void unix_fill_in_inode(struct inode *tmp_inode,
-       FILE_UNIX_INFO *pfindData, unsigned int *pobject_type, int isNewInode)
+void
+cifs_std_info_to_fattr(struct cifs_fattr *fattr, FIND_FILE_STANDARD_INFO *info,
+                      struct cifs_sb_info *cifs_sb)
 {
-       loff_t local_size;
-       struct timespec local_mtime;
-
-       struct cifsInodeInfo *cifsInfo = CIFS_I(tmp_inode);
-       struct cifs_sb_info *cifs_sb = CIFS_SB(tmp_inode->i_sb);
-
-       __u32 type = le32_to_cpu(pfindData->Type);
-       __u64 num_of_bytes = le64_to_cpu(pfindData->NumOfBytes);
-       __u64 end_of_file = le64_to_cpu(pfindData->EndOfFile);
-       cifsInfo->time = jiffies;
-       atomic_inc(&cifsInfo->inUse);
-
-       /* save mtime and size */
-       local_mtime = tmp_inode->i_mtime;
-       local_size  = tmp_inode->i_size;
-
-       tmp_inode->i_atime =
-           cifs_NTtimeToUnix(pfindData->LastAccessTime);
-       tmp_inode->i_mtime =
-           cifs_NTtimeToUnix(pfindData->LastModificationTime);
-       tmp_inode->i_ctime =
-           cifs_NTtimeToUnix(pfindData->LastStatusChange);
-
-       tmp_inode->i_mode = le64_to_cpu(pfindData->Permissions);
-       /* since we set the inode type below we need to mask off type
-          to avoid strange results if bits above were corrupt */
-       tmp_inode->i_mode &= ~S_IFMT;
-       if (type == UNIX_FILE) {
-               *pobject_type = DT_REG;
-               tmp_inode->i_mode |= S_IFREG;
-       } else if (type == UNIX_SYMLINK) {
-               *pobject_type = DT_LNK;
-               tmp_inode->i_mode |= S_IFLNK;
-       } else if (type == UNIX_DIR) {
-               *pobject_type = DT_DIR;
-               tmp_inode->i_mode |= S_IFDIR;
-       } else if (type == UNIX_CHARDEV) {
-               *pobject_type = DT_CHR;
-               tmp_inode->i_mode |= S_IFCHR;
-               tmp_inode->i_rdev = MKDEV(le64_to_cpu(pfindData->DevMajor),
-                               le64_to_cpu(pfindData->DevMinor) & MINORMASK);
-       } else if (type == UNIX_BLOCKDEV) {
-               *pobject_type = DT_BLK;
-               tmp_inode->i_mode |= S_IFBLK;
-               tmp_inode->i_rdev = MKDEV(le64_to_cpu(pfindData->DevMajor),
-                               le64_to_cpu(pfindData->DevMinor) & MINORMASK);
-       } else if (type == UNIX_FIFO) {
-               *pobject_type = DT_FIFO;
-               tmp_inode->i_mode |= S_IFIFO;
-       } else if (type == UNIX_SOCKET) {
-               *pobject_type = DT_SOCK;
-               tmp_inode->i_mode |= S_IFSOCK;
-       } else {
-               /* safest to just call it a file */
-               *pobject_type = DT_REG;
-               tmp_inode->i_mode |= S_IFREG;
-               cFYI(1, ("unknown inode type %d", type));
-       }
+       int offset = cifs_sb->tcon->ses->server->timeAdj;
 
-       if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_OVERR_UID)
-               tmp_inode->i_uid = cifs_sb->mnt_uid;
-       else
-               tmp_inode->i_uid = le64_to_cpu(pfindData->Uid);
-       if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_OVERR_GID)
-               tmp_inode->i_gid = cifs_sb->mnt_gid;
-       else
-               tmp_inode->i_gid = le64_to_cpu(pfindData->Gid);
-       tmp_inode->i_nlink = le64_to_cpu(pfindData->Nlinks);
-
-       cifsInfo->server_eof = end_of_file;
-       spin_lock(&tmp_inode->i_lock);
-       if (is_size_safe_to_change(cifsInfo, end_of_file)) {
-               /* can not safely change the file size here if the
-               client is writing to it due to potential races */
-               i_size_write(tmp_inode, end_of_file);
-
-       /* 512 bytes (2**9) is the fake blocksize that must be used */
-       /* for this calculation, not the real blocksize */
-               tmp_inode->i_blocks = (512 - 1 + num_of_bytes) >> 9;
-       }
-       spin_unlock(&tmp_inode->i_lock);
+       memset(fattr, 0, sizeof(*fattr));
+       fattr->cf_atime = cnvrtDosUnixTm(info->LastAccessDate,
+                                           info->LastAccessTime, offset);
+       fattr->cf_ctime = cnvrtDosUnixTm(info->LastWriteDate,
+                                           info->LastWriteTime, offset);
+       fattr->cf_mtime = cnvrtDosUnixTm(info->LastWriteDate,
+                                           info->LastWriteTime, offset);
 
-       if (S_ISREG(tmp_inode->i_mode)) {
-               cFYI(1, ("File inode"));
-               tmp_inode->i_op = &cifs_file_inode_ops;
+       fattr->cf_cifsattrs = le16_to_cpu(info->Attributes);
+       fattr->cf_bytes = le32_to_cpu(info->AllocationSize);
+       fattr->cf_eof = le32_to_cpu(info->DataSize);
 
-               if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DIRECT_IO) {
-                       if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_BRL)
-                               tmp_inode->i_fop = &cifs_file_direct_nobrl_ops;
-                       else
-                               tmp_inode->i_fop = &cifs_file_direct_ops;
-               } else if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_BRL)
-                       tmp_inode->i_fop = &cifs_file_nobrl_ops;
-               else
-                       tmp_inode->i_fop = &cifs_file_ops;
-
-               if ((cifs_sb->tcon) && (cifs_sb->tcon->ses) &&
-                  (cifs_sb->tcon->ses->server->maxBuf <
-                       PAGE_CACHE_SIZE + MAX_CIFS_HDR_SIZE))
-                       tmp_inode->i_data.a_ops = &cifs_addr_ops_smallbuf;
-               else
-                       tmp_inode->i_data.a_ops = &cifs_addr_ops;
-
-               if (isNewInode)
-                       return; /* No sense invalidating pages for new inode
-                                  since we have not started caching readahead
-                                  file data for it yet */
-
-               if (timespec_equal(&tmp_inode->i_mtime, &local_mtime) &&
-                       (local_size == tmp_inode->i_size)) {
-                       cFYI(1, ("inode exists but unchanged"));
-               } else {
-                       /* file may have changed on server */
-                       cFYI(1, ("invalidate inode, readdir detected change"));
-                       invalidate_remote_inode(tmp_inode);
-               }
-       } else if (S_ISDIR(tmp_inode->i_mode)) {
-               cFYI(1, ("Directory inode"));
-               tmp_inode->i_op = &cifs_dir_inode_ops;
-               tmp_inode->i_fop = &cifs_dir_ops;
-       } else if (S_ISLNK(tmp_inode->i_mode)) {
-               cFYI(1, ("Symbolic Link inode"));
-               tmp_inode->i_op = &cifs_symlink_inode_ops;
-/* tmp_inode->i_fop = *//* do not need to set to anything */
-       } else {
-               cFYI(1, ("Special inode"));
-               init_special_inode(tmp_inode, tmp_inode->i_mode,
-                                  tmp_inode->i_rdev);
-       }
+       cifs_fill_common_info(fattr, cifs_sb);
 }
 
 /* BB eventually need to add the following helper function to
@@ -872,7 +621,7 @@ static int cifs_get_name_from_search_buf(struct qstr *pqst,
                        len = strnlen(filename, PATH_MAX);
                }
 
-               *pinum = le64_to_cpu(pFindData->UniqueId);
+               *pinum = le64_to_cpu(pFindData->basic.UniqueId);
        } else if (level == SMB_FIND_FILE_DIRECTORY_INFO) {
                FILE_DIRECTORY_INFO *pFindData =
                        (FILE_DIRECTORY_INFO *)current_entry;
@@ -932,11 +681,12 @@ static int cifs_filldir(char *pfindEntry, struct file *file, filldir_t filldir,
        int rc = 0;
        struct qstr qstring;
        struct cifsFileInfo *pCifsF;
-       unsigned int obj_type;
-       __u64  inum;
+       u64    inum;
+       ino_t  ino;
+       struct super_block *sb;
        struct cifs_sb_info *cifs_sb;
-       struct inode *tmp_inode;
        struct dentry *tmp_dentry;
+       struct cifs_fattr fattr;
 
        /* get filename and len into qstring */
        /* get dentry */
@@ -954,60 +704,53 @@ static int cifs_filldir(char *pfindEntry, struct file *file, filldir_t filldir,
        if (rc != 0)
                return 0;
 
-       cifs_sb = CIFS_SB(file->f_path.dentry->d_sb);
+       sb = file->f_path.dentry->d_sb;
+       cifs_sb = CIFS_SB(sb);
 
        qstring.name = scratch_buf;
        rc = cifs_get_name_from_search_buf(&qstring, pfindEntry,
                        pCifsF->srch_inf.info_level,
                        pCifsF->srch_inf.unicode, cifs_sb,
-                       max_len,
-                       &inum /* returned */);
+                       max_len, &inum /* returned */);
 
        if (rc)
                return rc;
 
-       /* only these two infolevels return valid inode numbers */
-       if (pCifsF->srch_inf.info_level == SMB_FIND_FILE_UNIX ||
-           pCifsF->srch_inf.info_level == SMB_FIND_FILE_ID_FULL_DIR_INFO)
-               rc = construct_dentry(&qstring, file, &tmp_inode, &tmp_dentry,
-                                       &inum);
-       else
-               rc = construct_dentry(&qstring, file, &tmp_inode, &tmp_dentry,
-                                       NULL);
-
-       if ((tmp_inode == NULL) || (tmp_dentry == NULL))
-               return -ENOMEM;
-
-       /* we pass in rc below, indicating whether it is a new inode,
-          so we can figure out whether to invalidate the inode cached
-          data if the file has changed */
        if (pCifsF->srch_inf.info_level == SMB_FIND_FILE_UNIX)
-               unix_fill_in_inode(tmp_inode,
-                                  (FILE_UNIX_INFO *)pfindEntry,
-                                  &obj_type, rc);
+               cifs_unix_basic_to_fattr(&fattr,
+                                &((FILE_UNIX_INFO *) pfindEntry)->basic,
+                                cifs_sb);
        else if (pCifsF->srch_inf.info_level == SMB_FIND_FILE_INFO_STANDARD)
-               fill_in_inode(tmp_inode, 0 /* old level 1 buffer type */,
-                               pfindEntry, &obj_type, rc);
+               cifs_std_info_to_fattr(&fattr, (FIND_FILE_STANDARD_INFO *)
+                                       pfindEntry, cifs_sb);
        else
-               fill_in_inode(tmp_inode, 1 /* NT */, pfindEntry, &obj_type, rc);
+               cifs_dir_info_to_fattr(&fattr, (FILE_DIRECTORY_INFO *)
+                                       pfindEntry, cifs_sb);
 
-       if (rc) /* new inode - needs to be tied to dentry */ {
-               d_instantiate(tmp_dentry, tmp_inode);
-               if (rc == 2)
-                       d_rehash(tmp_dentry);
-       }
+       /* FIXME: make _to_fattr functions fill this out */
+       if (pCifsF->srch_inf.info_level == SMB_FIND_FILE_ID_FULL_DIR_INFO)
+               fattr.cf_uniqueid = inum;
+       else
+               fattr.cf_uniqueid = iunique(sb, ROOT_I);
 
+       ino = cifs_uniqueid_to_ino_t(fattr.cf_uniqueid);
+       tmp_dentry = cifs_readdir_lookup(file->f_dentry, &qstring, &fattr);
 
        rc = filldir(direntry, qstring.name, qstring.len, file->f_pos,
-                    tmp_inode->i_ino, obj_type);
+                    ino, fattr.cf_dtype);
+
+       /*
+        * we can not return filldir errors to the caller since they are
+        * "normal" when the stat blocksize is too small - we return remapped
+        * error instead
+        *
+        * FIXME: This looks bogus. filldir returns -EOVERFLOW in the above
+        * case already. Why should we be clobbering other errors from it?
+        */
        if (rc) {
                cFYI(1, ("filldir rc = %d", rc));
-               /* we can not return filldir errors to the caller
-               since they are "normal" when the stat blocksize
-               is too small - we return remapped error instead */
                rc = -EOVERFLOW;
        }
-
        dput(tmp_dentry);
        return rc;
 }
index 897a052270f90731628da48138ed93ada05cdf5f..7085a6275c4c9f0635383033dde2ee572bb046b0 100644 (file)
@@ -802,7 +802,7 @@ ssetup_ntlmssp_authenticate:
 #endif /* CONFIG_CIFS_UPCALL */
        } else {
 #ifdef CONFIG_CIFS_EXPERIMENTAL
-               if ((experimEnabled > 1) && (type == RawNTLMSSP)) {
+               if (type == RawNTLMSSP) {
                        if ((pSMB->req.hdr.Flags2 & SMBFLG2_UNICODE) == 0) {
                                cERROR(1, ("NTLMSSP requires Unicode support"));
                                rc = -ENOSYS;
index e9527eedc6396f9afd8dd25720a78730142a14b5..a75afa3dd9e18c9c606fe3f0c9ece44d343c47a0 100644 (file)
@@ -64,8 +64,9 @@ int cifs_removexattr(struct dentry *direntry, const char *ea_name)
 
        full_path = build_path_from_dentry(direntry);
        if (full_path == NULL) {
+               rc = -ENOMEM;
                FreeXid(xid);
-               return -ENOMEM;
+               return rc;
        }
        if (ea_name == NULL) {
                cFYI(1, ("Null xattr names not supported"));
@@ -118,8 +119,9 @@ int cifs_setxattr(struct dentry *direntry, const char *ea_name,
 
        full_path = build_path_from_dentry(direntry);
        if (full_path == NULL) {
+               rc = -ENOMEM;
                FreeXid(xid);
-               return -ENOMEM;
+               return rc;
        }
        /* return dos attributes as pseudo xattr */
        /* return alt name if available as pseudo attr */
@@ -225,8 +227,9 @@ ssize_t cifs_getxattr(struct dentry *direntry, const char *ea_name,
 
        full_path = build_path_from_dentry(direntry);
        if (full_path == NULL) {
+               rc = -ENOMEM;
                FreeXid(xid);
-               return -ENOMEM;
+               return rc;
        }
        /* return dos attributes as pseudo xattr */
        /* return alt name if available as pseudo attr */
@@ -351,8 +354,9 @@ ssize_t cifs_listxattr(struct dentry *direntry, char *data, size_t buf_size)
 
        full_path = build_path_from_dentry(direntry);
        if (full_path == NULL) {
+               rc = -ENOMEM;
                FreeXid(xid);
-               return -ENOMEM;
+               return rc;
        }
        /* return dos attributes as pseudo xattr */
        /* return alt name if available as pseudo attr */
index cdd51a3a7c537cd361d18ab21dabd1eafa4d4445..94502dab972af5ad4d2bd558f50f896cd8a35db3 100644 (file)
@@ -32,7 +32,6 @@
 #include <linux/smb_mount.h>
 #include <linux/ncp_mount.h>
 #include <linux/nfs4_mount.h>
-#include <linux/smp_lock.h>
 #include <linux/syscalls.h>
 #include <linux/ctype.h>
 #include <linux/module.h>
@@ -1486,8 +1485,8 @@ int compat_do_execve(char * filename,
        if (!bprm)
                goto out_files;
 
-       retval = mutex_lock_interruptible(&current->cred_guard_mutex);
-       if (retval < 0)
+       retval = -ERESTARTNOINTR;
+       if (mutex_lock_interruptible(&current->cred_guard_mutex))
                goto out_free;
        current->in_execve = 1;
 
index c135202c38b3667b30698114d13d8f49cc076ab2..f28f070a60fc3b30addbfe50d6e250df734a9879 100644 (file)
@@ -19,6 +19,7 @@
 #include <linux/compiler.h>
 #include <linux/sched.h>
 #include <linux/smp.h>
+#include <linux/smp_lock.h>
 #include <linux/ioctl.h>
 #include <linux/if.h>
 #include <linux/if_bridge.h>
@@ -31,6 +32,7 @@
 #include <linux/skbuff.h>
 #include <linux/netlink.h>
 #include <linux/vt.h>
+#include <linux/falloc.h>
 #include <linux/fs.h>
 #include <linux/file.h>
 #include <linux/ppp_defs.h>
@@ -1779,6 +1781,41 @@ lp_timeout_trans(unsigned int fd, unsigned int cmd, unsigned long arg)
        return sys_ioctl(fd, cmd, (unsigned long)tn);
 }
 
+/* on ia32 l_start is on a 32-bit boundary */
+#if defined(CONFIG_IA64) || defined(CONFIG_X86_64)
+struct space_resv_32 {
+       __s16           l_type;
+       __s16           l_whence;
+       __s64           l_start __attribute__((packed));
+                       /* len == 0 means until end of file */
+       __s64           l_len __attribute__((packed));
+       __s32           l_sysid;
+       __u32           l_pid;
+       __s32           l_pad[4];       /* reserve area */
+};
+
+#define FS_IOC_RESVSP_32               _IOW ('X', 40, struct space_resv_32)
+#define FS_IOC_RESVSP64_32     _IOW ('X', 42, struct space_resv_32)
+
+/* just account for different alignment */
+static int compat_ioctl_preallocate(struct file *file, unsigned long arg)
+{
+       struct space_resv_32    __user *p32 = (void __user *)arg;
+       struct space_resv       __user *p = compat_alloc_user_space(sizeof(*p));
+
+       if (copy_in_user(&p->l_type,    &p32->l_type,   sizeof(s16)) ||
+           copy_in_user(&p->l_whence,  &p32->l_whence, sizeof(s16)) ||
+           copy_in_user(&p->l_start,   &p32->l_start,  sizeof(s64)) ||
+           copy_in_user(&p->l_len,     &p32->l_len,    sizeof(s64)) ||
+           copy_in_user(&p->l_sysid,   &p32->l_sysid,  sizeof(s32)) ||
+           copy_in_user(&p->l_pid,     &p32->l_pid,    sizeof(u32)) ||
+           copy_in_user(&p->l_pad,     &p32->l_pad,    4*sizeof(u32)))
+               return -EFAULT;
+
+       return ioctl_preallocate(file, p);
+}
+#endif
+
 
 typedef int (*ioctl_trans_handler_t)(unsigned int, unsigned int,
                                        unsigned long, struct file *);
@@ -2756,6 +2793,18 @@ asmlinkage long compat_sys_ioctl(unsigned int fd, unsigned int cmd,
        case FIOQSIZE:
                break;
 
+#if defined(CONFIG_IA64) || defined(CONFIG_X86_64)
+       case FS_IOC_RESVSP_32:
+       case FS_IOC_RESVSP64_32:
+               error = compat_ioctl_preallocate(filp, arg);
+               goto out_fput;
+#else
+       case FS_IOC_RESVSP:
+       case FS_IOC_RESVSP64:
+               error = ioctl_preallocate(filp, (void __user *)arg);
+               goto out_fput;
+#endif
+
        case FIBMAP:
        case FIGETBSZ:
        case FIONREAD:
index 9b1d285f9fe6eb069c9fc62d02beea8df018cffc..75efb028974b991ebe49886f6b3c1b5f78e604ff 100644 (file)
@@ -423,7 +423,6 @@ static void devpts_kill_sb(struct super_block *sb)
 }
 
 static struct file_system_type devpts_fs_type = {
-       .owner          = THIS_MODULE,
        .name           = "devpts",
        .get_sb         = devpts_get_sb,
        .kill_sb        = devpts_kill_sb,
@@ -564,13 +563,4 @@ static int __init init_devpts_fs(void)
        }
        return err;
 }
-
-static void __exit exit_devpts_fs(void)
-{
-       unregister_filesystem(&devpts_fs_type);
-       mntput(devpts_mnt);
-}
-
 module_init(init_devpts_fs)
-module_exit(exit_devpts_fs)
-MODULE_LICENSE("GPL");
index 205ec95b347e3001b6cb4358b8c6539802d95bed..eb507c453c5ff7ca221f933619a085461bec3300 100644 (file)
@@ -435,7 +435,7 @@ static int search_rsb(struct dlm_ls *ls, char *name, int len, int b,
 static int find_rsb(struct dlm_ls *ls, char *name, int namelen,
                    unsigned int flags, struct dlm_rsb **r_ret)
 {
-       struct dlm_rsb *r, *tmp;
+       struct dlm_rsb *r = NULL, *tmp;
        uint32_t hash, bucket;
        int error = -EINVAL;
 
index cdb580a9c7a28352e903fa660c848826966b9dc1..618a60f03886bf75118cefbe1fa113c1733e6baf 100644 (file)
@@ -902,7 +902,7 @@ static void tcp_connect_to_sock(struct connection *con)
        int result = -EHOSTUNREACH;
        struct sockaddr_storage saddr, src_addr;
        int addr_len;
-       struct socket *sock;
+       struct socket *sock = NULL;
 
        if (con->nodeid == 0) {
                log_print("attempt to connect sock 0 foiled");
@@ -962,6 +962,8 @@ out_err:
        if (con->sock) {
                sock_release(con->sock);
                con->sock = NULL;
+       } else if (sock) {
+               sock_release(sock);
        }
        /*
         * Some errors are fatal and this list might need adjusting. For other
index 894a32d438d5094bb9f1882825f5f01f12f096d7..16f682e26c07e49493e8a667a6b36cf0cf9f6bb6 100644 (file)
@@ -353,7 +353,7 @@ static ssize_t dev_write(struct file *file, const char __user *u, size_t count,
 {
        struct dlm_plock_info info;
        struct plock_op *op;
-       int found = 0;
+       int found = 0, do_callback = 0;
 
        if (count != sizeof(info))
                return -EINVAL;
@@ -366,21 +366,24 @@ static ssize_t dev_write(struct file *file, const char __user *u, size_t count,
 
        spin_lock(&ops_lock);
        list_for_each_entry(op, &recv_list, list) {
-               if (op->info.fsid == info.fsid && op->info.number == info.number &&
+               if (op->info.fsid == info.fsid &&
+                   op->info.number == info.number &&
                    op->info.owner == info.owner) {
+                       struct plock_xop *xop = (struct plock_xop *)op;
                        list_del_init(&op->list);
-                       found = 1;
-                       op->done = 1;
                        memcpy(&op->info, &info, sizeof(info));
+                       if (xop->callback)
+                               do_callback = 1;
+                       else
+                               op->done = 1;
+                       found = 1;
                        break;
                }
        }
        spin_unlock(&ops_lock);
 
        if (found) {
-               struct plock_xop *xop;
-               xop = (struct plock_xop *)op;
-               if (xop->callback)
+               if (do_callback)
                        dlm_plock_callback(op);
                else
                        wake_up(&recv_wq);
index 3f0e1974abdcfbfb8cd8afff3a19346667768672..31d12de83a2a9584245e8c983e6c5f0e1a74ea29 100644 (file)
 #include <linux/list.h>
 #include <linux/spinlock.h>
 #include <linux/anon_inodes.h>
-#include <linux/eventfd.h>
 #include <linux/syscalls.h>
 #include <linux/module.h>
+#include <linux/kref.h>
+#include <linux/eventfd.h>
 
 struct eventfd_ctx {
+       struct kref kref;
        wait_queue_head_t wqh;
        /*
         * Every time that a write(2) is performed on an eventfd, the
         * value of the __u64 being written is added to "count" and a
         * wakeup is performed on "wqh". A read(2) will return the "count"
         * value to userspace, and will reset "count" to zero. The kernel
-        * size eventfd_signal() also, adds to the "count" counter and
+        * side eventfd_signal() also, adds to the "count" counter and
         * issue a wakeup.
         */
        __u64 count;
        unsigned int flags;
 };
 
-/*
- * Adds "n" to the eventfd counter "count". Returns "n" in case of
- * success, or a value lower then "n" in case of coutner overflow.
- * This function is supposed to be called by the kernel in paths
- * that do not allow sleeping. In this function we allow the counter
- * to reach the ULLONG_MAX value, and we signal this as overflow
- * condition by returining a POLLERR to poll(2).
+/**
+ * eventfd_signal - Adds @n to the eventfd counter.
+ * @ctx: [in] Pointer to the eventfd context.
+ * @n: [in] Value of the counter to be added to the eventfd internal counter.
+ *          The value cannot be negative.
+ *
+ * This function is supposed to be called by the kernel in paths that do not
+ * allow sleeping. In this function we allow the counter to reach the ULLONG_MAX
+ * value, and we signal this as overflow condition by returining a POLLERR
+ * to poll(2).
+ *
+ * Returns @n in case of success, a non-negative number lower than @n in case
+ * of overflow, or the following error codes:
+ *
+ * -EINVAL    : The value of @n is negative.
  */
-int eventfd_signal(struct file *file, int n)
+int eventfd_signal(struct eventfd_ctx *ctx, int n)
 {
-       struct eventfd_ctx *ctx = file->private_data;
        unsigned long flags;
 
        if (n < 0)
@@ -59,9 +68,45 @@ int eventfd_signal(struct file *file, int n)
 }
 EXPORT_SYMBOL_GPL(eventfd_signal);
 
+static void eventfd_free(struct kref *kref)
+{
+       struct eventfd_ctx *ctx = container_of(kref, struct eventfd_ctx, kref);
+
+       kfree(ctx);
+}
+
+/**
+ * eventfd_ctx_get - Acquires a reference to the internal eventfd context.
+ * @ctx: [in] Pointer to the eventfd context.
+ *
+ * Returns: In case of success, returns a pointer to the eventfd context.
+ */
+struct eventfd_ctx *eventfd_ctx_get(struct eventfd_ctx *ctx)
+{
+       kref_get(&ctx->kref);
+       return ctx;
+}
+EXPORT_SYMBOL_GPL(eventfd_ctx_get);
+
+/**
+ * eventfd_ctx_put - Releases a reference to the internal eventfd context.
+ * @ctx: [in] Pointer to eventfd context.
+ *
+ * The eventfd context reference must have been previously acquired either
+ * with eventfd_ctx_get() or eventfd_ctx_fdget()).
+ */
+void eventfd_ctx_put(struct eventfd_ctx *ctx)
+{
+       kref_put(&ctx->kref, eventfd_free);
+}
+EXPORT_SYMBOL_GPL(eventfd_ctx_put);
+
 static int eventfd_release(struct inode *inode, struct file *file)
 {
-       kfree(file->private_data);
+       struct eventfd_ctx *ctx = file->private_data;
+
+       wake_up_poll(&ctx->wqh, POLLHUP);
+       eventfd_ctx_put(ctx);
        return 0;
 }
 
@@ -185,6 +230,16 @@ static const struct file_operations eventfd_fops = {
        .write          = eventfd_write,
 };
 
+/**
+ * eventfd_fget - Acquire a reference of an eventfd file descriptor.
+ * @fd: [in] Eventfd file descriptor.
+ *
+ * Returns a pointer to the eventfd file structure in case of success, or the
+ * following error pointer:
+ *
+ * -EBADF    : Invalid @fd file descriptor.
+ * -EINVAL   : The @fd file descriptor is not an eventfd file.
+ */
 struct file *eventfd_fget(int fd)
 {
        struct file *file;
@@ -201,6 +256,48 @@ struct file *eventfd_fget(int fd)
 }
 EXPORT_SYMBOL_GPL(eventfd_fget);
 
+/**
+ * eventfd_ctx_fdget - Acquires a reference to the internal eventfd context.
+ * @fd: [in] Eventfd file descriptor.
+ *
+ * Returns a pointer to the internal eventfd context, otherwise the error
+ * pointers returned by the following functions:
+ *
+ * eventfd_fget
+ */
+struct eventfd_ctx *eventfd_ctx_fdget(int fd)
+{
+       struct file *file;
+       struct eventfd_ctx *ctx;
+
+       file = eventfd_fget(fd);
+       if (IS_ERR(file))
+               return (struct eventfd_ctx *) file;
+       ctx = eventfd_ctx_get(file->private_data);
+       fput(file);
+
+       return ctx;
+}
+EXPORT_SYMBOL_GPL(eventfd_ctx_fdget);
+
+/**
+ * eventfd_ctx_fileget - Acquires a reference to the internal eventfd context.
+ * @file: [in] Eventfd file pointer.
+ *
+ * Returns a pointer to the internal eventfd context, otherwise the error
+ * pointer:
+ *
+ * -EINVAL   : The @fd file descriptor is not an eventfd file.
+ */
+struct eventfd_ctx *eventfd_ctx_fileget(struct file *file)
+{
+       if (file->f_op != &eventfd_fops)
+               return ERR_PTR(-EINVAL);
+
+       return eventfd_ctx_get(file->private_data);
+}
+EXPORT_SYMBOL_GPL(eventfd_ctx_fileget);
+
 SYSCALL_DEFINE2(eventfd2, unsigned int, count, int, flags)
 {
        int fd;
@@ -217,6 +314,7 @@ SYSCALL_DEFINE2(eventfd2, unsigned int, count, int, flags)
        if (!ctx)
                return -ENOMEM;
 
+       kref_init(&ctx->kref);
        init_waitqueue_head(&ctx->wqh);
        ctx->count = count;
        ctx->flags = flags;
index e639957d7a57a310c12718e8fe3e4f0d9dfe2fe2..4a8849e45b2191ef5a91821ad3b47d0588e7b12b 100644 (file)
--- a/fs/exec.c
+++ b/fs/exec.c
@@ -1277,8 +1277,8 @@ int do_execve(char * filename,
        if (!bprm)
                goto out_files;
 
-       retval = mutex_lock_interruptible(&current->cred_guard_mutex);
-       if (retval < 0)
+       retval = -ERESTARTNOINTR;
+       if (mutex_lock_interruptible(&current->cred_guard_mutex))
                goto out_free;
        current->in_execve = 1;
 
index 24667eedc02329554735f72420cbc04d99faa871..c6718e4817feab5e56a2903b409493a458d3de84 100644 (file)
@@ -2,9 +2,7 @@
  * common.h - Common definitions for both Kernel and user-mode utilities
  *
  * Copyright (C) 2005, 2006
- * Avishay Traeger (avishay@gmail.com) (avishay@il.ibm.com)
- * Copyright (C) 2005, 2006
- * International Business Machines
+ * Avishay Traeger (avishay@gmail.com)
  * Copyright (C) 2008, 2009
  * Boaz Harrosh <bharrosh@panasas.com>
  *
index 65b0c8c776a1db8144c74ce0d7074512da882b51..4cfab1cc75c03a0bb7654e5c8150c2009fe4aa11 100644 (file)
@@ -1,8 +1,6 @@
 /*
  * Copyright (C) 2005, 2006
- * Avishay Traeger (avishay@gmail.com) (avishay@il.ibm.com)
- * Copyright (C) 2005, 2006
- * International Business Machines
+ * Avishay Traeger (avishay@gmail.com)
  * Copyright (C) 2008, 2009
  * Boaz Harrosh <bharrosh@panasas.com>
  *
index 0fd4c7859679390e11eac05838ec5d35e6718c74..5ec72e020b22bb8fcbb1f08d1df4af037ab179bd 100644 (file)
@@ -1,8 +1,6 @@
 /*
  * Copyright (C) 2005, 2006
- * Avishay Traeger (avishay@gmail.com) (avishay@il.ibm.com)
- * Copyright (C) 2005, 2006
- * International Business Machines
+ * Avishay Traeger (avishay@gmail.com)
  * Copyright (C) 2008, 2009
  * Boaz Harrosh <bharrosh@panasas.com>
  *
@@ -156,6 +154,9 @@ ino_t exofs_parent_ino(struct dentry *child);
 int exofs_set_link(struct inode *, struct exofs_dir_entry *, struct page *,
                    struct inode *);
 
+/* super.c               */
+int exofs_sync_fs(struct super_block *sb, int wait);
+
 /*********************
  * operation vectors *
  *********************/
index 6ed7fe4847522db1f7766528478d6b508ad64af7..839b9dc1e70f3f6663a428e2d48938f6aadfcb0c 100644 (file)
@@ -1,8 +1,6 @@
 /*
  * Copyright (C) 2005, 2006
- * Avishay Traeger (avishay@gmail.com) (avishay@il.ibm.com)
- * Copyright (C) 2005, 2006
- * International Business Machines
+ * Avishay Traeger (avishay@gmail.com)
  * Copyright (C) 2008, 2009
  * Boaz Harrosh <bharrosh@panasas.com>
  *
@@ -47,16 +45,23 @@ static int exofs_file_fsync(struct file *filp, struct dentry *dentry,
 {
        int ret;
        struct address_space *mapping = filp->f_mapping;
+       struct inode *inode = dentry->d_inode;
+       struct super_block *sb;
 
        ret = filemap_write_and_wait(mapping);
        if (ret)
                return ret;
 
-       /*Note: file_fsync below also calles sync_blockdev, which is a no-op
-        *      for exofs, but other then that it does sync_inode and
-        *      sync_superblock which is what we need here.
-        */
-       return file_fsync(filp, dentry, datasync);
+       /* sync the inode attributes */
+       ret = write_inode_now(inode, 1);
+
+       /* This is a good place to write the sb */
+       /* TODO: Sechedule an sb-sync on create */
+       sb = inode->i_sb;
+       if (sb->s_dirt)
+               exofs_sync_fs(sb, 1);
+
+       return ret;
 }
 
 static int exofs_flush(struct file *file, fl_owner_t id)
index 77d0a295eb1cd3e95443da014fc9801cf64f5aff..6c10f7476699c4da76b18453a844aefcaa6c9f09 100644 (file)
@@ -1,8 +1,6 @@
 /*
  * Copyright (C) 2005, 2006
- * Avishay Traeger (avishay@gmail.com) (avishay@il.ibm.com)
- * Copyright (C) 2005, 2006
- * International Business Machines
+ * Avishay Traeger (avishay@gmail.com)
  * Copyright (C) 2008, 2009
  * Boaz Harrosh <bharrosh@panasas.com>
  *
@@ -295,6 +293,9 @@ static int read_exec(struct page_collect *pcol, bool is_sync)
 err:
        if (!is_sync)
                _unlock_pcol_pages(pcol, ret, READ);
+       else /* Pages unlocked by caller in sync mode only free bio */
+               pcol_free(pcol);
+
        kfree(pcol_copy);
        if (or)
                osd_end_request(or);
index 77fdd765e76d13300432de102a7b19986da6fc09..b7dd0c23686376822ffd40c185bc9b1683796d31 100644 (file)
@@ -1,8 +1,6 @@
 /*
  * Copyright (C) 2005, 2006
- * Avishay Traeger (avishay@gmail.com) (avishay@il.ibm.com)
- * Copyright (C) 2005, 2006
- * International Business Machines
+ * Avishay Traeger (avishay@gmail.com)
  * Copyright (C) 2008, 2009
  * Boaz Harrosh <bharrosh@panasas.com>
  *
index b3d2ccb87aaa8981374e824066bfd2aa608fa86a..4372542df284ed8336a86f6ce205f9465980e707 100644 (file)
@@ -1,8 +1,6 @@
 /*
  * Copyright (C) 2005, 2006
- * Avishay Traeger (avishay@gmail.com) (avishay@il.ibm.com)
- * Copyright (C) 2005, 2006
- * International Business Machines
+ * Avishay Traeger (avishay@gmail.com)
  * Copyright (C) 2008, 2009
  * Boaz Harrosh <bharrosh@panasas.com>
  *
index 8216c5b77b5325db78970efc711ab3729a1ea46e..5ab10c3bbebec0dd1ba2ab81c340b6be415dcafd 100644 (file)
@@ -1,8 +1,6 @@
 /*
  * Copyright (C) 2005, 2006
- * Avishay Traeger (avishay@gmail.com) (avishay@il.ibm.com)
- * Copyright (C) 2005, 2006
- * International Business Machines
+ * Avishay Traeger (avishay@gmail.com)
  * Copyright (C) 2008, 2009
  * Boaz Harrosh <bharrosh@panasas.com>
  *
@@ -33,6 +31,7 @@
  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
  */
 
+#include <linux/smp_lock.h>
 #include <linux/string.h>
 #include <linux/parser.h>
 #include <linux/vfs.h>
@@ -200,7 +199,7 @@ static const struct export_operations exofs_export_ops;
 /*
  * Write the superblock to the OSD
  */
-static int exofs_sync_fs(struct super_block *sb, int wait)
+int exofs_sync_fs(struct super_block *sb, int wait)
 {
        struct exofs_sb_info *sbi;
        struct exofs_fscb *fscb;
index 36e2d7bc7f7bd2a93eb8363b7b9b31801732e60f..4dd687c3e74740f57b9ea4180859ed34f57da8cc 100644 (file)
@@ -1,8 +1,6 @@
 /*
  * Copyright (C) 2005, 2006
- * Avishay Traeger (avishay@gmail.com) (avishay@il.ibm.com)
- * Copyright (C) 2005, 2006
- * International Business Machines
+ * Avishay Traeger (avishay@gmail.com)
  * Copyright (C) 2008, 2009
  * Boaz Harrosh <bharrosh@panasas.com>
  *
index d46e38cb85c557e273e8206c32b38c9426799ae3..d636e1297cad71e13c6cc6b24e516369bde9bd3c 100644 (file)
@@ -125,37 +125,12 @@ fail:
        return ERR_PTR(-EINVAL);
 }
 
-static inline struct posix_acl *
-ext2_iget_acl(struct inode *inode, struct posix_acl **i_acl)
-{
-       struct posix_acl *acl = EXT2_ACL_NOT_CACHED;
-
-       spin_lock(&inode->i_lock);
-       if (*i_acl != EXT2_ACL_NOT_CACHED)
-               acl = posix_acl_dup(*i_acl);
-       spin_unlock(&inode->i_lock);
-
-       return acl;
-}
-
-static inline void
-ext2_iset_acl(struct inode *inode, struct posix_acl **i_acl,
-                  struct posix_acl *acl)
-{
-       spin_lock(&inode->i_lock);
-       if (*i_acl != EXT2_ACL_NOT_CACHED)
-               posix_acl_release(*i_acl);
-       *i_acl = posix_acl_dup(acl);
-       spin_unlock(&inode->i_lock);
-}
-
 /*
  * inode->i_mutex: don't care
  */
 static struct posix_acl *
 ext2_get_acl(struct inode *inode, int type)
 {
-       struct ext2_inode_info *ei = EXT2_I(inode);
        int name_index;
        char *value = NULL;
        struct posix_acl *acl;
@@ -164,23 +139,19 @@ ext2_get_acl(struct inode *inode, int type)
        if (!test_opt(inode->i_sb, POSIX_ACL))
                return NULL;
 
-       switch(type) {
-               case ACL_TYPE_ACCESS:
-                       acl = ext2_iget_acl(inode, &ei->i_acl);
-                       if (acl != EXT2_ACL_NOT_CACHED)
-                               return acl;
-                       name_index = EXT2_XATTR_INDEX_POSIX_ACL_ACCESS;
-                       break;
-
-               case ACL_TYPE_DEFAULT:
-                       acl = ext2_iget_acl(inode, &ei->i_default_acl);
-                       if (acl != EXT2_ACL_NOT_CACHED)
-                               return acl;
-                       name_index = EXT2_XATTR_INDEX_POSIX_ACL_DEFAULT;
-                       break;
-
-               default:
-                       return ERR_PTR(-EINVAL);
+       acl = get_cached_acl(inode, type);
+       if (acl != ACL_NOT_CACHED)
+               return acl;
+
+       switch (type) {
+       case ACL_TYPE_ACCESS:
+               name_index = EXT2_XATTR_INDEX_POSIX_ACL_ACCESS;
+               break;
+       case ACL_TYPE_DEFAULT:
+               name_index = EXT2_XATTR_INDEX_POSIX_ACL_DEFAULT;
+               break;
+       default:
+               BUG();
        }
        retval = ext2_xattr_get(inode, name_index, "", NULL, 0);
        if (retval > 0) {
@@ -197,17 +168,9 @@ ext2_get_acl(struct inode *inode, int type)
                acl = ERR_PTR(retval);
        kfree(value);
 
-       if (!IS_ERR(acl)) {
-               switch(type) {
-                       case ACL_TYPE_ACCESS:
-                               ext2_iset_acl(inode, &ei->i_acl, acl);
-                               break;
+       if (!IS_ERR(acl))
+               set_cached_acl(inode, type, acl);
 
-                       case ACL_TYPE_DEFAULT:
-                               ext2_iset_acl(inode, &ei->i_default_acl, acl);
-                               break;
-               }
-       }
        return acl;
 }
 
@@ -217,7 +180,6 @@ ext2_get_acl(struct inode *inode, int type)
 static int
 ext2_set_acl(struct inode *inode, int type, struct posix_acl *acl)
 {
-       struct ext2_inode_info *ei = EXT2_I(inode);
        int name_index;
        void *value = NULL;
        size_t size = 0;
@@ -263,17 +225,8 @@ ext2_set_acl(struct inode *inode, int type, struct posix_acl *acl)
        error = ext2_xattr_set(inode, name_index, "", value, size, 0);
 
        kfree(value);
-       if (!error) {
-               switch(type) {
-                       case ACL_TYPE_ACCESS:
-                               ext2_iset_acl(inode, &ei->i_acl, acl);
-                               break;
-
-                       case ACL_TYPE_DEFAULT:
-                               ext2_iset_acl(inode, &ei->i_default_acl, acl);
-                               break;
-               }
-       }
+       if (!error)
+               set_cached_acl(inode, type, acl);
        return error;
 }
 
index b42cf578554b5fd10ec8c290ea3fca3af05f9020..ecefe478898f9c67df951ce6c9283a15d1346be5 100644 (file)
@@ -53,10 +53,6 @@ static inline int ext2_acl_count(size_t size)
 
 #ifdef CONFIG_EXT2_FS_POSIX_ACL
 
-/* Value for inode->u.ext2_i.i_acl and inode->u.ext2_i.i_default_acl
-   if the ACL has not been cached */
-#define EXT2_ACL_NOT_CACHED ((void *)-1)
-
 /* acl.c */
 extern int ext2_permission (struct inode *, int);
 extern int ext2_acl_chmod (struct inode *);
index d988a718aedbad0cbabd35eb73accab9213f1adc..9a8a8e27a063963210056c42feab2b335c89b566 100644 (file)
@@ -46,10 +46,6 @@ struct ext2_inode_info {
         * EAs.
         */
        struct rw_semaphore xattr_sem;
-#endif
-#ifdef CONFIG_EXT2_FS_POSIX_ACL
-       struct posix_acl        *i_acl;
-       struct posix_acl        *i_default_acl;
 #endif
        rwlock_t i_meta_lock;
 
index 29ed682061f6453341c48a0c0f5aab34ac42cd89..e27130341d4f9cba4cb476186dc6c6e83b31b4fe 100644 (file)
@@ -1224,10 +1224,6 @@ struct inode *ext2_iget (struct super_block *sb, unsigned long ino)
                return inode;
 
        ei = EXT2_I(inode);
-#ifdef CONFIG_EXT2_FS_POSIX_ACL
-       ei->i_acl = EXT2_ACL_NOT_CACHED;
-       ei->i_default_acl = EXT2_ACL_NOT_CACHED;
-#endif
        ei->i_block_alloc_info = NULL;
 
        raw_inode = ext2_get_inode(inode->i_sb, ino, &bh);
index 7cb4badef927433ec90618b67c69cc08bec936f1..e7431309bdca9b7c873a34718263f14097b81ff5 100644 (file)
@@ -13,7 +13,6 @@
 #include <linux/sched.h>
 #include <linux/compat.h>
 #include <linux/mount.h>
-#include <linux/smp_lock.h>
 #include <asm/current.h>
 #include <asm/uaccess.h>
 
index 6524ecaebb7a6fe6910587026c5f8039b1a1f88c..e1dedb0f7873153199073e360dfbf255c13115c0 100644 (file)
@@ -66,8 +66,16 @@ static struct dentry *ext2_lookup(struct inode * dir, struct dentry *dentry, str
        inode = NULL;
        if (ino) {
                inode = ext2_iget(dir->i_sb, ino);
-               if (IS_ERR(inode))
-                       return ERR_CAST(inode);
+               if (unlikely(IS_ERR(inode))) {
+                       if (PTR_ERR(inode) == -ESTALE) {
+                               ext2_error(dir->i_sb, __func__,
+                                               "deleted inode referenced: %lu",
+                                               ino);
+                               return ERR_PTR(-EIO);
+                       } else {
+                               return ERR_CAST(inode);
+                       }
+               }
        }
        return d_splice_alias(inode, dentry);
 }
index 458999638c3dee387cd4a5b091a73010ff1d8150..1a9ffee47d56c545dcc9420680178fb32ea6c374 100644 (file)
@@ -152,10 +152,6 @@ static struct inode *ext2_alloc_inode(struct super_block *sb)
        ei = (struct ext2_inode_info *)kmem_cache_alloc(ext2_inode_cachep, GFP_KERNEL);
        if (!ei)
                return NULL;
-#ifdef CONFIG_EXT2_FS_POSIX_ACL
-       ei->i_acl = EXT2_ACL_NOT_CACHED;
-       ei->i_default_acl = EXT2_ACL_NOT_CACHED;
-#endif
        ei->i_block_alloc_info = NULL;
        ei->vfs_inode.i_version = 1;
        return &ei->vfs_inode;
@@ -198,18 +194,6 @@ static void destroy_inodecache(void)
 static void ext2_clear_inode(struct inode *inode)
 {
        struct ext2_block_alloc_info *rsv = EXT2_I(inode)->i_block_alloc_info;
-#ifdef CONFIG_EXT2_FS_POSIX_ACL
-       struct ext2_inode_info *ei = EXT2_I(inode);
-
-       if (ei->i_acl && ei->i_acl != EXT2_ACL_NOT_CACHED) {
-               posix_acl_release(ei->i_acl);
-               ei->i_acl = EXT2_ACL_NOT_CACHED;
-       }
-       if (ei->i_default_acl && ei->i_default_acl != EXT2_ACL_NOT_CACHED) {
-               posix_acl_release(ei->i_default_acl);
-               ei->i_default_acl = EXT2_ACL_NOT_CACHED;
-       }
-#endif
        ext2_discard_reservation(inode);
        EXT2_I(inode)->i_block_alloc_info = NULL;
        if (unlikely(rsv))
index e0c7454517158dde2ee69433526c78eeb5398cd2..e167bae37ef02eb572b3c660a3a412c2bace58e2 100644 (file)
@@ -126,33 +126,6 @@ fail:
        return ERR_PTR(-EINVAL);
 }
 
-static inline struct posix_acl *
-ext3_iget_acl(struct inode *inode, struct posix_acl **i_acl)
-{
-       struct posix_acl *acl = ACCESS_ONCE(*i_acl);
-
-       if (acl) {
-               spin_lock(&inode->i_lock);
-               acl = *i_acl;
-               if (acl != EXT3_ACL_NOT_CACHED)
-                       acl = posix_acl_dup(acl);
-               spin_unlock(&inode->i_lock);
-       }
-
-       return acl;
-}
-
-static inline void
-ext3_iset_acl(struct inode *inode, struct posix_acl **i_acl,
-                  struct posix_acl *acl)
-{
-       spin_lock(&inode->i_lock);
-       if (*i_acl != EXT3_ACL_NOT_CACHED)
-               posix_acl_release(*i_acl);
-       *i_acl = posix_acl_dup(acl);
-       spin_unlock(&inode->i_lock);
-}
-
 /*
  * Inode operation get_posix_acl().
  *
@@ -161,7 +134,6 @@ ext3_iset_acl(struct inode *inode, struct posix_acl **i_acl,
 static struct posix_acl *
 ext3_get_acl(struct inode *inode, int type)
 {
-       struct ext3_inode_info *ei = EXT3_I(inode);
        int name_index;
        char *value = NULL;
        struct posix_acl *acl;
@@ -170,24 +142,21 @@ ext3_get_acl(struct inode *inode, int type)
        if (!test_opt(inode->i_sb, POSIX_ACL))
                return NULL;
 
-       switch(type) {
-               case ACL_TYPE_ACCESS:
-                       acl = ext3_iget_acl(inode, &ei->i_acl);
-                       if (acl != EXT3_ACL_NOT_CACHED)
-                               return acl;
-                       name_index = EXT3_XATTR_INDEX_POSIX_ACL_ACCESS;
-                       break;
-
-               case ACL_TYPE_DEFAULT:
-                       acl = ext3_iget_acl(inode, &ei->i_default_acl);
-                       if (acl != EXT3_ACL_NOT_CACHED)
-                               return acl;
-                       name_index = EXT3_XATTR_INDEX_POSIX_ACL_DEFAULT;
-                       break;
-
-               default:
-                       return ERR_PTR(-EINVAL);
+       acl = get_cached_acl(inode, type);
+       if (acl != ACL_NOT_CACHED)
+               return acl;
+
+       switch (type) {
+       case ACL_TYPE_ACCESS:
+               name_index = EXT3_XATTR_INDEX_POSIX_ACL_ACCESS;
+               break;
+       case ACL_TYPE_DEFAULT:
+               name_index = EXT3_XATTR_INDEX_POSIX_ACL_DEFAULT;
+               break;
+       default:
+               BUG();
        }
+
        retval = ext3_xattr_get(inode, name_index, "", NULL, 0);
        if (retval > 0) {
                value = kmalloc(retval, GFP_NOFS);
@@ -203,17 +172,9 @@ ext3_get_acl(struct inode *inode, int type)
                acl = ERR_PTR(retval);
        kfree(value);
 
-       if (!IS_ERR(acl)) {
-               switch(type) {
-                       case ACL_TYPE_ACCESS:
-                               ext3_iset_acl(inode, &ei->i_acl, acl);
-                               break;
+       if (!IS_ERR(acl))
+               set_cached_acl(inode, type, acl);
 
-                       case ACL_TYPE_DEFAULT:
-                               ext3_iset_acl(inode, &ei->i_default_acl, acl);
-                               break;
-               }
-       }
        return acl;
 }
 
@@ -226,7 +187,6 @@ static int
 ext3_set_acl(handle_t *handle, struct inode *inode, int type,
             struct posix_acl *acl)
 {
-       struct ext3_inode_info *ei = EXT3_I(inode);
        int name_index;
        void *value = NULL;
        size_t size = 0;
@@ -271,17 +231,10 @@ ext3_set_acl(handle_t *handle, struct inode *inode, int type,
                                      value, size, 0);
 
        kfree(value);
-       if (!error) {
-               switch(type) {
-                       case ACL_TYPE_ACCESS:
-                               ext3_iset_acl(inode, &ei->i_acl, acl);
-                               break;
 
-                       case ACL_TYPE_DEFAULT:
-                               ext3_iset_acl(inode, &ei->i_default_acl, acl);
-                               break;
-               }
-       }
+       if (!error)
+               set_cached_acl(inode, type, acl);
+
        return error;
 }
 
index 42da16b8cac0a82d1bdd06a18c178308068e8d08..07d15a3a59696caceccd7dd89f8eab7ac6a78719 100644 (file)
@@ -53,10 +53,6 @@ static inline int ext3_acl_count(size_t size)
 
 #ifdef CONFIG_EXT3_FS_POSIX_ACL
 
-/* Value for inode->u.ext3_i.i_acl and inode->u.ext3_i.i_default_acl
-   if the ACL has not been cached */
-#define EXT3_ACL_NOT_CACHED ((void *)-1)
-
 /* acl.c */
 extern int ext3_permission (struct inode *, int);
 extern int ext3_acl_chmod (struct inode *);
index 05dea8132fc0f04fa588fe163a5c6d53e0c07769..5f51fed5c750870b8c575fdf7dd8e877fe986bfb 100644 (file)
@@ -2752,10 +2752,6 @@ struct inode *ext3_iget(struct super_block *sb, unsigned long ino)
                return inode;
 
        ei = EXT3_I(inode);
-#ifdef CONFIG_EXT3_FS_POSIX_ACL
-       ei->i_acl = EXT3_ACL_NOT_CACHED;
-       ei->i_default_acl = EXT3_ACL_NOT_CACHED;
-#endif
        ei->i_block_alloc_info = NULL;
 
        ret = __ext3_get_inode_loc(inode, &iloc, 0);
index 601e881e6105b886de6251fe71acaf51ec66ef8b..524b349c6299ca248b366cf299071939e5843aba 100644 (file)
@@ -464,10 +464,6 @@ static struct inode *ext3_alloc_inode(struct super_block *sb)
        ei = kmem_cache_alloc(ext3_inode_cachep, GFP_NOFS);
        if (!ei)
                return NULL;
-#ifdef CONFIG_EXT3_FS_POSIX_ACL
-       ei->i_acl = EXT3_ACL_NOT_CACHED;
-       ei->i_default_acl = EXT3_ACL_NOT_CACHED;
-#endif
        ei->i_block_alloc_info = NULL;
        ei->vfs_inode.i_version = 1;
        return &ei->vfs_inode;
@@ -518,18 +514,6 @@ static void destroy_inodecache(void)
 static void ext3_clear_inode(struct inode *inode)
 {
        struct ext3_block_alloc_info *rsv = EXT3_I(inode)->i_block_alloc_info;
-#ifdef CONFIG_EXT3_FS_POSIX_ACL
-       if (EXT3_I(inode)->i_acl &&
-                       EXT3_I(inode)->i_acl != EXT3_ACL_NOT_CACHED) {
-               posix_acl_release(EXT3_I(inode)->i_acl);
-               EXT3_I(inode)->i_acl = EXT3_ACL_NOT_CACHED;
-       }
-       if (EXT3_I(inode)->i_default_acl &&
-                       EXT3_I(inode)->i_default_acl != EXT3_ACL_NOT_CACHED) {
-               posix_acl_release(EXT3_I(inode)->i_default_acl);
-               EXT3_I(inode)->i_default_acl = EXT3_ACL_NOT_CACHED;
-       }
-#endif
        ext3_discard_reservation(inode);
        EXT3_I(inode)->i_block_alloc_info = NULL;
        if (unlikely(rsv))
index 605aeed96d68116589818b5c443b32d7f3ff01b0..f6d8967149ca116602ce77fb35c6762dbb179456 100644 (file)
@@ -126,33 +126,6 @@ fail:
        return ERR_PTR(-EINVAL);
 }
 
-static inline struct posix_acl *
-ext4_iget_acl(struct inode *inode, struct posix_acl **i_acl)
-{
-       struct posix_acl *acl = ACCESS_ONCE(*i_acl);
-
-       if (acl) {
-               spin_lock(&inode->i_lock);
-               acl = *i_acl;
-               if (acl != EXT4_ACL_NOT_CACHED)
-                       acl = posix_acl_dup(acl);
-               spin_unlock(&inode->i_lock);
-       }
-
-       return acl;
-}
-
-static inline void
-ext4_iset_acl(struct inode *inode, struct posix_acl **i_acl,
-               struct posix_acl *acl)
-{
-       spin_lock(&inode->i_lock);
-       if (*i_acl != EXT4_ACL_NOT_CACHED)
-               posix_acl_release(*i_acl);
-       *i_acl = posix_acl_dup(acl);
-       spin_unlock(&inode->i_lock);
-}
-
 /*
  * Inode operation get_posix_acl().
  *
@@ -161,7 +134,6 @@ ext4_iset_acl(struct inode *inode, struct posix_acl **i_acl,
 static struct posix_acl *
 ext4_get_acl(struct inode *inode, int type)
 {
-       struct ext4_inode_info *ei = EXT4_I(inode);
        int name_index;
        char *value = NULL;
        struct posix_acl *acl;
@@ -170,23 +142,19 @@ ext4_get_acl(struct inode *inode, int type)
        if (!test_opt(inode->i_sb, POSIX_ACL))
                return NULL;
 
+       acl = get_cached_acl(inode, type);
+       if (acl != ACL_NOT_CACHED)
+               return acl;
+
        switch (type) {
        case ACL_TYPE_ACCESS:
-               acl = ext4_iget_acl(inode, &ei->i_acl);
-               if (acl != EXT4_ACL_NOT_CACHED)
-                       return acl;
                name_index = EXT4_XATTR_INDEX_POSIX_ACL_ACCESS;
                break;
-
        case ACL_TYPE_DEFAULT:
-               acl = ext4_iget_acl(inode, &ei->i_default_acl);
-               if (acl != EXT4_ACL_NOT_CACHED)
-                       return acl;
                name_index = EXT4_XATTR_INDEX_POSIX_ACL_DEFAULT;
                break;
-
        default:
-               return ERR_PTR(-EINVAL);
+               BUG();
        }
        retval = ext4_xattr_get(inode, name_index, "", NULL, 0);
        if (retval > 0) {
@@ -203,17 +171,9 @@ ext4_get_acl(struct inode *inode, int type)
                acl = ERR_PTR(retval);
        kfree(value);
 
-       if (!IS_ERR(acl)) {
-               switch (type) {
-               case ACL_TYPE_ACCESS:
-                       ext4_iset_acl(inode, &ei->i_acl, acl);
-                       break;
+       if (!IS_ERR(acl))
+               set_cached_acl(inode, type, acl);
 
-               case ACL_TYPE_DEFAULT:
-                       ext4_iset_acl(inode, &ei->i_default_acl, acl);
-                       break;
-               }
-       }
        return acl;
 }
 
@@ -226,7 +186,6 @@ static int
 ext4_set_acl(handle_t *handle, struct inode *inode, int type,
             struct posix_acl *acl)
 {
-       struct ext4_inode_info *ei = EXT4_I(inode);
        int name_index;
        void *value = NULL;
        size_t size = 0;
@@ -271,17 +230,9 @@ ext4_set_acl(handle_t *handle, struct inode *inode, int type,
                                      value, size, 0);
 
        kfree(value);
-       if (!error) {
-               switch (type) {
-               case ACL_TYPE_ACCESS:
-                       ext4_iset_acl(inode, &ei->i_acl, acl);
-                       break;
+       if (!error)
+               set_cached_acl(inode, type, acl);
 
-               case ACL_TYPE_DEFAULT:
-                       ext4_iset_acl(inode, &ei->i_default_acl, acl);
-                       break;
-               }
-       }
        return error;
 }
 
index cb45257a246e888467f8db4bfb6822b00e7fddd7..949789d2bba66b47805cc9adc008afdd7f150ca5 100644 (file)
@@ -53,10 +53,6 @@ static inline int ext4_acl_count(size_t size)
 
 #ifdef CONFIG_EXT4_FS_POSIX_ACL
 
-/* Value for inode->u.ext4_i.i_acl and inode->u.ext4_i.i_default_acl
-   if the ACL has not been cached */
-#define EXT4_ACL_NOT_CACHED ((void *)-1)
-
 /* acl.c */
 extern int ext4_permission(struct inode *, int);
 extern int ext4_acl_chmod(struct inode *);
index 17b9998680e3b30b479f0417bea5a9401334b606..9714db393efe8a1b6fa2ff0b2e7cf36fb7ecc199 100644 (file)
@@ -93,20 +93,20 @@ typedef unsigned int ext4_group_t;
 struct ext4_allocation_request {
        /* target inode for block we're allocating */
        struct inode *inode;
+       /* how many blocks we want to allocate */
+       unsigned int len;
        /* logical block in target inode */
        ext4_lblk_t logical;
-       /* phys. target (a hint) */
-       ext4_fsblk_t goal;
        /* the closest logical allocated block to the left */
        ext4_lblk_t lleft;
-       /* phys. block for ^^^ */
-       ext4_fsblk_t pleft;
        /* the closest logical allocated block to the right */
        ext4_lblk_t lright;
-       /* phys. block for ^^^ */
+       /* phys. target (a hint) */
+       ext4_fsblk_t goal;
+       /* phys. block for the closest logical allocated block to the left */
+       ext4_fsblk_t pleft;
+       /* phys. block for the closest logical allocated block to the right */
        ext4_fsblk_t pright;
-       /* how many blocks we want to allocate */
-       unsigned int len;
        /* flags. see above EXT4_MB_HINT_* */
        unsigned int flags;
 };
@@ -595,10 +595,6 @@ struct ext4_inode_info {
         */
        struct rw_semaphore xattr_sem;
 #endif
-#ifdef CONFIG_EXT4_FS_POSIX_ACL
-       struct posix_acl        *i_acl;
-       struct posix_acl        *i_default_acl;
-#endif
 
        struct list_head i_orphan;      /* unlinked but open inodes */
 
index ad13a84644e1ff94000dda0ab8bbe09f05a417e7..eb27fd0f2ee86dd4c8badd2ed146f2a306e1f35f 100644 (file)
@@ -43,6 +43,8 @@ int __ext4_journal_forget(const char *where, handle_t *handle,
                        ext4_journal_abort_handle(where, __func__, bh,
                                                  handle, err);
        }
+       else
+               brelse(bh);
        return err;
 }
 
@@ -57,6 +59,8 @@ int __ext4_journal_revoke(const char *where, handle_t *handle,
                        ext4_journal_abort_handle(where, __func__, bh,
                                                  handle, err);
        }
+       else
+               brelse(bh);
        return err;
 }
 
index be2f426f680538065b86aac16bb1f2f822a49a48..139fb8cb87e40dabf2538ff28d163849ed8d2bfa 100644 (file)
@@ -131,9 +131,11 @@ int __ext4_journal_get_undo_access(const char *where, handle_t *handle,
 int __ext4_journal_get_write_access(const char *where, handle_t *handle,
                                struct buffer_head *bh);
 
+/* When called with an invalid handle, this will still do a put on the BH */
 int __ext4_journal_forget(const char *where, handle_t *handle,
                                struct buffer_head *bh);
 
+/* When called with an invalid handle, this will still do a put on the BH */
 int __ext4_journal_revoke(const char *where, handle_t *handle,
                                ext4_fsblk_t blocknr, struct buffer_head *bh);
 
@@ -281,10 +283,10 @@ static inline int ext4_should_order_data(struct inode *inode)
 
 static inline int ext4_should_writeback_data(struct inode *inode)
 {
-       if (EXT4_JOURNAL(inode) == NULL)
-               return 0;
        if (!S_ISREG(inode->i_mode))
                return 0;
+       if (EXT4_JOURNAL(inode) == NULL)
+               return 1;
        if (EXT4_I(inode)->i_flags & EXT4_JOURNAL_DATA_FL)
                return 0;
        if (test_opt(inode->i_sb, DATA_FLAGS) == EXT4_MOUNT_WRITEBACK_DATA)
index 50322a09bd01af54d66cf2d344765b8b92075332..73ebfb44ad750f0405976f7ff6c792936edb0765 100644 (file)
@@ -1977,6 +1977,7 @@ int ext4_ext_calc_credits_for_single_extent(struct inode *inode, int nrblocks,
                         */
                        /* 1 bitmap, 1 block group descriptor */
                        ret = 2 + EXT4_META_TRANS_BLOCKS(inode->i_sb);
+                       return ret;
                }
        }
 
index 2f645732e3b76ef84e76f58761c16116825c2763..29e6dc7299b8b6186cf46a39deac0a88594b6028 100644 (file)
@@ -833,7 +833,7 @@ struct inode *ext4_new_inode(handle_t *handle, struct inode *dir, int mode,
        if (!goal)
                goal = sbi->s_inode_goal;
 
-       if (goal && goal < le32_to_cpu(sbi->s_es->s_inodes_count)) {
+       if (goal && goal <= le32_to_cpu(sbi->s_es->s_inodes_count)) {
                group = (goal - 1) / EXT4_INODES_PER_GROUP(sb);
                ino = (goal - 1) % EXT4_INODES_PER_GROUP(sb);
                ret2 = 0;
index 7c17ae275af4c0a0910bf5e7af7bc243199889de..f9c642b22efabb56f5ec3ae109bf2eaf75beee8a 100644 (file)
@@ -78,16 +78,14 @@ static int ext4_inode_is_fast_symlink(struct inode *inode)
  * but there may still be a record of it in the journal, and that record
  * still needs to be revoked.
  *
- * If the handle isn't valid we're not journaling so there's nothing to do.
+ * If the handle isn't valid we're not journaling, but we still need to
+ * call into ext4_journal_revoke() to put the buffer head.
  */
 int ext4_forget(handle_t *handle, int is_metadata, struct inode *inode,
                struct buffer_head *bh, ext4_fsblk_t blocknr)
 {
        int err;
 
-       if (!ext4_handle_valid(handle))
-               return 0;
-
        might_sleep();
 
        BUFFER_TRACE(bh, "enter");
@@ -1513,14 +1511,14 @@ retry:
                 * Add inode to orphan list in case we crash before
                 * truncate finishes
                 */
-               if (pos + len > inode->i_size)
+               if (pos + len > inode->i_size && ext4_can_truncate(inode))
                        ext4_orphan_add(handle, inode);
 
                ext4_journal_stop(handle);
                if (pos + len > inode->i_size) {
-                       vmtruncate(inode, inode->i_size);
+                       ext4_truncate(inode);
                        /*
-                        * If vmtruncate failed early the inode might
+                        * If truncate failed early the inode might
                         * still be on the orphan list; we need to
                         * make sure the inode is removed from the
                         * orphan list in that case.
@@ -1614,7 +1612,7 @@ static int ext4_ordered_write_end(struct file *file,
                ret2 = ext4_generic_write_end(file, mapping, pos, len, copied,
                                                        page, fsdata);
                copied = ret2;
-               if (pos + len > inode->i_size)
+               if (pos + len > inode->i_size && ext4_can_truncate(inode))
                        /* if we have allocated more blocks and copied
                         * less. We will have blocks allocated outside
                         * inode->i_size. So truncate them
@@ -1628,9 +1626,9 @@ static int ext4_ordered_write_end(struct file *file,
                ret = ret2;
 
        if (pos + len > inode->i_size) {
-               vmtruncate(inode, inode->i_size);
+               ext4_truncate(inode);
                /*
-                * If vmtruncate failed early the inode might still be
+                * If truncate failed early the inode might still be
                 * on the orphan list; we need to make sure the inode
                 * is removed from the orphan list in that case.
                 */
@@ -1655,7 +1653,7 @@ static int ext4_writeback_write_end(struct file *file,
        ret2 = ext4_generic_write_end(file, mapping, pos, len, copied,
                                                        page, fsdata);
        copied = ret2;
-       if (pos + len > inode->i_size)
+       if (pos + len > inode->i_size && ext4_can_truncate(inode))
                /* if we have allocated more blocks and copied
                 * less. We will have blocks allocated outside
                 * inode->i_size. So truncate them
@@ -1670,9 +1668,9 @@ static int ext4_writeback_write_end(struct file *file,
                ret = ret2;
 
        if (pos + len > inode->i_size) {
-               vmtruncate(inode, inode->i_size);
+               ext4_truncate(inode);
                /*
-                * If vmtruncate failed early the inode might still be
+                * If truncate failed early the inode might still be
                 * on the orphan list; we need to make sure the inode
                 * is removed from the orphan list in that case.
                 */
@@ -1722,7 +1720,7 @@ static int ext4_journalled_write_end(struct file *file,
 
        unlock_page(page);
        page_cache_release(page);
-       if (pos + len > inode->i_size)
+       if (pos + len > inode->i_size && ext4_can_truncate(inode))
                /* if we have allocated more blocks and copied
                 * less. We will have blocks allocated outside
                 * inode->i_size. So truncate them
@@ -1733,9 +1731,9 @@ static int ext4_journalled_write_end(struct file *file,
        if (!ret)
                ret = ret2;
        if (pos + len > inode->i_size) {
-               vmtruncate(inode, inode->i_size);
+               ext4_truncate(inode);
                /*
-                * If vmtruncate failed early the inode might still be
+                * If truncate failed early the inode might still be
                 * on the orphan list; we need to make sure the inode
                 * is removed from the orphan list in that case.
                 */
@@ -2305,15 +2303,9 @@ flush_it:
        return;
 }
 
-static int ext4_bh_unmapped_or_delay(handle_t *handle, struct buffer_head *bh)
+static int ext4_bh_delay_or_unwritten(handle_t *handle, struct buffer_head *bh)
 {
-       /*
-        * unmapped buffer is possible for holes.
-        * delay buffer is possible with delayed allocation.
-        * We also need to consider unwritten buffer as unmapped.
-        */
-       return (!buffer_mapped(bh) || buffer_delay(bh) ||
-                               buffer_unwritten(bh)) && buffer_dirty(bh);
+       return (buffer_delay(bh) || buffer_unwritten(bh)) && buffer_dirty(bh);
 }
 
 /*
@@ -2398,9 +2390,9 @@ static int __mpage_da_writepage(struct page *page,
                         * We need to try to allocate
                         * unmapped blocks in the same page.
                         * Otherwise we won't make progress
-                        * with the page in ext4_da_writepage
+                        * with the page in ext4_writepage
                         */
-                       if (ext4_bh_unmapped_or_delay(NULL, bh)) {
+                       if (ext4_bh_delay_or_unwritten(NULL, bh)) {
                                mpage_add_bh_to_extent(mpd, logical,
                                                       bh->b_size,
                                                       bh->b_state);
@@ -2517,7 +2509,6 @@ static int noalloc_get_block_write(struct inode *inode, sector_t iblock,
         * so call get_block_wrap with create = 0
         */
        ret = ext4_get_blocks(NULL, inode, iblock, max_blocks, bh_result, 0);
-       BUG_ON(create && ret == 0);
        if (ret > 0) {
                bh_result->b_size = (ret << inode->i_blkbits);
                ret = 0;
@@ -2525,15 +2516,102 @@ static int noalloc_get_block_write(struct inode *inode, sector_t iblock,
        return ret;
 }
 
+static int bget_one(handle_t *handle, struct buffer_head *bh)
+{
+       get_bh(bh);
+       return 0;
+}
+
+static int bput_one(handle_t *handle, struct buffer_head *bh)
+{
+       put_bh(bh);
+       return 0;
+}
+
+static int __ext4_journalled_writepage(struct page *page,
+                                      struct writeback_control *wbc,
+                                      unsigned int len)
+{
+       struct address_space *mapping = page->mapping;
+       struct inode *inode = mapping->host;
+       struct buffer_head *page_bufs;
+       handle_t *handle = NULL;
+       int ret = 0;
+       int err;
+
+       page_bufs = page_buffers(page);
+       BUG_ON(!page_bufs);
+       walk_page_buffers(handle, page_bufs, 0, len, NULL, bget_one);
+       /* As soon as we unlock the page, it can go away, but we have
+        * references to buffers so we are safe */
+       unlock_page(page);
+
+       handle = ext4_journal_start(inode, ext4_writepage_trans_blocks(inode));
+       if (IS_ERR(handle)) {
+               ret = PTR_ERR(handle);
+               goto out;
+       }
+
+       ret = walk_page_buffers(handle, page_bufs, 0, len, NULL,
+                               do_journal_get_write_access);
+
+       err = walk_page_buffers(handle, page_bufs, 0, len, NULL,
+                               write_end_fn);
+       if (ret == 0)
+               ret = err;
+       err = ext4_journal_stop(handle);
+       if (!ret)
+               ret = err;
+
+       walk_page_buffers(handle, page_bufs, 0, len, NULL, bput_one);
+       EXT4_I(inode)->i_state |= EXT4_STATE_JDATA;
+out:
+       return ret;
+}
+
 /*
+ * Note that we don't need to start a transaction unless we're journaling data
+ * because we should have holes filled from ext4_page_mkwrite(). We even don't
+ * need to file the inode to the transaction's list in ordered mode because if
+ * we are writing back data added by write(), the inode is already there and if
+ * we are writing back data modified via mmap(), noone guarantees in which
+ * transaction the data will hit the disk. In case we are journaling data, we
+ * cannot start transaction directly because transaction start ranks above page
+ * lock so we have to do some magic.
+ *
  * This function can get called via...
  *   - ext4_da_writepages after taking page lock (have journal handle)
  *   - journal_submit_inode_data_buffers (no journal handle)
  *   - shrink_page_list via pdflush (no journal handle)
  *   - grab_page_cache when doing write_begin (have journal handle)
+ *
+ * We don't do any block allocation in this function. If we have page with
+ * multiple blocks we need to write those buffer_heads that are mapped. This
+ * is important for mmaped based write. So if we do with blocksize 1K
+ * truncate(f, 1024);
+ * a = mmap(f, 0, 4096);
+ * a[0] = 'a';
+ * truncate(f, 4096);
+ * we have in the page first buffer_head mapped via page_mkwrite call back
+ * but other bufer_heads would be unmapped but dirty(dirty done via the
+ * do_wp_page). So writepage should write the first block. If we modify
+ * the mmap area beyond 1024 we will again get a page_fault and the
+ * page_mkwrite callback will do the block allocation and mark the
+ * buffer_heads mapped.
+ *
+ * We redirty the page if we have any buffer_heads that is either delay or
+ * unwritten in the page.
+ *
+ * We can get recursively called as show below.
+ *
+ *     ext4_writepage() -> kmalloc() -> __alloc_pages() -> page_launder() ->
+ *             ext4_writepage()
+ *
+ * But since we don't do any block allocation we should not deadlock.
+ * Page also have the dirty flag cleared so we don't get recurive page_lock.
  */
-static int ext4_da_writepage(struct page *page,
-                               struct writeback_control *wbc)
+static int ext4_writepage(struct page *page,
+                         struct writeback_control *wbc)
 {
        int ret = 0;
        loff_t size;
@@ -2541,7 +2619,7 @@ static int ext4_da_writepage(struct page *page,
        struct buffer_head *page_bufs;
        struct inode *inode = page->mapping->host;
 
-       trace_ext4_da_writepage(inode, page);
+       trace_ext4_writepage(inode, page);
        size = i_size_read(inode);
        if (page->index == size >> PAGE_CACHE_SHIFT)
                len = size & ~PAGE_CACHE_MASK;
@@ -2551,7 +2629,7 @@ static int ext4_da_writepage(struct page *page,
        if (page_has_buffers(page)) {
                page_bufs = page_buffers(page);
                if (walk_page_buffers(NULL, page_bufs, 0, len, NULL,
-                                       ext4_bh_unmapped_or_delay)) {
+                                       ext4_bh_delay_or_unwritten)) {
                        /*
                         * We don't want to do  block allocation
                         * So redirty the page and return
@@ -2578,13 +2656,13 @@ static int ext4_da_writepage(struct page *page,
                 * all are mapped and non delay. We don't want to
                 * do block allocation here.
                 */
-               ret = block_prepare_write(page, 0, PAGE_CACHE_SIZE,
+               ret = block_prepare_write(page, 0, len,
                                          noalloc_get_block_write);
                if (!ret) {
                        page_bufs = page_buffers(page);
                        /* check whether all are mapped and non delay */
                        if (walk_page_buffers(NULL, page_bufs, 0, len, NULL,
-                                               ext4_bh_unmapped_or_delay)) {
+                                               ext4_bh_delay_or_unwritten)) {
                                redirty_page_for_writepage(wbc, page);
                                unlock_page(page);
                                return 0;
@@ -2600,7 +2678,16 @@ static int ext4_da_writepage(struct page *page,
                        return 0;
                }
                /* now mark the buffer_heads as dirty and uptodate */
-               block_commit_write(page, 0, PAGE_CACHE_SIZE);
+               block_commit_write(page, 0, len);
+       }
+
+       if (PageChecked(page) && ext4_should_journal_data(inode)) {
+               /*
+                * It's mmapped pagecache.  Add buffers and journal it.  There
+                * doesn't seem much point in redirtying the page here.
+                */
+               ClearPageChecked(page);
+               return __ext4_journalled_writepage(page, wbc, len);
        }
 
        if (test_opt(inode->i_sb, NOBH) && ext4_should_writeback_data(inode))
@@ -2907,7 +2994,7 @@ retry:
                 * i_size_read because we hold i_mutex.
                 */
                if (pos + len > inode->i_size)
-                       vmtruncate(inode, inode->i_size);
+                       ext4_truncate(inode);
        }
 
        if (ret == -ENOSPC && ext4_should_retry_alloc(inode->i_sb, &retries))
@@ -3130,222 +3217,6 @@ static sector_t ext4_bmap(struct address_space *mapping, sector_t block)
        return generic_block_bmap(mapping, block, ext4_get_block);
 }
 
-static int bget_one(handle_t *handle, struct buffer_head *bh)
-{
-       get_bh(bh);
-       return 0;
-}
-
-static int bput_one(handle_t *handle, struct buffer_head *bh)
-{
-       put_bh(bh);
-       return 0;
-}
-
-/*
- * Note that we don't need to start a transaction unless we're journaling data
- * because we should have holes filled from ext4_page_mkwrite(). We even don't
- * need to file the inode to the transaction's list in ordered mode because if
- * we are writing back data added by write(), the inode is already there and if
- * we are writing back data modified via mmap(), noone guarantees in which
- * transaction the data will hit the disk. In case we are journaling data, we
- * cannot start transaction directly because transaction start ranks above page
- * lock so we have to do some magic.
- *
- * In all journaling modes block_write_full_page() will start the I/O.
- *
- * Problem:
- *
- *     ext4_writepage() -> kmalloc() -> __alloc_pages() -> page_launder() ->
- *             ext4_writepage()
- *
- * Similar for:
- *
- *     ext4_file_write() -> generic_file_write() -> __alloc_pages() -> ...
- *
- * Same applies to ext4_get_block().  We will deadlock on various things like
- * lock_journal and i_data_sem
- *
- * Setting PF_MEMALLOC here doesn't work - too many internal memory
- * allocations fail.
- *
- * 16May01: If we're reentered then journal_current_handle() will be
- *         non-zero. We simply *return*.
- *
- * 1 July 2001: @@@ FIXME:
- *   In journalled data mode, a data buffer may be metadata against the
- *   current transaction.  But the same file is part of a shared mapping
- *   and someone does a writepage() on it.
- *
- *   We will move the buffer onto the async_data list, but *after* it has
- *   been dirtied. So there's a small window where we have dirty data on
- *   BJ_Metadata.
- *
- *   Note that this only applies to the last partial page in the file.  The
- *   bit which block_write_full_page() uses prepare/commit for.  (That's
- *   broken code anyway: it's wrong for msync()).
- *
- *   It's a rare case: affects the final partial page, for journalled data
- *   where the file is subject to bith write() and writepage() in the same
- *   transction.  To fix it we'll need a custom block_write_full_page().
- *   We'll probably need that anyway for journalling writepage() output.
- *
- * We don't honour synchronous mounts for writepage().  That would be
- * disastrous.  Any write() or metadata operation will sync the fs for
- * us.
- *
- */
-static int __ext4_normal_writepage(struct page *page,
-                                  struct writeback_control *wbc)
-{
-       struct inode *inode = page->mapping->host;
-
-       if (test_opt(inode->i_sb, NOBH))
-               return nobh_writepage(page, noalloc_get_block_write, wbc);
-       else
-               return block_write_full_page(page, noalloc_get_block_write,
-                                            wbc);
-}
-
-static int ext4_normal_writepage(struct page *page,
-                                struct writeback_control *wbc)
-{
-       struct inode *inode = page->mapping->host;
-       loff_t size = i_size_read(inode);
-       loff_t len;
-
-       trace_ext4_normal_writepage(inode, page);
-       J_ASSERT(PageLocked(page));
-       if (page->index == size >> PAGE_CACHE_SHIFT)
-               len = size & ~PAGE_CACHE_MASK;
-       else
-               len = PAGE_CACHE_SIZE;
-
-       if (page_has_buffers(page)) {
-               /* if page has buffers it should all be mapped
-                * and allocated. If there are not buffers attached
-                * to the page we know the page is dirty but it lost
-                * buffers. That means that at some moment in time
-                * after write_begin() / write_end() has been called
-                * all buffers have been clean and thus they must have been
-                * written at least once. So they are all mapped and we can
-                * happily proceed with mapping them and writing the page.
-                */
-               BUG_ON(walk_page_buffers(NULL, page_buffers(page), 0, len, NULL,
-                                       ext4_bh_unmapped_or_delay));
-       }
-
-       if (!ext4_journal_current_handle())
-               return __ext4_normal_writepage(page, wbc);
-
-       redirty_page_for_writepage(wbc, page);
-       unlock_page(page);
-       return 0;
-}
-
-static int __ext4_journalled_writepage(struct page *page,
-                                      struct writeback_control *wbc)
-{
-       struct address_space *mapping = page->mapping;
-       struct inode *inode = mapping->host;
-       struct buffer_head *page_bufs;
-       handle_t *handle = NULL;
-       int ret = 0;
-       int err;
-
-       ret = block_prepare_write(page, 0, PAGE_CACHE_SIZE,
-                                 noalloc_get_block_write);
-       if (ret != 0)
-               goto out_unlock;
-
-       page_bufs = page_buffers(page);
-       walk_page_buffers(handle, page_bufs, 0, PAGE_CACHE_SIZE, NULL,
-                                                               bget_one);
-       /* As soon as we unlock the page, it can go away, but we have
-        * references to buffers so we are safe */
-       unlock_page(page);
-
-       handle = ext4_journal_start(inode, ext4_writepage_trans_blocks(inode));
-       if (IS_ERR(handle)) {
-               ret = PTR_ERR(handle);
-               goto out;
-       }
-
-       ret = walk_page_buffers(handle, page_bufs, 0,
-                       PAGE_CACHE_SIZE, NULL, do_journal_get_write_access);
-
-       err = walk_page_buffers(handle, page_bufs, 0,
-                               PAGE_CACHE_SIZE, NULL, write_end_fn);
-       if (ret == 0)
-               ret = err;
-       err = ext4_journal_stop(handle);
-       if (!ret)
-               ret = err;
-
-       walk_page_buffers(handle, page_bufs, 0,
-                               PAGE_CACHE_SIZE, NULL, bput_one);
-       EXT4_I(inode)->i_state |= EXT4_STATE_JDATA;
-       goto out;
-
-out_unlock:
-       unlock_page(page);
-out:
-       return ret;
-}
-
-static int ext4_journalled_writepage(struct page *page,
-                                    struct writeback_control *wbc)
-{
-       struct inode *inode = page->mapping->host;
-       loff_t size = i_size_read(inode);
-       loff_t len;
-
-       trace_ext4_journalled_writepage(inode, page);
-       J_ASSERT(PageLocked(page));
-       if (page->index == size >> PAGE_CACHE_SHIFT)
-               len = size & ~PAGE_CACHE_MASK;
-       else
-               len = PAGE_CACHE_SIZE;
-
-       if (page_has_buffers(page)) {
-               /* if page has buffers it should all be mapped
-                * and allocated. If there are not buffers attached
-                * to the page we know the page is dirty but it lost
-                * buffers. That means that at some moment in time
-                * after write_begin() / write_end() has been called
-                * all buffers have been clean and thus they must have been
-                * written at least once. So they are all mapped and we can
-                * happily proceed with mapping them and writing the page.
-                */
-               BUG_ON(walk_page_buffers(NULL, page_buffers(page), 0, len, NULL,
-                                       ext4_bh_unmapped_or_delay));
-       }
-
-       if (ext4_journal_current_handle())
-               goto no_write;
-
-       if (PageChecked(page)) {
-               /*
-                * It's mmapped pagecache.  Add buffers and journal it.  There
-                * doesn't seem much point in redirtying the page here.
-                */
-               ClearPageChecked(page);
-               return __ext4_journalled_writepage(page, wbc);
-       } else {
-               /*
-                * It may be a page full of checkpoint-mode buffers.  We don't
-                * really know unless we go poke around in the buffer_heads.
-                * But block_write_full_page will do the right thing.
-                */
-               return block_write_full_page(page, noalloc_get_block_write,
-                                            wbc);
-       }
-no_write:
-       redirty_page_for_writepage(wbc, page);
-       unlock_page(page);
-       return 0;
-}
-
 static int ext4_readpage(struct file *file, struct page *page)
 {
        return mpage_readpage(page, ext4_get_block);
@@ -3492,7 +3363,7 @@ static int ext4_journalled_set_page_dirty(struct page *page)
 static const struct address_space_operations ext4_ordered_aops = {
        .readpage               = ext4_readpage,
        .readpages              = ext4_readpages,
-       .writepage              = ext4_normal_writepage,
+       .writepage              = ext4_writepage,
        .sync_page              = block_sync_page,
        .write_begin            = ext4_write_begin,
        .write_end              = ext4_ordered_write_end,
@@ -3507,7 +3378,7 @@ static const struct address_space_operations ext4_ordered_aops = {
 static const struct address_space_operations ext4_writeback_aops = {
        .readpage               = ext4_readpage,
        .readpages              = ext4_readpages,
-       .writepage              = ext4_normal_writepage,
+       .writepage              = ext4_writepage,
        .sync_page              = block_sync_page,
        .write_begin            = ext4_write_begin,
        .write_end              = ext4_writeback_write_end,
@@ -3522,7 +3393,7 @@ static const struct address_space_operations ext4_writeback_aops = {
 static const struct address_space_operations ext4_journalled_aops = {
        .readpage               = ext4_readpage,
        .readpages              = ext4_readpages,
-       .writepage              = ext4_journalled_writepage,
+       .writepage              = ext4_writepage,
        .sync_page              = block_sync_page,
        .write_begin            = ext4_write_begin,
        .write_end              = ext4_journalled_write_end,
@@ -3536,7 +3407,7 @@ static const struct address_space_operations ext4_journalled_aops = {
 static const struct address_space_operations ext4_da_aops = {
        .readpage               = ext4_readpage,
        .readpages              = ext4_readpages,
-       .writepage              = ext4_da_writepage,
+       .writepage              = ext4_writepage,
        .writepages             = ext4_da_writepages,
        .sync_page              = block_sync_page,
        .write_begin            = ext4_da_write_begin,
@@ -3583,7 +3454,8 @@ int ext4_block_truncate_page(handle_t *handle,
        struct page *page;
        int err = 0;
 
-       page = grab_cache_page(mapping, from >> PAGE_CACHE_SHIFT);
+       page = find_or_create_page(mapping, from >> PAGE_CACHE_SHIFT,
+                                  mapping_gfp_mask(mapping) & ~__GFP_FS);
        if (!page)
                return -EINVAL;
 
@@ -4453,10 +4325,6 @@ struct inode *ext4_iget(struct super_block *sb, unsigned long ino)
                return inode;
 
        ei = EXT4_I(inode);
-#ifdef CONFIG_EXT4_FS_POSIX_ACL
-       ei->i_acl = EXT4_ACL_NOT_CACHED;
-       ei->i_default_acl = EXT4_ACL_NOT_CACHED;
-#endif
 
        ret = __ext4_get_inode_loc(inode, &iloc, 0);
        if (ret < 0)
index bb415408fdb60cc18243b70c4eec8ea9d82a67ed..7050a9cd04a4361bb66851781b9e494893f257ee 100644 (file)
@@ -12,7 +12,6 @@
 #include <linux/capability.h>
 #include <linux/time.h>
 #include <linux/compat.h>
-#include <linux/smp_lock.h>
 #include <linux/mount.h>
 #include <linux/file.h>
 #include <asm/uaccess.h>
@@ -192,7 +191,7 @@ setversion_out:
        case EXT4_IOC_GROUP_EXTEND: {
                ext4_fsblk_t n_blocks_count;
                struct super_block *sb = inode->i_sb;
-               int err, err2;
+               int err, err2=0;
 
                if (!capable(CAP_SYS_RESOURCE))
                        return -EPERM;
@@ -205,9 +204,11 @@ setversion_out:
                        return err;
 
                err = ext4_group_extend(sb, EXT4_SB(sb)->s_es, n_blocks_count);
-               jbd2_journal_lock_updates(EXT4_SB(sb)->s_journal);
-               err2 = jbd2_journal_flush(EXT4_SB(sb)->s_journal);
-               jbd2_journal_unlock_updates(EXT4_SB(sb)->s_journal);
+               if (EXT4_SB(sb)->s_journal) {
+                       jbd2_journal_lock_updates(EXT4_SB(sb)->s_journal);
+                       err2 = jbd2_journal_flush(EXT4_SB(sb)->s_journal);
+                       jbd2_journal_unlock_updates(EXT4_SB(sb)->s_journal);
+               }
                if (err == 0)
                        err = err2;
                mnt_drop_write(filp->f_path.mnt);
@@ -252,7 +253,7 @@ setversion_out:
        case EXT4_IOC_GROUP_ADD: {
                struct ext4_new_group_data input;
                struct super_block *sb = inode->i_sb;
-               int err, err2;
+               int err, err2=0;
 
                if (!capable(CAP_SYS_RESOURCE))
                        return -EPERM;
@@ -266,9 +267,11 @@ setversion_out:
                        return err;
 
                err = ext4_group_add(sb, &input);
-               jbd2_journal_lock_updates(EXT4_SB(sb)->s_journal);
-               err2 = jbd2_journal_flush(EXT4_SB(sb)->s_journal);
-               jbd2_journal_unlock_updates(EXT4_SB(sb)->s_journal);
+               if (EXT4_SB(sb)->s_journal) {
+                       jbd2_journal_lock_updates(EXT4_SB(sb)->s_journal);
+                       err2 = jbd2_journal_flush(EXT4_SB(sb)->s_journal);
+                       jbd2_journal_unlock_updates(EXT4_SB(sb)->s_journal);
+               }
                if (err == 0)
                        err = err2;
                mnt_drop_write(filp->f_path.mnt);
index 519a0a686d946343ca646702aa5c4603c9a75308..cd258463e2a9e017f949367b403d87332e5a3d24 100644 (file)
@@ -657,7 +657,8 @@ static void ext4_mb_mark_free_simple(struct super_block *sb,
        }
 }
 
-static void ext4_mb_generate_buddy(struct super_block *sb,
+static noinline_for_stack
+void ext4_mb_generate_buddy(struct super_block *sb,
                                void *buddy, void *bitmap, ext4_group_t group)
 {
        struct ext4_group_info *grp = ext4_get_group_info(sb, group);
@@ -1480,7 +1481,8 @@ static void ext4_mb_measure_extent(struct ext4_allocation_context *ac,
        ext4_mb_check_limits(ac, e4b, 0);
 }
 
-static int ext4_mb_try_best_found(struct ext4_allocation_context *ac,
+static noinline_for_stack
+int ext4_mb_try_best_found(struct ext4_allocation_context *ac,
                                        struct ext4_buddy *e4b)
 {
        struct ext4_free_extent ex = ac->ac_b_ex;
@@ -1507,7 +1509,8 @@ static int ext4_mb_try_best_found(struct ext4_allocation_context *ac,
        return 0;
 }
 
-static int ext4_mb_find_by_goal(struct ext4_allocation_context *ac,
+static noinline_for_stack
+int ext4_mb_find_by_goal(struct ext4_allocation_context *ac,
                                struct ext4_buddy *e4b)
 {
        ext4_group_t group = ac->ac_g_ex.fe_group;
@@ -1566,7 +1569,8 @@ static int ext4_mb_find_by_goal(struct ext4_allocation_context *ac,
  * The routine scans buddy structures (not bitmap!) from given order
  * to max order and tries to find big enough chunk to satisfy the req
  */
-static void ext4_mb_simple_scan_group(struct ext4_allocation_context *ac,
+static noinline_for_stack
+void ext4_mb_simple_scan_group(struct ext4_allocation_context *ac,
                                        struct ext4_buddy *e4b)
 {
        struct super_block *sb = ac->ac_sb;
@@ -1609,7 +1613,8 @@ static void ext4_mb_simple_scan_group(struct ext4_allocation_context *ac,
  * In order to optimize scanning, caller must pass number of
  * free blocks in the group, so the routine can know upper limit.
  */
-static void ext4_mb_complex_scan_group(struct ext4_allocation_context *ac,
+static noinline_for_stack
+void ext4_mb_complex_scan_group(struct ext4_allocation_context *ac,
                                        struct ext4_buddy *e4b)
 {
        struct super_block *sb = ac->ac_sb;
@@ -1668,7 +1673,8 @@ static void ext4_mb_complex_scan_group(struct ext4_allocation_context *ac,
  * we try to find stripe-aligned chunks for stripe-size requests
  * XXX should do so at least for multiples of stripe size as well
  */
-static void ext4_mb_scan_aligned(struct ext4_allocation_context *ac,
+static noinline_for_stack
+void ext4_mb_scan_aligned(struct ext4_allocation_context *ac,
                                 struct ext4_buddy *e4b)
 {
        struct super_block *sb = ac->ac_sb;
@@ -1831,7 +1837,8 @@ void ext4_mb_put_buddy_cache_lock(struct super_block *sb,
 
 }
 
-static int ext4_mb_init_group(struct super_block *sb, ext4_group_t group)
+static noinline_for_stack
+int ext4_mb_init_group(struct super_block *sb, ext4_group_t group)
 {
 
        int ret;
@@ -2902,7 +2909,11 @@ int __init init_ext4_mballoc(void)
 
 void exit_ext4_mballoc(void)
 {
-       /* XXX: synchronize_rcu(); */
+       /* 
+        * Wait for completion of call_rcu()'s on ext4_pspace_cachep
+        * before destroying the slab cache.
+        */
+       rcu_barrier();
        kmem_cache_destroy(ext4_pspace_cachep);
        kmem_cache_destroy(ext4_ac_cachep);
        kmem_cache_destroy(ext4_free_ext_cachep);
@@ -3457,7 +3468,8 @@ static void ext4_mb_generate_from_freelist(struct super_block *sb, void *bitmap,
  * used in in-core bitmap. buddy must be generated from this bitmap
  * Need to be called with ext4 group lock held
  */
-static void ext4_mb_generate_from_pa(struct super_block *sb, void *bitmap,
+static noinline_for_stack
+void ext4_mb_generate_from_pa(struct super_block *sb, void *bitmap,
                                        ext4_group_t group)
 {
        struct ext4_group_info *grp = ext4_get_group_info(sb, group);
@@ -4215,14 +4227,9 @@ ext4_mb_initialize_context(struct ext4_allocation_context *ac,
        ext4_get_group_no_and_offset(sb, goal, &group, &block);
 
        /* set up allocation goals */
+       memset(ac, 0, sizeof(struct ext4_allocation_context));
        ac->ac_b_ex.fe_logical = ar->logical;
-       ac->ac_b_ex.fe_group = 0;
-       ac->ac_b_ex.fe_start = 0;
-       ac->ac_b_ex.fe_len = 0;
        ac->ac_status = AC_STATUS_CONTINUE;
-       ac->ac_groups_scanned = 0;
-       ac->ac_ex_scanned = 0;
-       ac->ac_found = 0;
        ac->ac_sb = sb;
        ac->ac_inode = ar->inode;
        ac->ac_o_ex.fe_logical = ar->logical;
@@ -4233,15 +4240,7 @@ ext4_mb_initialize_context(struct ext4_allocation_context *ac,
        ac->ac_g_ex.fe_group = group;
        ac->ac_g_ex.fe_start = block;
        ac->ac_g_ex.fe_len = len;
-       ac->ac_f_ex.fe_len = 0;
        ac->ac_flags = ar->flags;
-       ac->ac_2order = 0;
-       ac->ac_criteria = 0;
-       ac->ac_pa = NULL;
-       ac->ac_bitmap_page = NULL;
-       ac->ac_buddy_page = NULL;
-       ac->alloc_semp = NULL;
-       ac->ac_lg = NULL;
 
        /* we have to define context: we'll we work with a file or
         * locality group. this is a policy, actually */
@@ -4509,10 +4508,7 @@ ext4_fsblk_t ext4_mb_new_blocks(handle_t *handle,
        }
 
        ac = kmem_cache_alloc(ext4_ac_cachep, GFP_NOFS);
-       if (ac) {
-               ac->ac_sb = sb;
-               ac->ac_inode = ar->inode;
-       } else {
+       if (!ac) {
                ar->len = 0;
                *errp = -ENOMEM;
                goto out1;
index 8bb9e2d3e4b8dc69cdeb84086dea2f4bcfc4a519..8f4f079e6b9a2a850c459b8677f7911fd326f4ca 100644 (file)
@@ -666,10 +666,6 @@ static struct inode *ext4_alloc_inode(struct super_block *sb)
        if (!ei)
                return NULL;
 
-#ifdef CONFIG_EXT4_FS_POSIX_ACL
-       ei->i_acl = EXT4_ACL_NOT_CACHED;
-       ei->i_default_acl = EXT4_ACL_NOT_CACHED;
-#endif
        ei->vfs_inode.i_version = 1;
        ei->vfs_inode.i_data.writeback_index = 0;
        memset(&ei->i_cached_extent, 0, sizeof(struct ext4_ext_cache));
@@ -735,18 +731,6 @@ static void destroy_inodecache(void)
 
 static void ext4_clear_inode(struct inode *inode)
 {
-#ifdef CONFIG_EXT4_FS_POSIX_ACL
-       if (EXT4_I(inode)->i_acl &&
-                       EXT4_I(inode)->i_acl != EXT4_ACL_NOT_CACHED) {
-               posix_acl_release(EXT4_I(inode)->i_acl);
-               EXT4_I(inode)->i_acl = EXT4_ACL_NOT_CACHED;
-       }
-       if (EXT4_I(inode)->i_default_acl &&
-                       EXT4_I(inode)->i_default_acl != EXT4_ACL_NOT_CACHED) {
-               posix_acl_release(EXT4_I(inode)->i_default_acl);
-               EXT4_I(inode)->i_default_acl = EXT4_ACL_NOT_CACHED;
-       }
-#endif
        ext4_discard_preallocations(inode);
        if (EXT4_JOURNAL(inode))
                jbd2_journal_release_jbd_inode(EXT4_SB(inode->i_sb)->s_journal,
index 38ff75a0fe22d3b8764e9be001dd57857c5abe66..530b4ca0151037ae212fe9d2d8ffb827fc970f98 100644 (file)
@@ -16,7 +16,6 @@
 #include <linux/module.h>
 #include <linux/slab.h>
 #include <linux/time.h>
-#include <linux/smp_lock.h>
 #include <linux/buffer_head.h>
 #include <linux/compat.h>
 #include <asm/uaccess.h>
index b28ea646ff607cfdbe0f1ebda29158b5feadef88..f042b965c95c8a9c6c0dbb21020877372b1a9c21 100644 (file)
@@ -134,7 +134,7 @@ static int fat_file_release(struct inode *inode, struct file *filp)
        if ((filp->f_mode & FMODE_WRITE) &&
             MSDOS_SB(inode->i_sb)->options.flush) {
                fat_flush_inodes(inode->i_sb, inode, NULL);
-               congestion_wait(WRITE, HZ/10);
+               congestion_wait(BLK_RW_ASYNC, HZ/10);
        }
        return 0;
 }
index 82f88733b681accfa68bdeb86bed85734b9fcc6e..bbc94ae4fd77150203435058b79e46a03bfb40bc 100644 (file)
@@ -9,7 +9,6 @@
 #include <linux/module.h>
 #include <linux/time.h>
 #include <linux/buffer_head.h>
-#include <linux/smp_lock.h>
 #include "fat.h"
 
 /* Characters that are undesirable in an MS-DOS file name */
index 73471b7ecc8c2bd90591f43391afaaeacf6c39af..cb6e83557112d74e03cf00f37d6b3bddfa66cd83 100644 (file)
@@ -19,7 +19,6 @@
 #include <linux/jiffies.h>
 #include <linux/ctype.h>
 #include <linux/slab.h>
-#include <linux/smp_lock.h>
 #include <linux/buffer_head.h>
 #include <linux/namei.h>
 #include "fat.h"
index a040b764f8e38b6a5067642713d4f9c6e9dc92ba..ae413086db978093123b2a59947d78e23a02a693 100644 (file)
@@ -19,7 +19,6 @@
 #include <linux/signal.h>
 #include <linux/rcupdate.h>
 #include <linux/pid_namespace.h>
-#include <linux/smp_lock.h>
 
 #include <asm/poll.h>
 #include <asm/siginfo.h>
index cdbd1654e4cde4b6dd6b62e7bb6f2bd4a128a42c..1e8af939b3e4ad58d41726db3851269193a2e0c9 100644 (file)
@@ -38,6 +38,7 @@
 #include <linux/buffer_head.h>
 #include <linux/kernel.h>
 #include <linux/slab.h>
+#include <linux/smp_lock.h>
 #include <linux/stat.h>
 #include <linux/vfs.h>
 #include <linux/mount.h>
index caf049146ca27a537a7dddc4a38ba02f085a6b35..c54226be52948337fb11a78056e3ee3e90688545 100644 (file)
@@ -278,7 +278,26 @@ int sb_has_dirty_inodes(struct super_block *sb)
 EXPORT_SYMBOL(sb_has_dirty_inodes);
 
 /*
- * Write a single inode's dirty pages and inode data out to disk.
+ * Wait for writeback on an inode to complete.
+ */
+static void inode_wait_for_writeback(struct inode *inode)
+{
+       DEFINE_WAIT_BIT(wq, &inode->i_state, __I_SYNC);
+       wait_queue_head_t *wqh;
+
+       wqh = bit_waitqueue(&inode->i_state, __I_SYNC);
+       do {
+               spin_unlock(&inode_lock);
+               __wait_on_bit(wqh, &wq, inode_wait, TASK_UNINTERRUPTIBLE);
+               spin_lock(&inode_lock);
+       } while (inode->i_state & I_SYNC);
+}
+
+/*
+ * Write out an inode's dirty pages.  Called under inode_lock.  Either the
+ * caller has ref on the inode (either via __iget or via syscall against an fd)
+ * or the inode has I_WILL_FREE set (via generic_forget_inode)
+ *
  * If `wait' is set, wait on the writeout.
  *
  * The whole writeout design is quite complex and fragile.  We want to avoid
@@ -288,13 +307,38 @@ EXPORT_SYMBOL(sb_has_dirty_inodes);
  * Called under inode_lock.
  */
 static int
-__sync_single_inode(struct inode *inode, struct writeback_control *wbc)
+writeback_single_inode(struct inode *inode, struct writeback_control *wbc)
 {
-       unsigned dirty;
        struct address_space *mapping = inode->i_mapping;
        int wait = wbc->sync_mode == WB_SYNC_ALL;
+       unsigned dirty;
        int ret;
 
+       if (!atomic_read(&inode->i_count))
+               WARN_ON(!(inode->i_state & (I_WILL_FREE|I_FREEING)));
+       else
+               WARN_ON(inode->i_state & I_WILL_FREE);
+
+       if (inode->i_state & I_SYNC) {
+               /*
+                * If this inode is locked for writeback and we are not doing
+                * writeback-for-data-integrity, move it to s_more_io so that
+                * writeback can proceed with the other inodes on s_io.
+                *
+                * We'll have another go at writing back this inode when we
+                * completed a full scan of s_io.
+                */
+               if (!wait) {
+                       requeue_io(inode);
+                       return 0;
+               }
+
+               /*
+                * It's a data-integrity sync.  We must wait.
+                */
+               inode_wait_for_writeback(inode);
+       }
+
        BUG_ON(inode->i_state & I_SYNC);
 
        /* Set I_SYNC, reset I_DIRTY */
@@ -389,50 +433,6 @@ __sync_single_inode(struct inode *inode, struct writeback_control *wbc)
        return ret;
 }
 
-/*
- * Write out an inode's dirty pages.  Called under inode_lock.  Either the
- * caller has ref on the inode (either via __iget or via syscall against an fd)
- * or the inode has I_WILL_FREE set (via generic_forget_inode)
- */
-static int
-__writeback_single_inode(struct inode *inode, struct writeback_control *wbc)
-{
-       wait_queue_head_t *wqh;
-
-       if (!atomic_read(&inode->i_count))
-               WARN_ON(!(inode->i_state & (I_WILL_FREE|I_FREEING)));
-       else
-               WARN_ON(inode->i_state & I_WILL_FREE);
-
-       if ((wbc->sync_mode != WB_SYNC_ALL) && (inode->i_state & I_SYNC)) {
-               /*
-                * We're skipping this inode because it's locked, and we're not
-                * doing writeback-for-data-integrity.  Move it to s_more_io so
-                * that writeback can proceed with the other inodes on s_io.
-                * We'll have another go at writing back this inode when we
-                * completed a full scan of s_io.
-                */
-               requeue_io(inode);
-               return 0;
-       }
-
-       /*
-        * It's a data-integrity sync.  We must wait.
-        */
-       if (inode->i_state & I_SYNC) {
-               DEFINE_WAIT_BIT(wq, &inode->i_state, __I_SYNC);
-
-               wqh = bit_waitqueue(&inode->i_state, __I_SYNC);
-               do {
-                       spin_unlock(&inode_lock);
-                       __wait_on_bit(wqh, &wq, inode_wait,
-                                                       TASK_UNINTERRUPTIBLE);
-                       spin_lock(&inode_lock);
-               } while (inode->i_state & I_SYNC);
-       }
-       return __sync_single_inode(inode, wbc);
-}
-
 /*
  * Write out a superblock's list of dirty inodes.  A wait will be performed
  * upon no inodes, all inodes or the final one, depending upon sync_mode.
@@ -526,7 +526,7 @@ void generic_sync_sb_inodes(struct super_block *sb,
                BUG_ON(inode->i_state & (I_FREEING | I_CLEAR));
                __iget(inode);
                pages_skipped = wbc->pages_skipped;
-               __writeback_single_inode(inode, wbc);
+               writeback_single_inode(inode, wbc);
                if (current_is_pdflush())
                        writeback_release(bdi);
                if (wbc->pages_skipped != pages_skipped) {
@@ -708,7 +708,7 @@ int write_inode_now(struct inode *inode, int sync)
 
        might_sleep();
        spin_lock(&inode_lock);
-       ret = __writeback_single_inode(inode, &wbc);
+       ret = writeback_single_inode(inode, &wbc);
        spin_unlock(&inode_lock);
        if (sync)
                inode_sync_wait(inode);
@@ -732,7 +732,7 @@ int sync_inode(struct inode *inode, struct writeback_control *wbc)
        int ret;
 
        spin_lock(&inode_lock);
-       ret = __writeback_single_inode(inode, wbc);
+       ret = writeback_single_inode(inode, wbc);
        spin_unlock(&inode_lock);
        return ret;
 }
index 8fed2ed12f38b3ab468a042964ae800479f18d18..6484eb75acd6f318c04238a51763b7cf2c9599ea 100644 (file)
@@ -286,8 +286,8 @@ __releases(&fc->lock)
                }
                if (fc->num_background == FUSE_CONGESTION_THRESHOLD &&
                    fc->connected && fc->bdi_initialized) {
-                       clear_bdi_congested(&fc->bdi, READ);
-                       clear_bdi_congested(&fc->bdi, WRITE);
+                       clear_bdi_congested(&fc->bdi, BLK_RW_SYNC);
+                       clear_bdi_congested(&fc->bdi, BLK_RW_ASYNC);
                }
                fc->num_background--;
                fc->active_background--;
@@ -414,8 +414,8 @@ static void fuse_request_send_nowait_locked(struct fuse_conn *fc,
                fc->blocked = 1;
        if (fc->num_background == FUSE_CONGESTION_THRESHOLD &&
            fc->bdi_initialized) {
-               set_bdi_congested(&fc->bdi, READ);
-               set_bdi_congested(&fc->bdi, WRITE);
+               set_bdi_congested(&fc->bdi, BLK_RW_SYNC);
+               set_bdi_congested(&fc->bdi, BLK_RW_ASYNC);
        }
        list_add_tail(&req->list, &fc->bg_queue);
        flush_bg_queue(fc);
@@ -849,6 +849,81 @@ err:
        return err;
 }
 
+static int fuse_notify_inval_inode(struct fuse_conn *fc, unsigned int size,
+                                  struct fuse_copy_state *cs)
+{
+       struct fuse_notify_inval_inode_out outarg;
+       int err = -EINVAL;
+
+       if (size != sizeof(outarg))
+               goto err;
+
+       err = fuse_copy_one(cs, &outarg, sizeof(outarg));
+       if (err)
+               goto err;
+       fuse_copy_finish(cs);
+
+       down_read(&fc->killsb);
+       err = -ENOENT;
+       if (!fc->sb)
+               goto err_unlock;
+
+       err = fuse_reverse_inval_inode(fc->sb, outarg.ino,
+                                      outarg.off, outarg.len);
+
+err_unlock:
+       up_read(&fc->killsb);
+       return err;
+
+err:
+       fuse_copy_finish(cs);
+       return err;
+}
+
+static int fuse_notify_inval_entry(struct fuse_conn *fc, unsigned int size,
+                                  struct fuse_copy_state *cs)
+{
+       struct fuse_notify_inval_entry_out outarg;
+       int err = -EINVAL;
+       char buf[FUSE_NAME_MAX+1];
+       struct qstr name;
+
+       if (size < sizeof(outarg))
+               goto err;
+
+       err = fuse_copy_one(cs, &outarg, sizeof(outarg));
+       if (err)
+               goto err;
+
+       err = -ENAMETOOLONG;
+       if (outarg.namelen > FUSE_NAME_MAX)
+               goto err;
+
+       name.name = buf;
+       name.len = outarg.namelen;
+       err = fuse_copy_one(cs, buf, outarg.namelen + 1);
+       if (err)
+               goto err;
+       fuse_copy_finish(cs);
+       buf[outarg.namelen] = 0;
+       name.hash = full_name_hash(name.name, name.len);
+
+       down_read(&fc->killsb);
+       err = -ENOENT;
+       if (!fc->sb)
+               goto err_unlock;
+
+       err = fuse_reverse_inval_entry(fc->sb, outarg.parent, &name);
+
+err_unlock:
+       up_read(&fc->killsb);
+       return err;
+
+err:
+       fuse_copy_finish(cs);
+       return err;
+}
+
 static int fuse_notify(struct fuse_conn *fc, enum fuse_notify_code code,
                       unsigned int size, struct fuse_copy_state *cs)
 {
@@ -856,6 +931,12 @@ static int fuse_notify(struct fuse_conn *fc, enum fuse_notify_code code,
        case FUSE_NOTIFY_POLL:
                return fuse_notify_poll(fc, size, cs);
 
+       case FUSE_NOTIFY_INVAL_INODE:
+               return fuse_notify_inval_inode(fc, size, cs);
+
+       case FUSE_NOTIFY_INVAL_ENTRY:
+               return fuse_notify_inval_entry(fc, size, cs);
+
        default:
                fuse_copy_finish(cs);
                return -EINVAL;
@@ -910,7 +991,7 @@ static ssize_t fuse_dev_write(struct kiocb *iocb, const struct iovec *iov,
                               unsigned long nr_segs, loff_t pos)
 {
        int err;
-       unsigned nbytes = iov_length(iov, nr_segs);
+       size_t nbytes = iov_length(iov, nr_segs);
        struct fuse_req *req;
        struct fuse_out_header oh;
        struct fuse_copy_state cs;
index b3089a083d30c36a2afa17c03ca1345cc6d38206..e703654e7f40d901975d3a0953ce353a755248d7 100644 (file)
@@ -375,7 +375,7 @@ static int fuse_create_open(struct inode *dir, struct dentry *entry, int mode,
        struct fuse_conn *fc = get_fuse_conn(dir);
        struct fuse_req *req;
        struct fuse_req *forget_req;
-       struct fuse_open_in inarg;
+       struct fuse_create_in inarg;
        struct fuse_open_out outopen;
        struct fuse_entry_out outentry;
        struct fuse_file *ff;
@@ -399,15 +399,20 @@ static int fuse_create_open(struct inode *dir, struct dentry *entry, int mode,
        if (!ff)
                goto out_put_request;
 
+       if (!fc->dont_mask)
+               mode &= ~current_umask();
+
        flags &= ~O_NOCTTY;
        memset(&inarg, 0, sizeof(inarg));
        memset(&outentry, 0, sizeof(outentry));
        inarg.flags = flags;
        inarg.mode = mode;
+       inarg.umask = current_umask();
        req->in.h.opcode = FUSE_CREATE;
        req->in.h.nodeid = get_node_id(dir);
        req->in.numargs = 2;
-       req->in.args[0].size = sizeof(inarg);
+       req->in.args[0].size = fc->minor < 12 ? sizeof(struct fuse_open_in) :
+                                               sizeof(inarg);
        req->in.args[0].value = &inarg;
        req->in.args[1].size = entry->d_name.len + 1;
        req->in.args[1].value = entry->d_name.name;
@@ -546,12 +551,17 @@ static int fuse_mknod(struct inode *dir, struct dentry *entry, int mode,
        if (IS_ERR(req))
                return PTR_ERR(req);
 
+       if (!fc->dont_mask)
+               mode &= ~current_umask();
+
        memset(&inarg, 0, sizeof(inarg));
        inarg.mode = mode;
        inarg.rdev = new_encode_dev(rdev);
+       inarg.umask = current_umask();
        req->in.h.opcode = FUSE_MKNOD;
        req->in.numargs = 2;
-       req->in.args[0].size = sizeof(inarg);
+       req->in.args[0].size = fc->minor < 12 ? FUSE_COMPAT_MKNOD_IN_SIZE :
+                                               sizeof(inarg);
        req->in.args[0].value = &inarg;
        req->in.args[1].size = entry->d_name.len + 1;
        req->in.args[1].value = entry->d_name.name;
@@ -578,8 +588,12 @@ static int fuse_mkdir(struct inode *dir, struct dentry *entry, int mode)
        if (IS_ERR(req))
                return PTR_ERR(req);
 
+       if (!fc->dont_mask)
+               mode &= ~current_umask();
+
        memset(&inarg, 0, sizeof(inarg));
        inarg.mode = mode;
+       inarg.umask = current_umask();
        req->in.h.opcode = FUSE_MKDIR;
        req->in.numargs = 2;
        req->in.args[0].size = sizeof(inarg);
@@ -845,6 +859,43 @@ int fuse_update_attributes(struct inode *inode, struct kstat *stat,
        return err;
 }
 
+int fuse_reverse_inval_entry(struct super_block *sb, u64 parent_nodeid,
+                            struct qstr *name)
+{
+       int err = -ENOTDIR;
+       struct inode *parent;
+       struct dentry *dir;
+       struct dentry *entry;
+
+       parent = ilookup5(sb, parent_nodeid, fuse_inode_eq, &parent_nodeid);
+       if (!parent)
+               return -ENOENT;
+
+       mutex_lock(&parent->i_mutex);
+       if (!S_ISDIR(parent->i_mode))
+               goto unlock;
+
+       err = -ENOENT;
+       dir = d_find_alias(parent);
+       if (!dir)
+               goto unlock;
+
+       entry = d_lookup(dir, name);
+       dput(dir);
+       if (!entry)
+               goto unlock;
+
+       fuse_invalidate_attr(parent);
+       fuse_invalidate_entry(entry);
+       dput(entry);
+       err = 0;
+
+ unlock:
+       mutex_unlock(&parent->i_mutex);
+       iput(parent);
+       return err;
+}
+
 /*
  * Calling into a user-controlled filesystem gives the filesystem
  * daemon ptrace-like capabilities over the requester process.  This
index fce6ce694fdee3c4d6764c1dff661de755de675d..cbc464043b6f02f1383be3153e24b73b2e8f4875 100644 (file)
@@ -1922,7 +1922,7 @@ unsigned fuse_file_poll(struct file *file, poll_table *wait)
 
        req = fuse_get_req(fc);
        if (IS_ERR(req))
-               return PTR_ERR(req);
+               return POLLERR;
 
        req->in.h.opcode = FUSE_POLL;
        req->in.h.nodeid = ff->nodeid;
index aaf2f9ff970ec4b824b6bf792264db9dd579f58c..52b641fc0faf1f8d1a938c10cf6460f203f28205 100644 (file)
@@ -446,6 +446,9 @@ struct fuse_conn {
        /** Do multi-page cached writes */
        unsigned big_writes:1;
 
+       /** Don't apply umask to creation modes */
+       unsigned dont_mask:1;
+
        /** The number of requests waiting for completion */
        atomic_t num_waiting;
 
@@ -481,6 +484,12 @@ struct fuse_conn {
 
        /** Called on final put */
        void (*release)(struct fuse_conn *);
+
+       /** Super block for this connection. */
+       struct super_block *sb;
+
+       /** Read/write semaphore to hold when accessing sb. */
+       struct rw_semaphore killsb;
 };
 
 static inline struct fuse_conn *get_fuse_conn_super(struct super_block *sb)
@@ -508,6 +517,11 @@ extern const struct file_operations fuse_dev_operations;
 
 extern const struct dentry_operations fuse_dentry_operations;
 
+/**
+ * Inode to nodeid comparison.
+ */
+int fuse_inode_eq(struct inode *inode, void *_nodeidp);
+
 /**
  * Get a filled in inode
  */
@@ -708,6 +722,19 @@ void fuse_release_nowrite(struct inode *inode);
 
 u64 fuse_get_attr_version(struct fuse_conn *fc);
 
+/**
+ * File-system tells the kernel to invalidate cache for the given node id.
+ */
+int fuse_reverse_inval_inode(struct super_block *sb, u64 nodeid,
+                            loff_t offset, loff_t len);
+
+/**
+ * File-system tells the kernel to invalidate parent attributes and
+ * the dentry matching parent/name.
+ */
+int fuse_reverse_inval_entry(struct super_block *sb, u64 parent_nodeid,
+                            struct qstr *name);
+
 int fuse_do_open(struct fuse_conn *fc, u64 nodeid, struct file *file,
                 bool isdir);
 ssize_t fuse_direct_io(struct file *file, const char __user *buf,
index d8673ccf90b75033c0d4f0a37ed5a775accf0025..f91ccc4a189de18b52450f8d847b4983ac5e4311 100644 (file)
@@ -206,7 +206,7 @@ static void fuse_init_inode(struct inode *inode, struct fuse_attr *attr)
                BUG();
 }
 
-static int fuse_inode_eq(struct inode *inode, void *_nodeidp)
+int fuse_inode_eq(struct inode *inode, void *_nodeidp)
 {
        u64 nodeid = *(u64 *) _nodeidp;
        if (get_node_id(inode) == nodeid)
@@ -257,6 +257,31 @@ struct inode *fuse_iget(struct super_block *sb, u64 nodeid,
        return inode;
 }
 
+int fuse_reverse_inval_inode(struct super_block *sb, u64 nodeid,
+                            loff_t offset, loff_t len)
+{
+       struct inode *inode;
+       pgoff_t pg_start;
+       pgoff_t pg_end;
+
+       inode = ilookup5(sb, nodeid, fuse_inode_eq, &nodeid);
+       if (!inode)
+               return -ENOENT;
+
+       fuse_invalidate_attr(inode);
+       if (offset >= 0) {
+               pg_start = offset >> PAGE_CACHE_SHIFT;
+               if (len <= 0)
+                       pg_end = -1;
+               else
+                       pg_end = (offset + len - 1) >> PAGE_CACHE_SHIFT;
+               invalidate_inode_pages2_range(inode->i_mapping,
+                                             pg_start, pg_end);
+       }
+       iput(inode);
+       return 0;
+}
+
 static void fuse_umount_begin(struct super_block *sb)
 {
        fuse_abort_conn(get_fuse_conn_super(sb));
@@ -480,6 +505,7 @@ void fuse_conn_init(struct fuse_conn *fc)
        memset(fc, 0, sizeof(*fc));
        spin_lock_init(&fc->lock);
        mutex_init(&fc->inst_mutex);
+       init_rwsem(&fc->killsb);
        atomic_set(&fc->count, 1);
        init_waitqueue_head(&fc->waitq);
        init_waitqueue_head(&fc->blocked_waitq);
@@ -725,6 +751,8 @@ static void process_init_reply(struct fuse_conn *fc, struct fuse_req *req)
                        }
                        if (arg->flags & FUSE_BIG_WRITES)
                                fc->big_writes = 1;
+                       if (arg->flags & FUSE_DONT_MASK)
+                               fc->dont_mask = 1;
                } else {
                        ra_pages = fc->max_read / PAGE_CACHE_SIZE;
                        fc->no_lock = 1;
@@ -748,7 +776,7 @@ static void fuse_send_init(struct fuse_conn *fc, struct fuse_req *req)
        arg->minor = FUSE_KERNEL_MINOR_VERSION;
        arg->max_readahead = fc->bdi.ra_pages * PAGE_CACHE_SIZE;
        arg->flags |= FUSE_ASYNC_READ | FUSE_POSIX_LOCKS | FUSE_ATOMIC_O_TRUNC |
-               FUSE_EXPORT_SUPPORT | FUSE_BIG_WRITES;
+               FUSE_EXPORT_SUPPORT | FUSE_BIG_WRITES | FUSE_DONT_MASK;
        req->in.h.opcode = FUSE_INIT;
        req->in.numargs = 1;
        req->in.args[0].size = sizeof(*arg);
@@ -860,10 +888,16 @@ static int fuse_fill_super(struct super_block *sb, void *data, int silent)
        fuse_conn_init(fc);
 
        fc->dev = sb->s_dev;
+       fc->sb = sb;
        err = fuse_bdi_init(fc, sb);
        if (err)
                goto err_put_conn;
 
+       /* Handle umasking inside the fuse code */
+       if (sb->s_flags & MS_POSIXACL)
+               fc->dont_mask = 1;
+       sb->s_flags |= MS_POSIXACL;
+
        fc->release = fuse_free_conn;
        fc->flags = d.flags;
        fc->user_id = d.user_id;
@@ -941,12 +975,25 @@ static int fuse_get_sb(struct file_system_type *fs_type,
        return get_sb_nodev(fs_type, flags, raw_data, fuse_fill_super, mnt);
 }
 
+static void fuse_kill_sb_anon(struct super_block *sb)
+{
+       struct fuse_conn *fc = get_fuse_conn_super(sb);
+
+       if (fc) {
+               down_write(&fc->killsb);
+               fc->sb = NULL;
+               up_write(&fc->killsb);
+       }
+
+       kill_anon_super(sb);
+}
+
 static struct file_system_type fuse_fs_type = {
        .owner          = THIS_MODULE,
        .name           = "fuse",
        .fs_flags       = FS_HAS_SUBTYPE,
        .get_sb         = fuse_get_sb,
-       .kill_sb        = kill_anon_super,
+       .kill_sb        = fuse_kill_sb_anon,
 };
 
 #ifdef CONFIG_BLOCK
@@ -958,11 +1005,24 @@ static int fuse_get_sb_blk(struct file_system_type *fs_type,
                           mnt);
 }
 
+static void fuse_kill_sb_blk(struct super_block *sb)
+{
+       struct fuse_conn *fc = get_fuse_conn_super(sb);
+
+       if (fc) {
+               down_write(&fc->killsb);
+               fc->sb = NULL;
+               up_write(&fc->killsb);
+       }
+
+       kill_block_super(sb);
+}
+
 static struct file_system_type fuseblk_fs_type = {
        .owner          = THIS_MODULE,
        .name           = "fuseblk",
        .get_sb         = fuse_get_sb_blk,
-       .kill_sb        = kill_block_super,
+       .kill_sb        = fuse_kill_sb_blk,
        .fs_flags       = FS_REQUIRES_DEV | FS_HAS_SUBTYPE,
 };
 
index 98d6ef1c1dc067eba8a780fca4c5dac84dd1d379..148d55c14171dee39435c83d56c906c09dcd0cf8 100644 (file)
@@ -1,12 +1,11 @@
+#undef TRACE_SYSTEM
+#define TRACE_SYSTEM gfs2
+
 #if !defined(_TRACE_GFS2_H) || defined(TRACE_HEADER_MULTI_READ)
 #define _TRACE_GFS2_H
 
 #include <linux/tracepoint.h>
 
-#undef TRACE_SYSTEM
-#define TRACE_SYSTEM gfs2
-#define TRACE_INCLUDE_FILE trace_gfs2
-
 #include <linux/fs.h>
 #include <linux/buffer_head.h>
 #include <linux/dlmconstants.h>
@@ -403,5 +402,6 @@ TRACE_EVENT(gfs2_block_alloc,
 /* This part must be outside protection */
 #undef TRACE_INCLUDE_PATH
 #define TRACE_INCLUDE_PATH .
+#define TRACE_INCLUDE_FILE trace_gfs2
 #include <trace/define_trace.h>
 
index 6f833dc8e91022411939a290988af8a36e8d2018..f7fcbe49da723c40b56c816c8f04bea6e8d24616 100644 (file)
@@ -19,6 +19,7 @@
 #include <linux/nls.h>
 #include <linux/parser.h>
 #include <linux/seq_file.h>
+#include <linux/smp_lock.h>
 #include <linux/vfs.h>
 
 #include "hfs_fs.h"
index 9fc3af0c0dab6cd5b58af0f8a0cb0d0019ed9011..c0759fe0855b623863eac1345c8b8e4bf35608a9 100644 (file)
@@ -12,6 +12,7 @@
 #include <linux/pagemap.h>
 #include <linux/fs.h>
 #include <linux/slab.h>
+#include <linux/smp_lock.h>
 #include <linux/vfs.h>
 #include <linux/nls.h>
 
index fe02ad4740e76a2b4246657575d2a0f682b254f1..032604e5ef2ca36b1f9171d4fc2a775e9bcd7074 100644 (file)
@@ -972,6 +972,7 @@ static int hostfs_fill_sb_common(struct super_block *sb, void *d, int silent)
        sb->s_blocksize_bits = 10;
        sb->s_magic = HOSTFS_SUPER_MAGIC;
        sb->s_op = &hostfs_sbops;
+       sb->s_maxbytes = MAX_LFS_FILESIZE;
 
        /* NULL is printed as <NULL> by sprintf: avoid that. */
        if (req_root == NULL)
index 6916c41d70176f97dd22326dd7d47d4a39abfdeb..8865c94f55f602f19cb3b68182fc70bd41fcb4e4 100644 (file)
@@ -6,6 +6,7 @@
  *  directory VFS functions
  */
 
+#include <linux/smp_lock.h>
 #include "hpfs_fn.h"
 
 static int hpfs_dir_release(struct inode *inode, struct file *filp)
index 64ab52259204b24f20aa356d60ab73b1df982346..3efabff00367672a5a7bb722984590c14346338a 100644 (file)
@@ -6,6 +6,7 @@
  *  file VFS functions
  */
 
+#include <linux/smp_lock.h>
 #include "hpfs_fn.h"
 
 #define BLOCKS(size) (((size) + 511) >> 9)
index c2ea31bae313092dff76107889b79596cf7b417a..701ca54c0867fe482b9c33fdb6615a015114fa95 100644 (file)
@@ -13,7 +13,6 @@
 #include <linux/pagemap.h>
 #include <linux/buffer_head.h>
 #include <linux/slab.h>
-#include <linux/smp_lock.h>
 
 #include "hpfs.h"
 
index 39a1bfbea3122ed430fdffcd38f5aab02d62b68f..fe703ae46bc773f95a8502f12ccae915531d4271 100644 (file)
@@ -6,6 +6,7 @@
  *  inode VFS functions
  */
 
+#include <linux/smp_lock.h>
 #include "hpfs_fn.h"
 
 void hpfs_init_inode(struct inode *i)
index b649232dde97baf4eac591548b7944c5aedcc666..82b9c4ba9ed08b07eda6832d6a5953581f515967 100644 (file)
@@ -6,6 +6,7 @@
  *  adding & removing files & directories
  */
 #include <linux/sched.h>
+#include <linux/smp_lock.h>
 #include "hpfs_fn.h"
 
 static int hpfs_mkdir(struct inode *dir, struct dentry *dentry, int mode)
index f643be565df8e403a0fc807c4d1af554004c0d62..901bad1e5f1210cce8f2bc2a474345f5b1a4072a 100644 (file)
@@ -25,6 +25,7 @@
 #include <linux/fsnotify.h>
 #include <linux/mount.h>
 #include <linux/async.h>
+#include <linux/posix_acl.h>
 
 /*
  * This is needed for the following functions:
@@ -189,6 +190,9 @@ struct inode *inode_init_always(struct super_block *sb, struct inode *inode)
        }
        inode->i_private = NULL;
        inode->i_mapping = mapping;
+#ifdef CONFIG_FS_POSIX_ACL
+       inode->i_acl = inode->i_default_acl = ACL_NOT_CACHED;
+#endif
 
 #ifdef CONFIG_FSNOTIFY
        inode->i_fsnotify_mask = 0;
@@ -227,6 +231,12 @@ void destroy_inode(struct inode *inode)
        ima_inode_free(inode);
        security_inode_free(inode);
        fsnotify_inode_delete(inode);
+#ifdef CONFIG_FS_POSIX_ACL
+       if (inode->i_acl && inode->i_acl != ACL_NOT_CACHED)
+               posix_acl_release(inode->i_acl);
+       if (inode->i_default_acl && inode->i_default_acl != ACL_NOT_CACHED)
+               posix_acl_release(inode->i_default_acl);
+#endif
        if (inode->i_sb->s_op->destroy_inode)
                inode->i_sb->s_op->destroy_inode(inode);
        else
@@ -665,12 +675,17 @@ void unlock_new_inode(struct inode *inode)
        if (inode->i_mode & S_IFDIR) {
                struct file_system_type *type = inode->i_sb->s_type;
 
-               /*
-                * ensure nobody is actually holding i_mutex
-                */
-               mutex_destroy(&inode->i_mutex);
-               mutex_init(&inode->i_mutex);
-               lockdep_set_class(&inode->i_mutex, &type->i_mutex_dir_key);
+               /* Set new key only if filesystem hasn't already changed it */
+               if (!lockdep_match_class(&inode->i_mutex,
+                   &type->i_mutex_key)) {
+                       /*
+                        * ensure nobody is actually holding i_mutex
+                        */
+                       mutex_destroy(&inode->i_mutex);
+                       mutex_init(&inode->i_mutex);
+                       lockdep_set_class(&inode->i_mutex,
+                                         &type->i_mutex_dir_key);
+               }
        }
 #endif
        /*
index 001f8d3118f27329d89131feef43c7ba0c0b1a85..5612880fcbe7d7436f3579c7c1add7360170e407 100644 (file)
@@ -15,6 +15,7 @@
 #include <linux/uaccess.h>
 #include <linux/writeback.h>
 #include <linux/buffer_head.h>
+#include <linux/falloc.h>
 
 #include <asm/ioctls.h>
 
@@ -403,6 +404,37 @@ EXPORT_SYMBOL(generic_block_fiemap);
 
 #endif  /*  CONFIG_BLOCK  */
 
+/*
+ * This provides compatibility with legacy XFS pre-allocation ioctls
+ * which predate the fallocate syscall.
+ *
+ * Only the l_start, l_len and l_whence fields of the 'struct space_resv'
+ * are used here, rest are ignored.
+ */
+int ioctl_preallocate(struct file *filp, void __user *argp)
+{
+       struct inode *inode = filp->f_path.dentry->d_inode;
+       struct space_resv sr;
+
+       if (copy_from_user(&sr, argp, sizeof(sr)))
+               return -EFAULT;
+
+       switch (sr.l_whence) {
+       case SEEK_SET:
+               break;
+       case SEEK_CUR:
+               sr.l_start += filp->f_pos;
+               break;
+       case SEEK_END:
+               sr.l_start += i_size_read(inode);
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       return do_fallocate(filp, FALLOC_FL_KEEP_SIZE, sr.l_start, sr.l_len);
+}
+
 static int file_ioctl(struct file *filp, unsigned int cmd,
                unsigned long arg)
 {
@@ -414,6 +446,9 @@ static int file_ioctl(struct file *filp, unsigned int cmd,
                return ioctl_fibmap(filp, p);
        case FIONREAD:
                return put_user(i_size_read(inode) - filp->f_pos, p);
+       case FS_IOC_RESVSP:
+       case FS_IOC_RESVSP64:
+               return ioctl_preallocate(filp, p);
        }
 
        return vfs_ioctl(filp, cmd, arg);
index 58a7963e168ae4b8b4486fa54cd4b5fb5d66a9ee..85f96bc651c727ba04915138c50b45e9b63a3acd 100644 (file)
@@ -142,6 +142,7 @@ static const struct dentry_operations isofs_dentry_ops[] = {
 
 struct iso9660_options{
        unsigned int rock:1;
+       unsigned int joliet:1;
        unsigned int cruft:1;
        unsigned int hide:1;
        unsigned int showassoc:1;
@@ -151,7 +152,6 @@ struct iso9660_options{
        unsigned int gid_set:1;
        unsigned int utf8:1;
        unsigned char map;
-       char joliet;
        unsigned char check;
        unsigned int blocksize;
        mode_t fmode;
@@ -632,7 +632,7 @@ static int isofs_fill_super(struct super_block *s, void *data, int silent)
                        else if (isonum_711(vdp->type) == ISO_VD_SUPPLEMENTARY) {
                                sec = (struct iso_supplementary_descriptor *)vdp;
                                if (sec->escape[0] == 0x25 && sec->escape[1] == 0x2f) {
-                                       if (opt.joliet == 'y') {
+                                       if (opt.joliet) {
                                                if (sec->escape[2] == 0x40)
                                                        joliet_level = 1;
                                                else if (sec->escape[2] == 0x43)
index 18bfd5dab64220d7d11fc90b6efb7c79e807c16a..e378cb383979a3e8e54234b14aa354e890c54e26 100644 (file)
@@ -297,6 +297,7 @@ int jbd2_journal_write_metadata_buffer(transaction_t *transaction,
        unsigned int new_offset;
        struct buffer_head *bh_in = jh2bh(jh_in);
        struct jbd2_buffer_trigger_type *triggers;
+       journal_t *journal = transaction->t_journal;
 
        /*
         * The buffer really shouldn't be locked: only the current committing
@@ -310,6 +311,11 @@ int jbd2_journal_write_metadata_buffer(transaction_t *transaction,
        J_ASSERT_BH(bh_in, buffer_jbddirty(bh_in));
 
        new_bh = alloc_buffer_head(GFP_NOFS|__GFP_NOFAIL);
+       /* keep subsequent assertions sane */
+       new_bh->b_state = 0;
+       init_buffer(new_bh, NULL, NULL);
+       atomic_set(&new_bh->b_count, 1);
+       new_jh = jbd2_journal_add_journal_head(new_bh); /* This sleeps */
 
        /*
         * If a new transaction has already done a buffer copy-out, then
@@ -388,14 +394,6 @@ repeat:
                kunmap_atomic(mapped_data, KM_USER0);
        }
 
-       /* keep subsequent assertions sane */
-       new_bh->b_state = 0;
-       init_buffer(new_bh, NULL, NULL);
-       atomic_set(&new_bh->b_count, 1);
-       jbd_unlock_bh_state(bh_in);
-
-       new_jh = jbd2_journal_add_journal_head(new_bh); /* This sleeps */
-
        set_bh_page(new_bh, new_page, new_offset);
        new_jh->b_transaction = NULL;
        new_bh->b_size = jh2bh(jh_in)->b_size;
@@ -412,7 +410,11 @@ repeat:
         * copying is moved to the transaction's shadow queue.
         */
        JBUFFER_TRACE(jh_in, "file as BJ_Shadow");
-       jbd2_journal_file_buffer(jh_in, transaction, BJ_Shadow);
+       spin_lock(&journal->j_list_lock);
+       __jbd2_journal_file_buffer(jh_in, transaction, BJ_Shadow);
+       spin_unlock(&journal->j_list_lock);
+       jbd_unlock_bh_state(bh_in);
+
        JBUFFER_TRACE(new_jh, "file as BJ_IO");
        jbd2_journal_file_buffer(new_jh, transaction, BJ_IO);
 
@@ -2410,6 +2412,7 @@ const char *jbd2_dev_to_name(dev_t device)
        int     i = hash_32(device, CACHE_SIZE_BITS);
        char    *ret;
        struct block_device *bd;
+       static struct devname_cache *new_dev;
 
        rcu_read_lock();
        if (devcache[i] && devcache[i]->device == device) {
@@ -2419,20 +2422,20 @@ const char *jbd2_dev_to_name(dev_t device)
        }
        rcu_read_unlock();
 
+       new_dev = kmalloc(sizeof(struct devname_cache), GFP_KERNEL);
+       if (!new_dev)
+               return "NODEV-ALLOCFAILURE"; /* Something non-NULL */
        spin_lock(&devname_cache_lock);
        if (devcache[i]) {
                if (devcache[i]->device == device) {
+                       kfree(new_dev);
                        ret = devcache[i]->devname;
                        spin_unlock(&devname_cache_lock);
                        return ret;
                }
                call_rcu(&devcache[i]->rcu, free_devcache);
        }
-       devcache[i] = kmalloc(sizeof(struct devname_cache), GFP_KERNEL);
-       if (!devcache[i]) {
-               spin_unlock(&devname_cache_lock);
-               return "NODEV-ALLOCFAILURE"; /* Something non-NULL */
-       }
+       devcache[i] = new_dev;
        devcache[i]->device = device;
        bd = bdget(device);
        if (bd) {
index 494501edba6bcf0ce39c129848d5862177e1d38b..6213ac728f303286e15a2b6703fc90d69e2bd6ba 100644 (file)
@@ -499,34 +499,15 @@ void jbd2_journal_unlock_updates (journal_t *journal)
        wake_up(&journal->j_wait_transaction_locked);
 }
 
-/*
- * Report any unexpected dirty buffers which turn up.  Normally those
- * indicate an error, but they can occur if the user is running (say)
- * tune2fs to modify the live filesystem, so we need the option of
- * continuing as gracefully as possible.  #
- *
- * The caller should already hold the journal lock and
- * j_list_lock spinlock: most callers will need those anyway
- * in order to probe the buffer's journaling state safely.
- */
-static void jbd_unexpected_dirty_buffer(struct journal_head *jh)
+static void warn_dirty_buffer(struct buffer_head *bh)
 {
-       int jlist;
-
-       /* If this buffer is one which might reasonably be dirty
-        * --- ie. data, or not part of this journal --- then
-        * we're OK to leave it alone, but otherwise we need to
-        * move the dirty bit to the journal's own internal
-        * JBDDirty bit. */
-       jlist = jh->b_jlist;
+       char b[BDEVNAME_SIZE];
 
-       if (jlist == BJ_Metadata || jlist == BJ_Reserved ||
-           jlist == BJ_Shadow || jlist == BJ_Forget) {
-               struct buffer_head *bh = jh2bh(jh);
-
-               if (test_clear_buffer_dirty(bh))
-                       set_buffer_jbddirty(bh);
-       }
+       printk(KERN_WARNING
+              "JBD: Spotted dirty metadata buffer (dev = %s, blocknr = %llu). "
+              "There's a risk of filesystem corruption in case of system "
+              "crash.\n",
+              bdevname(bh->b_bdev, b), (unsigned long long)bh->b_blocknr);
 }
 
 /*
@@ -593,14 +574,16 @@ repeat:
                        if (jh->b_next_transaction)
                                J_ASSERT_JH(jh, jh->b_next_transaction ==
                                                        transaction);
+                       warn_dirty_buffer(bh);
                }
                /*
                 * In any case we need to clean the dirty flag and we must
                 * do it under the buffer lock to be sure we don't race
                 * with running write-out.
                 */
-               JBUFFER_TRACE(jh, "Unexpected dirty buffer");
-               jbd_unexpected_dirty_buffer(jh);
+               JBUFFER_TRACE(jh, "Journalling dirty buffer");
+               clear_buffer_dirty(bh);
+               set_buffer_jbddirty(bh);
        }
 
        unlock_buffer(bh);
@@ -843,6 +826,15 @@ int jbd2_journal_get_create_access(handle_t *handle, struct buffer_head *bh)
        J_ASSERT_JH(jh, buffer_locked(jh2bh(jh)));
 
        if (jh->b_transaction == NULL) {
+               /*
+                * Previous jbd2_journal_forget() could have left the buffer
+                * with jbddirty bit set because it was being committed. When
+                * the commit finished, we've filed the buffer for
+                * checkpointing and marked it dirty. Now we are reallocating
+                * the buffer so the transaction freeing it must have
+                * committed and so it's safe to clear the dirty bit.
+                */
+               clear_buffer_dirty(jh2bh(jh));
                jh->b_transaction = transaction;
 
                /* first access by this transaction */
@@ -1644,8 +1636,13 @@ static int __dispose_buffer(struct journal_head *jh, transaction_t *transaction)
 
        if (jh->b_cp_transaction) {
                JBUFFER_TRACE(jh, "on running+cp transaction");
+               /*
+                * We don't want to write the buffer anymore, clear the
+                * bit so that we don't confuse checks in
+                * __journal_file_buffer
+                */
+               clear_buffer_dirty(bh);
                __jbd2_journal_file_buffer(jh, transaction, BJ_Forget);
-               clear_buffer_jbddirty(bh);
                may_free = 0;
        } else {
                JBUFFER_TRACE(jh, "on running transaction");
@@ -1896,12 +1893,17 @@ void __jbd2_journal_file_buffer(struct journal_head *jh,
        if (jh->b_transaction && jh->b_jlist == jlist)
                return;
 
-       /* The following list of buffer states needs to be consistent
-        * with __jbd_unexpected_dirty_buffer()'s handling of dirty
-        * state. */
-
        if (jlist == BJ_Metadata || jlist == BJ_Reserved ||
            jlist == BJ_Shadow || jlist == BJ_Forget) {
+               /*
+                * For metadata buffers, we track dirty bit in buffer_jbddirty
+                * instead of buffer_dirty. We should not see a dirty bit set
+                * here because we clear it in do_get_write_access but e.g.
+                * tune2fs can modify the sb and set the dirty bit at any time
+                * so we try to gracefully handle that.
+                */
+               if (buffer_dirty(bh))
+                       warn_dirty_buffer(bh);
                if (test_clear_buffer_dirty(bh) ||
                    test_clear_buffer_jbddirty(bh))
                        was_dirty = 1;
index 043740dde20c75fb317bfdedac040abedf9004aa..8fcb6239218e53b7b9ced59a0ee9a854f4c77175 100644 (file)
@@ -156,48 +156,25 @@ static void *jffs2_acl_to_medium(const struct posix_acl *acl, size_t *size)
        return ERR_PTR(-EINVAL);
 }
 
-static struct posix_acl *jffs2_iget_acl(struct inode *inode, struct posix_acl **i_acl)
-{
-       struct posix_acl *acl = JFFS2_ACL_NOT_CACHED;
-
-       spin_lock(&inode->i_lock);
-       if (*i_acl != JFFS2_ACL_NOT_CACHED)
-               acl = posix_acl_dup(*i_acl);
-       spin_unlock(&inode->i_lock);
-       return acl;
-}
-
-static void jffs2_iset_acl(struct inode *inode, struct posix_acl **i_acl, struct posix_acl *acl)
-{
-       spin_lock(&inode->i_lock);
-       if (*i_acl != JFFS2_ACL_NOT_CACHED)
-               posix_acl_release(*i_acl);
-       *i_acl = posix_acl_dup(acl);
-       spin_unlock(&inode->i_lock);
-}
-
 static struct posix_acl *jffs2_get_acl(struct inode *inode, int type)
 {
-       struct jffs2_inode_info *f = JFFS2_INODE_INFO(inode);
        struct posix_acl *acl;
        char *value = NULL;
        int rc, xprefix;
 
+       acl = get_cached_acl(inode, type);
+       if (acl != ACL_NOT_CACHED)
+               return acl;
+
        switch (type) {
        case ACL_TYPE_ACCESS:
-               acl = jffs2_iget_acl(inode, &f->i_acl_access);
-               if (acl != JFFS2_ACL_NOT_CACHED)
-                       return acl;
                xprefix = JFFS2_XPREFIX_ACL_ACCESS;
                break;
        case ACL_TYPE_DEFAULT:
-               acl = jffs2_iget_acl(inode, &f->i_acl_default);
-               if (acl != JFFS2_ACL_NOT_CACHED)
-                       return acl;
                xprefix = JFFS2_XPREFIX_ACL_DEFAULT;
                break;
        default:
-               return ERR_PTR(-EINVAL);
+               BUG();
        }
        rc = do_jffs2_getxattr(inode, xprefix, "", NULL, 0);
        if (rc > 0) {
@@ -215,16 +192,8 @@ static struct posix_acl *jffs2_get_acl(struct inode *inode, int type)
        }
        if (value)
                kfree(value);
-       if (!IS_ERR(acl)) {
-               switch (type) {
-               case ACL_TYPE_ACCESS:
-                       jffs2_iset_acl(inode, &f->i_acl_access, acl);
-                       break;
-               case ACL_TYPE_DEFAULT:
-                       jffs2_iset_acl(inode, &f->i_acl_default, acl);
-                       break;
-               }
-       }
+       if (!IS_ERR(acl))
+               set_cached_acl(inode, type, acl);
        return acl;
 }
 
@@ -249,7 +218,6 @@ static int __jffs2_set_acl(struct inode *inode, int xprefix, struct posix_acl *a
 
 static int jffs2_set_acl(struct inode *inode, int type, struct posix_acl *acl)
 {
-       struct jffs2_inode_info *f = JFFS2_INODE_INFO(inode);
        int rc, xprefix;
 
        if (S_ISLNK(inode->i_mode))
@@ -285,16 +253,8 @@ static int jffs2_set_acl(struct inode *inode, int type, struct posix_acl *acl)
                return -EINVAL;
        }
        rc = __jffs2_set_acl(inode, xprefix, acl);
-       if (!rc) {
-               switch(type) {
-               case ACL_TYPE_ACCESS:
-                       jffs2_iset_acl(inode, &f->i_acl_access, acl);
-                       break;
-               case ACL_TYPE_DEFAULT:
-                       jffs2_iset_acl(inode, &f->i_acl_default, acl);
-                       break;
-               }
-       }
+       if (!rc)
+               set_cached_acl(inode, type, acl);
        return rc;
 }
 
@@ -321,12 +281,10 @@ int jffs2_permission(struct inode *inode, int mask)
 
 int jffs2_init_acl_pre(struct inode *dir_i, struct inode *inode, int *i_mode)
 {
-       struct jffs2_inode_info *f = JFFS2_INODE_INFO(inode);
        struct posix_acl *acl, *clone;
        int rc;
 
-       f->i_acl_default = NULL;
-       f->i_acl_access = NULL;
+       cache_no_acl(inode);
 
        if (S_ISLNK(*i_mode))
                return 0;       /* Symlink always has no-ACL */
@@ -339,7 +297,7 @@ int jffs2_init_acl_pre(struct inode *dir_i, struct inode *inode, int *i_mode)
                *i_mode &= ~current_umask();
        } else {
                if (S_ISDIR(*i_mode))
-                       jffs2_iset_acl(inode, &f->i_acl_default, acl);
+                       set_cached_acl(inode, ACL_TYPE_DEFAULT, acl);
 
                clone = posix_acl_clone(acl, GFP_KERNEL);
                if (!clone)
@@ -350,7 +308,7 @@ int jffs2_init_acl_pre(struct inode *dir_i, struct inode *inode, int *i_mode)
                        return rc;
                }
                if (rc > 0)
-                       jffs2_iset_acl(inode, &f->i_acl_access, clone);
+                       set_cached_acl(inode, ACL_TYPE_ACCESS, clone);
 
                posix_acl_release(clone);
        }
@@ -359,17 +317,16 @@ int jffs2_init_acl_pre(struct inode *dir_i, struct inode *inode, int *i_mode)
 
 int jffs2_init_acl_post(struct inode *inode)
 {
-       struct jffs2_inode_info *f = JFFS2_INODE_INFO(inode);
        int rc;
 
-       if (f->i_acl_default) {
-               rc = __jffs2_set_acl(inode, JFFS2_XPREFIX_ACL_DEFAULT, f->i_acl_default);
+       if (inode->i_default_acl) {
+               rc = __jffs2_set_acl(inode, JFFS2_XPREFIX_ACL_DEFAULT, inode->i_default_acl);
                if (rc)
                        return rc;
        }
 
-       if (f->i_acl_access) {
-               rc = __jffs2_set_acl(inode, JFFS2_XPREFIX_ACL_ACCESS, f->i_acl_access);
+       if (inode->i_acl) {
+               rc = __jffs2_set_acl(inode, JFFS2_XPREFIX_ACL_ACCESS, inode->i_acl);
                if (rc)
                        return rc;
        }
@@ -377,18 +334,6 @@ int jffs2_init_acl_post(struct inode *inode)
        return 0;
 }
 
-void jffs2_clear_acl(struct jffs2_inode_info *f)
-{
-       if (f->i_acl_access && f->i_acl_access != JFFS2_ACL_NOT_CACHED) {
-               posix_acl_release(f->i_acl_access);
-               f->i_acl_access = JFFS2_ACL_NOT_CACHED;
-       }
-       if (f->i_acl_default && f->i_acl_default != JFFS2_ACL_NOT_CACHED) {
-               posix_acl_release(f->i_acl_default);
-               f->i_acl_default = JFFS2_ACL_NOT_CACHED;
-       }
-}
-
 int jffs2_acl_chmod(struct inode *inode)
 {
        struct posix_acl *acl, *clone;
index 8ca058aed3840fa5f8c13c5b733127c473899739..fc929f2a14f6bfe16d1554767f67abe52986d137 100644 (file)
@@ -26,13 +26,10 @@ struct jffs2_acl_header {
 
 #ifdef CONFIG_JFFS2_FS_POSIX_ACL
 
-#define JFFS2_ACL_NOT_CACHED ((void *)-1)
-
 extern int jffs2_permission(struct inode *, int);
 extern int jffs2_acl_chmod(struct inode *);
 extern int jffs2_init_acl_pre(struct inode *, struct inode *, int *);
 extern int jffs2_init_acl_post(struct inode *);
-extern void jffs2_clear_acl(struct jffs2_inode_info *);
 
 extern struct xattr_handler jffs2_acl_access_xattr_handler;
 extern struct xattr_handler jffs2_acl_default_xattr_handler;
@@ -43,6 +40,5 @@ extern struct xattr_handler jffs2_acl_default_xattr_handler;
 #define jffs2_acl_chmod(inode)                 (0)
 #define jffs2_init_acl_pre(dir_i,inode,mode)   (0)
 #define jffs2_init_acl_post(inode)             (0)
-#define jffs2_clear_acl(f)
 
 #endif /* CONFIG_JFFS2_FS_POSIX_ACL */
index a0244740b75a4d9aa04eff4beb8cacb147a63ab2..b47679be118a5fe00a04585d54b07f9797e7f700 100644 (file)
@@ -270,19 +270,21 @@ static inline void jffs2_remove_node_refs_from_ino_list(struct jffs2_sb_info *c,
        D2({
                int i=0;
                struct jffs2_raw_node_ref *this;
-               printk(KERN_DEBUG "After remove_node_refs_from_ino_list: \n" KERN_DEBUG);
+               printk(KERN_DEBUG "After remove_node_refs_from_ino_list: \n");
 
                this = ic->nodes;
 
+               printk(KERN_DEBUG);
                while(this) {
-                       printk( "0x%08x(%d)->", ref_offset(this), ref_flags(this));
+                       printk(KERN_CONT "0x%08x(%d)->",
+                              ref_offset(this), ref_flags(this));
                        if (++i == 5) {
-                               printk("\n" KERN_DEBUG);
+                               printk(KERN_DEBUG);
                                i=0;
                        }
                        this = this->next_in_ino;
                }
-               printk("\n");
+               printk(KERN_CONT "\n");
        });
 
        switch (ic->class) {
index 4c41db91eaa45bffb0566d401d4a915abea4e32b..c6923da98263331c39dd3eea3d5c3c5f6232f39a 100644 (file)
@@ -50,10 +50,6 @@ struct jffs2_inode_info {
        uint16_t flags;
        uint8_t usercompr;
        struct inode vfs_inode;
-#ifdef CONFIG_JFFS2_FS_POSIX_ACL
-       struct posix_acl *i_acl_access;
-       struct posix_acl *i_acl_default;
-#endif
 };
 
 #endif /* _JFFS2_FS_I */
index 2228380c47b9e15435e05dd2e6768af0b1b80f6e..a7f03b7ebcb3c981777de0f64572957ed04ff03a 100644 (file)
@@ -56,10 +56,6 @@ static inline void jffs2_init_inode_info(struct jffs2_inode_info *f)
        f->target = NULL;
        f->flags = 0;
        f->usercompr = 0;
-#ifdef CONFIG_JFFS2_FS_POSIX_ACL
-       f->i_acl_access = JFFS2_ACL_NOT_CACHED;
-       f->i_acl_default = JFFS2_ACL_NOT_CACHED;
-#endif
 }
 
 
index 1fc1e92356eeb8f2a5c115082edf0109bb37a6db..1a80301004b8d82806c6dcdbf90a9bb4cbd71d5a 100644 (file)
@@ -1424,7 +1424,6 @@ void jffs2_do_clear_inode(struct jffs2_sb_info *c, struct jffs2_inode_info *f)
        struct jffs2_full_dirent *fd, *fds;
        int deleted;
 
-       jffs2_clear_acl(f);
        jffs2_xattr_delete_inode(c, f->inocache);
        mutex_lock(&f->sem);
        deleted = f->inocache && !f->inocache->pino_nlink;
index 7515e73e2bfbd0729069b0ec0f16df2da74f71a6..696686cc206e1d807df1b6706a4a1a54f3f6b2bf 100644 (file)
@@ -130,9 +130,9 @@ int jffs2_scan_medium(struct jffs2_sb_info *c)
        if (jffs2_sum_active()) {
                s = kzalloc(sizeof(struct jffs2_summary), GFP_KERNEL);
                if (!s) {
-                       kfree(flashbuf);
                        JFFS2_WARNING("Can't allocate memory for summary\n");
-                       return -ENOMEM;
+                       ret = -ENOMEM;
+                       goto out;
                }
        }
 
index 07a22caf26878223efffacdb01c69e23d4ce7a47..0035c021395ac840cd71bd38c82f28b4ad154f19 100644 (file)
@@ -12,6 +12,7 @@
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/slab.h>
+#include <linux/smp_lock.h>
 #include <linux/init.h>
 #include <linux/list.h>
 #include <linux/fs.h>
index 06ca1b8d205459e2a2bbbfb35282d0f576ee788c..91fa3ad6e8c2dc01144bcf1ab56c250a9c9e54bb 100644 (file)
@@ -31,27 +31,24 @@ static struct posix_acl *jfs_get_acl(struct inode *inode, int type)
 {
        struct posix_acl *acl;
        char *ea_name;
-       struct jfs_inode_info *ji = JFS_IP(inode);
-       struct posix_acl **p_acl;
        int size;
        char *value = NULL;
 
+       acl = get_cached_acl(inode, type);
+       if (acl != ACL_NOT_CACHED)
+               return acl;
+
        switch(type) {
                case ACL_TYPE_ACCESS:
                        ea_name = POSIX_ACL_XATTR_ACCESS;
-                       p_acl = &ji->i_acl;
                        break;
                case ACL_TYPE_DEFAULT:
                        ea_name = POSIX_ACL_XATTR_DEFAULT;
-                       p_acl = &ji->i_default_acl;
                        break;
                default:
                        return ERR_PTR(-EINVAL);
        }
 
-       if (*p_acl != JFS_ACL_NOT_CACHED)
-               return posix_acl_dup(*p_acl);
-
        size = __jfs_getxattr(inode, ea_name, NULL, 0);
 
        if (size > 0) {
@@ -62,17 +59,18 @@ static struct posix_acl *jfs_get_acl(struct inode *inode, int type)
        }
 
        if (size < 0) {
-               if (size == -ENODATA) {
-                       *p_acl = NULL;
+               if (size == -ENODATA)
                        acl = NULL;
-               else
+               else
                        acl = ERR_PTR(size);
        } else {
                acl = posix_acl_from_xattr(value, size);
-               if (!IS_ERR(acl))
-                       *p_acl = posix_acl_dup(acl);
        }
        kfree(value);
+       if (!IS_ERR(acl)) {
+               set_cached_acl(inode, type, acl);
+               posix_acl_release(acl);
+       }
        return acl;
 }
 
@@ -80,8 +78,6 @@ static int jfs_set_acl(tid_t tid, struct inode *inode, int type,
                       struct posix_acl *acl)
 {
        char *ea_name;
-       struct jfs_inode_info *ji = JFS_IP(inode);
-       struct posix_acl **p_acl;
        int rc;
        int size = 0;
        char *value = NULL;
@@ -92,11 +88,9 @@ static int jfs_set_acl(tid_t tid, struct inode *inode, int type,
        switch(type) {
                case ACL_TYPE_ACCESS:
                        ea_name = POSIX_ACL_XATTR_ACCESS;
-                       p_acl = &ji->i_acl;
                        break;
                case ACL_TYPE_DEFAULT:
                        ea_name = POSIX_ACL_XATTR_DEFAULT;
-                       p_acl = &ji->i_default_acl;
                        if (!S_ISDIR(inode->i_mode))
                                return acl ? -EACCES : 0;
                        break;
@@ -116,27 +110,24 @@ static int jfs_set_acl(tid_t tid, struct inode *inode, int type,
 out:
        kfree(value);
 
-       if (!rc) {
-               if (*p_acl && (*p_acl != JFS_ACL_NOT_CACHED))
-                       posix_acl_release(*p_acl);
-               *p_acl = posix_acl_dup(acl);
-       }
+       if (!rc)
+               set_cached_acl(inode, type, acl);
+
        return rc;
 }
 
 static int jfs_check_acl(struct inode *inode, int mask)
 {
-       struct jfs_inode_info *ji = JFS_IP(inode);
+       struct posix_acl *acl = jfs_get_acl(inode, ACL_TYPE_ACCESS);
 
-       if (ji->i_acl == JFS_ACL_NOT_CACHED) {
-               struct posix_acl *acl = jfs_get_acl(inode, ACL_TYPE_ACCESS);
-               if (IS_ERR(acl))
-                       return PTR_ERR(acl);
+       if (IS_ERR(acl))
+               return PTR_ERR(acl);
+       if (acl) {
+               int error = posix_acl_permission(inode, acl, mask);
                posix_acl_release(acl);
+               return error;
        }
 
-       if (ji->i_acl)
-               return posix_acl_permission(inode, ji->i_acl, mask);
        return -EAGAIN;
 }
 
index 439901d205feaf1b1a0243ea6141490267f1be30..1439f119ec830876ded18b7c5bf66b2ed1fdc80d 100644 (file)
@@ -74,10 +74,6 @@ struct jfs_inode_info {
        /* xattr_sem allows us to access the xattrs without taking i_mutex */
        struct rw_semaphore xattr_sem;
        lid_t   xtlid;          /* lid of xtree lock on directory */
-#ifdef CONFIG_JFS_POSIX_ACL
-       struct posix_acl *i_acl;
-       struct posix_acl *i_default_acl;
-#endif
        union {
                struct {
                        xtpage_t _xtroot;       /* 288: xtree root */
@@ -107,8 +103,6 @@ struct jfs_inode_info {
 #define i_inline u.link._inline
 #define i_inline_ea u.link._inline_ea
 
-#define JFS_ACL_NOT_CACHED ((void *)-1)
-
 #define IREAD_LOCK(ip, subclass) \
        down_read_nested(&JFS_IP(ip)->rdwrlock, subclass)
 #define IREAD_UNLOCK(ip)       up_read(&JFS_IP(ip)->rdwrlock)
index 09b1b6ee21861507e834d7e32322db15d5b957bb..37e6dcda8fc84f587508f8db58abdecee69524e1 100644 (file)
@@ -128,18 +128,6 @@ static void jfs_destroy_inode(struct inode *inode)
                ji->active_ag = -1;
        }
        spin_unlock_irq(&ji->ag_lock);
-
-#ifdef CONFIG_JFS_POSIX_ACL
-       if (ji->i_acl != JFS_ACL_NOT_CACHED) {
-               posix_acl_release(ji->i_acl);
-               ji->i_acl = JFS_ACL_NOT_CACHED;
-       }
-       if (ji->i_default_acl != JFS_ACL_NOT_CACHED) {
-               posix_acl_release(ji->i_default_acl);
-               ji->i_default_acl = JFS_ACL_NOT_CACHED;
-       }
-#endif
-
        kmem_cache_free(jfs_inode_cachep, ji);
 }
 
@@ -798,10 +786,6 @@ static void init_once(void *foo)
        init_rwsem(&jfs_ip->xattr_sem);
        spin_lock_init(&jfs_ip->ag_lock);
        jfs_ip->active_ag = -1;
-#ifdef CONFIG_JFS_POSIX_ACL
-       jfs_ip->i_acl = JFS_ACL_NOT_CACHED;
-       jfs_ip->i_default_acl = JFS_ACL_NOT_CACHED;
-#endif
        inode_init_once(&jfs_ip->vfs_inode);
 }
 
index 61dfa8173ebccdba37a099d1b2299716b6e89218..fad364548bc9e3716b08dc0f6ca66a58d1f9b56c 100644 (file)
@@ -727,10 +727,7 @@ static int can_set_system_xattr(struct inode *inode, const char *name,
                /*
                 * We're changing the ACL.  Get rid of the cached one
                 */
-               acl =JFS_IP(inode)->i_acl;
-               if (acl != JFS_ACL_NOT_CACHED)
-                       posix_acl_release(acl);
-               JFS_IP(inode)->i_acl = JFS_ACL_NOT_CACHED;
+               forget_cached_acl(inode, ACL_TYPE_ACCESS);
 
                return 0;
        } else if (strcmp(name, POSIX_ACL_XATTR_DEFAULT) == 0) {
@@ -746,10 +743,7 @@ static int can_set_system_xattr(struct inode *inode, const char *name,
                /*
                 * We're changing the default ACL.  Get rid of the cached one
                 */
-               acl =JFS_IP(inode)->i_default_acl;
-               if (acl && (acl != JFS_ACL_NOT_CACHED))
-                       posix_acl_release(acl);
-               JFS_IP(inode)->i_default_acl = JFS_ACL_NOT_CACHED;
+               forget_cached_acl(inode, ACL_TYPE_DEFAULT);
 
                return 0;
        }
index f2fdcbce143efa9bb43ed363301674e0db179294..4336adba952a770343150468053a866fe49016c7 100644 (file)
@@ -7,6 +7,7 @@
  */
 
 #include <linux/module.h>
+#include <linux/smp_lock.h>
 #include <linux/types.h>
 #include <linux/errno.h>
 #include <linux/fs.h>
index 1725037374c595e3919f2cbb566f33593fd388f1..bd173a6ca3b1b0723b29d796ca77d6883f4fd25f 100644 (file)
@@ -10,6 +10,7 @@
 #include <linux/types.h>
 #include <linux/time.h>
 #include <linux/slab.h>
+#include <linux/smp_lock.h>
 #include <linux/in.h>
 #include <linux/sunrpc/svc.h>
 #include <linux/sunrpc/clnt.h>
index 3688e55901fc48e733c24329d05e140252004648..e1d28ddd21699060a8b1e0907a8806bea9e62f95 100644 (file)
@@ -10,6 +10,7 @@
 #include <linux/types.h>
 #include <linux/time.h>
 #include <linux/slab.h>
+#include <linux/smp_lock.h>
 #include <linux/in.h>
 #include <linux/sunrpc/svc.h>
 #include <linux/sunrpc/clnt.h>
index 527119afb6a5cca3bea37efde7e6206e04052795..f3c5b278895a0d3e0f23fe6fd474e2728a1c6cb6 100644 (file)
@@ -1698,8 +1698,11 @@ struct file *do_filp_open(int dfd, const char *pathname,
        if (error)
                return ERR_PTR(error);
        error = path_walk(pathname, &nd);
-       if (error)
+       if (error) {
+               if (nd.root.mnt)
+                       path_put(&nd.root);
                return ERR_PTR(error);
+       }
        if (unlikely(!audit_dummy_context()))
                audit_inode(pathname, nd.path.dentry);
 
@@ -1758,7 +1761,13 @@ do_last:
                        goto exit;
                }
                filp = nameidata_to_filp(&nd, open_flag);
+               if (IS_ERR(filp))
+                       ima_counts_put(&nd.path,
+                                      acc_mode & (MAY_READ | MAY_WRITE |
+                                                  MAY_EXEC));
                mnt_drop_write(nd.path.mnt);
+               if (nd.root.mnt)
+                       path_put(&nd.root);
                return filp;
        }
 
@@ -1812,6 +1821,9 @@ ok:
                goto exit;
        }
        filp = nameidata_to_filp(&nd, open_flag);
+       if (IS_ERR(filp))
+               ima_counts_put(&nd.path,
+                              acc_mode & (MAY_READ | MAY_WRITE | MAY_EXEC));
        /*
         * It is now safe to drop the mnt write
         * because the filp has had a write taken
@@ -1819,6 +1831,8 @@ ok:
         */
        if (will_write)
                mnt_drop_write(nd.path.mnt);
+       if (nd.root.mnt)
+               path_put(&nd.root);
        return filp;
 
 exit_mutex_unlock:
@@ -1859,6 +1873,8 @@ do_link:
                 * with "intent.open".
                 */
                release_open_intent(&nd);
+               if (nd.root.mnt)
+                       path_put(&nd.root);
                return ERR_PTR(error);
        }
        nd.flags &= ~LOOKUP_PARENT;
index a7bea8c8bd469e7760aa1dc098478eef5b1be518..277c28a63ead1b564313cd21363bec9c15b2bf2e 100644 (file)
@@ -22,6 +22,7 @@
 #include <linux/seq_file.h>
 #include <linux/mnt_namespace.h>
 #include <linux/namei.h>
+#include <linux/nsproxy.h>
 #include <linux/security.h>
 #include <linux/mount.h>
 #include <linux/ramfs.h>
@@ -42,6 +43,8 @@ __cacheline_aligned_in_smp DEFINE_SPINLOCK(vfsmount_lock);
 static int event;
 static DEFINE_IDA(mnt_id_ida);
 static DEFINE_IDA(mnt_group_ida);
+static int mnt_id_start = 0;
+static int mnt_group_start = 1;
 
 static struct list_head *mount_hashtable __read_mostly;
 static struct kmem_cache *mnt_cache __read_mostly;
@@ -69,7 +72,9 @@ static int mnt_alloc_id(struct vfsmount *mnt)
 retry:
        ida_pre_get(&mnt_id_ida, GFP_KERNEL);
        spin_lock(&vfsmount_lock);
-       res = ida_get_new(&mnt_id_ida, &mnt->mnt_id);
+       res = ida_get_new_above(&mnt_id_ida, mnt_id_start, &mnt->mnt_id);
+       if (!res)
+               mnt_id_start = mnt->mnt_id + 1;
        spin_unlock(&vfsmount_lock);
        if (res == -EAGAIN)
                goto retry;
@@ -79,8 +84,11 @@ retry:
 
 static void mnt_free_id(struct vfsmount *mnt)
 {
+       int id = mnt->mnt_id;
        spin_lock(&vfsmount_lock);
-       ida_remove(&mnt_id_ida, mnt->mnt_id);
+       ida_remove(&mnt_id_ida, id);
+       if (mnt_id_start > id)
+               mnt_id_start = id;
        spin_unlock(&vfsmount_lock);
 }
 
@@ -91,10 +99,18 @@ static void mnt_free_id(struct vfsmount *mnt)
  */
 static int mnt_alloc_group_id(struct vfsmount *mnt)
 {
+       int res;
+
        if (!ida_pre_get(&mnt_group_ida, GFP_KERNEL))
                return -ENOMEM;
 
-       return ida_get_new_above(&mnt_group_ida, 1, &mnt->mnt_group_id);
+       res = ida_get_new_above(&mnt_group_ida,
+                               mnt_group_start,
+                               &mnt->mnt_group_id);
+       if (!res)
+               mnt_group_start = mnt->mnt_group_id + 1;
+
+       return res;
 }
 
 /*
@@ -102,7 +118,10 @@ static int mnt_alloc_group_id(struct vfsmount *mnt)
  */
 void mnt_release_group_id(struct vfsmount *mnt)
 {
-       ida_remove(&mnt_group_ida, mnt->mnt_group_id);
+       int id = mnt->mnt_group_id;
+       ida_remove(&mnt_group_ida, id);
+       if (mnt_group_start > id)
+               mnt_group_start = id;
        mnt->mnt_group_id = 0;
 }
 
@@ -2222,16 +2241,9 @@ static void __init init_mount_tree(void)
        mnt = do_kern_mount("rootfs", 0, "rootfs", NULL);
        if (IS_ERR(mnt))
                panic("Can't create rootfs");
-       ns = kmalloc(sizeof(*ns), GFP_KERNEL);
-       if (!ns)
+       ns = create_mnt_ns(mnt);
+       if (IS_ERR(ns))
                panic("Can't allocate initial namespace");
-       atomic_set(&ns->count, 1);
-       INIT_LIST_HEAD(&ns->list);
-       init_waitqueue_head(&ns->poll);
-       ns->event = 0;
-       list_add(&mnt->mnt_list, &ns->list);
-       ns->root = mnt;
-       mnt->mnt_ns = ns;
 
        init_task.nsproxy->mnt_ns = ns;
        get_mnt_ns(ns);
index af05b918cb5bcce6655aee1d16adaf9000fe9d25..6dd48a4405b46d409af629d4195b27b17e83dab1 100644 (file)
@@ -10,6 +10,7 @@
 #include <linux/kthread.h>
 #include <linux/module.h>
 #include <linux/sched.h>
+#include <linux/smp_lock.h>
 #include <linux/spinlock.h>
 
 #include <linux/nfs4.h>
index 89f98e9a024b73accbfce55d575834e9357be491..38d42c29fb923191e38e7fa045b05f49a808b0ab 100644 (file)
@@ -29,7 +29,6 @@
 #include <linux/nfs_fs.h>
 #include <linux/nfs_mount.h>
 #include <linux/pagemap.h>
-#include <linux/smp_lock.h>
 #include <linux/pagevec.h>
 #include <linux/namei.h>
 #include <linux/mount.h>
index 0055b813ec2c7004e9647ad781c3706066aeac3e..05062329b678a148c464990b0f9d4f6a68ab617f 100644 (file)
@@ -26,7 +26,6 @@
 #include <linux/mm.h>
 #include <linux/slab.h>
 #include <linux/pagemap.h>
-#include <linux/smp_lock.h>
 #include <linux/aio.h>
 
 #include <asm/uaccess.h>
index 46177cb8706402cff250c18a7b10640deee0b38f..b35d2a616066ada8029be5e62b8a23dca6988113 100644 (file)
@@ -30,7 +30,6 @@
 #include <linux/nfs_idmap.h>
 #include <linux/vfs.h>
 #include <linux/namei.h>
-#include <linux/mnt_namespace.h>
 #include <linux/security.h>
 
 #include <asm/system.h>
index 64f87194d3907620709c5413f23c95324b23afd9..bd7938eda6a8258a6e3ced41f495b78ab57afb3d 100644 (file)
@@ -30,7 +30,6 @@
 #include <linux/nfs_mount.h>
 #include <linux/nfs4_mount.h>
 #include <linux/lockd/bind.h>
-#include <linux/smp_lock.h>
 #include <linux/seq_file.h>
 #include <linux/mount.h>
 #include <linux/nfs_idmap.h>
index 92ce4351781459e648958e58c0cf59d106b3bc5c..ff0c080db59bd01f2b715a701aa256256abd136f 100644 (file)
@@ -45,7 +45,6 @@
 #include <linux/nfs4.h>
 #include <linux/nfs_fs.h>
 #include <linux/nfs_page.h>
-#include <linux/smp_lock.h>
 #include <linux/namei.h>
 #include <linux/mount.h>
 #include <linux/module.h>
index 96c4ebfa46f4f8892b125fcf59bdb300cc2f01ad..73ea5e8d66ceebbfab4079c4ab91b62809093ed7 100644 (file)
@@ -18,7 +18,6 @@
 #include <linux/sunrpc/clnt.h>
 #include <linux/nfs_fs.h>
 #include <linux/nfs_page.h>
-#include <linux/smp_lock.h>
 
 #include <asm/system.h>
 
index ce728829f79a5dce2b238ccbe763631adec71343..0a0a2ff767c318d5924c603a3f67ed7f5ccc9402 100644 (file)
@@ -202,8 +202,10 @@ static int nfs_set_page_writeback(struct page *page)
                struct nfs_server *nfss = NFS_SERVER(inode);
 
                if (atomic_long_inc_return(&nfss->writeback) >
-                               NFS_CONGESTION_ON_THRESH)
-                       set_bdi_congested(&nfss->backing_dev_info, WRITE);
+                               NFS_CONGESTION_ON_THRESH) {
+                       set_bdi_congested(&nfss->backing_dev_info,
+                                               BLK_RW_ASYNC);
+               }
        }
        return ret;
 }
@@ -215,7 +217,7 @@ static void nfs_end_page_writeback(struct page *page)
 
        end_page_writeback(page);
        if (atomic_long_dec_return(&nfss->writeback) < NFS_CONGESTION_OFF_THRESH)
-               clear_bdi_congested(&nfss->backing_dev_info, WRITE);
+               clear_bdi_congested(&nfss->backing_dev_info, BLK_RW_ASYNC);
 }
 
 /*
index 1250fb978ac1451b8d00f87bfe5183eb12d9f26f..6d0847562d876374a6e5ba838651af37c00aad2d 100644 (file)
@@ -25,7 +25,6 @@
 #include <linux/init.h>
 #include <linux/inet.h>
 #include <linux/string.h>
-#include <linux/smp_lock.h>
 #include <linux/ctype.h>
 
 #include <linux/nfs.h>
index d4c9884cd54b2bf680cc2360eaa1a9f20dec8b55..492c79b7800b5b7fcb4f8a8813b2d369a5039d7a 100644 (file)
@@ -18,7 +18,6 @@
 #include <linux/unistd.h>
 #include <linux/slab.h>
 #include <linux/smp.h>
-#include <linux/smp_lock.h>
 #include <linux/freezer.h>
 #include <linux/fs_struct.h>
 #include <linux/kthread.h>
index 4145083dcf8817ed883652939cac1faa4dfd7cac..23341c1063bcd05fb2841dc6b49d0a91eef36293 100644 (file)
@@ -678,7 +678,6 @@ __be32
 nfsd_open(struct svc_rqst *rqstp, struct svc_fh *fhp, int type,
                        int access, struct file **filp)
 {
-       const struct cred *cred = current_cred();
        struct dentry   *dentry;
        struct inode    *inode;
        int             flags = O_RDONLY|O_LARGEFILE;
@@ -733,7 +732,7 @@ nfsd_open(struct svc_rqst *rqstp, struct svc_fh *fhp, int type,
                vfs_dq_init(inode);
        }
        *filp = dentry_open(dget(dentry), mntget(fhp->fh_export->ex_path.mnt),
-                           flags, cred);
+                           flags, current_cred());
        if (IS_ERR(*filp))
                host_err = PTR_ERR(*filp);
        else
index 36df60b6d8a4b79e9fde8f0f58e3a76ee8d0a1f4..99d58a028b94c3c9698661bac527e14ed2812a72 100644 (file)
@@ -568,6 +568,7 @@ void nilfs_bmap_abort_update_v(struct nilfs_bmap *bmap,
 }
 
 static struct lock_class_key nilfs_bmap_dat_lock_key;
+static struct lock_class_key nilfs_bmap_mdt_lock_key;
 
 /**
  * nilfs_bmap_read - read a bmap from an inode
@@ -603,7 +604,11 @@ int nilfs_bmap_read(struct nilfs_bmap *bmap, struct nilfs_inode *raw_inode)
                bmap->b_ptr_type = NILFS_BMAP_PTR_VS;
                bmap->b_last_allocated_key = 0;
                bmap->b_last_allocated_ptr = NILFS_BMAP_INVALID_PTR;
+               lockdep_set_class(&bmap->b_sem, &nilfs_bmap_mdt_lock_key);
                break;
+       case NILFS_IFILE_INO:
+               lockdep_set_class(&bmap->b_sem, &nilfs_bmap_mdt_lock_key);
+               /* Fall through */
        default:
                bmap->b_ptr_type = NILFS_BMAP_PTR_VM;
                bmap->b_last_allocated_key = 0;
index 7d49813f66d6c157d95c9ec8f6568379fa71565c..aec942cf79e34cc35764d270e645fd3f24a29229 100644 (file)
@@ -307,7 +307,7 @@ int nilfs_cpfile_delete_checkpoints(struct inode *cpfile,
                ret = nilfs_cpfile_get_checkpoint_block(cpfile, cno, 0, &cp_bh);
                if (ret < 0) {
                        if (ret != -ENOENT)
-                               goto out_header;
+                               break;
                        /* skip hole */
                        ret = 0;
                        continue;
@@ -340,7 +340,7 @@ int nilfs_cpfile_delete_checkpoints(struct inode *cpfile,
                                        continue;
                                printk(KERN_ERR "%s: cannot delete block\n",
                                       __func__);
-                               goto out_header;
+                               break;
                        }
                }
 
@@ -358,7 +358,6 @@ int nilfs_cpfile_delete_checkpoints(struct inode *cpfile,
                kunmap_atomic(kaddr, KM_USER0);
        }
 
- out_header:
        brelse(header_bh);
 
  out_sem:
index 0b2710e2d56547ac7aa36b6367e5ed6f36685c49..8927ca27e6f79cbd82db5028d5dfd002baa99bb0 100644 (file)
@@ -134,15 +134,6 @@ void nilfs_dat_commit_start(struct inode *dat, struct nilfs_palloc_req *req,
        entry = nilfs_palloc_block_get_entry(dat, req->pr_entry_nr,
                                             req->pr_entry_bh, kaddr);
        entry->de_start = cpu_to_le64(nilfs_mdt_cno(dat));
-       if (entry->de_blocknr != cpu_to_le64(0) ||
-           entry->de_end != cpu_to_le64(NILFS_CNO_MAX)) {
-               printk(KERN_CRIT
-                      "%s: vbn = %llu, start = %llu, end = %llu, pbn = %llu\n",
-                      __func__, (unsigned long long)req->pr_entry_nr,
-                      (unsigned long long)le64_to_cpu(entry->de_start),
-                      (unsigned long long)le64_to_cpu(entry->de_end),
-                      (unsigned long long)le64_to_cpu(entry->de_blocknr));
-       }
        entry->de_blocknr = cpu_to_le64(blocknr);
        kunmap_atomic(kaddr, KM_USER0);
 
index 54100acc1102706ed6c39116b89f7fbaa6c72f02..1a4fa04cf071bd8a82ae9f21d079612e963b419b 100644 (file)
@@ -43,7 +43,6 @@
  */
 
 #include <linux/pagemap.h>
-#include <linux/smp_lock.h>
 #include "nilfs.h"
 #include "page.h"
 
index 2696d6b513b7177d2efb9c2805ca878ebf0277a3..fe9d8f2a13f8785bf366f0a5884261af8ccfd782 100644 (file)
@@ -309,10 +309,6 @@ struct inode *nilfs_new_inode(struct inode *dir, int mode)
        /* ii->i_file_acl = 0; */
        /* ii->i_dir_acl = 0; */
        ii->i_dir_start_lookup = 0;
-#ifdef CONFIG_NILFS_FS_POSIX_ACL
-       ii->i_acl = NULL;
-       ii->i_default_acl = NULL;
-#endif
        ii->i_cno = 0;
        nilfs_set_inode_flags(inode);
        spin_lock(&sbi->s_next_gen_lock);
@@ -434,10 +430,6 @@ static int __nilfs_read_inode(struct super_block *sb, unsigned long ino,
 
        raw_inode = nilfs_ifile_map_inode(sbi->s_ifile, ino, bh);
 
-#ifdef CONFIG_NILFS_FS_POSIX_ACL
-       ii->i_acl = NILFS_ACL_NOT_CACHED;
-       ii->i_default_acl = NILFS_ACL_NOT_CACHED;
-#endif
        if (nilfs_read_inode_common(inode, raw_inode))
                goto failed_unmap;
 
index edf6a59d9f2a1710e404e45250308dfa06ba28f9..724c63766e827c9232bd197a99b93af8064aea20 100644 (file)
@@ -57,10 +57,6 @@ struct nilfs_inode_info {
         * EAs.
         */
        struct rw_semaphore xattr_sem;
-#endif
-#ifdef CONFIG_NILFS_POSIX_ACL
-       struct posix_acl *i_acl;
-       struct posix_acl *i_default_acl;
 #endif
        struct buffer_head *i_bh;       /* i_bh contains a new or dirty
                                           disk inode */
index aa977549919ecd2d92d40ff3d3d4f17f207f4814..8b5e4778cf28bc780fcf516400ccc7a2e963c076 100644 (file)
@@ -1829,26 +1829,13 @@ static int nilfs_segctor_write(struct nilfs_sc_info *sci,
                err = nilfs_segbuf_write(segbuf, &wi);
 
                res = nilfs_segbuf_wait(segbuf, &wi);
-               err = unlikely(err) ? : res;
-               if (unlikely(err))
+               err = err ? : res;
+               if (err)
                        return err;
        }
        return 0;
 }
 
-static int nilfs_page_has_uncleared_buffer(struct page *page)
-{
-       struct buffer_head *head, *bh;
-
-       head = bh = page_buffers(page);
-       do {
-               if (buffer_dirty(bh) && !list_empty(&bh->b_assoc_buffers))
-                       return 1;
-               bh = bh->b_this_page;
-       } while (bh != head);
-       return 0;
-}
-
 static void __nilfs_end_page_io(struct page *page, int err)
 {
        if (!err) {
@@ -1872,12 +1859,11 @@ static void nilfs_end_page_io(struct page *page, int err)
        if (!page)
                return;
 
-       if (buffer_nilfs_node(page_buffers(page)) &&
-           nilfs_page_has_uncleared_buffer(page))
-               /* For b-tree node pages, this function may be called twice
-                  or more because they might be split in a segment.
-                  This check assures that cleanup has been done for all
-                  buffers in a split btnode page. */
+       if (buffer_nilfs_node(page_buffers(page)) && !PageWriteback(page))
+               /*
+                * For b-tree node pages, this function may be called twice
+                * or more because they might be split in a segment.
+                */
                return;
 
        __nilfs_end_page_io(page, err);
@@ -1940,7 +1926,7 @@ static void nilfs_segctor_abort_write(struct nilfs_sc_info *sci,
                        }
                        if (bh->b_page != fs_page) {
                                nilfs_end_page_io(fs_page, err);
-                               if (unlikely(fs_page == failed_page))
+                               if (fs_page && fs_page == failed_page)
                                        goto done;
                                fs_page = bh->b_page;
                        }
index ab785f85aa501abb40691a61b24395e0419c62f8..8e2ec43b18f4f458b6f683fc94a9f656a36a9c3a 100644 (file)
@@ -189,16 +189,6 @@ static void nilfs_clear_inode(struct inode *inode)
 {
        struct nilfs_inode_info *ii = NILFS_I(inode);
 
-#ifdef CONFIG_NILFS_POSIX_ACL
-       if (ii->i_acl && ii->i_acl != NILFS_ACL_NOT_CACHED) {
-               posix_acl_release(ii->i_acl);
-               ii->i_acl = NILFS_ACL_NOT_CACHED;
-       }
-       if (ii->i_default_acl && ii->i_default_acl != NILFS_ACL_NOT_CACHED) {
-               posix_acl_release(ii->i_default_acl);
-               ii->i_default_acl = NILFS_ACL_NOT_CACHED;
-       }
-#endif
        /*
         * Free resources allocated in nilfs_read_inode(), here.
         */
index ff231ad23895ea179a5507ace2e4ca5c54db1470..ff27a2965844cbc20ea56279cc419ea1c584faf5 100644 (file)
@@ -296,12 +296,15 @@ static int inotify_fasync(int fd, struct file *file, int on)
 static int inotify_release(struct inode *ignored, struct file *file)
 {
        struct fsnotify_group *group = file->private_data;
+       struct user_struct *user = group->inotify_data.user;
 
        fsnotify_clear_marks_by_group(group);
 
        /* free this group, matching get was inotify_init->fsnotify_obtain_group */
        fsnotify_put_group(group);
 
+       atomic_dec(&user->inotify_devs);
+
        return 0;
 }
 
index 6cdeaa76f27fec651b0c14f40a48e31f3aa8f71e..110bb57c46abe76bb83ae1b689e185684384c944 100644 (file)
@@ -92,6 +92,9 @@ struct ocfs2_unblock_ctl {
        enum ocfs2_unblock_action unblock_action;
 };
 
+/* Lockdep class keys */
+struct lock_class_key lockdep_keys[OCFS2_NUM_LOCK_TYPES];
+
 static int ocfs2_check_meta_downconvert(struct ocfs2_lock_res *lockres,
                                        int new_level);
 static void ocfs2_set_meta_lvb(struct ocfs2_lock_res *lockres);
@@ -317,9 +320,16 @@ static int ocfs2_lock_create(struct ocfs2_super *osb,
                             u32 dlm_flags);
 static inline int ocfs2_may_continue_on_blocked_lock(struct ocfs2_lock_res *lockres,
                                                     int wanted);
-static void ocfs2_cluster_unlock(struct ocfs2_super *osb,
-                                struct ocfs2_lock_res *lockres,
-                                int level);
+static void __ocfs2_cluster_unlock(struct ocfs2_super *osb,
+                                  struct ocfs2_lock_res *lockres,
+                                  int level, unsigned long caller_ip);
+static inline void ocfs2_cluster_unlock(struct ocfs2_super *osb,
+                                       struct ocfs2_lock_res *lockres,
+                                       int level)
+{
+       __ocfs2_cluster_unlock(osb, lockres, level, _RET_IP_);
+}
+
 static inline void ocfs2_generic_handle_downconvert_action(struct ocfs2_lock_res *lockres);
 static inline void ocfs2_generic_handle_convert_action(struct ocfs2_lock_res *lockres);
 static inline void ocfs2_generic_handle_attach_action(struct ocfs2_lock_res *lockres);
@@ -489,6 +499,13 @@ static void ocfs2_lock_res_init_common(struct ocfs2_super *osb,
        ocfs2_add_lockres_tracking(res, osb->osb_dlm_debug);
 
        ocfs2_init_lock_stats(res);
+#ifdef CONFIG_DEBUG_LOCK_ALLOC
+       if (type != OCFS2_LOCK_TYPE_OPEN)
+               lockdep_init_map(&res->l_lockdep_map, ocfs2_lock_type_strings[type],
+                                &lockdep_keys[type], 0);
+       else
+               res->l_lockdep_map.key = NULL;
+#endif
 }
 
 void ocfs2_lock_res_init_once(struct ocfs2_lock_res *res)
@@ -644,14 +661,10 @@ static void ocfs2_nfs_sync_lock_res_init(struct ocfs2_lock_res *res,
 static void ocfs2_orphan_scan_lock_res_init(struct ocfs2_lock_res *res,
                                            struct ocfs2_super *osb)
 {
-       struct ocfs2_orphan_scan_lvb *lvb;
-
        ocfs2_lock_res_init_once(res);
        ocfs2_build_lock_name(OCFS2_LOCK_TYPE_ORPHAN_SCAN, 0, 0, res->l_name);
        ocfs2_lock_res_init_common(osb, res, OCFS2_LOCK_TYPE_ORPHAN_SCAN,
                                   &ocfs2_orphan_scan_lops, osb);
-       lvb = ocfs2_dlm_lvb(&res->l_lksb);
-       lvb->lvb_version = OCFS2_ORPHAN_LVB_VERSION;
 }
 
 void ocfs2_file_lock_res_init(struct ocfs2_lock_res *lockres,
@@ -1256,11 +1269,13 @@ static int ocfs2_wait_for_mask_interruptible(struct ocfs2_mask_waiter *mw,
        return ret;
 }
 
-static int ocfs2_cluster_lock(struct ocfs2_super *osb,
-                             struct ocfs2_lock_res *lockres,
-                             int level,
-                             u32 lkm_flags,
-                             int arg_flags)
+static int __ocfs2_cluster_lock(struct ocfs2_super *osb,
+                               struct ocfs2_lock_res *lockres,
+                               int level,
+                               u32 lkm_flags,
+                               int arg_flags,
+                               int l_subclass,
+                               unsigned long caller_ip)
 {
        struct ocfs2_mask_waiter mw;
        int wait, catch_signals = !(osb->s_mount_opt & OCFS2_MOUNT_NOINTR);
@@ -1403,13 +1418,37 @@ out:
        }
        ocfs2_update_lock_stats(lockres, level, &mw, ret);
 
+#ifdef CONFIG_DEBUG_LOCK_ALLOC
+       if (!ret && lockres->l_lockdep_map.key != NULL) {
+               if (level == DLM_LOCK_PR)
+                       rwsem_acquire_read(&lockres->l_lockdep_map, l_subclass,
+                               !!(arg_flags & OCFS2_META_LOCK_NOQUEUE),
+                               caller_ip);
+               else
+                       rwsem_acquire(&lockres->l_lockdep_map, l_subclass,
+                               !!(arg_flags & OCFS2_META_LOCK_NOQUEUE),
+                               caller_ip);
+       }
+#endif
        mlog_exit(ret);
        return ret;
 }
 
-static void ocfs2_cluster_unlock(struct ocfs2_super *osb,
-                                struct ocfs2_lock_res *lockres,
-                                int level)
+static inline int ocfs2_cluster_lock(struct ocfs2_super *osb,
+                                    struct ocfs2_lock_res *lockres,
+                                    int level,
+                                    u32 lkm_flags,
+                                    int arg_flags)
+{
+       return __ocfs2_cluster_lock(osb, lockres, level, lkm_flags, arg_flags,
+                                   0, _RET_IP_);
+}
+
+
+static void __ocfs2_cluster_unlock(struct ocfs2_super *osb,
+                                  struct ocfs2_lock_res *lockres,
+                                  int level,
+                                  unsigned long caller_ip)
 {
        unsigned long flags;
 
@@ -1418,6 +1457,10 @@ static void ocfs2_cluster_unlock(struct ocfs2_super *osb,
        ocfs2_dec_holders(lockres, level);
        ocfs2_downconvert_on_unlock(osb, lockres);
        spin_unlock_irqrestore(&lockres->l_lock, flags);
+#ifdef CONFIG_DEBUG_LOCK_ALLOC
+       if (lockres->l_lockdep_map.key != NULL)
+               rwsem_release(&lockres->l_lockdep_map, 1, caller_ip);
+#endif
        mlog_exit_void();
 }
 
@@ -1989,7 +2032,8 @@ static inline int ocfs2_meta_lvb_is_trustable(struct inode *inode,
 {
        struct ocfs2_meta_lvb *lvb = ocfs2_dlm_lvb(&lockres->l_lksb);
 
-       if (lvb->lvb_version == OCFS2_LVB_VERSION
+       if (ocfs2_dlm_lvb_valid(&lockres->l_lksb)
+           && lvb->lvb_version == OCFS2_LVB_VERSION
            && be32_to_cpu(lvb->lvb_igeneration) == inode->i_generation)
                return 1;
        return 0;
@@ -2162,10 +2206,11 @@ static int ocfs2_assign_bh(struct inode *inode,
  * returns < 0 error if the callback will never be called, otherwise
  * the result of the lock will be communicated via the callback.
  */
-int ocfs2_inode_lock_full(struct inode *inode,
-                        struct buffer_head **ret_bh,
-                        int ex,
-                        int arg_flags)
+int ocfs2_inode_lock_full_nested(struct inode *inode,
+                                struct buffer_head **ret_bh,
+                                int ex,
+                                int arg_flags,
+                                int subclass)
 {
        int status, level, acquired;
        u32 dlm_flags;
@@ -2203,7 +2248,8 @@ int ocfs2_inode_lock_full(struct inode *inode,
        if (arg_flags & OCFS2_META_LOCK_NOQUEUE)
                dlm_flags |= DLM_LKF_NOQUEUE;
 
-       status = ocfs2_cluster_lock(osb, lockres, level, dlm_flags, arg_flags);
+       status = __ocfs2_cluster_lock(osb, lockres, level, dlm_flags,
+                                     arg_flags, subclass, _RET_IP_);
        if (status < 0) {
                if (status != -EAGAIN && status != -EIOCBRETRY)
                        mlog_errno(status);
@@ -2369,35 +2415,45 @@ void ocfs2_inode_unlock(struct inode *inode,
        mlog_exit_void();
 }
 
-int ocfs2_orphan_scan_lock(struct ocfs2_super *osb, u32 *seqno, int ex)
+int ocfs2_orphan_scan_lock(struct ocfs2_super *osb, u32 *seqno)
 {
        struct ocfs2_lock_res *lockres;
        struct ocfs2_orphan_scan_lvb *lvb;
-       int level = ex ? DLM_LOCK_EX : DLM_LOCK_PR;
        int status = 0;
 
+       if (ocfs2_is_hard_readonly(osb))
+               return -EROFS;
+
+       if (ocfs2_mount_local(osb))
+               return 0;
+
        lockres = &osb->osb_orphan_scan.os_lockres;
-       status = ocfs2_cluster_lock(osb, lockres, level, 0, 0);
+       status = ocfs2_cluster_lock(osb, lockres, DLM_LOCK_EX, 0, 0);
        if (status < 0)
                return status;
 
        lvb = ocfs2_dlm_lvb(&lockres->l_lksb);
-       if (lvb->lvb_version == OCFS2_ORPHAN_LVB_VERSION)
+       if (ocfs2_dlm_lvb_valid(&lockres->l_lksb) &&
+           lvb->lvb_version == OCFS2_ORPHAN_LVB_VERSION)
                *seqno = be32_to_cpu(lvb->lvb_os_seqno);
+       else
+               *seqno = osb->osb_orphan_scan.os_seqno + 1;
+
        return status;
 }
 
-void ocfs2_orphan_scan_unlock(struct ocfs2_super *osb, u32 seqno, int ex)
+void ocfs2_orphan_scan_unlock(struct ocfs2_super *osb, u32 seqno)
 {
        struct ocfs2_lock_res *lockres;
        struct ocfs2_orphan_scan_lvb *lvb;
-       int level = ex ? DLM_LOCK_EX : DLM_LOCK_PR;
 
-       lockres = &osb->osb_orphan_scan.os_lockres;
-       lvb = ocfs2_dlm_lvb(&lockres->l_lksb);
-       lvb->lvb_version = OCFS2_ORPHAN_LVB_VERSION;
-       lvb->lvb_os_seqno = cpu_to_be32(seqno);
-       ocfs2_cluster_unlock(osb, lockres, level);
+       if (!ocfs2_is_hard_readonly(osb) && !ocfs2_mount_local(osb)) {
+               lockres = &osb->osb_orphan_scan.os_lockres;
+               lvb = ocfs2_dlm_lvb(&lockres->l_lksb);
+               lvb->lvb_version = OCFS2_ORPHAN_LVB_VERSION;
+               lvb->lvb_os_seqno = cpu_to_be32(seqno);
+               ocfs2_cluster_unlock(osb, lockres, DLM_LOCK_EX);
+       }
 }
 
 int ocfs2_super_lock(struct ocfs2_super *osb,
@@ -3627,7 +3683,8 @@ static int ocfs2_refresh_qinfo(struct ocfs2_mem_dqinfo *oinfo)
        struct ocfs2_global_disk_dqinfo *gdinfo;
        int status = 0;
 
-       if (lvb->lvb_version == OCFS2_QINFO_LVB_VERSION) {
+       if (ocfs2_dlm_lvb_valid(&lockres->l_lksb) &&
+           lvb->lvb_version == OCFS2_QINFO_LVB_VERSION) {
                info->dqi_bgrace = be32_to_cpu(lvb->lvb_bgrace);
                info->dqi_igrace = be32_to_cpu(lvb->lvb_igrace);
                oinfo->dqi_syncms = be32_to_cpu(lvb->lvb_syncms);
index 31b90d7b8f51f0dc449da138e8e7b14f118aabb4..7553836931de8f7e5c5b72a9a55fdc3c428d94a9 100644 (file)
@@ -78,6 +78,14 @@ struct ocfs2_orphan_scan_lvb {
 /* don't block waiting for the downconvert thread, instead return -EAGAIN */
 #define OCFS2_LOCK_NONBLOCK            (0x04)
 
+/* Locking subclasses of inode cluster lock */
+enum {
+       OI_LS_NORMAL = 0,
+       OI_LS_PARENT,
+       OI_LS_RENAME1,
+       OI_LS_RENAME2,
+};
+
 int ocfs2_dlm_init(struct ocfs2_super *osb);
 void ocfs2_dlm_shutdown(struct ocfs2_super *osb, int hangup_pending);
 void ocfs2_lock_res_init_once(struct ocfs2_lock_res *res);
@@ -104,25 +112,31 @@ void ocfs2_open_unlock(struct inode *inode);
 int ocfs2_inode_lock_atime(struct inode *inode,
                          struct vfsmount *vfsmnt,
                          int *level);
-int ocfs2_inode_lock_full(struct inode *inode,
+int ocfs2_inode_lock_full_nested(struct inode *inode,
                         struct buffer_head **ret_bh,
                         int ex,
-                        int arg_flags);
+                        int arg_flags,
+                        int subclass);
 int ocfs2_inode_lock_with_page(struct inode *inode,
                              struct buffer_head **ret_bh,
                              int ex,
                              struct page *page);
+/* Variants without special locking class or flags */
+#define ocfs2_inode_lock_full(i, r, e, f)\
+               ocfs2_inode_lock_full_nested(i, r, e, f, OI_LS_NORMAL)
+#define ocfs2_inode_lock_nested(i, b, e, s)\
+               ocfs2_inode_lock_full_nested(i, b, e, 0, s)
 /* 99% of the time we don't want to supply any additional flags --
  * those are for very specific cases only. */
-#define ocfs2_inode_lock(i, b, e) ocfs2_inode_lock_full(i, b, e, 0)
+#define ocfs2_inode_lock(i, b, e) ocfs2_inode_lock_full_nested(i, b, e, 0, OI_LS_NORMAL)
 void ocfs2_inode_unlock(struct inode *inode,
                       int ex);
 int ocfs2_super_lock(struct ocfs2_super *osb,
                     int ex);
 void ocfs2_super_unlock(struct ocfs2_super *osb,
                        int ex);
-int ocfs2_orphan_scan_lock(struct ocfs2_super *osb, u32 *seqno, int ex);
-void ocfs2_orphan_scan_unlock(struct ocfs2_super *osb, u32 seqno, int ex);
+int ocfs2_orphan_scan_lock(struct ocfs2_super *osb, u32 *seqno);
+void ocfs2_orphan_scan_unlock(struct ocfs2_super *osb, u32 seqno);
 
 int ocfs2_rename_lock(struct ocfs2_super *osb);
 void ocfs2_rename_unlock(struct ocfs2_super *osb);
index 07267e0da909410294a3f330eb08fea5d1feefb8..62442e413a001cfbe57607c43e06d408418cf13e 100644 (file)
@@ -2026,7 +2026,7 @@ static ssize_t ocfs2_file_splice_read(struct file *in,
                                      size_t len,
                                      unsigned int flags)
 {
-       int ret = 0;
+       int ret = 0, lock_level = 0;
        struct inode *inode = in->f_path.dentry->d_inode;
 
        mlog_entry("(0x%p, 0x%p, %u, '%.*s')\n", in, pipe,
@@ -2037,12 +2037,12 @@ static ssize_t ocfs2_file_splice_read(struct file *in,
        /*
         * See the comment in ocfs2_file_aio_read()
         */
-       ret = ocfs2_inode_lock(inode, NULL, 0);
+       ret = ocfs2_inode_lock_atime(inode, in->f_vfsmnt, &lock_level);
        if (ret < 0) {
                mlog_errno(ret);
                goto bail;
        }
-       ocfs2_inode_unlock(inode, 0);
+       ocfs2_inode_unlock(inode, lock_level);
 
        ret = generic_file_splice_read(in, ppos, pipe, len, flags);
 
index 10e1fa87396aedf9ea0a1cfbd501c25361a872e7..4dc8890ba31615a3e8ce450d8b33fd38fcc202e8 100644 (file)
@@ -215,6 +215,8 @@ bail:
 static int ocfs2_init_locked_inode(struct inode *inode, void *opaque)
 {
        struct ocfs2_find_inode_args *args = opaque;
+       static struct lock_class_key ocfs2_quota_ip_alloc_sem_key,
+                                    ocfs2_file_ip_alloc_sem_key;
 
        mlog_entry("inode = %p, opaque = %p\n", inode, opaque);
 
@@ -223,6 +225,15 @@ static int ocfs2_init_locked_inode(struct inode *inode, void *opaque)
        if (args->fi_sysfile_type != 0)
                lockdep_set_class(&inode->i_mutex,
                        &ocfs2_sysfile_lock_key[args->fi_sysfile_type]);
+       if (args->fi_sysfile_type == USER_QUOTA_SYSTEM_INODE ||
+           args->fi_sysfile_type == GROUP_QUOTA_SYSTEM_INODE ||
+           args->fi_sysfile_type == LOCAL_USER_QUOTA_SYSTEM_INODE ||
+           args->fi_sysfile_type == LOCAL_GROUP_QUOTA_SYSTEM_INODE)
+               lockdep_set_class(&OCFS2_I(inode)->ip_alloc_sem,
+                                 &ocfs2_quota_ip_alloc_sem_key);
+       else
+               lockdep_set_class(&OCFS2_I(inode)->ip_alloc_sem,
+                                 &ocfs2_file_ip_alloc_sem_key);
 
        mlog_exit(0);
        return 0;
index 9fcd36dcc9a05920e5cc3f2d4d001d5bc8a82120..467b413bec21e7b407f45a2adba2002e72504e72 100644 (file)
@@ -7,7 +7,6 @@
 
 #include <linux/fs.h>
 #include <linux/mount.h>
-#include <linux/smp_lock.h>
 
 #define MLOG_MASK_PREFIX ML_INODE
 #include <cluster/masklog.h>
index 4a3b9e6b31adcc6247dc28fea3887a426f9a09d7..f033760ecbeaae0dde0944d190828aedb7b9c5d0 100644 (file)
@@ -1880,13 +1880,20 @@ void ocfs2_queue_orphan_scan(struct ocfs2_super *osb)
 
        os = &osb->osb_orphan_scan;
 
-       status = ocfs2_orphan_scan_lock(osb, &seqno, DLM_LOCK_EX);
+       if (atomic_read(&os->os_state) == ORPHAN_SCAN_INACTIVE)
+               goto out;
+
+       status = ocfs2_orphan_scan_lock(osb, &seqno);
        if (status < 0) {
                if (status != -EAGAIN)
                        mlog_errno(status);
                goto out;
        }
 
+       /* Do no queue the tasks if the volume is being umounted */
+       if (atomic_read(&os->os_state) == ORPHAN_SCAN_INACTIVE)
+               goto unlock;
+
        if (os->os_seqno != seqno) {
                os->os_seqno = seqno;
                goto unlock;
@@ -1903,7 +1910,7 @@ void ocfs2_queue_orphan_scan(struct ocfs2_super *osb)
        os->os_count++;
        os->os_scantime = CURRENT_TIME;
 unlock:
-       ocfs2_orphan_scan_unlock(osb, seqno, DLM_LOCK_EX);
+       ocfs2_orphan_scan_unlock(osb, seqno);
 out:
        return;
 }
@@ -1920,8 +1927,9 @@ void ocfs2_orphan_scan_work(struct work_struct *work)
 
        mutex_lock(&os->os_lock);
        ocfs2_queue_orphan_scan(osb);
-       schedule_delayed_work(&os->os_orphan_scan_work,
-                             ocfs2_orphan_scan_timeout());
+       if (atomic_read(&os->os_state) == ORPHAN_SCAN_ACTIVE)
+               schedule_delayed_work(&os->os_orphan_scan_work,
+                                     ocfs2_orphan_scan_timeout());
        mutex_unlock(&os->os_lock);
 }
 
@@ -1930,26 +1938,33 @@ void ocfs2_orphan_scan_stop(struct ocfs2_super *osb)
        struct ocfs2_orphan_scan *os;
 
        os = &osb->osb_orphan_scan;
-       mutex_lock(&os->os_lock);
-       cancel_delayed_work(&os->os_orphan_scan_work);
-       mutex_unlock(&os->os_lock);
+       if (atomic_read(&os->os_state) == ORPHAN_SCAN_ACTIVE) {
+               atomic_set(&os->os_state, ORPHAN_SCAN_INACTIVE);
+               mutex_lock(&os->os_lock);
+               cancel_delayed_work(&os->os_orphan_scan_work);
+               mutex_unlock(&os->os_lock);
+       }
 }
 
-int ocfs2_orphan_scan_init(struct ocfs2_super *osb)
+void ocfs2_orphan_scan_init(struct ocfs2_super *osb)
 {
        struct ocfs2_orphan_scan *os;
 
        os = &osb->osb_orphan_scan;
        os->os_osb = osb;
        os->os_count = 0;
+       os->os_seqno = 0;
        os->os_scantime = CURRENT_TIME;
        mutex_init(&os->os_lock);
-
-       INIT_DELAYED_WORK(&os->os_orphan_scan_work,
-                         ocfs2_orphan_scan_work);
-       schedule_delayed_work(&os->os_orphan_scan_work,
-                             ocfs2_orphan_scan_timeout());
-       return 0;
+       INIT_DELAYED_WORK(&os->os_orphan_scan_work, ocfs2_orphan_scan_work);
+
+       if (ocfs2_is_hard_readonly(osb) || ocfs2_mount_local(osb))
+               atomic_set(&os->os_state, ORPHAN_SCAN_INACTIVE);
+       else {
+               atomic_set(&os->os_state, ORPHAN_SCAN_ACTIVE);
+               schedule_delayed_work(&os->os_orphan_scan_work,
+                                     ocfs2_orphan_scan_timeout());
+       }
 }
 
 struct ocfs2_orphan_filldir_priv {
index 61045eeb3f6ea0c83f45e7e012b2aab1da34626a..5432c7f79cc6a959d3c39cd2cbcb41663ef599b5 100644 (file)
@@ -144,7 +144,7 @@ static inline void ocfs2_inode_set_new(struct ocfs2_super *osb,
 }
 
 /* Exported only for the journal struct init code in super.c. Do not call. */
-int ocfs2_orphan_scan_init(struct ocfs2_super *osb);
+void ocfs2_orphan_scan_init(struct ocfs2_super *osb);
 void ocfs2_orphan_scan_stop(struct ocfs2_super *osb);
 void ocfs2_orphan_scan_exit(struct ocfs2_super *osb);
 
index 33464c6b60a2ca91252af9d4f588398379089c04..8601f934010b80e37c528b326e9121c72213ea7b 100644 (file)
@@ -118,7 +118,7 @@ static struct dentry *ocfs2_lookup(struct inode *dir, struct dentry *dentry,
        mlog(0, "find name %.*s in directory %llu\n", dentry->d_name.len,
             dentry->d_name.name, (unsigned long long)OCFS2_I(dir)->ip_blkno);
 
-       status = ocfs2_inode_lock(dir, NULL, 0);
+       status = ocfs2_inode_lock_nested(dir, NULL, 0, OI_LS_PARENT);
        if (status < 0) {
                if (status != -ENOENT)
                        mlog_errno(status);
@@ -636,7 +636,7 @@ static int ocfs2_link(struct dentry *old_dentry,
        if (S_ISDIR(inode->i_mode))
                return -EPERM;
 
-       err = ocfs2_inode_lock(dir, &parent_fe_bh, 1);
+       err = ocfs2_inode_lock_nested(dir, &parent_fe_bh, 1, OI_LS_PARENT);
        if (err < 0) {
                if (err != -ENOENT)
                        mlog_errno(err);
@@ -800,7 +800,8 @@ static int ocfs2_unlink(struct inode *dir,
                return -EPERM;
        }
 
-       status = ocfs2_inode_lock(dir, &parent_node_bh, 1);
+       status = ocfs2_inode_lock_nested(dir, &parent_node_bh, 1,
+                                        OI_LS_PARENT);
        if (status < 0) {
                if (status != -ENOENT)
                        mlog_errno(status);
@@ -978,7 +979,8 @@ static int ocfs2_double_lock(struct ocfs2_super *osb,
                        inode1 = tmpinode;
                }
                /* lock id2 */
-               status = ocfs2_inode_lock(inode2, bh2, 1);
+               status = ocfs2_inode_lock_nested(inode2, bh2, 1,
+                                                OI_LS_RENAME1);
                if (status < 0) {
                        if (status != -ENOENT)
                                mlog_errno(status);
@@ -987,7 +989,7 @@ static int ocfs2_double_lock(struct ocfs2_super *osb,
        }
 
        /* lock id1 */
-       status = ocfs2_inode_lock(inode1, bh1, 1);
+       status = ocfs2_inode_lock_nested(inode1, bh1, 1, OI_LS_RENAME2);
        if (status < 0) {
                /*
                 * An error return must mean that no cluster locks
@@ -1103,7 +1105,8 @@ static int ocfs2_rename(struct inode *old_dir,
         * won't have to concurrently downconvert the inode and the
         * dentry locks.
         */
-       status = ocfs2_inode_lock(old_inode, &old_inode_bh, 1);
+       status = ocfs2_inode_lock_nested(old_inode, &old_inode_bh, 1,
+                                        OI_LS_PARENT);
        if (status < 0) {
                if (status != -ENOENT)
                        mlog_errno(status);
index 18c1d9ec1c93cdc5421150e7ec39e45d4162d737..c9345ebb849343873adf6b2b67ae226f8181f65e 100644 (file)
@@ -34,6 +34,7 @@
 #include <linux/workqueue.h>
 #include <linux/kref.h>
 #include <linux/mutex.h>
+#include <linux/lockdep.h>
 #ifndef CONFIG_OCFS2_COMPAT_JBD
 # include <linux/jbd2.h>
 #else
@@ -152,6 +153,14 @@ struct ocfs2_lock_res {
        unsigned int             l_lock_max_exmode;        /* Max wait for EX */
        unsigned int             l_lock_refresh;           /* Disk refreshes */
 #endif
+#ifdef CONFIG_DEBUG_LOCK_ALLOC
+       struct lockdep_map       l_lockdep_map;
+#endif
+};
+
+enum ocfs2_orphan_scan_state {
+       ORPHAN_SCAN_ACTIVE,
+       ORPHAN_SCAN_INACTIVE
 };
 
 struct ocfs2_orphan_scan {
@@ -162,6 +171,7 @@ struct ocfs2_orphan_scan {
        struct timespec         os_scantime;  /* time this node ran the scan */
        u32                     os_count;      /* tracks node specific scans */
        u32                     os_seqno;       /* tracks cluster wide scans */
+       atomic_t                os_state;              /* ACTIVE or INACTIVE */
 };
 
 struct ocfs2_dlm_debug {
index fcd120f1493afb0ba8838bf543495eadb2b639b8..3f661376a2ded76e08769f1766de3c1523d448d9 100644 (file)
@@ -236,6 +236,16 @@ static int o2cb_dlm_lock_status(union ocfs2_dlm_lksb *lksb)
        return dlm_status_to_errno(lksb->lksb_o2dlm.status);
 }
 
+/*
+ * o2dlm aways has a "valid" LVB. If the dlm loses track of the LVB
+ * contents, it will zero out the LVB.  Thus the caller can always trust
+ * the contents.
+ */
+static int o2cb_dlm_lvb_valid(union ocfs2_dlm_lksb *lksb)
+{
+       return 1;
+}
+
 static void *o2cb_dlm_lvb(union ocfs2_dlm_lksb *lksb)
 {
        return (void *)(lksb->lksb_o2dlm.lvb);
@@ -354,6 +364,7 @@ static struct ocfs2_stack_operations o2cb_stack_ops = {
        .dlm_lock       = o2cb_dlm_lock,
        .dlm_unlock     = o2cb_dlm_unlock,
        .lock_status    = o2cb_dlm_lock_status,
+       .lvb_valid      = o2cb_dlm_lvb_valid,
        .lock_lvb       = o2cb_dlm_lvb,
        .dump_lksb      = o2cb_dump_lksb,
 };
index 9b76d41a8ac6ed2898021bcc255ffa8e159b61cb..ff4c798a5635f23d64739356b2fc8277c370e1b9 100644 (file)
@@ -738,6 +738,13 @@ static int user_dlm_lock_status(union ocfs2_dlm_lksb *lksb)
        return lksb->lksb_fsdlm.sb_status;
 }
 
+static int user_dlm_lvb_valid(union ocfs2_dlm_lksb *lksb)
+{
+       int invalid = lksb->lksb_fsdlm.sb_flags & DLM_SBF_VALNOTVALID;
+
+       return !invalid;
+}
+
 static void *user_dlm_lvb(union ocfs2_dlm_lksb *lksb)
 {
        if (!lksb->lksb_fsdlm.sb_lvbptr)
@@ -873,6 +880,7 @@ static struct ocfs2_stack_operations ocfs2_user_plugin_ops = {
        .dlm_lock       = user_dlm_lock,
        .dlm_unlock     = user_dlm_unlock,
        .lock_status    = user_dlm_lock_status,
+       .lvb_valid      = user_dlm_lvb_valid,
        .lock_lvb       = user_dlm_lvb,
        .plock          = user_plock,
        .dump_lksb      = user_dlm_dump_lksb,
index 68b668b0e60a0a231436fcde4e41bd23083a032d..3f2f1c45b7b6bf4abf6ac9bbaddd3e24f456171a 100644 (file)
@@ -6,7 +6,7 @@
  * Code which implements an OCFS2 specific interface to underlying
  * cluster stacks.
  *
- * Copyright (C) 2007 Oracle.  All rights reserved.
+ * Copyright (C) 2007, 2009 Oracle.  All rights reserved.
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public
@@ -271,11 +271,12 @@ int ocfs2_dlm_lock_status(union ocfs2_dlm_lksb *lksb)
 }
 EXPORT_SYMBOL_GPL(ocfs2_dlm_lock_status);
 
-/*
- * Why don't we cast to ocfs2_meta_lvb?  The "clean" answer is that we
- * don't cast at the glue level.  The real answer is that the header
- * ordering is nigh impossible.
- */
+int ocfs2_dlm_lvb_valid(union ocfs2_dlm_lksb *lksb)
+{
+       return active_stack->sp_ops->lvb_valid(lksb);
+}
+EXPORT_SYMBOL_GPL(ocfs2_dlm_lvb_valid);
+
 void *ocfs2_dlm_lvb(union ocfs2_dlm_lksb *lksb)
 {
        return active_stack->sp_ops->lock_lvb(lksb);
index c571af375ef87b98e6e24aad5d44c6fd7e114163..03a44d60eac91bc83699371f66f2f6cc333962fa 100644 (file)
@@ -185,6 +185,11 @@ struct ocfs2_stack_operations {
         */
        int (*lock_status)(union ocfs2_dlm_lksb *lksb);
 
+       /*
+        * Return non-zero if the LVB is valid.
+        */
+       int (*lvb_valid)(union ocfs2_dlm_lksb *lksb);
+
        /*
         * Pull the lvb pointer off of the stack-specific lksb.
         */
@@ -252,6 +257,7 @@ int ocfs2_dlm_unlock(struct ocfs2_cluster_connection *conn,
                     struct ocfs2_lock_res *astarg);
 
 int ocfs2_dlm_lock_status(union ocfs2_dlm_lksb *lksb);
+int ocfs2_dlm_lvb_valid(union ocfs2_dlm_lksb *lksb);
 void *ocfs2_dlm_lvb(union ocfs2_dlm_lksb *lksb);
 void ocfs2_dlm_dump_lksb(union ocfs2_dlm_lksb *lksb);
 
index 8439f6b324b91ef1fc7bf2f459f569a49365ee77..73a16d4666dc463472e9254449ac98c9a6363188 100644 (file)
@@ -923,14 +923,23 @@ static int ocfs2_test_bg_bit_allocatable(struct buffer_head *bg_bh,
                                         int nr)
 {
        struct ocfs2_group_desc *bg = (struct ocfs2_group_desc *) bg_bh->b_data;
+       int ret;
 
        if (ocfs2_test_bit(nr, (unsigned long *)bg->bg_bitmap))
                return 0;
-       if (!buffer_jbd(bg_bh) || !bh2jh(bg_bh)->b_committed_data)
+
+       if (!buffer_jbd(bg_bh))
                return 1;
 
+       jbd_lock_bh_state(bg_bh);
        bg = (struct ocfs2_group_desc *) bh2jh(bg_bh)->b_committed_data;
-       return !ocfs2_test_bit(nr, (unsigned long *)bg->bg_bitmap);
+       if (bg)
+               ret = !ocfs2_test_bit(nr, (unsigned long *)bg->bg_bitmap);
+       else
+               ret = 1;
+       jbd_unlock_bh_state(bg_bh);
+
+       return ret;
 }
 
 static int ocfs2_block_group_find_clear_bits(struct ocfs2_super *osb,
@@ -1885,6 +1894,7 @@ static inline int ocfs2_block_group_clear_bits(handle_t *handle,
        unsigned int tmp;
        int journal_type = OCFS2_JOURNAL_ACCESS_WRITE;
        struct ocfs2_group_desc *undo_bg = NULL;
+       int cluster_bitmap = 0;
 
        mlog_entry_void();
 
@@ -1905,18 +1915,28 @@ static inline int ocfs2_block_group_clear_bits(handle_t *handle,
        }
 
        if (ocfs2_is_cluster_bitmap(alloc_inode))
-               undo_bg = (struct ocfs2_group_desc *) bh2jh(group_bh)->b_committed_data;
+               cluster_bitmap = 1;
+
+       if (cluster_bitmap) {
+               jbd_lock_bh_state(group_bh);
+               undo_bg = (struct ocfs2_group_desc *)
+                                       bh2jh(group_bh)->b_committed_data;
+               BUG_ON(!undo_bg);
+       }
 
        tmp = num_bits;
        while(tmp--) {
                ocfs2_clear_bit((bit_off + tmp),
                                (unsigned long *) bg->bg_bitmap);
-               if (ocfs2_is_cluster_bitmap(alloc_inode))
+               if (cluster_bitmap)
                        ocfs2_set_bit(bit_off + tmp,
                                      (unsigned long *) undo_bg->bg_bitmap);
        }
        le16_add_cpu(&bg->bg_free_bits_count, num_bits);
 
+       if (cluster_bitmap)
+               jbd_unlock_bh_state(group_bh);
+
        status = ocfs2_journal_dirty(handle, group_bh);
        if (status < 0)
                mlog_errno(status);
index 0d3ed7407a043effbab862610ca5847589eae396..7efb349fb9bdafe0678bd63786db244bba410b4a 100644 (file)
@@ -205,11 +205,10 @@ static const match_table_t tokens = {
 #ifdef CONFIG_DEBUG_FS
 static int ocfs2_osb_dump(struct ocfs2_super *osb, char *buf, int len)
 {
-       int out = 0;
-       int i;
        struct ocfs2_cluster_connection *cconn = osb->cconn;
        struct ocfs2_recovery_map *rm = osb->recovery_map;
-       struct ocfs2_orphan_scan *os;
+       struct ocfs2_orphan_scan *os = &osb->osb_orphan_scan;
+       int i, out = 0;
 
        out += snprintf(buf + out, len - out,
                        "%10s => Id: %-s  Uuid: %-s  Gen: 0x%X  Label: %-s\n",
@@ -234,20 +233,24 @@ static int ocfs2_osb_dump(struct ocfs2_super *osb, char *buf, int len)
                        "%10s => Opts: 0x%lX  AtimeQuanta: %u\n", "Mount",
                        osb->s_mount_opt, osb->s_atime_quantum);
 
-       out += snprintf(buf + out, len - out,
-                       "%10s => Stack: %s  Name: %*s  Version: %d.%d\n",
-                       "Cluster",
-                       (*osb->osb_cluster_stack == '\0' ?
-                        "o2cb" : osb->osb_cluster_stack),
-                       cconn->cc_namelen, cconn->cc_name,
-                       cconn->cc_version.pv_major, cconn->cc_version.pv_minor);
+       if (cconn) {
+               out += snprintf(buf + out, len - out,
+                               "%10s => Stack: %s  Name: %*s  "
+                               "Version: %d.%d\n", "Cluster",
+                               (*osb->osb_cluster_stack == '\0' ?
+                                "o2cb" : osb->osb_cluster_stack),
+                               cconn->cc_namelen, cconn->cc_name,
+                               cconn->cc_version.pv_major,
+                               cconn->cc_version.pv_minor);
+       }
 
        spin_lock(&osb->dc_task_lock);
        out += snprintf(buf + out, len - out,
                        "%10s => Pid: %d  Count: %lu  WakeSeq: %lu  "
                        "WorkSeq: %lu\n", "DownCnvt",
-                       task_pid_nr(osb->dc_task), osb->blocked_lock_count,
-                       osb->dc_wake_sequence, osb->dc_work_sequence);
+                       (osb->dc_task ?  task_pid_nr(osb->dc_task) : -1),
+                       osb->blocked_lock_count, osb->dc_wake_sequence,
+                       osb->dc_work_sequence);
        spin_unlock(&osb->dc_task_lock);
 
        spin_lock(&osb->osb_lock);
@@ -267,14 +270,15 @@ static int ocfs2_osb_dump(struct ocfs2_super *osb, char *buf, int len)
 
        out += snprintf(buf + out, len - out,
                        "%10s => Pid: %d  Interval: %lu  Needs: %d\n", "Commit",
-                       task_pid_nr(osb->commit_task), osb->osb_commit_interval,
+                       (osb->commit_task ? task_pid_nr(osb->commit_task) : -1),
+                       osb->osb_commit_interval,
                        atomic_read(&osb->needs_checkpoint));
 
        out += snprintf(buf + out, len - out,
-                       "%10s => State: %d  NumTxns: %d  TxnId: %lu\n",
+                       "%10s => State: %d  TxnId: %lu  NumTxns: %d\n",
                        "Journal", osb->journal->j_state,
-                       atomic_read(&osb->journal->j_num_trans),
-                       osb->journal->j_trans_id);
+                       osb->journal->j_trans_id,
+                       atomic_read(&osb->journal->j_num_trans));
 
        out += snprintf(buf + out, len - out,
                        "%10s => GlobalAllocs: %d  LocalAllocs: %d  "
@@ -300,9 +304,18 @@ static int ocfs2_osb_dump(struct ocfs2_super *osb, char *buf, int len)
                        atomic_read(&osb->s_num_inodes_stolen));
        spin_unlock(&osb->osb_lock);
 
+       out += snprintf(buf + out, len - out, "OrphanScan => ");
+       out += snprintf(buf + out, len - out, "Local: %u  Global: %u ",
+                       os->os_count, os->os_seqno);
+       out += snprintf(buf + out, len - out, " Last Scan: ");
+       if (atomic_read(&os->os_state) == ORPHAN_SCAN_INACTIVE)
+               out += snprintf(buf + out, len - out, "Disabled\n");
+       else
+               out += snprintf(buf + out, len - out, "%lu seconds ago\n",
+                               (get_seconds() - os->os_scantime.tv_sec));
+
        out += snprintf(buf + out, len - out, "%10s => %3s  %10s\n",
                        "Slots", "Num", "RecoGen");
-
        for (i = 0; i < osb->max_slots; ++i) {
                out += snprintf(buf + out, len - out,
                                "%10s  %c %3d  %10d\n",
@@ -311,13 +324,6 @@ static int ocfs2_osb_dump(struct ocfs2_super *osb, char *buf, int len)
                                i, osb->slot_recovery_generations[i]);
        }
 
-       os = &osb->osb_orphan_scan;
-       out += snprintf(buf + out, len - out, "Orphan Scan=> ");
-       out += snprintf(buf + out, len - out, "Local: %u  Global: %u ",
-                       os->os_count, os->os_seqno);
-       out += snprintf(buf + out, len - out, " Last Scan: %lu seconds ago\n",
-                       (get_seconds() - os->os_scantime.tv_sec));
-
        return out;
 }
 
@@ -1175,6 +1181,9 @@ static int ocfs2_fill_super(struct super_block *sb, void *data, int silent)
        atomic_set(&osb->vol_state, VOLUME_MOUNTED_QUOTAS);
        wake_up(&osb->osb_mount_event);
 
+       /* Start this when the mount is almost sure of being successful */
+       ocfs2_orphan_scan_init(osb);
+
        mlog_exit(status);
        return status;
 
@@ -1810,14 +1819,15 @@ static void ocfs2_dismount_volume(struct super_block *sb, int mnt_err)
 
        debugfs_remove(osb->osb_ctxt);
 
+       /* Orphan scan should be stopped as early as possible */
+       ocfs2_orphan_scan_stop(osb);
+
        ocfs2_disable_quotas(osb);
 
        ocfs2_shutdown_local_alloc(osb);
 
        ocfs2_truncate_log_shutdown(osb);
 
-       ocfs2_orphan_scan_stop(osb);
-
        /* This will disable recovery and flush any recovery work. */
        ocfs2_recovery_exit(osb);
 
@@ -1978,13 +1988,6 @@ static int ocfs2_initialize_super(struct super_block *sb,
                goto bail;
        }
 
-       status = ocfs2_orphan_scan_init(osb);
-       if (status) {
-               mlog(ML_ERROR, "Unable to initialize delayed orphan scan\n");
-               mlog_errno(status);
-               goto bail;
-       }
-
        init_waitqueue_head(&osb->checkpoint_event);
        atomic_set(&osb->needs_checkpoint, 0);
 
index ab713ebdd5468222899654f706c4b80955a9bfe8..40e53702948cdbc2ed92ce1e22f0827f76017417 100644 (file)
@@ -50,6 +50,10 @@ static inline int is_in_system_inode_array(struct ocfs2_super *osb,
                                           int type,
                                           u32 slot);
 
+#ifdef CONFIG_DEBUG_LOCK_ALLOC
+static struct lock_class_key ocfs2_sysfile_cluster_lock_key[NUM_SYSTEM_INODES];
+#endif
+
 static inline int is_global_system_inode(int type)
 {
        return type >= OCFS2_FIRST_ONLINE_SYSTEM_INODE &&
@@ -118,6 +122,21 @@ static struct inode * _ocfs2_get_system_file_inode(struct ocfs2_super *osb,
                inode = NULL;
                goto bail;
        }
+#ifdef CONFIG_DEBUG_LOCK_ALLOC
+       if (type == LOCAL_USER_QUOTA_SYSTEM_INODE ||
+           type == LOCAL_GROUP_QUOTA_SYSTEM_INODE ||
+           type == JOURNAL_SYSTEM_INODE) {
+               /* Ignore inode lock on these inodes as the lock does not
+                * really belong to any process and lockdep cannot handle
+                * that */
+               OCFS2_I(inode)->ip_inode_lockres.l_lockdep_map.key = NULL;
+       } else {
+               lockdep_init_map(&OCFS2_I(inode)->ip_inode_lockres.
+                                                               l_lockdep_map,
+                                ocfs2_system_inodes[type].si_name,
+                                &ocfs2_sysfile_cluster_lock_key[type], 0);
+       }
+#endif
 bail:
 
        return inode;
index 7200e23d9258ce09a76caacee7f1a71e7b25ce7f..dd98e8076024d638cb0987b57b24269d20588587 100644 (file)
--- a/fs/open.c
+++ b/fs/open.c
@@ -378,63 +378,63 @@ SYSCALL_ALIAS(sys_ftruncate64, SyS_ftruncate64);
 #endif
 #endif /* BITS_PER_LONG == 32 */
 
-SYSCALL_DEFINE(fallocate)(int fd, int mode, loff_t offset, loff_t len)
+
+int do_fallocate(struct file *file, int mode, loff_t offset, loff_t len)
 {
-       struct file *file;
-       struct inode *inode;
-       long ret = -EINVAL;
+       struct inode *inode = file->f_path.dentry->d_inode;
+       long ret;
 
        if (offset < 0 || len <= 0)
-               goto out;
+               return -EINVAL;
 
        /* Return error if mode is not supported */
-       ret = -EOPNOTSUPP;
        if (mode && !(mode & FALLOC_FL_KEEP_SIZE))
-               goto out;
+               return -EOPNOTSUPP;
 
-       ret = -EBADF;
-       file = fget(fd);
-       if (!file)
-               goto out;
        if (!(file->f_mode & FMODE_WRITE))
-               goto out_fput;
+               return -EBADF;
        /*
         * Revalidate the write permissions, in case security policy has
         * changed since the files were opened.
         */
        ret = security_file_permission(file, MAY_WRITE);
        if (ret)
-               goto out_fput;
+               return ret;
 
-       inode = file->f_path.dentry->d_inode;
-
-       ret = -ESPIPE;
        if (S_ISFIFO(inode->i_mode))
-               goto out_fput;
+               return -ESPIPE;
 
-       ret = -ENODEV;
        /*
         * Let individual file system decide if it supports preallocation
         * for directories or not.
         */
        if (!S_ISREG(inode->i_mode) && !S_ISDIR(inode->i_mode))
-               goto out_fput;
+               return -ENODEV;
 
-       ret = -EFBIG;
        /* Check for wrap through zero too */
        if (((offset + len) > inode->i_sb->s_maxbytes) || ((offset + len) < 0))
-               goto out_fput;
+               return -EFBIG;
 
-       if (inode->i_op->fallocate)
-               ret = inode->i_op->fallocate(inode, mode, offset, len);
-       else
-               ret = -EOPNOTSUPP;
+       if (!inode->i_op->fallocate)
+               return -EOPNOTSUPP;
 
-out_fput:
-       fput(file);
-out:
-       return ret;
+       return inode->i_op->fallocate(inode, mode, offset, len);
 }
+
+SYSCALL_DEFINE(fallocate)(int fd, int mode, loff_t offset, loff_t len)
+{
+       struct file *file;
+       int error = -EBADF;
+
+       file = fget(fd);
+       if (file) {
+               error = do_fallocate(file, mode, offset, len);
+               fput(file);
+       }
+
+       return error;
+}
+
 #ifdef CONFIG_HAVE_SYSCALL_WRAPPERS
 asmlinkage long SyS_fallocate(long fd, long mode, loff_t offset, loff_t len)
 {
index 1a9c7878f8649b1df14531f66aa247fd2587e2c8..ea4e6cb29e1394f709f834df066a7659e12b1d2e 100644 (file)
@@ -436,7 +436,7 @@ struct hd_struct *add_partition(struct gendisk *disk, int partno,
        rcu_assign_pointer(ptbl->part[partno], p);
 
        /* suppress uevent if the disk supresses it */
-       if (!dev_get_uevent_suppress(pdev))
+       if (!dev_get_uevent_suppress(ddev))
                kobject_uevent(&pdev->kobj, KOBJ_ADD);
 
        return p;
index 607c579e5eca0cc0427c53a844d68ff159186e47..70f36c043d623ef8c5cc81d60591268673913795 100644 (file)
@@ -2042,8 +2042,8 @@ static int vfs_load_quota_inode(struct inode *inode, int type, int format_id,
                 * changes */
                invalidate_bdev(sb->s_bdev);
        }
-       mutex_lock(&inode->i_mutex);
        mutex_lock(&dqopt->dqonoff_mutex);
+       mutex_lock_nested(&inode->i_mutex, I_MUTEX_QUOTA);
        if (sb_has_quota_loaded(sb, type)) {
                error = -EBUSY;
                goto out_lock;
@@ -2094,7 +2094,6 @@ out_file_init:
        dqopt->files[type] = NULL;
        iput(inode);
 out_lock:
-       mutex_unlock(&dqopt->dqonoff_mutex);
        if (oldflags != -1) {
                down_write(&dqopt->dqptr_sem);
                /* Set the flags back (in the case of accidental quotaon()
@@ -2104,6 +2103,7 @@ out_lock:
                up_write(&dqopt->dqptr_sem);
        }
        mutex_unlock(&inode->i_mutex);
+       mutex_unlock(&dqopt->dqonoff_mutex);
 out_fmt:
        put_quota_format(fmt);
 
index 6fd0f47e45db72b252808386450e468ad425af61..a14d6cd9eeda2670251c0ec3377518912cb465a2 100644 (file)
@@ -1131,8 +1131,6 @@ static void init_inode(struct inode *inode, struct treepath *path)
        REISERFS_I(inode)->i_trans_id = 0;
        REISERFS_I(inode)->i_jl = NULL;
        mutex_init(&(REISERFS_I(inode)->i_mmap));
-       reiserfs_init_acl_access(inode);
-       reiserfs_init_acl_default(inode);
        reiserfs_init_xattr_rwsem(inode);
 
        if (stat_data_v1(ih)) {
@@ -1834,8 +1832,6 @@ int reiserfs_new_inode(struct reiserfs_transaction_handle *th,
            REISERFS_I(dir)->i_attrs & REISERFS_INHERIT_MASK;
        sd_attrs_to_i_attrs(REISERFS_I(inode)->i_attrs, inode);
        mutex_init(&(REISERFS_I(inode)->i_mmap));
-       reiserfs_init_acl_access(inode);
-       reiserfs_init_acl_default(inode);
        reiserfs_init_xattr_rwsem(inode);
 
        /* key to search for correct place for new stat data */
index 77f5bb746bf073969140539752ee87dc8f4f0861..90622200b39c0622e0f159d423c929a036d76257 100644 (file)
@@ -997,7 +997,7 @@ static int reiserfs_async_progress_wait(struct super_block *s)
        DEFINE_WAIT(wait);
        struct reiserfs_journal *j = SB_JOURNAL(s);
        if (atomic_read(&j->j_async_throttle))
-               congestion_wait(WRITE, HZ / 10);
+               congestion_wait(BLK_RW_ASYNC, HZ / 10);
        return 0;
 }
 
index 238e9d9b31e04bf877f1644630990672d1c5daba..18b315d3d104ea0cebfbb5a1991356038dc8c4fd 100644 (file)
@@ -82,7 +82,6 @@ int reiserfs_resize(struct super_block *s, unsigned long block_count_new)
                if (reiserfs_allocate_list_bitmaps(s, jbitmap, bmap_nr_new) < 0) {
                        printk
                            ("reiserfs_resize: unable to allocate memory for journal bitmaps\n");
-                       unlock_super(s);
                        return -ENOMEM;
                }
                /* the new journal bitmaps are zero filled, now we copy in the bitmap
index 2969773cfc22abb000e2eceb90f0011ef0fd2f34..7adea74d6a8ac829d3c1efb877b9feec5027ccaa 100644 (file)
@@ -24,7 +24,6 @@
 #include <linux/exportfs.h>
 #include <linux/quotaops.h>
 #include <linux/vfs.h>
-#include <linux/mnt_namespace.h>
 #include <linux/mount.h>
 #include <linux/namei.h>
 #include <linux/crc32.h>
@@ -529,10 +528,6 @@ static void init_once(void *foo)
 
        INIT_LIST_HEAD(&ei->i_prealloc_list);
        inode_init_once(&ei->vfs_inode);
-#ifdef CONFIG_REISERFS_FS_POSIX_ACL
-       ei->i_acl_access = NULL;
-       ei->i_acl_default = NULL;
-#endif
 }
 
 static int init_inodecache(void)
@@ -580,25 +575,6 @@ static void reiserfs_dirty_inode(struct inode *inode)
        reiserfs_write_unlock(inode->i_sb);
 }
 
-#ifdef CONFIG_REISERFS_FS_POSIX_ACL
-static void reiserfs_clear_inode(struct inode *inode)
-{
-       struct posix_acl *acl;
-
-       acl = REISERFS_I(inode)->i_acl_access;
-       if (acl && !IS_ERR(acl))
-               posix_acl_release(acl);
-       REISERFS_I(inode)->i_acl_access = NULL;
-
-       acl = REISERFS_I(inode)->i_acl_default;
-       if (acl && !IS_ERR(acl))
-               posix_acl_release(acl);
-       REISERFS_I(inode)->i_acl_default = NULL;
-}
-#else
-#define reiserfs_clear_inode NULL
-#endif
-
 #ifdef CONFIG_QUOTA
 static ssize_t reiserfs_quota_write(struct super_block *, int, const char *,
                                    size_t, loff_t);
@@ -612,7 +588,6 @@ static const struct super_operations reiserfs_sops = {
        .write_inode = reiserfs_write_inode,
        .dirty_inode = reiserfs_dirty_inode,
        .delete_inode = reiserfs_delete_inode,
-       .clear_inode = reiserfs_clear_inode,
        .put_super = reiserfs_put_super,
        .write_super = reiserfs_write_super,
        .sync_fs = reiserfs_sync_fs,
index f3d47d8568482f3dd2b20077e296b40bc8a428f1..6925b835a43b6f2f94e8a4217180b2e8d1735ab7 100644 (file)
@@ -46,7 +46,6 @@
 #include <linux/reiserfs_acl.h>
 #include <asm/uaccess.h>
 #include <net/checksum.h>
-#include <linux/smp_lock.h>
 #include <linux/stat.h>
 #include <linux/quotaops.h>
 
index c303c426fe2ba6ffec8d708323026f36fbd40f90..35d6e672a2796f7aaed49b31f96621c25593c51b 100644 (file)
@@ -188,29 +188,6 @@ static void *posix_acl_to_disk(const struct posix_acl *acl, size_t * size)
        return ERR_PTR(-EINVAL);
 }
 
-static inline void iset_acl(struct inode *inode, struct posix_acl **i_acl,
-                           struct posix_acl *acl)
-{
-       spin_lock(&inode->i_lock);
-       if (*i_acl != ERR_PTR(-ENODATA))
-               posix_acl_release(*i_acl);
-       *i_acl = posix_acl_dup(acl);
-       spin_unlock(&inode->i_lock);
-}
-
-static inline struct posix_acl *iget_acl(struct inode *inode,
-                                        struct posix_acl **i_acl)
-{
-       struct posix_acl *acl = ERR_PTR(-ENODATA);
-
-       spin_lock(&inode->i_lock);
-       if (*i_acl != ERR_PTR(-ENODATA))
-               acl = posix_acl_dup(*i_acl);
-       spin_unlock(&inode->i_lock);
-
-       return acl;
-}
-
 /*
  * Inode operation get_posix_acl().
  *
@@ -220,34 +197,29 @@ static inline struct posix_acl *iget_acl(struct inode *inode,
 struct posix_acl *reiserfs_get_acl(struct inode *inode, int type)
 {
        char *name, *value;
-       struct posix_acl *acl, **p_acl;
+       struct posix_acl *acl;
        int size;
        int retval;
-       struct reiserfs_inode_info *reiserfs_i = REISERFS_I(inode);
+
+       acl = get_cached_acl(inode, type);
+       if (acl != ACL_NOT_CACHED)
+               return acl;
 
        switch (type) {
        case ACL_TYPE_ACCESS:
                name = POSIX_ACL_XATTR_ACCESS;
-               p_acl = &reiserfs_i->i_acl_access;
                break;
        case ACL_TYPE_DEFAULT:
                name = POSIX_ACL_XATTR_DEFAULT;
-               p_acl = &reiserfs_i->i_acl_default;
                break;
        default:
-               return ERR_PTR(-EINVAL);
+               BUG();
        }
 
-       acl = iget_acl(inode, p_acl);
-       if (acl && !IS_ERR(acl))
-               return acl;
-       else if (PTR_ERR(acl) == -ENODATA)
-               return NULL;
-
        size = reiserfs_xattr_get(inode, name, NULL, 0);
        if (size < 0) {
                if (size == -ENODATA || size == -ENOSYS) {
-                       *p_acl = ERR_PTR(-ENODATA);
+                       set_cached_acl(inode, type, NULL);
                        return NULL;
                }
                return ERR_PTR(size);
@@ -262,14 +234,13 @@ struct posix_acl *reiserfs_get_acl(struct inode *inode, int type)
                /* This shouldn't actually happen as it should have
                   been caught above.. but just in case */
                acl = NULL;
-               *p_acl = ERR_PTR(-ENODATA);
        } else if (retval < 0) {
                acl = ERR_PTR(retval);
        } else {
                acl = posix_acl_from_disk(value, retval);
-               if (!IS_ERR(acl))
-                       iset_acl(inode, p_acl, acl);
        }
+       if (!IS_ERR(acl))
+               set_cached_acl(inode, type, acl);
 
        kfree(value);
        return acl;
@@ -287,10 +258,8 @@ reiserfs_set_acl(struct reiserfs_transaction_handle *th, struct inode *inode,
 {
        char *name;
        void *value = NULL;
-       struct posix_acl **p_acl;
        size_t size = 0;
        int error;
-       struct reiserfs_inode_info *reiserfs_i = REISERFS_I(inode);
 
        if (S_ISLNK(inode->i_mode))
                return -EOPNOTSUPP;
@@ -298,7 +267,6 @@ reiserfs_set_acl(struct reiserfs_transaction_handle *th, struct inode *inode,
        switch (type) {
        case ACL_TYPE_ACCESS:
                name = POSIX_ACL_XATTR_ACCESS;
-               p_acl = &reiserfs_i->i_acl_access;
                if (acl) {
                        mode_t mode = inode->i_mode;
                        error = posix_acl_equiv_mode(acl, &mode);
@@ -313,7 +281,6 @@ reiserfs_set_acl(struct reiserfs_transaction_handle *th, struct inode *inode,
                break;
        case ACL_TYPE_DEFAULT:
                name = POSIX_ACL_XATTR_DEFAULT;
-               p_acl = &reiserfs_i->i_acl_default;
                if (!S_ISDIR(inode->i_mode))
                        return acl ? -EACCES : 0;
                break;
@@ -346,7 +313,7 @@ reiserfs_set_acl(struct reiserfs_transaction_handle *th, struct inode *inode,
        kfree(value);
 
        if (!error)
-               iset_acl(inode, p_acl, acl);
+               set_cached_acl(inode, type, acl);
 
        return error;
 }
@@ -379,11 +346,8 @@ reiserfs_inherit_default_acl(struct reiserfs_transaction_handle *th,
        }
 
        acl = reiserfs_get_acl(dir, ACL_TYPE_DEFAULT);
-       if (IS_ERR(acl)) {
-               if (PTR_ERR(acl) == -ENODATA)
-                       goto apply_umask;
+       if (IS_ERR(acl))
                return PTR_ERR(acl);
-       }
 
        if (acl) {
                struct posix_acl *acl_copy;
index 3b52770f46ffdcfbd4c6187a6dfd928f6135203c..cb5fc57e370be3babf4de90514fa89c2656f99f3 100644 (file)
@@ -30,6 +30,7 @@
 #include <linux/fs.h>
 #include <linux/vfs.h>
 #include <linux/slab.h>
+#include <linux/smp_lock.h>
 #include <linux/mutex.h>
 #include <linux/pagemap.h>
 #include <linux/init.h>
index d40d53a22fb595d3489e1273ac6efb26481b39e1..2761d3e22ed92321f204a34f8de08491db6f3083 100644 (file)
@@ -608,6 +608,7 @@ void emergency_remount(void)
 
 static DEFINE_IDA(unnamed_dev_ida);
 static DEFINE_SPINLOCK(unnamed_dev_lock);/* protects the above */
+static int unnamed_dev_start = 0; /* don't bother trying below it */
 
 int set_anon_super(struct super_block *s, void *data)
 {
@@ -618,7 +619,9 @@ int set_anon_super(struct super_block *s, void *data)
        if (ida_pre_get(&unnamed_dev_ida, GFP_ATOMIC) == 0)
                return -ENOMEM;
        spin_lock(&unnamed_dev_lock);
-       error = ida_get_new(&unnamed_dev_ida, &dev);
+       error = ida_get_new_above(&unnamed_dev_ida, unnamed_dev_start, &dev);
+       if (!error)
+               unnamed_dev_start = dev + 1;
        spin_unlock(&unnamed_dev_lock);
        if (error == -EAGAIN)
                /* We raced and lost with another CPU. */
@@ -629,6 +632,8 @@ int set_anon_super(struct super_block *s, void *data)
        if ((dev & MAX_ID_MASK) == (1 << MINORBITS)) {
                spin_lock(&unnamed_dev_lock);
                ida_remove(&unnamed_dev_ida, dev);
+               if (unnamed_dev_start > dev)
+                       unnamed_dev_start = dev;
                spin_unlock(&unnamed_dev_lock);
                return -EMFILE;
        }
@@ -645,6 +650,8 @@ void kill_anon_super(struct super_block *sb)
        generic_shutdown_super(sb);
        spin_lock(&unnamed_dev_lock);
        ida_remove(&unnamed_dev_ida, slot);
+       if (slot < unnamed_dev_start)
+               unnamed_dev_start = slot;
        spin_unlock(&unnamed_dev_lock);
 }
 
index dd200025af8521d65e7bf28efceaece55994c59d..3422ba61d86dcad558fd47d59756b411bfae7a81 100644 (file)
--- a/fs/sync.c
+++ b/fs/sync.c
@@ -112,8 +112,13 @@ restart:
        mutex_unlock(&mutex);
 }
 
+/*
+ * sync everything.  Start out by waking pdflush, because that writes back
+ * all queues in parallel.
+ */
 SYSCALL_DEFINE0(sync)
 {
+       wakeup_pdflush(0);
        sync_filesystems(0);
        sync_filesystems(1);
        if (unlikely(laptop_mode))
index 9345806c8853e369ba34695542081bb2e3f347db..2524714bece1b87e68d68c6928cfd720f0a9b259 100644 (file)
@@ -171,6 +171,7 @@ static ssize_t write(struct file *file, const char __user *userbuf,
        if (count > 0)
                *off = offs + count;
 
+       kfree(temp);
        return count;
 }
 
index bc5857199ec2a021c1f9f9838b11329461704b4f..762a7d6cec73de8433c58c6a6c691115e3c23e1c 100644 (file)
@@ -297,6 +297,7 @@ static enum hrtimer_restart wbuf_timer_callback_nolock(struct hrtimer *timer)
 {
        struct ubifs_wbuf *wbuf = container_of(timer, struct ubifs_wbuf, timer);
 
+       dbg_io("jhead %d", wbuf->jhead);
        wbuf->need_sync = 1;
        wbuf->c->need_wbuf_sync = 1;
        ubifs_wake_up_bgt(wbuf->c);
@@ -311,8 +312,12 @@ static void new_wbuf_timer_nolock(struct ubifs_wbuf *wbuf)
 {
        ubifs_assert(!hrtimer_active(&wbuf->timer));
 
-       if (!ktime_to_ns(wbuf->softlimit))
+       if (wbuf->no_timer)
                return;
+       dbg_io("set timer for jhead %d, %llu-%llu millisecs", wbuf->jhead,
+              div_u64(ktime_to_ns(wbuf->softlimit), USEC_PER_SEC),
+              div_u64(ktime_to_ns(wbuf->softlimit) + wbuf->delta,
+                      USEC_PER_SEC));
        hrtimer_start_range_ns(&wbuf->timer, wbuf->softlimit, wbuf->delta,
                               HRTIMER_MODE_REL);
 }
@@ -323,11 +328,8 @@ static void new_wbuf_timer_nolock(struct ubifs_wbuf *wbuf)
  */
 static void cancel_wbuf_timer_nolock(struct ubifs_wbuf *wbuf)
 {
-       /*
-        * If the syncer is waiting for the lock (from the background thread's
-        * context) and another task is changing write-buffer then the syncing
-        * should be canceled.
-        */
+       if (wbuf->no_timer)
+               return;
        wbuf->need_sync = 0;
        hrtimer_cancel(&wbuf->timer);
 }
@@ -349,8 +351,8 @@ int ubifs_wbuf_sync_nolock(struct ubifs_wbuf *wbuf)
                /* Write-buffer is empty or not seeked */
                return 0;
 
-       dbg_io("LEB %d:%d, %d bytes",
-              wbuf->lnum, wbuf->offs, wbuf->used);
+       dbg_io("LEB %d:%d, %d bytes, jhead %d",
+              wbuf->lnum, wbuf->offs, wbuf->used, wbuf->jhead);
        ubifs_assert(!(c->vfs_sb->s_flags & MS_RDONLY));
        ubifs_assert(!(wbuf->avail & 7));
        ubifs_assert(wbuf->offs + c->min_io_size <= c->leb_size);
@@ -390,7 +392,7 @@ int ubifs_wbuf_sync_nolock(struct ubifs_wbuf *wbuf)
  * @offs: logical eraseblock offset to seek to
  * @dtype: data type
  *
- * This function targets the write buffer to logical eraseblock @lnum:@offs.
+ * This function targets the write-buffer to logical eraseblock @lnum:@offs.
  * The write-buffer is synchronized if it is not empty. Returns zero in case of
  * success and a negative error code in case of failure.
  */
@@ -399,7 +401,7 @@ int ubifs_wbuf_seek_nolock(struct ubifs_wbuf *wbuf, int lnum, int offs,
 {
        const struct ubifs_info *c = wbuf->c;
 
-       dbg_io("LEB %d:%d", lnum, offs);
+       dbg_io("LEB %d:%d, jhead %d", lnum, offs, wbuf->jhead);
        ubifs_assert(lnum >= 0 && lnum < c->leb_cnt);
        ubifs_assert(offs >= 0 && offs <= c->leb_size);
        ubifs_assert(offs % c->min_io_size == 0 && !(offs & 7));
@@ -506,9 +508,9 @@ int ubifs_wbuf_write_nolock(struct ubifs_wbuf *wbuf, void *buf, int len)
        struct ubifs_info *c = wbuf->c;
        int err, written, n, aligned_len = ALIGN(len, 8), offs;
 
-       dbg_io("%d bytes (%s) to wbuf at LEB %d:%d", len,
-              dbg_ntype(((struct ubifs_ch *)buf)->node_type), wbuf->lnum,
-              wbuf->offs + wbuf->used);
+       dbg_io("%d bytes (%s) to jhead %d wbuf at LEB %d:%d", len,
+              dbg_ntype(((struct ubifs_ch *)buf)->node_type), wbuf->jhead,
+              wbuf->lnum, wbuf->offs + wbuf->used);
        ubifs_assert(len > 0 && wbuf->lnum >= 0 && wbuf->lnum < c->leb_cnt);
        ubifs_assert(wbuf->offs >= 0 && wbuf->offs % c->min_io_size == 0);
        ubifs_assert(!(wbuf->offs & 7) && wbuf->offs <= c->leb_size);
@@ -533,8 +535,8 @@ int ubifs_wbuf_write_nolock(struct ubifs_wbuf *wbuf, void *buf, int len)
                memcpy(wbuf->buf + wbuf->used, buf, len);
 
                if (aligned_len == wbuf->avail) {
-                       dbg_io("flush wbuf to LEB %d:%d", wbuf->lnum,
-                               wbuf->offs);
+                       dbg_io("flush jhead %d wbuf to LEB %d:%d",
+                              wbuf->jhead, wbuf->lnum, wbuf->offs);
                        err = ubi_leb_write(c->ubi, wbuf->lnum, wbuf->buf,
                                            wbuf->offs, c->min_io_size,
                                            wbuf->dtype);
@@ -562,7 +564,8 @@ int ubifs_wbuf_write_nolock(struct ubifs_wbuf *wbuf, void *buf, int len)
         * minimal I/O unit. We have to fill and flush write-buffer and switch
         * to the next min. I/O unit.
         */
-       dbg_io("flush wbuf to LEB %d:%d", wbuf->lnum, wbuf->offs);
+       dbg_io("flush jhead %d wbuf to LEB %d:%d",
+              wbuf->jhead, wbuf->lnum, wbuf->offs);
        memcpy(wbuf->buf + wbuf->used, buf, wbuf->avail);
        err = ubi_leb_write(c->ubi, wbuf->lnum, wbuf->buf, wbuf->offs,
                            c->min_io_size, wbuf->dtype);
@@ -695,7 +698,8 @@ int ubifs_read_node_wbuf(struct ubifs_wbuf *wbuf, void *buf, int type, int len,
        int err, rlen, overlap;
        struct ubifs_ch *ch = buf;
 
-       dbg_io("LEB %d:%d, %s, length %d", lnum, offs, dbg_ntype(type), len);
+       dbg_io("LEB %d:%d, %s, length %d, jhead %d", lnum, offs,
+              dbg_ntype(type), len, wbuf->jhead);
        ubifs_assert(wbuf && lnum >= 0 && lnum < c->leb_cnt && offs >= 0);
        ubifs_assert(!(offs & 7) && offs < c->leb_size);
        ubifs_assert(type >= 0 && type < UBIFS_NODE_TYPES_CNT);
@@ -819,13 +823,12 @@ out:
  * @c: UBIFS file-system description object
  * @wbuf: write-buffer to initialize
  *
- * This function initializes write buffer. Returns zero in case of success
+ * This function initializes write-buffer. Returns zero in case of success
  * %-ENOMEM in case of failure.
  */
 int ubifs_wbuf_init(struct ubifs_info *c, struct ubifs_wbuf *wbuf)
 {
        size_t size;
-       ktime_t hardlimit;
 
        wbuf->buf = kmalloc(c->min_io_size, GFP_KERNEL);
        if (!wbuf->buf)
@@ -851,22 +854,16 @@ int ubifs_wbuf_init(struct ubifs_info *c, struct ubifs_wbuf *wbuf)
 
        hrtimer_init(&wbuf->timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
        wbuf->timer.function = wbuf_timer_callback_nolock;
-       /*
-        * Make write-buffer soft limit to be 20% of the hard limit. The
-        * write-buffer timer is allowed to expire any time between the soft
-        * and hard limits.
-        */
-       hardlimit = ktime_set(DEFAULT_WBUF_TIMEOUT_SECS, 0);
-       wbuf->delta = (DEFAULT_WBUF_TIMEOUT_SECS * NSEC_PER_SEC) * 2 / 10;
-       wbuf->softlimit = ktime_sub_ns(hardlimit, wbuf->delta);
-       hrtimer_set_expires_range_ns(&wbuf->timer,  wbuf->softlimit,
-                                    wbuf->delta);
+       wbuf->softlimit = ktime_set(WBUF_TIMEOUT_SOFTLIMIT, 0);
+       wbuf->delta = WBUF_TIMEOUT_HARDLIMIT - WBUF_TIMEOUT_SOFTLIMIT;
+       wbuf->delta *= 1000000000ULL;
+       ubifs_assert(wbuf->delta <= ULONG_MAX);
        return 0;
 }
 
 /**
  * ubifs_wbuf_add_ino_nolock - add an inode number into the wbuf inode array.
- * @wbuf: the write-buffer whereto add
+ * @wbuf: the write-buffer where to add
  * @inum: the inode number
  *
  * This function adds an inode number to the inode array of the write-buffer.
index 6db7a6be6c9732a8a14cecc8ea60683522493442..8aacd64957a223c0a01e2d9c54dd73c9d7fbd409 100644 (file)
@@ -25,7 +25,6 @@
 /* This file implements EXT2-compatible extended attribute ioctl() calls */
 
 #include <linux/compat.h>
-#include <linux/smp_lock.h>
 #include <linux/mount.h>
 #include "ubifs.h"
 
index 805605250f128af9b6a978fa8c29c5c31660539a..e5f6cf8a115535e469a646e4806d9dcdbf19a490 100644 (file)
@@ -52,6 +52,25 @@ static int is_empty(void *buf, int len)
        return 1;
 }
 
+/**
+ * first_non_ff - find offset of the first non-0xff byte.
+ * @buf: buffer to search in
+ * @len: length of buffer
+ *
+ * This function returns offset of the first non-0xff byte in @buf or %-1 if
+ * the buffer contains only 0xff bytes.
+ */
+static int first_non_ff(void *buf, int len)
+{
+       uint8_t *p = buf;
+       int i;
+
+       for (i = 0; i < len; i++)
+               if (*p++ != 0xff)
+                       return i;
+       return -1;
+}
+
 /**
  * get_master_node - get the last valid master node allowing for corruption.
  * @c: UBIFS file-system description object
@@ -357,11 +376,7 @@ static int is_last_write(const struct ubifs_info *c, void *buf, int offs)
        empty_offs = ALIGN(offs + 1, c->min_io_size);
        check_len = c->leb_size - empty_offs;
        p = buf + empty_offs - offs;
-
-       for (; check_len > 0; check_len--)
-               if (*p++ != 0xff)
-                       return 0;
-       return 1;
+       return is_empty(p, check_len);
 }
 
 /**
@@ -543,8 +558,8 @@ static int drop_incomplete_group(struct ubifs_scan_leb *sleb, int *offs)
  *
  * This function does a scan of a LEB, but caters for errors that might have
  * been caused by the unclean unmount from which we are attempting to recover.
- *
- * This function returns %0 on success and a negative error code on failure.
+ * Returns %0 in case of success, %-EUCLEAN if an unrecoverable corruption is
+ * found, and a negative error code in case of failure.
  */
 struct ubifs_scan_leb *ubifs_recover_leb(struct ubifs_info *c, int lnum,
                                         int offs, void *sbuf, int grouped)
@@ -643,7 +658,8 @@ struct ubifs_scan_leb *ubifs_recover_leb(struct ubifs_info *c, int lnum,
                        goto corrupted;
                default:
                        dbg_err("unknown");
-                       goto corrupted;
+                       err = -EINVAL;
+                       goto error;
                }
        }
 
@@ -652,8 +668,13 @@ struct ubifs_scan_leb *ubifs_recover_leb(struct ubifs_info *c, int lnum,
                        clean_buf(c, &buf, lnum, &offs, &len);
                        need_clean = 1;
                } else {
-                       ubifs_err("corrupt empty space at LEB %d:%d",
-                                 lnum, offs);
+                       int corruption = first_non_ff(buf, len);
+
+                       ubifs_err("corrupt empty space LEB %d:%d, corruption "
+                                 "starts at %d", lnum, offs, corruption);
+                       /* Make sure we dump interesting non-0xFF data */
+                       offs = corruption;
+                       buf += corruption;
                        goto corrupted;
                }
        }
@@ -813,7 +834,7 @@ struct ubifs_scan_leb *ubifs_recover_log_leb(struct ubifs_info *c, int lnum,
 static int recover_head(const struct ubifs_info *c, int lnum, int offs,
                        void *sbuf)
 {
-       int len, err, need_clean = 0;
+       int len, err;
 
        if (c->min_io_size > 1)
                len = c->min_io_size;
@@ -827,19 +848,7 @@ static int recover_head(const struct ubifs_info *c, int lnum, int offs,
 
        /* Read at the head location and check it is empty flash */
        err = ubi_read(c->ubi, lnum, sbuf, offs, len);
-       if (err)
-               need_clean = 1;
-       else {
-               uint8_t *p = sbuf;
-
-               while (len--)
-                       if (*p++ != 0xff) {
-                               need_clean = 1;
-                               break;
-                       }
-       }
-
-       if (need_clean) {
+       if (err || !is_empty(sbuf, len)) {
                dbg_rcvry("cleaning head at %d:%d", lnum, offs);
                if (offs == 0)
                        return ubifs_leb_unmap(c, lnum);
index 11cc80125a49524cef118b97173ed7ff5fb94fd9..2970500f32dfbb76ca9b8d6ff39fd8ee08fada4a 100644 (file)
@@ -837,9 +837,10 @@ static int replay_log_leb(struct ubifs_info *c, int lnum, int offs, void *sbuf)
 
        dbg_mnt("replay log LEB %d:%d", lnum, offs);
        sleb = ubifs_scan(c, lnum, offs, sbuf);
-       if (IS_ERR(sleb)) {
-               if (c->need_recovery)
-                       sleb = ubifs_recover_log_leb(c, lnum, offs, sbuf);
+       if (IS_ERR(sleb) ) {
+               if (PTR_ERR(sleb) != -EUCLEAN || !c->need_recovery)
+                       return PTR_ERR(sleb);
+               sleb = ubifs_recover_log_leb(c, lnum, offs, sbuf);
                if (IS_ERR(sleb))
                        return PTR_ERR(sleb);
        }
@@ -957,7 +958,7 @@ out:
        return err;
 
 out_dump:
-       ubifs_err("log error detected while replying the log at LEB %d:%d",
+       ubifs_err("log error detected while replaying the log at LEB %d:%d",
                  lnum, offs + snod->offs);
        dbg_dump_node(c, snod->node);
        ubifs_scan_destroy(sleb);
index 0ed82479b44b4daca156a80107fee1b040ec10a7..892ebfee4fe538fe033596c5d42d13860d5fe82a 100644 (file)
@@ -238,12 +238,12 @@ void ubifs_scanned_corruption(const struct ubifs_info *c, int lnum, int offs,
 {
        int len;
 
-       ubifs_err("corrupted data at LEB %d:%d", lnum, offs);
+       ubifs_err("corruption at LEB %d:%d", lnum, offs);
        if (dbg_failure_mode)
                return;
        len = c->leb_size - offs;
-       if (len > 4096)
-               len = 4096;
+       if (len > 8192)
+               len = 8192;
        dbg_err("first %d bytes from LEB %d:%d", len, lnum, offs);
        print_hex_dump(KERN_DEBUG, "", DUMP_PREFIX_OFFSET, 32, 4, buf, len, 1);
 }
@@ -256,7 +256,9 @@ void ubifs_scanned_corruption(const struct ubifs_info *c, int lnum, int offs,
  * @sbuf: scan buffer (must be c->leb_size)
  *
  * This function scans LEB number @lnum and returns complete information about
- * its contents. Returns an error code in case of failure.
+ * its contents. Returns the scaned information in case of success and,
+ * %-EUCLEAN if the LEB neads recovery, and other negative error codes in case
+ * of failure.
  */
 struct ubifs_scan_leb *ubifs_scan(const struct ubifs_info *c, int lnum,
                                  int offs, void *sbuf)
@@ -279,7 +281,6 @@ struct ubifs_scan_leb *ubifs_scan(const struct ubifs_info *c, int lnum,
                cond_resched();
 
                ret = ubifs_scan_a_node(c, buf, len, lnum, offs, 0);
-
                if (ret > 0) {
                        /* Padding bytes or a valid padding node */
                        offs += ret;
@@ -304,7 +305,8 @@ struct ubifs_scan_leb *ubifs_scan(const struct ubifs_info *c, int lnum,
                        goto corrupted;
                default:
                        dbg_err("unknown");
-                       goto corrupted;
+                       err = -EINVAL;
+                       goto error;
                }
 
                err = ubifs_add_snod(c, sleb, buf, offs);
@@ -317,8 +319,10 @@ struct ubifs_scan_leb *ubifs_scan(const struct ubifs_info *c, int lnum,
                len -= node_len;
        }
 
-       if (offs % c->min_io_size)
-               goto corrupted;
+       if (offs % c->min_io_size) {
+               ubifs_err("empty space starts at non-aligned offset %d", offs);
+               goto corrupted;;
+       }
 
        ubifs_end_scan(c, sleb, lnum, offs);
 
index 79fad43f3c57ecc71b9d6adaf8dfd5e650e6fa08..26d2e0d8046598ed579a400293dbebd38eefc7e3 100644 (file)
@@ -797,7 +797,7 @@ static int alloc_wbufs(struct ubifs_info *c)
         * does not need to be synchronized by timer.
         */
        c->jheads[GCHD].wbuf.dtype = UBI_LONGTERM;
-       c->jheads[GCHD].wbuf.softlimit = ktime_set(0, 0);
+       c->jheads[GCHD].wbuf.no_timer = 1;
 
        return 0;
 }
@@ -986,7 +986,7 @@ static int ubifs_parse_options(struct ubifs_info *c, char *options,
                switch (token) {
                /*
                 * %Opt_fast_unmount and %Opt_norm_unmount options are ignored.
-                * We accepte them in order to be backware-compatible. But this
+                * We accept them in order to be backward-compatible. But this
                 * should be removed at some point.
                 */
                case Opt_fast_unmount:
@@ -1287,6 +1287,9 @@ static int mount_ubifs(struct ubifs_info *c)
        if (err)
                goto out_journal;
 
+       /* Calculate 'min_idx_lebs' after journal replay */
+       c->min_idx_lebs = ubifs_calc_min_idx_lebs(c);
+
        err = ubifs_mount_orphans(c, c->need_recovery, mounted_read_only);
        if (err)
                goto out_orphans;
@@ -1754,10 +1757,8 @@ static void ubifs_put_super(struct super_block *sb)
 
                /* Synchronize write-buffers */
                if (c->jheads)
-                       for (i = 0; i < c->jhead_cnt; i++) {
+                       for (i = 0; i < c->jhead_cnt; i++)
                                ubifs_wbuf_sync(&c->jheads[i].wbuf);
-                               hrtimer_cancel(&c->jheads[i].wbuf.timer);
-                       }
 
                /*
                 * On fatal errors c->ro_media is set to 1, in which case we do
@@ -1975,7 +1976,8 @@ static int ubifs_fill_super(struct super_block *sb, void *data, int silent)
        err  = bdi_init(&c->bdi);
        if (err)
                goto out_close;
-       err = bdi_register(&c->bdi, NULL, "ubifs");
+       err = bdi_register(&c->bdi, NULL, "ubifs_%d_%d",
+                          c->vi.ubi_num, c->vi.vol_id);
        if (err)
                goto out_bdi;
 
index 1bf01d8200667503cb0f0e310fafbc4304701721..a29349094422731766fa82a95201e0f14ad3c7fb 100644 (file)
@@ -95,8 +95,9 @@
  */
 #define BGT_NAME_PATTERN "ubifs_bgt%d_%d"
 
-/* Default write-buffer synchronization timeout in seconds */
-#define DEFAULT_WBUF_TIMEOUT_SECS 5
+/* Write-buffer synchronization timeout interval in seconds */
+#define WBUF_TIMEOUT_SOFTLIMIT 3
+#define WBUF_TIMEOUT_HARDLIMIT 5
 
 /* Maximum possible inode number (only 32-bit inodes are supported now) */
 #define MAX_INUM 0xFFFFFFFF
@@ -654,7 +655,8 @@ typedef int (*ubifs_lpt_scan_callback)(struct ubifs_info *c,
  * @delta: hard and soft timeouts delta (the timer expire inteval is @softlimit
  *         and @softlimit + @delta)
  * @timer: write-buffer timer
- * @need_sync: it is set if its timer expired and needs sync
+ * @no_timer: non-zero if this write-buffer does not have a timer
+ * @need_sync: non-zero if the timer expired and the wbuf needs sync'ing
  * @next_ino: points to the next position of the following inode number
  * @inodes: stores the inode numbers of the nodes which are in wbuf
  *
@@ -683,7 +685,8 @@ struct ubifs_wbuf {
        ktime_t softlimit;
        unsigned long long delta;
        struct hrtimer timer;
-       int need_sync;
+       unsigned int no_timer:1;
+       unsigned int need_sync:1;
        int next_ino;
        ino_t *inodes;
 };
index cfd31e229c89d48e3315edd8f96613a262c16979..adafcf556531c0d4c81a7843a36f573289781875 100644 (file)
@@ -55,9 +55,9 @@
  * ACL support is not implemented.
  */
 
+#include "ubifs.h"
 #include <linux/xattr.h>
 #include <linux/posix_acl_xattr.h>
-#include "ubifs.h"
 
 /*
  * Limit the number of extended attributes per inode so that the total size
index e48e9a3af76312d683723658ed42c51db7d8a740..1e068535b58bfc78b0970dc3ccb34e03cc7c1ecb 100644 (file)
@@ -238,7 +238,7 @@ static int udf_bitmap_prealloc_blocks(struct super_block *sb,
 
        mutex_lock(&sbi->s_alloc_mutex);
        part_len = sbi->s_partmaps[partition].s_partition_len;
-       if (first_block < 0 || first_block >= part_len)
+       if (first_block >= part_len)
                goto out;
 
        if (first_block + block_count > part_len)
@@ -297,7 +297,7 @@ static int udf_bitmap_new_block(struct super_block *sb,
        mutex_lock(&sbi->s_alloc_mutex);
 
 repeat:
-       if (goal < 0 || goal >= sbi->s_partmaps[partition].s_partition_len)
+       if (goal >= sbi->s_partmaps[partition].s_partition_len)
                goal = 0;
 
        nr_groups = bitmap->s_nr_groups;
@@ -666,8 +666,7 @@ static int udf_table_prealloc_blocks(struct super_block *sb,
        int8_t etype = -1;
        struct udf_inode_info *iinfo;
 
-       if (first_block < 0 ||
-               first_block >= sbi->s_partmaps[partition].s_partition_len)
+       if (first_block >= sbi->s_partmaps[partition].s_partition_len)
                return 0;
 
        iinfo = UDF_I(table);
@@ -743,7 +742,7 @@ static int udf_table_new_block(struct super_block *sb,
                return newblock;
 
        mutex_lock(&sbi->s_alloc_mutex);
-       if (goal < 0 || goal >= sbi->s_partmaps[partition].s_partition_len)
+       if (goal >= sbi->s_partmaps[partition].s_partition_len)
                goal = 0;
 
        /* We search for the closest matching block to goal. If we find
index 703843f30ffd383f556639af7146c0d99a212c25..1b88fd5df05d6d7f6694a3d9284162d4ed386a0b 100644 (file)
@@ -56,7 +56,12 @@ unsigned long udf_get_last_block(struct super_block *sb)
        struct block_device *bdev = sb->s_bdev;
        unsigned long lblock = 0;
 
-       if (ioctl_by_bdev(bdev, CDROM_LAST_WRITTEN, (unsigned long) &lblock))
+       /*
+        * ioctl failed or returned obviously bogus value?
+        * Try using the device size...
+        */
+       if (ioctl_by_bdev(bdev, CDROM_LAST_WRITTEN, (unsigned long) &lblock) ||
+           lblock == 0)
                lblock = bdev->bd_inode->i_size >> sb->s_blocksize_bits;
 
        if (lblock)
index 1cd3b55ee3d227d5916c18d95c2dd84a45e5285d..2d3f90afe5f14ee6ef3543d0bd6e01be014952ba 100644 (file)
@@ -53,7 +53,7 @@ kmem_alloc(size_t size, unsigned int __nocast flags)
                        printk(KERN_ERR "XFS: possible memory allocation "
                                        "deadlock in %s (mode:0x%x)\n",
                                        __func__, lflags);
-               congestion_wait(WRITE, HZ/50);
+               congestion_wait(BLK_RW_ASYNC, HZ/50);
        } while (1);
 }
 
@@ -130,7 +130,7 @@ kmem_zone_alloc(kmem_zone_t *zone, unsigned int __nocast flags)
                        printk(KERN_ERR "XFS: possible memory allocation "
                                        "deadlock in %s (mode:0x%x)\n",
                                        __func__, lflags);
-               congestion_wait(WRITE, HZ/50);
+               congestion_wait(BLK_RW_ASYNC, HZ/50);
        } while (1);
 }
 
index 1e9d1246eebc8e946e508e1c24f070f5aa28c394..b23a5450644608fddbc7d5146e6c20f638209450 100644 (file)
 #include <linux/posix_acl_xattr.h>
 
 
-#define XFS_ACL_NOT_CACHED     ((void *)-1)
-
 /*
  * Locking scheme:
  *  - all ACL updates are protected by inode->i_mutex, which is taken before
  *    calling into this file.
- *  - access and updates to the ip->i_acl and ip->i_default_acl pointers are
- *    protected by inode->i_lock.
  */
 
 STATIC struct posix_acl *
@@ -102,59 +98,35 @@ xfs_acl_to_disk(struct xfs_acl *aclp, const struct posix_acl *acl)
        }
 }
 
-/*
- * Update the cached ACL pointer in the inode.
- *
- * Because we don't hold any locks while reading/writing the attribute
- * from/to disk another thread could have raced and updated the cached
- * ACL value before us. In that case we release the previous cached value
- * and update it with our new value.
- */
-STATIC void
-xfs_update_cached_acl(struct inode *inode, struct posix_acl **p_acl,
-               struct posix_acl *acl)
-{
-       spin_lock(&inode->i_lock);
-       if (*p_acl && *p_acl != XFS_ACL_NOT_CACHED)
-               posix_acl_release(*p_acl);
-       *p_acl = posix_acl_dup(acl);
-       spin_unlock(&inode->i_lock);
-}
-
 struct posix_acl *
 xfs_get_acl(struct inode *inode, int type)
 {
        struct xfs_inode *ip = XFS_I(inode);
-       struct posix_acl *acl = NULL, **p_acl;
+       struct posix_acl *acl;
        struct xfs_acl *xfs_acl;
        int len = sizeof(struct xfs_acl);
        char *ea_name;
        int error;
 
+       acl = get_cached_acl(inode, type);
+       if (acl != ACL_NOT_CACHED)
+               return acl;
+
        switch (type) {
        case ACL_TYPE_ACCESS:
                ea_name = SGI_ACL_FILE;
-               p_acl = &ip->i_acl;
                break;
        case ACL_TYPE_DEFAULT:
                ea_name = SGI_ACL_DEFAULT;
-               p_acl = &ip->i_default_acl;
                break;
        default:
-               return ERR_PTR(-EINVAL);
+               BUG();
        }
 
-       spin_lock(&inode->i_lock);
-       if (*p_acl != XFS_ACL_NOT_CACHED)
-               acl = posix_acl_dup(*p_acl);
-       spin_unlock(&inode->i_lock);
-
        /*
         * If we have a cached ACLs value just return it, not need to
         * go out to the disk.
         */
-       if (acl)
-               return acl;
 
        xfs_acl = kzalloc(sizeof(struct xfs_acl), GFP_KERNEL);
        if (!xfs_acl)
@@ -165,7 +137,7 @@ xfs_get_acl(struct inode *inode, int type)
                /*
                 * If the attribute doesn't exist make sure we have a negative
                 * cache entry, for any other error assume it is transient and
-                * leave the cache entry as XFS_ACL_NOT_CACHED.
+                * leave the cache entry as ACL_NOT_CACHED.
                 */
                if (error == -ENOATTR) {
                        acl = NULL;
@@ -179,7 +151,7 @@ xfs_get_acl(struct inode *inode, int type)
                goto out;
 
  out_update_cache:
-       xfs_update_cached_acl(inode, p_acl, acl);
+       set_cached_acl(inode, type, acl);
  out:
        kfree(xfs_acl);
        return acl;
@@ -189,7 +161,6 @@ STATIC int
 xfs_set_acl(struct inode *inode, int type, struct posix_acl *acl)
 {
        struct xfs_inode *ip = XFS_I(inode);
-       struct posix_acl **p_acl;
        char *ea_name;
        int error;
 
@@ -199,13 +170,11 @@ xfs_set_acl(struct inode *inode, int type, struct posix_acl *acl)
        switch (type) {
        case ACL_TYPE_ACCESS:
                ea_name = SGI_ACL_FILE;
-               p_acl = &ip->i_acl;
                break;
        case ACL_TYPE_DEFAULT:
                if (!S_ISDIR(inode->i_mode))
                        return acl ? -EACCES : 0;
                ea_name = SGI_ACL_DEFAULT;
-               p_acl = &ip->i_default_acl;
                break;
        default:
                return -EINVAL;
@@ -242,7 +211,7 @@ xfs_set_acl(struct inode *inode, int type, struct posix_acl *acl)
        }
 
        if (!error)
-               xfs_update_cached_acl(inode, p_acl, acl);
+               set_cached_acl(inode, type, acl);
        return error;
 }
 
@@ -384,30 +353,6 @@ xfs_acl_chmod(struct inode *inode)
        return error;
 }
 
-void
-xfs_inode_init_acls(struct xfs_inode *ip)
-{
-       /*
-        * No need for locking, inode is not live yet.
-        */
-       ip->i_acl = XFS_ACL_NOT_CACHED;
-       ip->i_default_acl = XFS_ACL_NOT_CACHED;
-}
-
-void
-xfs_inode_clear_acls(struct xfs_inode *ip)
-{
-       /*
-        * No need for locking here, the inode is not live anymore
-        * and just about to be freed.
-        */
-       if (ip->i_acl != XFS_ACL_NOT_CACHED)
-               posix_acl_release(ip->i_acl);
-       if (ip->i_default_acl != XFS_ACL_NOT_CACHED)
-               posix_acl_release(ip->i_default_acl);
-}
-
-
 /*
  * System xattr handlers.
  *
index 1418b916fc2755306cca61e60c734154d543c82f..0c93c7ef3d187a27dbe6b8196de4aaa08be66447 100644 (file)
@@ -412,7 +412,7 @@ _xfs_buf_lookup_pages(
 
                        XFS_STATS_INC(xb_page_retries);
                        xfsbufd_wakeup(0, gfp_mask);
-                       congestion_wait(WRITE, HZ/50);
+                       congestion_wait(BLK_RW_ASYNC, HZ/50);
                        goto retry;
                }
 
index f4e25544157422812b4a1e576d3539e86b75b9bd..0542fd50764945935bd6975bc8094a8df2348601 100644 (file)
@@ -41,7 +41,6 @@
 #include "xfs_ioctl.h"
 
 #include <linux/dcache.h>
-#include <linux/smp_lock.h>
 
 static struct vm_operations_struct xfs_file_vm_ops;
 
index 63dc1f2efad5bbf1c291b79b312d326b3aebc82d..947b150df8ede4576550f6f5d8f10a618348ca7e 100644 (file)
@@ -46,8 +46,6 @@ extern int xfs_check_acl(struct inode *inode, int mask);
 extern struct posix_acl *xfs_get_acl(struct inode *inode, int type);
 extern int xfs_inherit_acl(struct inode *inode, struct posix_acl *default_acl);
 extern int xfs_acl_chmod(struct inode *inode);
-extern void xfs_inode_init_acls(struct xfs_inode *ip);
-extern void xfs_inode_clear_acls(struct xfs_inode *ip);
 extern int posix_acl_access_exists(struct inode *inode);
 extern int posix_acl_default_exists(struct inode *inode);
 
@@ -57,8 +55,6 @@ extern struct xattr_handler xfs_xattr_system_handler;
 # define xfs_get_acl(inode, type)                      NULL
 # define xfs_inherit_acl(inode, default_acl)           0
 # define xfs_acl_chmod(inode)                          0
-# define xfs_inode_init_acls(ip)
-# define xfs_inode_clear_acls(ip)
 # define posix_acl_access_exists(inode)                        0
 # define posix_acl_default_exists(inode)               0
 #endif /* CONFIG_XFS_POSIX_ACL */
index 76c540f719e49bb73ef6fd7c99b8d1e0c6d80a54..5fcec6f020a7ddff25df7e54e58750ca651733b1 100644 (file)
@@ -83,7 +83,6 @@ xfs_inode_alloc(
        memset(&ip->i_d, 0, sizeof(xfs_icdinode_t));
        ip->i_size = 0;
        ip->i_new_size = 0;
-       xfs_inode_init_acls(ip);
 
        /*
         * Initialize inode's trace buffers.
@@ -560,7 +559,6 @@ xfs_ireclaim(
        ASSERT(atomic_read(&ip->i_pincount) == 0);
        ASSERT(!spin_is_locked(&ip->i_flags_lock));
        ASSERT(completion_done(&ip->i_flush));
-       xfs_inode_clear_acls(ip);
        kmem_zone_free(xfs_inode_zone, ip);
 }
 
index 77016702938b23cca6c9b4e6a4b48e164ae176ac..1804f866a71d285b760db6bd5df1574676ecb898 100644 (file)
@@ -273,11 +273,6 @@ typedef struct xfs_inode {
        /* VFS inode */
        struct inode            i_vnode;        /* embedded VFS inode */
 
-#ifdef CONFIG_XFS_POSIX_ACL
-       struct posix_acl        *i_acl;
-       struct posix_acl        *i_default_acl;
-#endif
-
        /* Trace buffers per inode. */
 #ifdef XFS_INODE_TRACE
        struct ktrace           *i_trace;       /* general inode trace */
index c34b11022908a01c521367ddf85249fcacb98ffe..c65e4ce6c3afa38e41ada87bfac5fd5d29c27f36 100644 (file)
@@ -114,10 +114,13 @@ struct acpi_device_ops {
        acpi_op_notify notify;
 };
 
+#define ACPI_DRIVER_ALL_NOTIFY_EVENTS  0x1     /* system AND device events */
+
 struct acpi_driver {
        char name[80];
        char class[80];
        const struct acpi_device_id *ids; /* Supported Hardware IDs */
+       unsigned int flags;
        struct acpi_device_ops ops;
        struct device_driver drv;
        struct module *owner;
@@ -168,7 +171,7 @@ struct acpi_device_dir {
 
 /* Plug and Play */
 
-typedef char acpi_bus_id[5];
+typedef char acpi_bus_id[8];
 typedef unsigned long acpi_bus_address;
 typedef char acpi_hardware_id[15];
 typedef char acpi_unique_id[9];
@@ -365,10 +368,10 @@ struct acpi_bus_type {
 int register_acpi_bus_type(struct acpi_bus_type *);
 int unregister_acpi_bus_type(struct acpi_bus_type *);
 struct device *acpi_get_physical_device(acpi_handle);
-struct device *acpi_get_physical_pci_device(acpi_handle);
 
 /* helper */
 acpi_handle acpi_get_child(acpi_handle, acpi_integer);
+int acpi_is_root_bridge(acpi_handle);
 acpi_handle acpi_get_pci_rootbridge_handle(unsigned int, unsigned int);
 #define DEVICE_ACPI_HANDLE(dev) ((acpi_handle)((dev)->archdata.acpi_handle))
 
index 0352c8f0b05b5f89182a8f3cce886a0b33d94752..f4906f6568d4142d1eb77c12f5997ba5da8ce5f7 100644 (file)
@@ -57,8 +57,7 @@
  */
 
 #define ACPI_POWER_HID                 "LNXPOWER"
-#define ACPI_PROCESSOR_OBJECT_HID      "ACPI_CPU"
-#define ACPI_PROCESSOR_HID             "ACPI0007"
+#define ACPI_PROCESSOR_OBJECT_HID      "LNXCPU"
 #define ACPI_SYSTEM_HID                        "LNXSYSTM"
 #define ACPI_THERMAL_HID               "LNXTHERM"
 #define ACPI_BUTTON_HID_POWERF         "LNXPWRBN"
@@ -91,17 +90,15 @@ int acpi_pci_link_free_irq(acpi_handle handle);
 
 /* ACPI PCI Interrupt Routing (pci_irq.c) */
 
-int acpi_pci_irq_add_prt(acpi_handle handle, int segment, int bus);
-void acpi_pci_irq_del_prt(int segment, int bus);
+int acpi_pci_irq_add_prt(acpi_handle handle, struct pci_bus *bus);
+void acpi_pci_irq_del_prt(struct pci_bus *bus);
 
 /* ACPI PCI Device Binding (pci_bind.c) */
 
 struct pci_bus;
 
-acpi_status acpi_get_pci_id(acpi_handle handle, struct acpi_pci_id *id);
-int acpi_pci_bind(struct acpi_device *device);
-int acpi_pci_bind_root(struct acpi_device *device, struct acpi_pci_id *id,
-                      struct pci_bus *bus);
+struct pci_dev *acpi_get_pci_dev(acpi_handle);
+int acpi_pci_bind_root(struct acpi_device *device);
 
 /* Arch-defined function to add a bus to the system */
 
index 4927c063347c024b4528af2ecd430eeea391b0eb..baf1e0a9a7ee9f4ccc309cb72e1554e7bdf46ff8 100644 (file)
@@ -258,6 +258,7 @@ DECLARE_PER_CPU(struct acpi_processor *, processors);
 extern struct acpi_processor_errata errata;
 
 void arch_acpi_processor_init_pdc(struct acpi_processor *pr);
+void arch_acpi_processor_cleanup_pdc(struct acpi_processor *pr);
 
 #ifdef ARCH_HAS_POWER_INIT
 void acpi_processor_power_init_bm_check(struct acpi_processor_flags *flags,
index af6fe95fd3d004e88e0d2cafa63c682a611e687e..cf7be3dd157bec5572a2b9f3220e4e1274d5f27b 100644 (file)
@@ -3,10 +3,10 @@
 
 #if (defined CONFIG_ACPI_VIDEO || defined CONFIG_ACPI_VIDEO_MODULE)
 extern int acpi_video_register(void);
-extern int acpi_video_exit(void);
+extern void acpi_video_unregister(void);
 #else
 static inline int acpi_video_register(void) { return 0; }
-static inline void acpi_video_exit(void) { return; }
+static inline void acpi_video_unregister(void) { return; }
 #endif
 
 #endif
index d7d50d7ee51ec0716baa0c3725ad5f5ae85602a2..aa00800adaccdfbb751e6d85786474d1775006ce 100644 (file)
@@ -97,4 +97,8 @@ extern void setup_per_cpu_areas(void);
 #define PER_CPU_ATTRIBUTES
 #endif
 
+#ifndef PER_CPU_DEF_ATTRIBUTES
+#define PER_CPU_DEF_ATTRIBUTES
+#endif
+
 #endif /* _ASM_GENERIC_PERCPU_H_ */
index 92b73b6140ff4328741ef415468b8008428215cc..a553f1041cf1e1fe7210c92e5be2e5159975a65d 100644 (file)
        . = ALIGN(align);                                               \
        *(.data.cacheline_aligned)
 
-#define INIT_TASK(align)                                               \
+#define INIT_TASK_DATA(align)                                          \
        . = ALIGN(align);                                               \
        *(.data.init_task)
 
 /*
  * Init task
  */
-#define INIT_TASK_DATA(align)                                          \
+#define INIT_TASK_DATA_SECTION(align)                                  \
        . = ALIGN(align);                                               \
        .data.init_task : {                                             \
-               INIT_TASK                                               \
+               INIT_TASK_DATA(align)                                   \
        }
 
 #ifdef CONFIG_CONSTRUCTORS
-#define KERNEL_CTORS() VMLINUX_SYMBOL(__ctors_start) = .; \
+#define KERNEL_CTORS() . = ALIGN(8);                      \
+                       VMLINUX_SYMBOL(__ctors_start) = .; \
                        *(.ctors)                          \
                        VMLINUX_SYMBOL(__ctors_end) = .;
 #else
  * matches the requirment of PAGE_ALIGNED_DATA.
  *
  * use 0 as page_align if page_aligned data is not used */
-#define RW_DATA_SECTION(cacheline, nosave, pagealigned, inittask)      \
+#define RW_DATA_SECTION(cacheline, pagealigned, inittask)              \
        . = ALIGN(PAGE_SIZE);                                           \
        .data : AT(ADDR(.data) - LOAD_OFFSET) {                         \
-               INIT_TASK(inittask)                                     \
+               INIT_TASK_DATA(inittask)                                \
                CACHELINE_ALIGNED_DATA(cacheline)                       \
                READ_MOSTLY_DATA(cacheline)                             \
                DATA_DATA                                               \
                CONSTRUCTORS                                            \
-               NOSAVE_DATA(nosave)                                     \
+               NOSAVE_DATA                                             \
                PAGE_ALIGNED_DATA(pagealigned)                          \
        }
 
index c263e4d71754095d56ec29489f20804cab5ad3d0..7d6c9a2dfcbbb8608e400e310640511031c27f76 100644 (file)
@@ -35,11 +35,11 @@ struct est_timings {
 } __attribute__((packed));
 
 /* 00=16:10, 01=4:3, 10=5:4, 11=16:9 */
-#define EDID_TIMING_ASPECT_SHIFT 0
+#define EDID_TIMING_ASPECT_SHIFT 6
 #define EDID_TIMING_ASPECT_MASK  (0x3 << EDID_TIMING_ASPECT_SHIFT)
 
 /* need to add 60 */
-#define EDID_TIMING_VFREQ_SHIFT  2
+#define EDID_TIMING_VFREQ_SHIFT  0
 #define EDID_TIMING_VFREQ_MASK   (0x3f << EDID_TIMING_VFREQ_SHIFT)
 
 struct std_timing {
@@ -47,11 +47,11 @@ struct std_timing {
        u8 vfreq_aspect;
 } __attribute__((packed));
 
-#define DRM_EDID_PT_HSYNC_POSITIVE (1 << 6)
-#define DRM_EDID_PT_VSYNC_POSITIVE (1 << 5)
+#define DRM_EDID_PT_HSYNC_POSITIVE (1 << 1)
+#define DRM_EDID_PT_VSYNC_POSITIVE (1 << 2)
 #define DRM_EDID_PT_SEPARATE_SYNC  (3 << 3)
-#define DRM_EDID_PT_STEREO         (1 << 2)
-#define DRM_EDID_PT_INTERLACED     (1 << 1)
+#define DRM_EDID_PT_STEREO         (1 << 5)
+#define DRM_EDID_PT_INTERLACED     (1 << 7)
 
 /* If detailed data is pixel timing */
 struct detailed_pixel_timing {
@@ -93,7 +93,7 @@ struct detailed_data_monitor_range {
 } __attribute__((packed));
 
 struct detailed_data_wpindex {
-       u8 white_xy_lo; /* Upper 2 bits each */
+       u8 white_yx_lo; /* Lower 2 bits each */
        u8 white_x_hi;
        u8 white_y_hi;
        u8 gamma; /* need to divide by 100 then add 1 */
@@ -135,21 +135,21 @@ struct detailed_timing {
        } data;
 } __attribute__((packed));
 
-#define DRM_EDID_INPUT_SERRATION_VSYNC (1 << 7)
-#define DRM_EDID_INPUT_SYNC_ON_GREEN   (1 << 5)
-#define DRM_EDID_INPUT_COMPOSITE_SYNC  (1 << 4)
+#define DRM_EDID_INPUT_SERRATION_VSYNC (1 << 0)
+#define DRM_EDID_INPUT_SYNC_ON_GREEN   (1 << 1)
+#define DRM_EDID_INPUT_COMPOSITE_SYNC  (1 << 2)
 #define DRM_EDID_INPUT_SEPARATE_SYNCS  (1 << 3)
-#define DRM_EDID_INPUT_BLANK_TO_BLACK  (1 << 2)
-#define DRM_EDID_INPUT_VIDEO_LEVEL     (3 << 1)
-#define DRM_EDID_INPUT_DIGITAL         (1 << 0) /* bits above must be zero if set */
+#define DRM_EDID_INPUT_BLANK_TO_BLACK  (1 << 4)
+#define DRM_EDID_INPUT_VIDEO_LEVEL     (3 << 5)
+#define DRM_EDID_INPUT_DIGITAL         (1 << 7) /* bits below must be zero if set */
 
-#define DRM_EDID_FEATURE_DEFAULT_GTF      (1 << 7)
-#define DRM_EDID_FEATURE_PREFERRED_TIMING (1 << 6)
-#define DRM_EDID_FEATURE_STANDARD_COLOR   (1 << 5)
+#define DRM_EDID_FEATURE_DEFAULT_GTF      (1 << 0)
+#define DRM_EDID_FEATURE_PREFERRED_TIMING (1 << 1)
+#define DRM_EDID_FEATURE_STANDARD_COLOR   (1 << 2)
 #define DRM_EDID_FEATURE_DISPLAY_TYPE     (3 << 3) /* 00=mono, 01=rgb, 10=non-rgb, 11=unknown */
-#define DRM_EDID_FEATURE_PM_ACTIVE_OFF    (1 << 2)
-#define DRM_EDID_FEATURE_PM_SUSPEND       (1 << 1)
-#define DRM_EDID_FEATURE_PM_STANDBY       (1 << 0)
+#define DRM_EDID_FEATURE_PM_ACTIVE_OFF    (1 << 5)
+#define DRM_EDID_FEATURE_PM_SUSPEND       (1 << 6)
+#define DRM_EDID_FEATURE_PM_STANDBY       (1 << 7)
 
 struct edid {
        u8 header[8];
index 45c18672b0936dc50c04b0cb33f105376401db2b..7174818c2c13a3a561d8ab13e28f4283d02c75d1 100644 (file)
@@ -43,6 +43,7 @@
        {0x1002, 0x4A4F, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|RADEON_NEW_MEMMAP}, \
        {0x1002, 0x4A50, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|RADEON_NEW_MEMMAP}, \
        {0x1002, 0x4A54, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|RADEON_NEW_MEMMAP}, \
+       {0x1002, 0x4B48, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|RADEON_NEW_MEMMAP}, \
        {0x1002, 0x4B49, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|RADEON_NEW_MEMMAP}, \
        {0x1002, 0x4B4A, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|RADEON_NEW_MEMMAP}, \
        {0x1002, 0x4B4B, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|RADEON_NEW_MEMMAP}, \
        {0x1002, 0x9440, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV770|RADEON_NEW_MEMMAP}, \
        {0x1002, 0x9441, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV770|RADEON_NEW_MEMMAP}, \
        {0x1002, 0x9442, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV770|RADEON_NEW_MEMMAP}, \
+       {0x1002, 0x9443, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV770|RADEON_NEW_MEMMAP}, \
        {0x1002, 0x9444, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV770|RADEON_NEW_MEMMAP}, \
        {0x1002, 0x9446, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV770|RADEON_NEW_MEMMAP}, \
        {0x1002, 0x944A, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV770|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \
        {0x1002, 0x9599, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV635|RADEON_NEW_MEMMAP}, \
        {0x1002, 0x959B, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV635|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \
        {0x1002, 0x95C0, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV620|RADEON_NEW_MEMMAP}, \
+       {0x1002, 0x95C2, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV620|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \
+       {0x1002, 0x95C4, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV620|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \
        {0x1002, 0x95C5, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV620|RADEON_NEW_MEMMAP}, \
        {0x1002, 0x95C6, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV620|RADEON_NEW_MEMMAP}, \
        {0x1002, 0x95C7, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV620|RADEON_NEW_MEMMAP}, \
        {0x1002, 0x95C9, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV620|RADEON_NEW_MEMMAP}, \
-       {0x1002, 0x95C2, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV620|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \
-       {0x1002, 0x95C4, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV620|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \
        {0x1002, 0x95CC, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV620|RADEON_NEW_MEMMAP}, \
        {0x1002, 0x95CD, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV620|RADEON_NEW_MEMMAP}, \
        {0x1002, 0x95CE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV620|RADEON_NEW_MEMMAP}, \
index 03f22076381ff4df51d2b3fe3db2bbc8fd08e4ad..334a3593cdfd4076e7522a2a40439ba5625559a8 100644 (file)
@@ -57,6 +57,7 @@ header-y += dlmconstants.h
 header-y += dlm_device.h
 header-y += dlm_netlink.h
 header-y += dm-ioctl.h
+header-y += dm-log-userspace.h
 header-y += dn.h
 header-y += dqblk_xfs.h
 header-y += efs_fs_sb.h
index 51b4b0a5ce8cf00b00fd849ee26e0e7bc504a795..34321cfffeab02010ac142f353b06c4cb7e501ad 100644 (file)
@@ -113,9 +113,6 @@ void acpi_irq_stats_init(void);
 extern u32 acpi_irq_handled;
 extern u32 acpi_irq_not_handled;
 
-extern struct acpi_mcfg_allocation *pci_mmcfg_config;
-extern int pci_mmcfg_config_num;
-
 extern int sbf_port;
 extern unsigned long acpi_realmode_flags;
 
@@ -293,7 +290,10 @@ void __init acpi_s4_no_nvs(void);
                                OSC_PCI_EXPRESS_CAP_STRUCTURE_CONTROL)
 
 extern acpi_status acpi_pci_osc_control_set(acpi_handle handle, u32 flags);
+extern void acpi_early_init(void);
+
 #else  /* CONFIG_ACPI */
+static inline void acpi_early_init(void) { }
 
 static inline int early_acpi_boot_init(void)
 {
index b16a957030f87e16341efe5b41b476a04e742fc2..47f7d932a01d5d7694835b184429112f681f139b 100644 (file)
@@ -121,9 +121,9 @@ struct kiocb {
 
        /*
         * If the aio_resfd field of the userspace iocb is not zero,
-        * this is the underlying file* to deliver event to.
+        * this is the underlying eventfd context to deliver events to.
         */
-       struct file             *ki_eventfd;
+       struct eventfd_ctx      *ki_eventfd;
 };
 
 #define is_sync_kiocb(iocb)    ((iocb)->ki_key == KIOCB_SYNC_KEY)
index 4fa2810b675e6a157293a0aa431e1af95d71d99b..3c7a358241a71d78c9aa288f08b1d83a61a1abb8 100644 (file)
@@ -599,6 +599,8 @@ extern void             audit_log_untrustedstring(struct audit_buffer *ab,
 extern void                audit_log_d_path(struct audit_buffer *ab,
                                             const char *prefix,
                                             struct path *path);
+extern void                audit_log_key(struct audit_buffer *ab,
+                                         char *key);
 extern void                audit_log_lost(const char *message);
 extern int                 audit_update_lsm_rules(void);
 
@@ -621,6 +623,7 @@ extern int audit_enabled;
 #define audit_log_n_untrustedstring(a,n,s) do { ; } while (0)
 #define audit_log_untrustedstring(a,s) do { ; } while (0)
 #define audit_log_d_path(b, p, d) do { ; } while (0)
+#define audit_log_key(b, k) do { ; } while (0)
 #define audit_enabled 0
 #endif
 #endif
index 0ec2c594868e657ad20cfaffc21227bf7ee2e18b..1d52425a61189e15c739a1009449e97022bd2eb8 100644 (file)
@@ -229,9 +229,14 @@ static inline int bdi_rw_congested(struct backing_dev_info *bdi)
                                  (1 << BDI_async_congested));
 }
 
-void clear_bdi_congested(struct backing_dev_info *bdi, int rw);
-void set_bdi_congested(struct backing_dev_info *bdi, int rw);
-long congestion_wait(int rw, long timeout);
+enum {
+       BLK_RW_ASYNC    = 0,
+       BLK_RW_SYNC     = 1,
+};
+
+void clear_bdi_congested(struct backing_dev_info *bdi, int sync);
+void set_bdi_congested(struct backing_dev_info *bdi, int sync);
+long congestion_wait(int sync, long timeout);
 
 
 static inline bool bdi_cap_writeback_dirty(struct backing_dev_info *bdi)
index 2a04eb54c0dd05b8eda048c8463b9a8eddabde46..2892b710771c5b112b74670c56051ccffb05e7da 100644 (file)
@@ -319,7 +319,6 @@ static inline int bio_has_allocated_vec(struct bio *bio)
  */
 struct bio_integrity_payload {
        struct bio              *bip_bio;       /* parent bio */
-       struct bio_vec          *bip_vec;       /* integrity data vector */
 
        sector_t                bip_sector;     /* virtual start sector */
 
@@ -328,11 +327,12 @@ struct bio_integrity_payload {
 
        unsigned int            bip_size;
 
-       unsigned short          bip_pool;       /* pool the ivec came from */
+       unsigned short          bip_slab;       /* slab the bip came from */
        unsigned short          bip_vcnt;       /* # of integrity bio_vecs */
        unsigned short          bip_idx;        /* current bip_vec index */
 
        struct work_struct      bip_work;       /* I/O completion */
+       struct bio_vec          bip_vec[0];     /* embedded bvec array */
 };
 #endif /* CONFIG_BLK_DEV_INTEGRITY */
 
@@ -430,6 +430,9 @@ struct bio_set {
        unsigned int front_pad;
 
        mempool_t *bio_pool;
+#if defined(CONFIG_BLK_DEV_INTEGRITY)
+       mempool_t *bio_integrity_pool;
+#endif
        mempool_t *bvec_pool;
 };
 
@@ -634,8 +637,9 @@ static inline struct bio *bio_list_get(struct bio_list *bl)
 
 #define bio_integrity(bio) (bio->bi_integrity != NULL)
 
+extern struct bio_integrity_payload *bio_integrity_alloc_bioset(struct bio *, gfp_t, unsigned int, struct bio_set *);
 extern struct bio_integrity_payload *bio_integrity_alloc(struct bio *, gfp_t, unsigned int);
-extern void bio_integrity_free(struct bio *);
+extern void bio_integrity_free(struct bio *, struct bio_set *);
 extern int bio_integrity_add_page(struct bio *, struct page *, unsigned int, unsigned int);
 extern int bio_integrity_enabled(struct bio *bio);
 extern int bio_integrity_set_tag(struct bio *, void *, unsigned int);
@@ -645,21 +649,27 @@ extern void bio_integrity_endio(struct bio *, int);
 extern void bio_integrity_advance(struct bio *, unsigned int);
 extern void bio_integrity_trim(struct bio *, unsigned int, unsigned int);
 extern void bio_integrity_split(struct bio *, struct bio_pair *, int);
-extern int bio_integrity_clone(struct bio *, struct bio *, gfp_t);
+extern int bio_integrity_clone(struct bio *, struct bio *, gfp_t, struct bio_set *);
+extern int bioset_integrity_create(struct bio_set *, int);
+extern void bioset_integrity_free(struct bio_set *);
+extern void bio_integrity_init(void);
 
 #else /* CONFIG_BLK_DEV_INTEGRITY */
 
 #define bio_integrity(a)               (0)
+#define bioset_integrity_create(a, b)  (0)
 #define bio_integrity_prep(a)          (0)
 #define bio_integrity_enabled(a)       (0)
-#define bio_integrity_clone(a, b, c)   (0)
-#define bio_integrity_free(a)          do { } while (0)
+#define bio_integrity_clone(a, b, c, d)        (0)
+#define bioset_integrity_free(a)       do { } while (0)
+#define bio_integrity_free(a, b)       do { } while (0)
 #define bio_integrity_endio(a, b)      do { } while (0)
 #define bio_integrity_advance(a, b)    do { } while (0)
 #define bio_integrity_trim(a, b, c)    do { } while (0)
 #define bio_integrity_split(a, b, c)   do { } while (0)
 #define bio_integrity_set_tag(a, b, c) do { } while (0)
 #define bio_integrity_get_tag(a, b, c) do { } while (0)
+#define bio_integrity_init(a)          do { } while (0)
 
 #endif /* CONFIG_BLK_DEV_INTEGRITY */
 
index 8963d9149b5fcf77e47d9b0c32379bd8f28e2476..e7cb5dbf6c26a0daa4182c1d9eca0877583113b5 100644 (file)
@@ -70,11 +70,6 @@ enum rq_cmd_type_bits {
        REQ_TYPE_ATA_PC,
 };
 
-enum {
-       BLK_RW_ASYNC    = 0,
-       BLK_RW_SYNC     = 1,
-};
-
 /*
  * For request of type REQ_TYPE_LINUX_BLOCK, rq->cmd[0] is the opcode being
  * sent down (similar to how REQ_TYPE_BLOCK_PC means that ->cmd[] holds a
@@ -301,12 +296,6 @@ struct blk_queue_tag {
 #define BLK_SCSI_MAX_CMDS      (256)
 #define BLK_SCSI_CMD_PER_LONG  (BLK_SCSI_MAX_CMDS / (sizeof(long) * 8))
 
-struct blk_cmd_filter {
-       unsigned long read_ok[BLK_SCSI_CMD_PER_LONG];
-       unsigned long write_ok[BLK_SCSI_CMD_PER_LONG];
-       struct kobject kobj;
-};
-
 struct queue_limits {
        unsigned long           bounce_pfn;
        unsigned long           seg_boundary_mask;
@@ -445,7 +434,6 @@ struct request_queue
 #if defined(CONFIG_BLK_DEV_BSG)
        struct bsg_class_device bsg_dev;
 #endif
-       struct blk_cmd_filter cmd_filter;
 };
 
 #define QUEUE_FLAG_CLUSTER     0       /* cluster several segments into 1 */
@@ -730,6 +718,7 @@ struct rq_map_data {
        int nr_entries;
        unsigned long offset;
        int null_mapped;
+       int from_user;
 };
 
 struct req_iterator {
@@ -786,18 +775,18 @@ extern int sg_scsi_ioctl(struct request_queue *, struct gendisk *, fmode_t,
  * congested queues, and wake up anyone who was waiting for requests to be
  * put back.
  */
-static inline void blk_clear_queue_congested(struct request_queue *q, int rw)
+static inline void blk_clear_queue_congested(struct request_queue *q, int sync)
 {
-       clear_bdi_congested(&q->backing_dev_info, rw);
+       clear_bdi_congested(&q->backing_dev_info, sync);
 }
 
 /*
  * A queue has just entered congestion.  Flag that in the queue's VM-visible
  * state flags and increment the global gounter of congested queues.
  */
-static inline void blk_set_queue_congested(struct request_queue *q, int rw)
+static inline void blk_set_queue_congested(struct request_queue *q, int sync)
 {
-       set_bdi_congested(&q->backing_dev_info, rw);
+       set_bdi_congested(&q->backing_dev_info, sync);
 }
 
 extern void blk_start_queue(struct request_queue *q);
@@ -998,13 +987,7 @@ static inline int sb_issue_discard(struct super_block *sb,
        return blkdev_issue_discard(sb->s_bdev, block, nr_blocks, GFP_KERNEL);
 }
 
-/*
-* command filter functions
-*/
-extern int blk_verify_command(struct blk_cmd_filter *filter,
-                             unsigned char *cmd, fmode_t has_write_perm);
-extern void blk_unregister_filter(struct gendisk *disk);
-extern void blk_set_cmd_filter_defaults(struct blk_cmd_filter *filter);
+extern int blk_verify_command(unsigned char *cmd, fmode_t has_write_perm);
 
 #define MAX_PHYS_SEGMENTS 128
 #define MAX_HW_SEGMENTS 128
index 20a100fe2b4f3040554f3994706d8f7b238460af..3a1dbba4d3ae2da500e710387d130cd8ad5dd4c2 100644 (file)
@@ -143,12 +143,3 @@ extern void clockevents_notify(unsigned long reason, void *arg);
 #endif
 
 #endif
-
-#ifdef CONFIG_GENERIC_CLOCKEVENTS
-extern ktime_t clockevents_get_next_event(int cpu);
-#else
-static inline ktime_t clockevents_get_next_event(int cpu)
-{
-       return (ktime_t) { .tv64 = KTIME_MAX };
-}
-#endif
index b9966e64604e81b965526afcc39b4209e3a8148c..b68d27850d518073d75ff5abfb451263a26803a8 100644 (file)
 #define CN_IDX_BB                      0x5     /* BlackBoard, from the TSP GPL sampling framework */
 #define CN_DST_IDX                     0x6
 #define CN_DST_VAL                     0x1
+#define CN_IDX_DM                      0x7     /* Device Mapper */
+#define CN_VAL_DM_USERSPACE_LOG                0x1
 
-#define CN_NETLINK_USERS               7
+#define CN_NETLINK_USERS               8
 
 /*
  * Maximum connector's message size.
index d71f7c0f931b34b63bfacde2b06d19ffc5001616..38fe59dc89aefaa97871270371f28ff74bf8ca3f 100644 (file)
@@ -89,7 +89,6 @@ struct vc_data {
        unsigned int    vc_need_wrap    : 1;
        unsigned int    vc_can_do_color : 1;
        unsigned int    vc_report_mouse : 2;
-       unsigned int    vc_kmalloced    : 1;
        unsigned char   vc_utf          : 1;    /* Unicode UTF-8 encoding */
        unsigned char   vc_utf_count;
                 int    vc_utf_char;
index 2dac064d8359046c178f0d98bd9ea915ca369eaa..0026f267da20d6e9f1a0dc5343b978c1e5f0b6f1 100644 (file)
@@ -3,7 +3,6 @@
 
 #ifdef CONFIG_CRASH_DUMP
 #include <linux/kexec.h>
-#include <linux/smp_lock.h>
 #include <linux/device.h>
 #include <linux/proc_fs.h>
 
index 49c2362977fde10457c72d00e3672ba71142cd42..0d6310657f32a41cc6f5af7150f13db9c35a51e7 100644 (file)
@@ -11,6 +11,7 @@
 #include <linux/bio.h>
 #include <linux/blkdev.h>
 
+struct dm_dev;
 struct dm_target;
 struct dm_table;
 struct mapped_device;
@@ -21,6 +22,7 @@ typedef enum { STATUSTYPE_INFO, STATUSTYPE_TABLE } status_type_t;
 union map_info {
        void *ptr;
        unsigned long long ll;
+       unsigned flush_request;
 };
 
 /*
@@ -80,6 +82,15 @@ typedef int (*dm_ioctl_fn) (struct dm_target *ti, unsigned int cmd,
 typedef int (*dm_merge_fn) (struct dm_target *ti, struct bvec_merge_data *bvm,
                            struct bio_vec *biovec, int max_size);
 
+typedef int (*iterate_devices_callout_fn) (struct dm_target *ti,
+                                          struct dm_dev *dev,
+                                          sector_t physical_start,
+                                          void *data);
+
+typedef int (*dm_iterate_devices_fn) (struct dm_target *ti,
+                                     iterate_devices_callout_fn fn,
+                                     void *data);
+
 /*
  * Returns:
  *    0: The target can handle the next I/O immediately.
@@ -92,7 +103,8 @@ void dm_error(const char *message);
 /*
  * Combine device limits.
  */
-void dm_set_device_limits(struct dm_target *ti, struct block_device *bdev);
+int dm_set_device_limits(struct dm_target *ti, struct dm_dev *dev,
+                        sector_t start, void *data);
 
 struct dm_dev {
        struct block_device *bdev;
@@ -138,23 +150,12 @@ struct target_type {
        dm_ioctl_fn ioctl;
        dm_merge_fn merge;
        dm_busy_fn busy;
+       dm_iterate_devices_fn iterate_devices;
 
        /* For internal device-mapper use. */
        struct list_head list;
 };
 
-struct io_restrictions {
-       unsigned long bounce_pfn;
-       unsigned long seg_boundary_mask;
-       unsigned max_hw_sectors;
-       unsigned max_sectors;
-       unsigned max_segment_size;
-       unsigned short logical_block_size;
-       unsigned short max_hw_segments;
-       unsigned short max_phys_segments;
-       unsigned char no_cluster; /* inverted so that 0 is default */
-};
-
 struct dm_target {
        struct dm_table *table;
        struct target_type *type;
@@ -163,15 +164,18 @@ struct dm_target {
        sector_t begin;
        sector_t len;
 
-       /* FIXME: turn this into a mask, and merge with io_restrictions */
        /* Always a power of 2 */
        sector_t split_io;
 
        /*
-        * These are automatically filled in by
-        * dm_table_get_device.
+        * A number of zero-length barrier requests that will be submitted
+        * to the target for the purpose of flushing cache.
+        *
+        * The request number will be placed in union map_info->flush_request.
+        * It is a responsibility of the target driver to remap these requests
+        * to the real underlying devices.
         */
-       struct io_restrictions limits;
+       unsigned num_flush_requests;
 
        /* target specific data */
        void *private;
@@ -230,6 +234,7 @@ struct gendisk *dm_disk(struct mapped_device *md);
 int dm_suspended(struct mapped_device *md);
 int dm_noflush_suspending(struct dm_target *ti);
 union map_info *dm_get_mapinfo(struct bio *bio);
+union map_info *dm_get_rq_mapinfo(struct request *rq);
 
 /*
  * Geometry functions.
@@ -392,4 +397,12 @@ static inline unsigned long to_bytes(sector_t n)
        return (n << SECTOR_SHIFT);
 }
 
+/*-----------------------------------------------------------------
+ * Helper for block layer and dm core operations
+ *---------------------------------------------------------------*/
+void dm_dispatch_request(struct request *rq);
+void dm_requeue_unmapped_request(struct request *rq);
+void dm_kill_unmapped_request(struct request *rq, int error);
+int dm_underlying_device_busy(struct request_queue *q);
+
 #endif /* _LINUX_DEVICE_MAPPER_H */
index ed4e39f2c4230da03f93651f5d323f805cdb6c94..aebb81036db2d368a7b55664f5a2b9d102c5109d 100644 (file)
@@ -25,8 +25,6 @@
 #include <asm/atomic.h>
 #include <asm/device.h>
 
-#define BUS_ID_SIZE            20
-
 struct device;
 struct device_private;
 struct device_driver;
index 48e44ee2b466b1a0da649057af1cbb5402dd61b4..2ab84c83c31a9d7d11b8c18ee744cb85ca520fd8 100644 (file)
@@ -123,6 +123,16 @@ struct dm_ioctl {
        __u32 target_count;     /* in/out */
        __s32 open_count;       /* out */
        __u32 flags;            /* in/out */
+
+       /*
+        * event_nr holds either the event number (input and output) or the
+        * udev cookie value (input only).
+        * The DM_DEV_WAIT ioctl takes an event number as input.
+        * The DM_SUSPEND, DM_DEV_REMOVE and DM_DEV_RENAME ioctls
+        * use the field as a cookie to return in the DM_COOKIE
+        * variable with the uevents they issue.
+        * For output, the ioctls return the event number, not the cookie.
+        */
        __u32 event_nr;         /* in/out */
        __u32 padding;
 
@@ -256,9 +266,9 @@ enum {
 #define DM_DEV_SET_GEOMETRY    _IOWR(DM_IOCTL, DM_DEV_SET_GEOMETRY_CMD, struct dm_ioctl)
 
 #define DM_VERSION_MAJOR       4
-#define DM_VERSION_MINOR       14
+#define DM_VERSION_MINOR       15
 #define DM_VERSION_PATCHLEVEL  0
-#define DM_VERSION_EXTRA       "-ioctl (2008-04-23)"
+#define DM_VERSION_EXTRA       "-ioctl (2009-04-01)"
 
 /* Status bits */
 #define DM_READONLY_FLAG       (1 << 0) /* In/Out */
diff --git a/include/linux/dm-log-userspace.h b/include/linux/dm-log-userspace.h
new file mode 100644 (file)
index 0000000..642e301
--- /dev/null
@@ -0,0 +1,386 @@
+/*
+ * Copyright (C) 2006-2009 Red Hat, Inc.
+ *
+ * This file is released under the LGPL.
+ */
+
+#ifndef __DM_LOG_USERSPACE_H__
+#define __DM_LOG_USERSPACE_H__
+
+#include <linux/dm-ioctl.h> /* For DM_UUID_LEN */
+
+/*
+ * The device-mapper userspace log module consists of a kernel component and
+ * a user-space component.  The kernel component implements the API defined
+ * in dm-dirty-log.h.  Its purpose is simply to pass the parameters and
+ * return values of those API functions between kernel and user-space.
+ *
+ * Below are defined the 'request_types' - DM_ULOG_CTR, DM_ULOG_DTR, etc.
+ * These request types represent the different functions in the device-mapper
+ * dirty log API.  Each of these is described in more detail below.
+ *
+ * The user-space program must listen for requests from the kernel (representing
+ * the various API functions) and process them.
+ *
+ * User-space begins by setting up the communication link (error checking
+ * removed for clarity):
+ *     fd = socket(PF_NETLINK, SOCK_DGRAM, NETLINK_CONNECTOR);
+ *     addr.nl_family = AF_NETLINK;
+ *     addr.nl_groups = CN_IDX_DM;
+ *     addr.nl_pid = 0;
+ *     r = bind(fd, (struct sockaddr *) &addr, sizeof(addr));
+ *     opt = addr.nl_groups;
+ *     setsockopt(fd, SOL_NETLINK, NETLINK_ADD_MEMBERSHIP, &opt, sizeof(opt));
+ *
+ * User-space will then wait to receive requests form the kernel, which it
+ * will process as described below.  The requests are received in the form,
+ * ((struct dm_ulog_request) + (additional data)).  Depending on the request
+ * type, there may or may not be 'additional data'.  In the descriptions below,
+ * you will see 'Payload-to-userspace' and 'Payload-to-kernel'.  The
+ * 'Payload-to-userspace' is what the kernel sends in 'additional data' as
+ * necessary parameters to complete the request.  The 'Payload-to-kernel' is
+ * the 'additional data' returned to the kernel that contains the necessary
+ * results of the request.  The 'data_size' field in the dm_ulog_request
+ * structure denotes the availability and amount of payload data.
+ */
+
+/*
+ * DM_ULOG_CTR corresponds to (found in dm-dirty-log.h):
+ * int (*ctr)(struct dm_dirty_log *log, struct dm_target *ti,
+ *           unsigned argc, char **argv);
+ *
+ * Payload-to-userspace:
+ *     A single string containing all the argv arguments separated by ' 's
+ * Payload-to-kernel:
+ *     None.  ('data_size' in the dm_ulog_request struct should be 0.)
+ *
+ * The UUID contained in the dm_ulog_request structure is the reference that
+ * will be used by all request types to a specific log.  The constructor must
+ * record this assotiation with instance created.
+ *
+ * When the request has been processed, user-space must return the
+ * dm_ulog_request to the kernel - setting the 'error' field and
+ * 'data_size' appropriately.
+ */
+#define DM_ULOG_CTR                    1
+
+/*
+ * DM_ULOG_DTR corresponds to (found in dm-dirty-log.h):
+ * void (*dtr)(struct dm_dirty_log *log);
+ *
+ * Payload-to-userspace:
+ *     A single string containing all the argv arguments separated by ' 's
+ * Payload-to-kernel:
+ *     None.  ('data_size' in the dm_ulog_request struct should be 0.)
+ *
+ * The UUID contained in the dm_ulog_request structure is all that is
+ * necessary to identify the log instance being destroyed.  There is no
+ * payload data.
+ *
+ * When the request has been processed, user-space must return the
+ * dm_ulog_request to the kernel - setting the 'error' field and clearing
+ * 'data_size' appropriately.
+ */
+#define DM_ULOG_DTR                    2
+
+/*
+ * DM_ULOG_PRESUSPEND corresponds to (found in dm-dirty-log.h):
+ * int (*presuspend)(struct dm_dirty_log *log);
+ *
+ * Payload-to-userspace:
+ *     None.
+ * Payload-to-kernel:
+ *     None.
+ *
+ * The UUID contained in the dm_ulog_request structure is all that is
+ * necessary to identify the log instance being presuspended.  There is no
+ * payload data.
+ *
+ * When the request has been processed, user-space must return the
+ * dm_ulog_request to the kernel - setting the 'error' field and
+ * 'data_size' appropriately.
+ */
+#define DM_ULOG_PRESUSPEND             3
+
+/*
+ * DM_ULOG_POSTSUSPEND corresponds to (found in dm-dirty-log.h):
+ * int (*postsuspend)(struct dm_dirty_log *log);
+ *
+ * Payload-to-userspace:
+ *     None.
+ * Payload-to-kernel:
+ *     None.
+ *
+ * The UUID contained in the dm_ulog_request structure is all that is
+ * necessary to identify the log instance being postsuspended.  There is no
+ * payload data.
+ *
+ * When the request has been processed, user-space must return the
+ * dm_ulog_request to the kernel - setting the 'error' field and
+ * 'data_size' appropriately.
+ */
+#define DM_ULOG_POSTSUSPEND            4
+
+/*
+ * DM_ULOG_RESUME corresponds to (found in dm-dirty-log.h):
+ * int (*resume)(struct dm_dirty_log *log);
+ *
+ * Payload-to-userspace:
+ *     None.
+ * Payload-to-kernel:
+ *     None.
+ *
+ * The UUID contained in the dm_ulog_request structure is all that is
+ * necessary to identify the log instance being resumed.  There is no
+ * payload data.
+ *
+ * When the request has been processed, user-space must return the
+ * dm_ulog_request to the kernel - setting the 'error' field and
+ * 'data_size' appropriately.
+ */
+#define DM_ULOG_RESUME                 5
+
+/*
+ * DM_ULOG_GET_REGION_SIZE corresponds to (found in dm-dirty-log.h):
+ * uint32_t (*get_region_size)(struct dm_dirty_log *log);
+ *
+ * Payload-to-userspace:
+ *     None.
+ * Payload-to-kernel:
+ *     uint64_t - contains the region size
+ *
+ * The region size is something that was determined at constructor time.
+ * It is returned in the payload area and 'data_size' is set to
+ * reflect this.
+ *
+ * When the request has been processed, user-space must return the
+ * dm_ulog_request to the kernel - setting the 'error' field appropriately.
+ */
+#define DM_ULOG_GET_REGION_SIZE        6
+
+/*
+ * DM_ULOG_IS_CLEAN corresponds to (found in dm-dirty-log.h):
+ * int (*is_clean)(struct dm_dirty_log *log, region_t region);
+ *
+ * Payload-to-userspace:
+ *     uint64_t - the region to get clean status on
+ * Payload-to-kernel:
+ *     int64_t  - 1 if clean, 0 otherwise
+ *
+ * Payload is sizeof(uint64_t) and contains the region for which the clean
+ * status is being made.
+ *
+ * When the request has been processed, user-space must return the
+ * dm_ulog_request to the kernel - filling the payload with 0 (not clean) or
+ * 1 (clean), setting 'data_size' and 'error' appropriately.
+ */
+#define DM_ULOG_IS_CLEAN               7
+
+/*
+ * DM_ULOG_IN_SYNC corresponds to (found in dm-dirty-log.h):
+ * int (*in_sync)(struct dm_dirty_log *log, region_t region,
+ *               int can_block);
+ *
+ * Payload-to-userspace:
+ *     uint64_t - the region to get sync status on
+ * Payload-to-kernel:
+ *     int64_t - 1 if in-sync, 0 otherwise
+ *
+ * Exactly the same as 'is_clean' above, except this time asking "has the
+ * region been recovered?" vs. "is the region not being modified?"
+ */
+#define DM_ULOG_IN_SYNC                8
+
+/*
+ * DM_ULOG_FLUSH corresponds to (found in dm-dirty-log.h):
+ * int (*flush)(struct dm_dirty_log *log);
+ *
+ * Payload-to-userspace:
+ *     None.
+ * Payload-to-kernel:
+ *     None.
+ *
+ * No incoming or outgoing payload.  Simply flush log state to disk.
+ *
+ * When the request has been processed, user-space must return the
+ * dm_ulog_request to the kernel - setting the 'error' field and clearing
+ * 'data_size' appropriately.
+ */
+#define DM_ULOG_FLUSH                  9
+
+/*
+ * DM_ULOG_MARK_REGION corresponds to (found in dm-dirty-log.h):
+ * void (*mark_region)(struct dm_dirty_log *log, region_t region);
+ *
+ * Payload-to-userspace:
+ *     uint64_t [] - region(s) to mark
+ * Payload-to-kernel:
+ *     None.
+ *
+ * Incoming payload contains the one or more regions to mark dirty.
+ * The number of regions contained in the payload can be determined from
+ * 'data_size/sizeof(uint64_t)'.
+ *
+ * When the request has been processed, user-space must return the
+ * dm_ulog_request to the kernel - setting the 'error' field and clearing
+ * 'data_size' appropriately.
+ */
+#define DM_ULOG_MARK_REGION           10
+
+/*
+ * DM_ULOG_CLEAR_REGION corresponds to (found in dm-dirty-log.h):
+ * void (*clear_region)(struct dm_dirty_log *log, region_t region);
+ *
+ * Payload-to-userspace:
+ *     uint64_t [] - region(s) to clear
+ * Payload-to-kernel:
+ *     None.
+ *
+ * Incoming payload contains the one or more regions to mark clean.
+ * The number of regions contained in the payload can be determined from
+ * 'data_size/sizeof(uint64_t)'.
+ *
+ * When the request has been processed, user-space must return the
+ * dm_ulog_request to the kernel - setting the 'error' field and clearing
+ * 'data_size' appropriately.
+ */
+#define DM_ULOG_CLEAR_REGION          11
+
+/*
+ * DM_ULOG_GET_RESYNC_WORK corresponds to (found in dm-dirty-log.h):
+ * int (*get_resync_work)(struct dm_dirty_log *log, region_t *region);
+ *
+ * Payload-to-userspace:
+ *     None.
+ * Payload-to-kernel:
+ *     {
+ *             int64_t i; -- 1 if recovery necessary, 0 otherwise
+ *             uint64_t r; -- The region to recover if i=1
+ *     }
+ * 'data_size' should be set appropriately.
+ *
+ * When the request has been processed, user-space must return the
+ * dm_ulog_request to the kernel - setting the 'error' field appropriately.
+ */
+#define DM_ULOG_GET_RESYNC_WORK       12
+
+/*
+ * DM_ULOG_SET_REGION_SYNC corresponds to (found in dm-dirty-log.h):
+ * void (*set_region_sync)(struct dm_dirty_log *log,
+ *                        region_t region, int in_sync);
+ *
+ * Payload-to-userspace:
+ *     {
+ *             uint64_t - region to set sync state on
+ *             int64_t  - 0 if not-in-sync, 1 if in-sync
+ *     }
+ * Payload-to-kernel:
+ *     None.
+ *
+ * When the request has been processed, user-space must return the
+ * dm_ulog_request to the kernel - setting the 'error' field and clearing
+ * 'data_size' appropriately.
+ */
+#define DM_ULOG_SET_REGION_SYNC       13
+
+/*
+ * DM_ULOG_GET_SYNC_COUNT corresponds to (found in dm-dirty-log.h):
+ * region_t (*get_sync_count)(struct dm_dirty_log *log);
+ *
+ * Payload-to-userspace:
+ *     None.
+ * Payload-to-kernel:
+ *     uint64_t - the number of in-sync regions
+ *
+ * No incoming payload.  Kernel-bound payload contains the number of
+ * regions that are in-sync (in a size_t).
+ *
+ * When the request has been processed, user-space must return the
+ * dm_ulog_request to the kernel - setting the 'error' field and
+ * 'data_size' appropriately.
+ */
+#define DM_ULOG_GET_SYNC_COUNT        14
+
+/*
+ * DM_ULOG_STATUS_INFO corresponds to (found in dm-dirty-log.h):
+ * int (*status)(struct dm_dirty_log *log, STATUSTYPE_INFO,
+ *              char *result, unsigned maxlen);
+ *
+ * Payload-to-userspace:
+ *     None.
+ * Payload-to-kernel:
+ *     Character string containing STATUSTYPE_INFO
+ *
+ * When the request has been processed, user-space must return the
+ * dm_ulog_request to the kernel - setting the 'error' field and
+ * 'data_size' appropriately.
+ */
+#define DM_ULOG_STATUS_INFO           15
+
+/*
+ * DM_ULOG_STATUS_TABLE corresponds to (found in dm-dirty-log.h):
+ * int (*status)(struct dm_dirty_log *log, STATUSTYPE_TABLE,
+ *              char *result, unsigned maxlen);
+ *
+ * Payload-to-userspace:
+ *     None.
+ * Payload-to-kernel:
+ *     Character string containing STATUSTYPE_TABLE
+ *
+ * When the request has been processed, user-space must return the
+ * dm_ulog_request to the kernel - setting the 'error' field and
+ * 'data_size' appropriately.
+ */
+#define DM_ULOG_STATUS_TABLE          16
+
+/*
+ * DM_ULOG_IS_REMOTE_RECOVERING corresponds to (found in dm-dirty-log.h):
+ * int (*is_remote_recovering)(struct dm_dirty_log *log, region_t region);
+ *
+ * Payload-to-userspace:
+ *     uint64_t - region to determine recovery status on
+ * Payload-to-kernel:
+ *     {
+ *             int64_t is_recovering;  -- 0 if no, 1 if yes
+ *             uint64_t in_sync_hint;  -- lowest region still needing resync
+ *     }
+ *
+ * When the request has been processed, user-space must return the
+ * dm_ulog_request to the kernel - setting the 'error' field and
+ * 'data_size' appropriately.
+ */
+#define DM_ULOG_IS_REMOTE_RECOVERING  17
+
+/*
+ * (DM_ULOG_REQUEST_MASK & request_type) to get the request type
+ *
+ * Payload-to-userspace:
+ *     A single string containing all the argv arguments separated by ' 's
+ * Payload-to-kernel:
+ *     None.  ('data_size' in the dm_ulog_request struct should be 0.)
+ *
+ * We are reserving 8 bits of the 32-bit 'request_type' field for the
+ * various request types above.  The remaining 24-bits are currently
+ * set to zero and are reserved for future use and compatibility concerns.
+ *
+ * User-space should always use DM_ULOG_REQUEST_TYPE to aquire the
+ * request type from the 'request_type' field to maintain forward compatibility.
+ */
+#define DM_ULOG_REQUEST_MASK 0xFF
+#define DM_ULOG_REQUEST_TYPE(request_type) \
+       (DM_ULOG_REQUEST_MASK & (request_type))
+
+struct dm_ulog_request {
+       char uuid[DM_UUID_LEN]; /* Ties a request to a specific mirror log */
+       char padding[7];        /* Padding because DM_UUID_LEN = 129 */
+
+       int32_t error;          /* Used to report back processing errors */
+
+       uint32_t seq;           /* Sequence number for request */
+       uint32_t request_type;  /* DM_ULOG_* defined above */
+       uint32_t data_size;     /* How much data (not including this struct) */
+
+       char data[0];
+};
+
+#endif /* __DM_LOG_USERSPACE_H__ */
index 1731fb5fd775a3ee312b5c712fa38b33f12c5a9b..4a2b162c256aac373afa166638fbed5938b773db 100644 (file)
@@ -126,6 +126,8 @@ extern int free_irte(int irq);
 extern int irq_remapped(int irq);
 extern struct intel_iommu *map_dev_to_ir(struct pci_dev *dev);
 extern struct intel_iommu *map_ioapic_to_ir(int apic);
+extern int set_ioapic_sid(struct irte *irte, int apic);
+extern int set_msi_sid(struct irte *irte, struct pci_dev *dev);
 #else
 static inline int alloc_irte(struct intel_iommu *iommu, int irq, u16 count)
 {
@@ -156,6 +158,15 @@ static inline struct intel_iommu *map_ioapic_to_ir(int apic)
 {
        return NULL;
 }
+static inline int set_ioapic_sid(struct irte *irte, int apic)
+{
+       return 0;
+}
+static inline int set_msi_sid(struct irte *irte, struct pci_dev *dev)
+{
+       return 0;
+}
+
 #define irq_remapped(irq)              (0)
 #define enable_intr_remapping(mode)    (-1)
 #define disable_intr_remapping()       (0)
index 7605c5e9589f4cc9d08c4aca7ccebd3f707fb710..00d6a68d04215e7e289a3451ca4a8f714e2b6975 100644 (file)
@@ -122,9 +122,10 @@ static inline void elf_core_copy_kernel_regs(elf_gregset_t *elfregs, struct pt_r
 
 static inline int elf_core_copy_task_regs(struct task_struct *t, elf_gregset_t* elfregs)
 {
-#ifdef ELF_CORE_COPY_TASK_REGS
-       
+#if defined (ELF_CORE_COPY_TASK_REGS)
        return ELF_CORE_COPY_TASK_REGS(t, elfregs);
+#elif defined (task_pt_regs)
+       elf_core_copy_regs(elfregs, task_pt_regs(t));
 #endif
        return 0;
 }
index f45a8ae5f8281bc51348b942a36899b8355f13d9..3b85ba6479f48e31f3173de8c2ff86959a190bb3 100644 (file)
@@ -8,10 +8,8 @@
 #ifndef _LINUX_EVENTFD_H
 #define _LINUX_EVENTFD_H
 
-#ifdef CONFIG_EVENTFD
-
-/* For O_CLOEXEC and O_NONBLOCK */
 #include <linux/fcntl.h>
+#include <linux/file.h>
 
 /*
  * CAREFUL: Check include/asm-generic/fcntl.h when defining
 #define EFD_SHARED_FCNTL_FLAGS (O_CLOEXEC | O_NONBLOCK)
 #define EFD_FLAGS_SET (EFD_SHARED_FCNTL_FLAGS | EFD_SEMAPHORE)
 
+#ifdef CONFIG_EVENTFD
+
+struct eventfd_ctx *eventfd_ctx_get(struct eventfd_ctx *ctx);
+void eventfd_ctx_put(struct eventfd_ctx *ctx);
 struct file *eventfd_fget(int fd);
-int eventfd_signal(struct file *file, int n);
+struct eventfd_ctx *eventfd_ctx_fdget(int fd);
+struct eventfd_ctx *eventfd_ctx_fileget(struct file *file);
+int eventfd_signal(struct eventfd_ctx *ctx, int n);
 
 #else /* CONFIG_EVENTFD */
 
-#define eventfd_fget(fd) ERR_PTR(-ENOSYS)
-static inline int eventfd_signal(struct file *file, int n)
-{ return 0; }
+/*
+ * Ugly ugly ugly error layer to support modules that uses eventfd but
+ * pretend to work in !CONFIG_EVENTFD configurations. Namely, AIO.
+ */
+static inline struct eventfd_ctx *eventfd_ctx_fdget(int fd)
+{
+       return ERR_PTR(-ENOSYS);
+}
+
+static inline int eventfd_signal(struct eventfd_ctx *ctx, int n)
+{
+       return -ENOSYS;
+}
+
+static inline void eventfd_ctx_put(struct eventfd_ctx *ctx)
+{
+
+}
 
-#endif /* CONFIG_EVENTFD */
+#endif
 
 #endif /* _LINUX_EVENTFD_H */
 
index 7894dd0f3b77544a8006ff1d4471554f460be093..ca1bfe90004fa5473f35b884ad0e33abbde6ef25 100644 (file)
@@ -103,10 +103,6 @@ struct ext3_inode_info {
         */
        struct rw_semaphore xattr_sem;
 #endif
-#ifdef CONFIG_EXT3_FS_POSIX_ACL
-       struct posix_acl        *i_acl;
-       struct posix_acl        *i_default_acl;
-#endif
 
        struct list_head i_orphan;      /* unlinked but open inodes */
 
index 8e912ab6a072603a8280a252e57ad6c99c129b7b..3c155107d61f3d2f4be840dd2d175651ae1c1aa9 100644 (file)
@@ -3,4 +3,25 @@
 
 #define FALLOC_FL_KEEP_SIZE    0x01 /* default is extend size */
 
+#ifdef __KERNEL__
+
+/*
+ * Space reservation ioctls and argument structure
+ * are designed to be compatible with the legacy XFS ioctls.
+ */
+struct space_resv {
+       __s16           l_type;
+       __s16           l_whence;
+       __s64           l_start;
+       __s64           l_len;          /* len == 0 means until end of file */
+       __s32           l_sysid;
+       __u32           l_pid;
+       __s32           l_pad[4];       /* reserved area */
+};
+
+#define FS_IOC_RESVSP          _IOW('X', 40, struct space_resv)
+#define FS_IOC_RESVSP64                _IOW('X', 42, struct space_resv)
+
+#endif /* __KERNEL__ */
+
 #endif /* _FALLOC_H_ */
index dd68358996b716da2b1be8e1ab9069b282ab9902..f847df9e99b6f4fcd44991e757c1d5b7ca50681a 100644 (file)
@@ -819,6 +819,7 @@ struct fb_info {
        int node;
        int flags;
        struct mutex lock;              /* Lock for open/release/ioctl funcs */
+       struct mutex mm_lock;           /* Lock for fb_mmap and smem_* fields */
        struct fb_var_screeninfo var;   /* Current var */
        struct fb_fix_screeninfo fix;   /* Current fix */
        struct fb_monspecs monspecs;    /* Current Monitor specs */
index 9823946adbc513af5f2784b9f7c7a97f622d1a36..192d1e43c43c394ce14a967ee32ecbd3de261606 100644 (file)
@@ -127,6 +127,7 @@ struct fw_card {
        struct delayed_work work;
        int bm_retries;
        int bm_generation;
+       __be32 bm_transaction_data[2];
 
        bool broadcast_channel_allocated;
        u32 broadcast_channel;
index 1ff5e4e019524124ece3f762f36b841b0d2e1d73..0872372184fe159a62475b48a99a1a6a26d8f1cd 100644 (file)
@@ -710,6 +710,9 @@ static inline int mapping_writably_mapped(struct address_space *mapping)
 #define i_size_ordered_init(inode) do { } while (0)
 #endif
 
+struct posix_acl;
+#define ACL_NOT_CACHED ((void *)(-1))
+
 struct inode {
        struct hlist_node       i_hash;
        struct list_head        i_list;
@@ -772,6 +775,10 @@ struct inode {
        atomic_t                i_writecount;
 #ifdef CONFIG_SECURITY
        void                    *i_security;
+#endif
+#ifdef CONFIG_FS_POSIX_ACL
+       struct posix_acl        *i_acl;
+       struct posix_acl        *i_default_acl;
 #endif
        void                    *i_private; /* fs or device private pointer */
 };
@@ -1906,6 +1913,8 @@ static inline int break_lease(struct inode *inode, unsigned int mode)
 
 extern int do_truncate(struct dentry *, loff_t start, unsigned int time_attrs,
                       struct file *filp);
+extern int do_fallocate(struct file *file, int mode, loff_t offset,
+                       loff_t len);
 extern long do_sys_open(int dfd, const char __user *filename, int flags,
                        int mode);
 extern struct file *filp_open(const char *, int, int);
@@ -1914,6 +1923,10 @@ extern struct file * dentry_open(struct dentry *, struct vfsmount *, int,
 extern int filp_close(struct file *, fl_owner_t id);
 extern char * getname(const char __user *);
 
+/* fs/ioctl.c */
+
+extern int ioctl_preallocate(struct file *filp, void __user *argp);
+
 /* fs/dcache.c */
 extern void __init vfs_caches_init_early(void);
 extern void __init vfs_caches_init(unsigned long);
index 44848aa830dcd9def22f98785df0fda957bce1d4..6c3de999fb3486b56bc677c3a359f23a4a2b66bf 100644 (file)
@@ -280,7 +280,7 @@ static inline void __fsnotify_update_dcache_flags(struct dentry *dentry)
        assert_spin_locked(&dentry->d_lock);
 
        parent = dentry->d_parent;
-       if (fsnotify_inode_watches_children(parent->d_inode))
+       if (parent->d_inode && fsnotify_inode_watches_children(parent->d_inode))
                dentry->d_flags |= DCACHE_FSNOTIFY_PARENT_WATCHED;
        else
                dentry->d_flags &= ~DCACHE_FSNOTIFY_PARENT_WATCHED;
index d41ed593f79fe01f8cc5ea25b3e6ea000cdc0e4c..cf593bf9fd3253a3fbc2ae963ff95f1b3a5c3ccf 100644 (file)
  *  - add IOCTL message
  *  - add unsolicited notification support
  *  - add POLL message and NOTIFY_POLL notification
+ *
+ * 7.12
+ *  - add umask flag to input argument of open, mknod and mkdir
+ *  - add notification messages for invalidation of inodes and
+ *    directory entries
  */
 
 #ifndef _LINUX_FUSE_H
@@ -36,7 +41,7 @@
 #define FUSE_KERNEL_VERSION 7
 
 /** Minor version number of this interface */
-#define FUSE_KERNEL_MINOR_VERSION 11
+#define FUSE_KERNEL_MINOR_VERSION 12
 
 /** The node ID of the root inode */
 #define FUSE_ROOT_ID 1
@@ -112,6 +117,7 @@ struct fuse_file_lock {
  * INIT request/reply flags
  *
  * FUSE_EXPORT_SUPPORT: filesystem handles lookups of "." and ".."
+ * FUSE_DONT_MASK: don't apply umask to file mode on create operations
  */
 #define FUSE_ASYNC_READ                (1 << 0)
 #define FUSE_POSIX_LOCKS       (1 << 1)
@@ -119,6 +125,7 @@ struct fuse_file_lock {
 #define FUSE_ATOMIC_O_TRUNC    (1 << 3)
 #define FUSE_EXPORT_SUPPORT    (1 << 4)
 #define FUSE_BIG_WRITES                (1 << 5)
+#define FUSE_DONT_MASK         (1 << 6)
 
 /**
  * CUSE INIT request/reply flags
@@ -224,6 +231,8 @@ enum fuse_opcode {
 
 enum fuse_notify_code {
        FUSE_NOTIFY_POLL   = 1,
+       FUSE_NOTIFY_INVAL_INODE = 2,
+       FUSE_NOTIFY_INVAL_ENTRY = 3,
        FUSE_NOTIFY_CODE_MAX,
 };
 
@@ -262,14 +271,18 @@ struct fuse_attr_out {
        struct fuse_attr attr;
 };
 
+#define FUSE_COMPAT_MKNOD_IN_SIZE 8
+
 struct fuse_mknod_in {
        __u32   mode;
        __u32   rdev;
+       __u32   umask;
+       __u32   padding;
 };
 
 struct fuse_mkdir_in {
        __u32   mode;
-       __u32   padding;
+       __u32   umask;
 };
 
 struct fuse_rename_in {
@@ -300,8 +313,15 @@ struct fuse_setattr_in {
 };
 
 struct fuse_open_in {
+       __u32   flags;
+       __u32   unused;
+};
+
+struct fuse_create_in {
        __u32   flags;
        __u32   mode;
+       __u32   umask;
+       __u32   padding;
 };
 
 struct fuse_open_out {
@@ -508,4 +528,16 @@ struct fuse_dirent {
 #define FUSE_DIRENT_SIZE(d) \
        FUSE_DIRENT_ALIGN(FUSE_NAME_OFFSET + (d)->namelen)
 
+struct fuse_notify_inval_inode_out {
+       __u64   ino;
+       __s64   off;
+       __s64   len;
+};
+
+struct fuse_notify_inval_entry_out {
+       __u64   parent;
+       __u32   namelen;
+       __u32   padding;
+};
+
 #endif /* _LINUX_FUSE_H */
index 45257475623cad94c90304d82b4b5cd68bc498d8..8246c697863d72cec6bae27889d0149a88ab830f 100644 (file)
@@ -2,7 +2,9 @@
 #define LINUX_HARDIRQ_H
 
 #include <linux/preempt.h>
+#ifdef CONFIG_PREEMPT
 #include <linux/smp_lock.h>
+#endif
 #include <linux/lockdep.h>
 #include <linux/ftrace_irq.h>
 #include <asm/hardirq.h>
index 7400900de94a692320c771e8881661e10ebe51b7..4759917adc71ae371da1cc3a45d46b22a55d4015 100644 (file)
@@ -21,6 +21,7 @@
 #include <linux/list.h>
 #include <linux/wait.h>
 #include <linux/percpu.h>
+#include <linux/timer.h>
 
 
 struct hrtimer_clock_base;
@@ -447,6 +448,8 @@ extern void timer_stats_update_stats(void *timer, pid_t pid, void *startf,
 
 static inline void timer_stats_account_hrtimer(struct hrtimer *timer)
 {
+       if (likely(!timer->start_site))
+               return;
        timer_stats_update_stats(timer, timer->start_pid, timer->start_site,
                                 timer->function, timer->start_comm, 0);
 }
@@ -456,6 +459,8 @@ extern void __timer_stats_hrtimer_set_start_info(struct hrtimer *timer,
 
 static inline void timer_stats_hrtimer_set_start_info(struct hrtimer *timer)
 {
+       if (likely(!timer_stats_active))
+               return;
        __timer_stats_hrtimer_set_start_info(timer, __builtin_return_address(0));
 }
 
index 10d701eec484cb353508afa13efbf63d506e2759..b6a85183c33389e164d7d8f54390501e31c9d415 100644 (file)
@@ -175,16 +175,16 @@ struct icmp6_filter {
 
 
 extern void                            icmpv6_send(struct sk_buff *skb,
-                                                   int type, int code,
+                                                   u8 type, u8 code,
                                                    __u32 info, 
                                                    struct net_device *dev);
 
 extern int                             icmpv6_init(void);
-extern int                             icmpv6_err_convert(int type, int code,
+extern int                             icmpv6_err_convert(u8 type, u8 code,
                                                           int *err);
 extern void                            icmpv6_cleanup(void);
 extern void                            icmpv6_param_prob(struct sk_buff *skb,
-                                                         int code, int pos);
+                                                         u8 code, int pos);
 
 struct flowi;
 struct in6_addr;
index 95c6e00a72e826e709258734554a8d70091247c5..edc93a6d931db45fecc9ba3064aecb0619ea6115 100644 (file)
@@ -1062,7 +1062,6 @@ int generic_ide_ioctl(ide_drive_t *, struct block_device *, unsigned, unsigned l
 extern int ide_vlb_clk;
 extern int ide_pci_clk;
 
-unsigned int ide_rq_bytes(struct request *);
 int ide_end_rq(ide_drive_t *, struct request *, int, unsigned int);
 void ide_kill_rq(ide_drive_t *, struct request *);
 
@@ -1361,7 +1360,6 @@ int ide_in_drive_list(u16 *, const struct drive_list_entry *);
 #ifdef CONFIG_BLK_DEV_IDEDMA
 int ide_dma_good_drive(ide_drive_t *);
 int __ide_dma_bad_drive(ide_drive_t *);
-int ide_id_dma_bug(ide_drive_t *);
 
 u8 ide_find_dma_mode(ide_drive_t *, u8);
 
@@ -1402,7 +1400,6 @@ void ide_dma_lost_irq(ide_drive_t *);
 ide_startstop_t ide_dma_timeout_retry(ide_drive_t *, int);
 
 #else
-static inline int ide_id_dma_bug(ide_drive_t *drive) { return 0; }
 static inline u8 ide_find_dma_mode(ide_drive_t *drive, u8 speed) { return 0; }
 static inline u8 ide_max_dma_mode(ide_drive_t *drive) { return 0; }
 static inline void ide_dma_off_quietly(ide_drive_t *drive) { ; }
@@ -1422,6 +1419,7 @@ static inline void ide_dma_unmap_sg(ide_drive_t *drive,
 
 #ifdef CONFIG_BLK_DEV_IDEACPI
 int ide_acpi_init(void);
+bool ide_port_acpi(ide_hwif_t *hwif);
 extern int ide_acpi_exec_tfs(ide_drive_t *drive);
 extern void ide_acpi_get_timing(ide_hwif_t *hwif);
 extern void ide_acpi_push_timing(ide_hwif_t *hwif);
@@ -1430,6 +1428,7 @@ void ide_acpi_port_init_devices(ide_hwif_t *);
 extern void ide_acpi_set_state(ide_hwif_t *hwif, int on);
 #else
 static inline int ide_acpi_init(void) { return 0; }
+static inline bool ide_port_acpi(ide_hwif_t *hwif) { return 0; }
 static inline int ide_acpi_exec_tfs(ide_drive_t *drive) { return 0; }
 static inline void ide_acpi_get_timing(ide_hwif_t *hwif) { ; }
 static inline void ide_acpi_push_timing(ide_hwif_t *hwif) { ; }
index ae3a1871413dd031b41edcd9e4159f92a1363081..70fdba2bbf7160788c5876462500d553da8bf710 100644 (file)
@@ -78,6 +78,7 @@
 #define ETH_P_PAE      0x888E          /* Port Access Entity (IEEE 802.1X) */
 #define ETH_P_AOE      0x88A2          /* ATA over Ethernet            */
 #define ETH_P_TIPC     0x88CA          /* TIPC                         */
+#define ETH_P_1588     0x88F7          /* IEEE 1588 Timesync */
 #define ETH_P_FCOE     0x8906          /* Fibre Channel over Ethernet  */
 #define ETH_P_FIP      0x8914          /* FCoE Initialization Protocol */
 #define ETH_P_EDSA     0xDADA          /* Ethertype DSA [ NOT AN OFFICIALLY REGISTERED ID ] */
index b1b827d091a995e3d5b2e4a0d1e7f18e975e9319..0e3f2a4c25f6ef0270f8e007a985a21cb74d6234 100644 (file)
@@ -24,6 +24,7 @@ extern int ima_path_check(struct path *path, int mask, int update_counts);
 extern void ima_file_free(struct file *file);
 extern int ima_file_mmap(struct file *file, unsigned long prot);
 extern void ima_counts_get(struct file *file);
+extern void ima_counts_put(struct path *path, int mask);
 
 #else
 static inline int ima_bprm_check(struct linux_binprm *bprm)
@@ -60,5 +61,10 @@ static inline void ima_counts_get(struct file *file)
 {
        return;
 }
+
+static inline void ima_counts_put(struct path *path, int mask)
+{
+       return;
+}
 #endif /* CONFIG_IMA_H */
 #endif /* _LINUX_IMA_H */
index 5368fbdc78018c573c9f20a1dab76adbc8cb0f24..7fc01b13be43cfdd7b089b2e8498971f6440d253 100644 (file)
@@ -183,5 +183,8 @@ extern struct cred init_cred;
        LIST_HEAD_INIT(cpu_timers[2]),                                  \
 }
 
+/* Attach to the init_task data structure for proper alignment */
+#define __init_task_data __attribute__((__section__(".data.init_task")))
+
 
 #endif
diff --git a/include/linux/input/matrix_keypad.h b/include/linux/input/matrix_keypad.h
new file mode 100644 (file)
index 0000000..7964516
--- /dev/null
@@ -0,0 +1,65 @@
+#ifndef _MATRIX_KEYPAD_H
+#define _MATRIX_KEYPAD_H
+
+#include <linux/types.h>
+#include <linux/input.h>
+
+#define MATRIX_MAX_ROWS                16
+#define MATRIX_MAX_COLS                16
+
+#define KEY(row, col, val)     ((((row) & (MATRIX_MAX_ROWS - 1)) << 24) |\
+                                (((col) & (MATRIX_MAX_COLS - 1)) << 16) |\
+                                (val & 0xffff))
+
+#define KEY_ROW(k)             (((k) >> 24) & 0xff)
+#define KEY_COL(k)             (((k) >> 16) & 0xff)
+#define KEY_VAL(k)             ((k) & 0xffff)
+
+/**
+ * struct matrix_keymap_data - keymap for matrix keyboards
+ * @keymap: pointer to array of uint32 values encoded with KEY() macro
+ *     representing keymap
+ * @keymap_size: number of entries (initialized) in this keymap
+ * @max_keymap_size: maximum size of keymap supported by the device
+ *
+ * This structure is supposed to be used by platform code to supply
+ * keymaps to drivers that implement matrix-like keypads/keyboards.
+ */
+struct matrix_keymap_data {
+       const uint32_t *keymap;
+       unsigned int    keymap_size;
+       unsigned int    max_keymap_size;
+};
+
+/**
+ * struct matrix_keypad_platform_data - platform-dependent keypad data
+ * @keymap_data: pointer to &matrix_keymap_data
+ * @row_gpios: array of gpio numbers reporesenting rows
+ * @col_gpios: array of gpio numbers reporesenting colums
+ * @num_row_gpios: actual number of row gpios used by device
+ * @num_col_gpios: actual number of col gpios used by device
+ * @col_scan_delay_us: delay, measured in microseconds, that is
+ *     needed before we can keypad after activating column gpio
+ * @debounce_ms: debounce interval in milliseconds
+ *
+ * This structure represents platform-specific data that use used by
+ * matrix_keypad driver to perform proper initialization.
+ */
+struct matrix_keypad_platform_data {
+       const struct matrix_keymap_data *keymap_data;
+
+       unsigned int    row_gpios[MATRIX_MAX_ROWS];
+       unsigned int    col_gpios[MATRIX_MAX_COLS];
+       unsigned int    num_row_gpios;
+       unsigned int    num_col_gpios;
+
+       unsigned int    col_scan_delay_us;
+
+       /* key debounce interval in milli-second */
+       unsigned int    debounce_ms;
+
+       bool            active_low;
+       bool            wakeup;
+};
+
+#endif /* _MATRIX_KEYPAD_H */
index fac104e7186ae0bb13ef19ceaaf87022446af966..d6320a3e8def0fc22a9595d8ff03f52c08983404 100644 (file)
@@ -303,6 +303,7 @@ extern int oops_in_progress;                /* If set, an oops, panic(), BUG() or die() is in
 extern int panic_timeout;
 extern int panic_on_oops;
 extern int panic_on_unrecovered_nmi;
+extern int panic_on_io_nmi;
 extern const char *print_tainted(void);
 extern void add_taint(unsigned flag);
 extern int test_taint(unsigned flag);
index 7796aed6cdd5fdbb47a67b95b9a610f6417a384b..6a63807f714e197b59ad639149803af270e20e93 100644 (file)
@@ -27,6 +27,7 @@ extern void kmemleak_init(void);
 extern void kmemleak_alloc(const void *ptr, size_t size, int min_count,
                           gfp_t gfp);
 extern void kmemleak_free(const void *ptr);
+extern void kmemleak_free_part(const void *ptr, size_t size);
 extern void kmemleak_padding(const void *ptr, unsigned long offset,
                             size_t size);
 extern void kmemleak_not_leak(const void *ptr);
@@ -71,6 +72,9 @@ static inline void kmemleak_alloc_recursive(const void *ptr, size_t size,
 static inline void kmemleak_free(const void *ptr)
 {
 }
+static inline void kmemleak_free_part(const void *ptr, size_t size)
+{
+}
 static inline void kmemleak_free_recursive(const void *ptr, unsigned long flags)
 {
 }
index aacc5449f586376a6551518c2a946a7a151ada46..16713dc672e4215b4ae2b092980181cdf29a12e4 100644 (file)
@@ -125,6 +125,7 @@ struct kvm_kernel_irq_routing_entry {
 struct kvm {
        struct mutex lock; /* protects the vcpus array and APIC accesses */
        spinlock_t mmu_lock;
+       spinlock_t requests_lock;
        struct rw_semaphore slots_lock;
        struct mm_struct *mm; /* userspace tied to this vm */
        int nmemslots;
diff --git a/include/linux/leds-lp3944.h b/include/linux/leds-lp3944.h
new file mode 100644 (file)
index 0000000..afc9f9f
--- /dev/null
@@ -0,0 +1,53 @@
+/*
+ * leds-lp3944.h - platform data structure for lp3944 led controller
+ *
+ * Copyright (C) 2009 Antonio Ospite <ospite@studenti.unina.it>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ */
+
+#ifndef __LINUX_LEDS_LP3944_H
+#define __LINUX_LEDS_LP3944_H
+
+#include <linux/leds.h>
+#include <linux/workqueue.h>
+
+#define LP3944_LED0 0
+#define LP3944_LED1 1
+#define LP3944_LED2 2
+#define LP3944_LED3 3
+#define LP3944_LED4 4
+#define LP3944_LED5 5
+#define LP3944_LED6 6
+#define LP3944_LED7 7
+#define LP3944_LEDS_MAX 8
+
+#define LP3944_LED_STATUS_MASK 0x03
+enum lp3944_status {
+       LP3944_LED_STATUS_OFF  = 0x0,
+       LP3944_LED_STATUS_ON   = 0x1,
+       LP3944_LED_STATUS_DIM0 = 0x2,
+       LP3944_LED_STATUS_DIM1 = 0x3
+};
+
+enum lp3944_type {
+       LP3944_LED_TYPE_NONE,
+       LP3944_LED_TYPE_LED,
+       LP3944_LED_TYPE_LED_INVERTED,
+};
+
+struct lp3944_led {
+       char *name;
+       enum lp3944_type type;
+       enum lp3944_status status;
+};
+
+struct lp3944_platform_data {
+       struct lp3944_led leds[LP3944_LEDS_MAX];
+       u8 leds_size;
+};
+
+#endif /* __LINUX_LEDS_LP3944_H */
index 376fe07732ea9261dc81f3ff7411d49ac9051fb3..d8bf9665e70cc09b40d781a82c638e1b95dd82af 100644 (file)
@@ -45,7 +45,10 @@ struct led_classdev {
        /* Get LED brightness level */
        enum led_brightness (*brightness_get)(struct led_classdev *led_cdev);
 
-       /* Activate hardware accelerated blink */
+       /* Activate hardware accelerated blink, delays are in
+        * miliseconds and if none is provided then a sensible default
+        * should be chosen. The call can adjust the timings if it can't
+        * match the values specified exactly. */
        int             (*blink_set)(struct led_classdev *led_cdev,
                                     unsigned long *delay_on,
                                     unsigned long *delay_off);
@@ -141,9 +144,14 @@ struct gpio_led {
        const char *name;
        const char *default_trigger;
        unsigned        gpio;
-       u8              active_low : 1;
-       u8              retain_state_suspended : 1;
+       unsigned        active_low : 1;
+       unsigned        retain_state_suspended : 1;
+       unsigned        default_state : 2;
+       /* default_state should be one of LEDS_GPIO_DEFSTATE_(ON|OFF|KEEP) */
 };
+#define LEDS_GPIO_DEFSTATE_OFF 0
+#define LEDS_GPIO_DEFSTATE_ON  1
+#define LEDS_GPIO_DEFSTATE_KEEP        2
 
 struct gpio_led_platform_data {
        int             num_leds;
index 7bc1440fc47305418967134e2f65e0e23ea24572..dbf2479e808ef30e650cd23b2f52755a4cb22c37 100644 (file)
@@ -11,7 +11,7 @@
 #define LG_CLOCK_MIN_DELTA     100UL
 #define LG_CLOCK_MAX_DELTA     ULONG_MAX
 
-/*G:032 The second method of communicating with the Host is to via "struct
+/*G:031 The second method of communicating with the Host is to via "struct
  * lguest_data".  Once the Guest's initialization hypercall tells the Host where
  * this is, the Guest and Host both publish information in it. :*/
 struct lguest_data
index 3d501db36a26a52f0f960e59fc8e1a1504356c58..79b6d7fd4ac2d217bea7bfebe81b6c4b7a5b770b 100644 (file)
@@ -385,6 +385,7 @@ enum {
                                                    not multiple of 16 bytes */
        ATA_HORKAGE_FIRMWARE_WARN = (1 << 12),  /* firmware update warning */
        ATA_HORKAGE_1_5_GBPS    = (1 << 13),    /* force 1.5 Gbps */
+       ATA_HORKAGE_NOSETXFER   = (1 << 14),    /* skip SETXFER, SATA only */
 
         /* DMA mask for user DMA control: User visible values; DO NOT
            renumber */
index fee9e59649c12faee1a8bb573b51fa5758ca884b..691f59171c6c722e52faaeaed4e086d46f646eb2 100644 (file)
 #define __page_aligned_data    __section(.data.page_aligned) __aligned(PAGE_SIZE)
 #define __page_aligned_bss     __section(.bss.page_aligned) __aligned(PAGE_SIZE)
 
+/*
+ * For assembly routines.
+ *
+ * Note when using these that you must specify the appropriate
+ * alignment directives yourself
+ */
+#define __PAGE_ALIGNED_DATA    .section ".data.page_aligned", "aw"
+#define __PAGE_ALIGNED_BSS     .section ".bss.page_aligned", "aw"
+
 /*
  * This is used by architectures to keep arguments on the stack
  * untouched by the compiler by keeping them live until the end.
index da5a5a1f4cd2ec17fb2a5f544cc71f8e800b2d10..b25d1b53df0dfdefce12db40c2592b3cb1f0f546 100644 (file)
@@ -258,6 +258,16 @@ extern void lockdep_init_map(struct lockdep_map *lock, const char *name,
 #define lockdep_set_subclass(lock, sub)        \
                lockdep_init_map(&(lock)->dep_map, #lock, \
                                 (lock)->dep_map.key, sub)
+/*
+ * Compare locking classes
+ */
+#define lockdep_match_class(lock, key) lockdep_match_key(&(lock)->dep_map, key)
+
+static inline int lockdep_match_key(struct lockdep_map *lock,
+                                   struct lock_class_key *key)
+{
+       return lock->key == key;
+}
 
 /*
  * Acquire a lock.
@@ -326,6 +336,11 @@ static inline void lockdep_on(void)
 #define lockdep_set_class_and_subclass(lock, key, sub) \
                do { (void)(key); } while (0)
 #define lockdep_set_subclass(lock, sub)                do { } while (0)
+/*
+ * We don't define lockdep_match_class() and lockdep_match_key() for !LOCKDEP
+ * case since the result is not well defined and the caller should rather
+ * #ifdef the call himself.
+ */
 
 # define INIT_LOCKDEP
 # define lockdep_reset()               do { debug_locks = 1; } while (0)
diff --git a/include/linux/max17040_battery.h b/include/linux/max17040_battery.h
new file mode 100644 (file)
index 0000000..ad97b06
--- /dev/null
@@ -0,0 +1,19 @@
+/*
+ *  Copyright (C) 2009 Samsung Electronics
+ *  Minkyu Kang <mk7.kang@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef __MAX17040_BATTERY_H_
+#define __MAX17040_BATTERY_H_
+
+struct max17040_platform_data {
+       int (*battery_online)(void);
+       int (*charger_online)(void);
+       int (*charger_enable)(void);
+};
+
+#endif
index d006e93d5c93c3323da45ebd14d0f7920722120b..ba3a7cb1eaa0d6a3d3c67401592728c58742917f 100644 (file)
@@ -826,7 +826,7 @@ extern int make_pages_present(unsigned long addr, unsigned long end);
 extern int access_process_vm(struct task_struct *tsk, unsigned long addr, void *buf, int len, int write);
 
 int get_user_pages(struct task_struct *tsk, struct mm_struct *mm,
-                       unsigned long start, int len, int write, int force,
+                       unsigned long start, int nr_pages, int write, int force,
                        struct page **pages, struct vm_area_struct **vmas);
 int get_user_pages_fast(unsigned long start, int nr_pages, int write,
                        struct page **pages);
index 3beb2592b03f54a09a4d2c8cb922951f8cc3fcd5..d74785c2393ad03976925e8ea6b63e3716718b79 100644 (file)
@@ -2,10 +2,9 @@
 #define _NAMESPACE_H_
 #ifdef __KERNEL__
 
-#include <linux/mount.h>
-#include <linux/sched.h>
-#include <linux/nsproxy.h>
+#include <linux/path.h>
 #include <linux/seq_file.h>
+#include <linux/wait.h>
 
 struct mnt_namespace {
        atomic_t                count;
@@ -28,14 +27,6 @@ extern struct mnt_namespace *create_mnt_ns(struct vfsmount *mnt);
 extern struct mnt_namespace *copy_mnt_ns(unsigned long, struct mnt_namespace *,
                struct fs_struct *);
 extern void put_mnt_ns(struct mnt_namespace *ns);
-
-static inline void exit_mnt_ns(struct task_struct *p)
-{
-       struct mnt_namespace *ns = p->nsproxy->mnt_ns;
-       if (ns)
-               put_mnt_ns(ns);
-}
-
 static inline void get_mnt_ns(struct mnt_namespace *ns)
 {
        atomic_inc(&ns->count);
index 3430c775194828b6cea57984d14c6c80d45c5fe4..7ae05338e94c3bce924c3dac8eb87875abe237a6 100644 (file)
@@ -81,4 +81,17 @@ struct xt_conntrack_mtinfo1 {
        __u8 state_mask, status_mask;
 };
 
+struct xt_conntrack_mtinfo2 {
+       union nf_inet_addr origsrc_addr, origsrc_mask;
+       union nf_inet_addr origdst_addr, origdst_mask;
+       union nf_inet_addr replsrc_addr, replsrc_mask;
+       union nf_inet_addr repldst_addr, repldst_mask;
+       __u32 expires_min, expires_max;
+       __u16 l4proto;
+       __be16 origsrc_port, origdst_port;
+       __be16 replsrc_port, repldst_port;
+       __u16 match_flags, invert_flags;
+       __u16 state_mask, status_mask;
+};
+
 #endif /*_XT_CONNTRACK_H*/
index fd2272e0959a4377cc54bf65b03cdd1cf57caed7..18afa495f9737b9915732b953729ee7f2dd91459 100644 (file)
@@ -20,6 +20,8 @@
 #ifndef _XT_OSF_H
 #define _XT_OSF_H
 
+#include <linux/types.h>
+
 #define MAXGENRELEN            32
 
 #define XT_OSF_GENRE           (1<<0)
index d304ddf412d064750956d9ee689fcb42a4b86706..115fb7ba508907ce85704f1f2a9eb7bac5b9be4c 100644 (file)
@@ -1145,7 +1145,7 @@ static inline void pci_set_drvdata(struct pci_dev *pdev, void *data)
 /* If you want to know what to call your pci_dev, ask this function.
  * Again, it's a wrapper around the generic device.
  */
-static inline const char *pci_name(struct pci_dev *pdev)
+static inline const char *pci_name(const struct pci_dev *pdev)
 {
        return dev_name(&pdev->dev);
 }
index b3646cd7fd5af6a823aafce45f2c3d8290689ab8..4391741b99dc15a4083c2b0063efbe77aacc2e61 100644 (file)
@@ -229,7 +229,6 @@ struct hotplug_params {
 extern acpi_status acpi_get_hp_params_from_firmware(struct pci_bus *bus,
                                struct hotplug_params *hpp);
 int acpi_get_hp_hw_control_from_firmware(struct pci_dev *dev, u32 flags);
-int acpi_root_bridge(acpi_handle handle);
 int acpi_pci_check_ejectable(struct pci_bus *pbus, acpi_handle handle);
 int acpi_pci_detect_ejectable(struct pci_bus *pbus);
 #endif
index a3b0003657955da3651542059572387fda381308..73b46b6b904fc87b977ceeaae2b462c5ac0f5e60 100644 (file)
 #define PCI_DEVICE_ID_NETMOS_9835      0x9835
 #define PCI_DEVICE_ID_NETMOS_9845      0x9845
 #define PCI_DEVICE_ID_NETMOS_9855      0x9855
+#define PCI_DEVICE_ID_NETMOS_9901      0x9901
 
 #define PCI_VENDOR_ID_3COM_2           0xa727
 
index 8f921d74f49f12d2922dc492943bb7aa2356ea86..68438e18fff4fde80a80af87a00748a3a69b44b7 100644 (file)
@@ -24,7 +24,8 @@
 
 #define DEFINE_PER_CPU_SECTION(type, name, section)                    \
        __attribute__((__section__(PER_CPU_BASE_SECTION section)))      \
-       PER_CPU_ATTRIBUTES __typeof__(type) per_cpu__##name
+       PER_CPU_ATTRIBUTES PER_CPU_DEF_ATTRIBUTES                       \
+       __typeof__(type) per_cpu__##name
 
 /*
  * Variant on the per-CPU variable declaration/definition theme used for
index 89698d8aba5c1dc1f92dbc6cbf6addd8f96790f4..5e970c7d3fd5b1c484ddc621dbbbc29921071926 100644 (file)
@@ -178,8 +178,10 @@ struct perf_counter_attr {
                                mmap           :  1, /* include mmap data     */
                                comm           :  1, /* include comm data     */
                                freq           :  1, /* use freq, not period  */
+                               inherit_stat   :  1, /* per task counts       */
+                               enable_on_exec :  1, /* next exec enables     */
 
-                               __reserved_1   : 53;
+                               __reserved_1   : 51;
 
        __u32                   wakeup_events;  /* wakeup every n events */
        __u32                   __reserved_2;
@@ -232,6 +234,14 @@ struct perf_counter_mmap_page {
        __u32   lock;                   /* seqlock for synchronization */
        __u32   index;                  /* hardware counter identifier */
        __s64   offset;                 /* add to hardware counter value */
+       __u64   time_enabled;           /* time counter active */
+       __u64   time_running;           /* time counter on cpu */
+
+               /*
+                * Hole for extension of the self monitor capabilities
+                */
+
+       __u64   __reserved[123];        /* align to 1k */
 
        /*
         * Control data for the mmap() data buffer.
@@ -253,7 +263,6 @@ struct perf_counter_mmap_page {
 #define PERF_EVENT_MISC_KERNEL                 (1 << 0)
 #define PERF_EVENT_MISC_USER                   (2 << 0)
 #define PERF_EVENT_MISC_HYPERVISOR             (3 << 0)
-#define PERF_EVENT_MISC_OVERFLOW               (1 << 2)
 
 struct perf_event_header {
        __u32   type;
@@ -327,9 +336,18 @@ enum perf_event_type {
        PERF_EVENT_FORK                 = 7,
 
        /*
-        * When header.misc & PERF_EVENT_MISC_OVERFLOW the event_type field
-        * will be PERF_SAMPLE_*
-        *
+        * struct {
+        *      struct perf_event_header        header;
+        *      u32                             pid, tid;
+        *      u64                             value;
+        *      { u64           time_enabled;   } && PERF_FORMAT_ENABLED
+        *      { u64           time_running;   } && PERF_FORMAT_RUNNING
+        *      { u64           parent_id;      } && PERF_FORMAT_ID
+        * };
+        */
+       PERF_EVENT_READ                 = 8,
+
+       /*
         * struct {
         *      struct perf_event_header        header;
         *
@@ -337,8 +355,9 @@ enum perf_event_type {
         *      { u32                   pid, tid; } && PERF_SAMPLE_TID
         *      { u64                   time;     } && PERF_SAMPLE_TIME
         *      { u64                   addr;     } && PERF_SAMPLE_ADDR
-        *      { u64                   config;   } && PERF_SAMPLE_CONFIG
+        *      { u64                   id;       } && PERF_SAMPLE_ID
         *      { u32                   cpu, res; } && PERF_SAMPLE_CPU
+        *      { u64                   period;   } && PERF_SAMPLE_PERIOD
         *
         *      { u64                   nr;
         *        { u64 id, val; }      cnt[nr];  } && PERF_SAMPLE_GROUP
@@ -347,6 +366,9 @@ enum perf_event_type {
         *        u64                   ips[nr];  } && PERF_SAMPLE_CALLCHAIN
         * };
         */
+       PERF_EVENT_SAMPLE               = 9,
+
+       PERF_EVENT_MAX,                 /* non-ABI */
 };
 
 enum perf_callchain_context {
@@ -582,6 +604,7 @@ struct perf_counter_context {
        int                             nr_counters;
        int                             nr_active;
        int                             is_active;
+       int                             nr_stat;
        atomic_t                        refcount;
        struct task_struct              *task;
 
@@ -669,7 +692,16 @@ static inline int is_software_counter(struct perf_counter *counter)
                (counter->attr.type != PERF_TYPE_HW_CACHE);
 }
 
-extern void perf_swcounter_event(u32, u64, int, struct pt_regs *, u64);
+extern atomic_t perf_swcounter_enabled[PERF_COUNT_SW_MAX];
+
+extern void __perf_swcounter_event(u32, u64, int, struct pt_regs *, u64);
+
+static inline void
+perf_swcounter_event(u32 event, u64 nr, int nmi, struct pt_regs *regs, u64 addr)
+{
+       if (atomic_read(&perf_swcounter_enabled[event]))
+               __perf_swcounter_event(event, nr, nmi, regs, addr);
+}
 
 extern void __perf_counter_mmap(struct vm_area_struct *vma);
 
index a84e9ff9b27e9d59cfd1f2d0e8b3403e21b07ca0..126120819a0dba4aeb931094094c27d3d80f9aa0 100644 (file)
@@ -40,7 +40,10 @@ enum {
  * Security-relevant compatibility flags that must be
  * cleared upon setuid or setgid exec:
  */
-#define PER_CLEAR_ON_SETID (READ_IMPLIES_EXEC|ADDR_NO_RANDOMIZE)
+#define PER_CLEAR_ON_SETID (READ_IMPLIES_EXEC  | \
+                           ADDR_NO_RANDOMIZE  | \
+                           ADDR_COMPAT_LAYOUT | \
+                           MMAP_PAGE_ZERO)
 
 /*
  * Personality types.
index 4bc241290c241e6668faa8debc9d5985b5a2d447..065a3652a3eaf92a8381db3f35e78f86e470a488 100644 (file)
@@ -83,4 +83,78 @@ extern int posix_acl_chmod_masq(struct posix_acl *, mode_t);
 extern struct posix_acl *get_posix_acl(struct inode *, int);
 extern int set_posix_acl(struct inode *, int, struct posix_acl *);
 
+#ifdef CONFIG_FS_POSIX_ACL
+static inline struct posix_acl *get_cached_acl(struct inode *inode, int type)
+{
+       struct posix_acl **p, *acl;
+       switch (type) {
+       case ACL_TYPE_ACCESS:
+               p = &inode->i_acl;
+               break;
+       case ACL_TYPE_DEFAULT:
+               p = &inode->i_default_acl;
+               break;
+       default:
+               return ERR_PTR(-EINVAL);
+       }
+       acl = ACCESS_ONCE(*p);
+       if (acl) {
+               spin_lock(&inode->i_lock);
+               acl = *p;
+               if (acl != ACL_NOT_CACHED)
+                       acl = posix_acl_dup(acl);
+               spin_unlock(&inode->i_lock);
+       }
+       return acl;
+}
+
+static inline void set_cached_acl(struct inode *inode,
+                                 int type,
+                                 struct posix_acl *acl)
+{
+       struct posix_acl *old = NULL;
+       spin_lock(&inode->i_lock);
+       switch (type) {
+       case ACL_TYPE_ACCESS:
+               old = inode->i_acl;
+               inode->i_acl = posix_acl_dup(acl);
+               break;
+       case ACL_TYPE_DEFAULT:
+               old = inode->i_default_acl;
+               inode->i_default_acl = posix_acl_dup(acl);
+               break;
+       }
+       spin_unlock(&inode->i_lock);
+       if (old != ACL_NOT_CACHED)
+               posix_acl_release(old);
+}
+
+static inline void forget_cached_acl(struct inode *inode, int type)
+{
+       struct posix_acl *old = NULL;
+       spin_lock(&inode->i_lock);
+       switch (type) {
+       case ACL_TYPE_ACCESS:
+               old = inode->i_acl;
+               inode->i_acl = ACL_NOT_CACHED;
+               break;
+       case ACL_TYPE_DEFAULT:
+               old = inode->i_default_acl;
+               inode->i_default_acl = ACL_NOT_CACHED;
+               break;
+       }
+       spin_unlock(&inode->i_lock);
+       if (old != ACL_NOT_CACHED)
+               posix_acl_release(old);
+}
+#endif
+
+static inline void cache_no_acl(struct inode *inode)
+{
+#ifdef CONFIG_FS_POSIX_ACL
+       inode->i_acl = NULL;
+       inode->i_default_acl = NULL;
+#endif
+}
+
 #endif  /* __LINUX_POSIX_ACL_H */
index 7bc457593684aaad13a4e27b0759066832f130f0..26361c4c037a15f24feb2952070de8d1a9b2eab5 100644 (file)
@@ -7,7 +7,6 @@
 #ifndef _LINUX_QUOTAOPS_
 #define _LINUX_QUOTAOPS_
 
-#include <linux/smp_lock.h>
 #include <linux/fs.h>
 
 static inline struct quota_info *sb_dqopt(struct super_block *sb)
index 8cc65757e47adfc476ed4b2ca2c1d020c06ab6bf..b4448853900ed85a17ff24a9ce074ab5f890572f 100644 (file)
@@ -56,15 +56,6 @@ int reiserfs_cache_default_acl(struct inode *dir);
 extern struct xattr_handler reiserfs_posix_acl_default_handler;
 extern struct xattr_handler reiserfs_posix_acl_access_handler;
 
-static inline void reiserfs_init_acl_access(struct inode *inode)
-{
-       REISERFS_I(inode)->i_acl_access = NULL;
-}
-
-static inline void reiserfs_init_acl_default(struct inode *inode)
-{
-       REISERFS_I(inode)->i_acl_default = NULL;
-}
 #else
 
 #define reiserfs_cache_default_acl(inode) 0
@@ -86,12 +77,4 @@ reiserfs_inherit_default_acl(struct reiserfs_transaction_handle *th,
 {
        return 0;
 }
-
-static inline void reiserfs_init_acl_access(struct inode *inode)
-{
-}
-
-static inline void reiserfs_init_acl_default(struct inode *inode)
-{
-}
 #endif
index 76360b36ac3324040a5066cc15ddca9b5c2e98b0..89f4d3abbf5af501610edeac780448e94cc4de55 100644 (file)
@@ -54,10 +54,6 @@ struct reiserfs_inode_info {
        unsigned int i_trans_id;
        struct reiserfs_journal_list *i_jl;
        struct mutex i_mmap;
-#ifdef CONFIG_REISERFS_FS_POSIX_ACL
-       struct posix_acl *i_acl_access;
-       struct posix_acl *i_acl_default;
-#endif
 #ifdef CONFIG_REISERFS_FS_XATTR
        struct rw_semaphore i_xattr_sem;
 #endif
index e73e2429a1b1cab128e1561865b3f12ca822a8e8..2ce29831feb61d9c0d7aefa5f0f3446f17519220 100644 (file)
@@ -99,7 +99,6 @@ enum rfkill_user_states {
 #undef RFKILL_STATE_UNBLOCKED
 #undef RFKILL_STATE_HARD_BLOCKED
 
-#include <linux/types.h>
 #include <linux/kernel.h>
 #include <linux/list.h>
 #include <linux/mutex.h>
index 4d075426988428820aae1f451015744bc2e50440..16a982e389fb289560d13039bfb608fd82bbdae2 100644 (file)
@@ -349,8 +349,20 @@ extern int mutex_spin_on_owner(struct mutex *lock, struct thread_info *owner);
 struct nsproxy;
 struct user_namespace;
 
-/* Maximum number of active map areas.. This is a random (large) number */
-#define DEFAULT_MAX_MAP_COUNT  65536
+/*
+ * Default maximum number of active map areas, this limits the number of vmas
+ * per mm struct. Users can overwrite this number by sysctl but there is a
+ * problem.
+ *
+ * When a program's coredump is generated as ELF format, a section is created
+ * per a vma. In ELF, the number of sections is represented in unsigned short.
+ * This means the number of sections should be smaller than 65535 at coredump.
+ * Because the kernel adds some informative sections to a image of program at
+ * generating coredump, we need some margin. The number of extra sections is
+ * 1-3 now and depends on arch. We use "5" as safe margin, here.
+ */
+#define MAPCOUNT_ELF_CORE_MARGIN       (5)
+#define DEFAULT_MAX_MAP_COUNT  (USHORT_MAX - MAPCOUNT_ELF_CORE_MARGIN)
 
 extern int sysctl_max_map_count;
 
@@ -486,6 +498,15 @@ struct task_cputime {
                .sum_exec_runtime = 0,                          \
        }
 
+/*
+ * Disable preemption until the scheduler is running.
+ * Reset by start_kernel()->sched_init()->init_idle().
+ *
+ * We include PREEMPT_ACTIVE to avoid cond_resched() from working
+ * before the scheduler is active -- see should_resched().
+ */
+#define INIT_PREEMPT_COUNT     (1 + PREEMPT_ACTIVE)
+
 /**
  * struct thread_group_cputimer - thread group interval timer counts
  * @cputime:           thread group interval timers.
index fd83f2584b157b5e76b593344c55f3381f149014..abff6c9b413c10c118e30dc537ea7b7f5e357c8d 100644 (file)
@@ -19,10 +19,6 @@ struct shmem_inode_info {
        swp_entry_t             i_direct[SHMEM_NR_DIRECT]; /* first blocks */
        struct list_head        swaplist;       /* chain of maybes on swap */
        struct inode            vfs_inode;
-#ifdef CONFIG_TMPFS_POSIX_ACL
-       struct posix_acl        *i_acl;
-       struct posix_acl        *i_default_acl;
-#endif
 };
 
 struct shmem_sb_info {
@@ -45,7 +41,6 @@ static inline struct shmem_inode_info *SHMEM_I(struct inode *inode)
 #ifdef CONFIG_TMPFS_POSIX_ACL
 int shmem_permission(struct inode *, int);
 int shmem_acl_init(struct inode *, struct inode *);
-void shmem_acl_destroy_inode(struct inode *);
 
 extern struct xattr_handler shmem_xattr_acl_access_handler;
 extern struct xattr_handler shmem_xattr_acl_default_handler;
@@ -57,9 +52,6 @@ static inline int shmem_acl_init(struct inode *inode, struct inode *dir)
 {
        return 0;
 }
-static inline void shmem_acl_destroy_inode(struct inode *inode)
-{
-}
 #endif  /* CONFIG_TMPFS_POSIX_ACL */
 
 #endif
index b47b3f039d147ee63cd4dbb1f99201c1e1814bb7..f2c69a2cca172aff841e6ce97656d5fa9cb412a9 100644 (file)
@@ -1342,12 +1342,12 @@ static inline int skb_network_offset(const struct sk_buff *skb)
  * shifting the start of the packet by 2 bytes. Drivers should do this
  * with:
  *
- * skb_reserve(NET_IP_ALIGN);
+ * skb_reserve(skb, NET_IP_ALIGN);
  *
  * The downside to this alignment of the IP header is that the DMA is now
  * unaligned. On some architectures the cost of an unaligned DMA is high
  * and this cost outweighs the gains made by aligning the IP header.
- * 
+ *
  * Since this trade off varies between architectures, we allow NET_IP_ALIGN
  * to be overridden.
  */
index 4dcbc2c71491ec9dc736b83c1eeedb03f4650a95..c1c862b1d01a2b41cccce3f462262ad4564ab782 100644 (file)
@@ -11,6 +11,7 @@
 #include <linux/workqueue.h>
 #include <linux/kobject.h>
 #include <linux/kmemtrace.h>
+#include <linux/kmemleak.h>
 
 enum stat_item {
        ALLOC_FASTPATH,         /* Allocation from cpu slab */
@@ -233,6 +234,7 @@ static __always_inline void *kmalloc_large(size_t size, gfp_t flags)
        unsigned int order = get_order(size);
        void *ret = (void *) __get_free_pages(flags | __GFP_COMP, order);
 
+       kmemleak_alloc(ret, size, 1, flags);
        trace_kmalloc(_THIS_IP_, ret, size, PAGE_SIZE << order, flags);
 
        return ret;
index 9c4cd27f4685250c274c375951ec695615dbe8ea..c47c4b4da97e5a606ab2823d3126a32f42e446f0 100644 (file)
@@ -80,6 +80,8 @@ struct spi_device {
 #define        SPI_LSB_FIRST   0x08                    /* per-word bits-on-wire */
 #define        SPI_3WIRE       0x10                    /* SI/SO signals shared */
 #define        SPI_LOOP        0x20                    /* loopback mode */
+#define        SPI_NO_CS       0x40                    /* 1 dev/bus, no chipselect */
+#define        SPI_READY       0x80                    /* slave pulls low to pause */
        u8                      bits_per_word;
        int                     irq;
        void                    *controller_state;
@@ -248,6 +250,10 @@ struct spi_master {
        /* spi_device.mode flags understood by this controller driver */
        u16                     mode_bits;
 
+       /* other constraints relevant to this driver */
+       u16                     flags;
+#define SPI_MASTER_HALF_DUPLEX BIT(0)          /* can't do full duplex */
+
        /* Setup mode and clock, etc (spi driver may call many times).
         *
         * IMPORTANT:  this may be called when transfers to another
index 95251ccd5a07072ac3421f6566e4a89658e1f578..bf0570a84f7a4aeb83e76d8e842b9f17b89c1143 100644 (file)
@@ -40,6 +40,8 @@
 #define SPI_LSB_FIRST          0x08
 #define SPI_3WIRE              0x10
 #define SPI_LOOP               0x20
+#define SPI_NO_CS              0x40
+#define SPI_READY              0x80
 
 /*---------------------------------------------------------------------------*/
 
index 252b245cfcf4cb098658da65f60f02436b12902f..4be57ab03478c837bf470e7f9d9a04fccf5fad27 100644 (file)
@@ -132,6 +132,11 @@ do {                                                               \
 #endif /*__raw_spin_is_contended*/
 #endif
 
+/* The lock does not imply full memory barrier. */
+#ifndef ARCH_HAS_SMP_MB_AFTER_LOCK
+static inline void smp_mb__after_lock(void) { smp_mb(); }
+#endif
+
 /**
  * spin_unlock_wait - wait until the spinlock gets unlocked
  * @lock: the spinlock in question.
index d8910b68e1bdd981cabe3ac8c34150ae85fa0627..b99c625fddfe764754b5005d44ea79933b74fc09 100644 (file)
@@ -12,7 +12,6 @@
 #include <linux/uio.h>
 #include <asm/byteorder.h>
 #include <linux/scatterlist.h>
-#include <linux/smp_lock.h>
 
 /*
  * Buffer adjustment
index fa4242cdade86f9b956c949b5253e965e7aa74c9..80de7003d8c2340f7a71d98614eaa3ba2baa7c18 100644 (file)
@@ -321,6 +321,8 @@ asmlinkage long sys_rt_sigtimedwait(const sigset_t __user *uthese,
                                siginfo_t __user *uinfo,
                                const struct timespec __user *uts,
                                size_t sigsetsize);
+asmlinkage long sys_rt_tgsigqueueinfo(pid_t tgid, pid_t  pid, int sig,
+               siginfo_t __user *uinfo);
 asmlinkage long sys_kill(int pid, int sig);
 asmlinkage long sys_tgkill(int tgid, int pid, int sig);
 asmlinkage long sys_tkill(int pid, int sig);
index 98a1d8cfb73d1902d7f55466bc9aa034e8436b2b..99adcdc0d3ca9062173f976cb27cd7f8bf8a0a91 100644 (file)
@@ -14,6 +14,8 @@
 #ifndef _LINUX_SYSRQ_H
 #define _LINUX_SYSRQ_H
 
+#include <linux/errno.h>
+
 struct pt_regs;
 struct tty_struct;
 
index ccf882eed8f8d5c35852ec65151c5b4112e8b564..be62ec2ebea54fc0c9bd97f3b630882385fa2943 100644 (file)
@@ -190,6 +190,8 @@ extern unsigned long get_next_timer_interrupt(unsigned long now);
  */
 #ifdef CONFIG_TIMER_STATS
 
+extern int timer_stats_active;
+
 #define TIMER_STATS_FLAG_DEFERRABLE    0x1
 
 extern void init_timer_stats(void);
@@ -203,6 +205,8 @@ extern void __timer_stats_timer_set_start_info(struct timer_list *timer,
 
 static inline void timer_stats_timer_set_start_info(struct timer_list *timer)
 {
+       if (likely(!timer_stats_active))
+               return;
        __timer_stats_timer_set_start_info(timer, __builtin_return_address(0));
 }
 
index 84929e9140341583cbc8fd7050c4e5e5a12b8d29..b1e3c2fbfe1170fdd8fc4cdb023d628b1a0b4a43 100644 (file)
@@ -888,8 +888,6 @@ struct usb_driver {
  * struct usb_device_driver - identifies USB device driver to usbcore
  * @name: The driver name should be unique among USB drivers,
  *     and should normally be the same as the module name.
- * @nodename: Callback to provide a naming hint for a possible
- *     device node to create.
  * @probe: Called to see if the driver is willing to manage a particular
  *     device.  If it is, probe returns zero and uses dev_set_drvdata()
  *     to associate driver-specific data with the device.  If unwilling
@@ -924,6 +922,8 @@ extern struct bus_type usb_bus_type;
 /**
  * struct usb_class_driver - identifies a USB driver that wants to use the USB major number
  * @name: the usb class device name for this driver.  Will show up in sysfs.
+ * @nodename: Callback to provide a naming hint for a possible
+ *     device node to create.
  * @fops: pointer to the struct file_operations of this driver.
  * @minor_base: the start of the minor range for this driver.
  *
@@ -1046,6 +1046,8 @@ typedef void (*usb_complete_t)(struct urb *);
  *     the device driver is saying that it provided this DMA address,
  *     which the host controller driver should use in preference to the
  *     transfer_buffer.
+ * @sg: scatter gather buffer list
+ * @num_sgs: number of entries in the sg list
  * @transfer_buffer_length: How big is transfer_buffer.  The transfer may
  *     be broken up into chunks according to the current maximum packet
  *     size for the endpoint, which is a function of the configuration
diff --git a/include/linux/usb/langwell_otg.h b/include/linux/usb/langwell_otg.h
deleted file mode 100644 (file)
index e115ae6..0000000
+++ /dev/null
@@ -1,177 +0,0 @@
-/*
- * Intel Langwell USB OTG transceiver driver
- * Copyright (C) 2008, Intel Corporation.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms and conditions of the GNU General Public License,
- * version 2, as published by the Free Software Foundation.
- *
- * This program is distributed in the hope it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
- *
- */
-
-#ifndef __LANGWELL_OTG_H__
-#define __LANGWELL_OTG_H__
-
-/* notify transceiver driver about OTG events */
-extern void langwell_update_transceiver(void);
-/* HCD register bus driver */
-extern int langwell_register_host(struct pci_driver *host_driver);
-/* HCD unregister bus driver */
-extern void langwell_unregister_host(struct pci_driver *host_driver);
-/* DCD register bus driver */
-extern int langwell_register_peripheral(struct pci_driver *client_driver);
-/* DCD unregister bus driver */
-extern void langwell_unregister_peripheral(struct pci_driver *client_driver);
-/* No silent failure, output warning message */
-extern void langwell_otg_nsf_msg(unsigned long message);
-
-#define CI_USBCMD              0x30
-#      define USBCMD_RST               BIT(1)
-#      define USBCMD_RS                BIT(0)
-#define CI_USBSTS              0x34
-#      define USBSTS_SLI               BIT(8)
-#      define USBSTS_URI               BIT(6)
-#      define USBSTS_PCI               BIT(2)
-#define CI_PORTSC1             0x74
-#      define PORTSC_PP                BIT(12)
-#      define PORTSC_LS                (BIT(11) | BIT(10))
-#      define PORTSC_SUSP              BIT(7)
-#      define PORTSC_CCS               BIT(0)
-#define CI_HOSTPC1             0xb4
-#      define HOSTPC1_PHCD             BIT(22)
-#define CI_OTGSC               0xf4
-#      define OTGSC_DPIE               BIT(30)
-#      define OTGSC_1MSE               BIT(29)
-#      define OTGSC_BSEIE              BIT(28)
-#      define OTGSC_BSVIE              BIT(27)
-#      define OTGSC_ASVIE              BIT(26)
-#      define OTGSC_AVVIE              BIT(25)
-#      define OTGSC_IDIE               BIT(24)
-#      define OTGSC_DPIS               BIT(22)
-#      define OTGSC_1MSS               BIT(21)
-#      define OTGSC_BSEIS              BIT(20)
-#      define OTGSC_BSVIS              BIT(19)
-#      define OTGSC_ASVIS              BIT(18)
-#      define OTGSC_AVVIS              BIT(17)
-#      define OTGSC_IDIS               BIT(16)
-#      define OTGSC_DPS                BIT(14)
-#      define OTGSC_1MST               BIT(13)
-#      define OTGSC_BSE                BIT(12)
-#      define OTGSC_BSV                BIT(11)
-#      define OTGSC_ASV                BIT(10)
-#      define OTGSC_AVV                BIT(9)
-#      define OTGSC_ID                 BIT(8)
-#      define OTGSC_HABA               BIT(7)
-#      define OTGSC_HADP               BIT(6)
-#      define OTGSC_IDPU               BIT(5)
-#      define OTGSC_DP                 BIT(4)
-#      define OTGSC_OT                 BIT(3)
-#      define OTGSC_HAAR               BIT(2)
-#      define OTGSC_VC                 BIT(1)
-#      define OTGSC_VD                 BIT(0)
-#      define OTGSC_INTEN_MASK         (0x7f << 24)
-#      define OTGSC_INTSTS_MASK        (0x7f << 16)
-#define CI_USBMODE             0xf8
-#      define USBMODE_CM               (BIT(1) | BIT(0))
-#      define USBMODE_IDLE             0
-#      define USBMODE_DEVICE           0x2
-#      define USBMODE_HOST             0x3
-
-#define INTR_DUMMY_MASK (USBSTS_SLI | USBSTS_URI | USBSTS_PCI)
-
-struct otg_hsm {
-       /* Input */
-       int a_bus_resume;
-       int a_bus_suspend;
-       int a_conn;
-       int a_sess_vld;
-       int a_srp_det;
-       int a_vbus_vld;
-       int b_bus_resume;
-       int b_bus_suspend;
-       int b_conn;
-       int b_se0_srp;
-       int b_sess_end;
-       int b_sess_vld;
-       int id;
-
-       /* Internal variables */
-       int a_set_b_hnp_en;
-       int b_srp_done;
-       int b_hnp_enable;
-
-       /* Timeout indicator for timers */
-       int a_wait_vrise_tmout;
-       int a_wait_bcon_tmout;
-       int a_aidl_bdis_tmout;
-       int b_ase0_brst_tmout;
-       int b_bus_suspend_tmout;
-       int b_srp_res_tmout;
-
-       /* Informative variables */
-       int a_bus_drop;
-       int a_bus_req;
-       int a_clr_err;
-       int a_suspend_req;
-       int b_bus_req;
-
-       /* Output */
-       int drv_vbus;
-       int loc_conn;
-       int loc_sof;
-
-       /* Others */
-       int b_bus_suspend_vld;
-};
-
-#define TA_WAIT_VRISE  100
-#define TA_WAIT_BCON   30000
-#define TA_AIDL_BDIS   15000
-#define TB_ASE0_BRST   5000
-#define TB_SE0_SRP     2
-#define TB_SRP_RES     100
-#define TB_BUS_SUSPEND 500
-
-struct langwell_otg_timer {
-       unsigned long expires;  /* Number of count increase to timeout */
-       unsigned long count;    /* Tick counter */
-       void (*function)(unsigned long);        /* Timeout function */
-       unsigned long data;     /* Data passed to function */
-       struct list_head list;
-};
-
-struct langwell_otg {
-       struct otg_transceiver  otg;
-       struct otg_hsm          hsm;
-       void __iomem            *regs;
-       unsigned                region;
-       struct pci_driver       *host_ops;
-       struct pci_driver       *client_ops;
-       struct pci_dev          *pdev;
-       struct work_struct      work;
-       struct workqueue_struct *qwork;
-       spinlock_t              lock;
-       spinlock_t              wq_lock;
-};
-
-static inline struct langwell_otg *otg_to_langwell(struct otg_transceiver *otg)
-{
-       return container_of(otg, struct langwell_otg, otg);
-}
-
-#ifdef DEBUG
-#define otg_dbg(fmt, args...) \
-       printk(KERN_DEBUG fmt , ## args)
-#else
-#define otg_dbg(fmt, args...) \
-       do { } while (0)
-#endif /* DEBUG */
-#endif /* __LANGWELL_OTG_H__ */
index 44801d26a37a7888d7ebd88dbb5cf0e4a1836de0..0ec50ba62139e5bde97db61a10b8585c2882c916 100644 (file)
@@ -317,7 +317,8 @@ extern int usb_serial_generic_register(int debug);
 extern void usb_serial_generic_deregister(void);
 extern void usb_serial_generic_resubmit_read_urb(struct usb_serial_port *port,
                                                 gfp_t mem_flags);
-extern int usb_serial_handle_sysrq_char(struct usb_serial_port *port,
+extern int usb_serial_handle_sysrq_char(struct tty_struct *tty,
+                                       struct usb_serial_port *port,
                                        unsigned int ch);
 extern int usb_serial_handle_break(struct usb_serial_port *port);
 
index 5d44059f6d63feb02dbc8f2defc3d6ffb1d9cfba..310e18a880fff5da371f000225a871008afbb84e 100644 (file)
@@ -42,7 +42,6 @@ struct usbnet {
 
        /* protocol/interface state */
        struct net_device       *net;
-       struct net_device_stats stats;
        int                     msg_enable;
        unsigned long           data [5];
        u32                     xid;
index 8a025d510904609ec4b1b244f10a0d8cd7bdff8b..95846d988011469be4f2050814e4acb924909c69 100644 (file)
@@ -318,6 +318,8 @@ struct v4l2_pix_format {
 /* see http://www.siliconimaging.com/RGB%20Bayer.htm */
 #define V4L2_PIX_FMT_SBGGR8  v4l2_fourcc('B', 'A', '8', '1') /*  8  BGBG.. GRGR.. */
 #define V4L2_PIX_FMT_SGBRG8  v4l2_fourcc('G', 'B', 'R', 'G') /*  8  GBGB.. RGRG.. */
+#define V4L2_PIX_FMT_SGRBG8  v4l2_fourcc('G', 'R', 'B', 'G') /*  8  GRGR.. BGBG.. */
+
 /*
  * 10bit raw bayer, expanded to 16 bits
  * xxxxrrrrrrrrrrxxxxgggggggggg xxxxggggggggggxxxxbbbbbbbbbb...
index cec79adbe3ea60934ad69f3ef00484f12b97b065..9c543d6ac535699cf8bab7a4c7209a997cc8e8d1 100644 (file)
@@ -27,6 +27,7 @@
 #define VIRTIO_NET_F_CTRL_VQ   17      /* Control channel available */
 #define VIRTIO_NET_F_CTRL_RX   18      /* Control channel RX mode support */
 #define VIRTIO_NET_F_CTRL_VLAN 19      /* Control channel VLAN filtering */
+#define VIRTIO_NET_F_CTRL_RX_EXTRA 20  /* Extra RX mode control support */
 
 #define VIRTIO_NET_S_LINK_UP   1       /* Link is up */
 
@@ -81,14 +82,19 @@ typedef __u8 virtio_net_ctrl_ack;
 #define VIRTIO_NET_ERR    1
 
 /*
- * Control the RX mode, ie. promisucous and allmulti.  PROMISC and
- * ALLMULTI commands require an "out" sg entry containing a 1 byte
- * state value, zero = disable, non-zero = enable.  These commands
- * are supported with the VIRTIO_NET_F_CTRL_RX feature.
+ * Control the RX mode, ie. promisucous, allmulti, etc...
+ * All commands require an "out" sg entry containing a 1 byte
+ * state value, zero = disable, non-zero = enable.  Commands
+ * 0 and 1 are supported with the VIRTIO_NET_F_CTRL_RX feature.
+ * Commands 2-5 are added with VIRTIO_NET_F_CTRL_RX_EXTRA.
  */
 #define VIRTIO_NET_CTRL_RX    0
  #define VIRTIO_NET_CTRL_RX_PROMISC      0
  #define VIRTIO_NET_CTRL_RX_ALLMULTI     1
+ #define VIRTIO_NET_CTRL_RX_ALLUNI       2
+ #define VIRTIO_NET_CTRL_RX_NOMULTI      3
+ #define VIRTIO_NET_CTRL_RX_NOUNI        4
+ #define VIRTIO_NET_CTRL_RX_NOBCAST      5
 
 /*
  * Control the MAC filter table.
index 4d7e2272c42f0c37e0aabb5dbc912c6c24361a34..11a4a2d3e364f355e32c21dd3fca6df8576cc261 100644 (file)
@@ -155,6 +155,9 @@ enum {
        /* module cafe_ccic, just ident 8801 */
        V4L2_IDENT_CAFE = 8801,
 
+       /* module mt9v011, just ident 8243 */
+       V4L2_IDENT_MT9V011 = 8243,
+
        /* module tw9910: just ident 9910 */
        V4L2_IDENT_TW9910 = 9910,
 
index a632689b61b40f581e4cc1d25fe65ebcac053995..cbdd6284996d3cd29732c0ae406833a678a3fb80 100644 (file)
@@ -258,8 +258,8 @@ static inline bool nf_ct_kill(struct nf_conn *ct)
 /* Update TCP window tracking data when NAT mangles the packet */
 extern void nf_conntrack_tcp_update(const struct sk_buff *skb,
                                    unsigned int dataoff,
-                                   struct nf_conn *ct,
-                                   int dir);
+                                   struct nf_conn *ct, int dir,
+                                   s16 offset);
 
 /* Fake conntrack entry for untracked connections */
 extern struct nf_conn nf_conntrack_untracked;
index 5054dc5ea2c260439277a6c252f51df68cd72a39..29d126736611c7ad693f9e84439d3bab56f012ad 100644 (file)
@@ -45,6 +45,7 @@ int phonet_address_add(struct net_device *dev, u8 addr);
 int phonet_address_del(struct net_device *dev, u8 addr);
 u8 phonet_address_get(struct net_device *dev, u8 addr);
 int phonet_address_lookup(struct net *net, u8 addr);
+void phonet_address_notify(int event, struct net_device *dev, u8 addr);
 
 #define PN_NO_ADDR     0xff
 
index ffa5b8b1f1df7c1c92d3e679c3ffacde656faae4..1089d5aabd4990f8b028e6fb3c7db8f82195950d 100644 (file)
@@ -53,7 +53,7 @@ struct inet6_protocol
 
        void    (*err_handler)(struct sk_buff *skb,
                               struct inet6_skb_parm *opt,
-                              int type, int code, int offset,
+                              u8 type, u8 code, int offset,
                               __be32 info);
 
        int     (*gso_send_check)(struct sk_buff *skb);
index 8a22599f26ba9ce4fe7b9e649e23321fc359263d..f6b9b830df8c445e3ce88f0ff45d27fc07908c2c 100644 (file)
@@ -6,7 +6,7 @@
 #include <net/protocol.h>
 
 void raw6_icmp_error(struct sk_buff *, int nexthdr,
-               int type, int code, int inner_offset, __be32);
+               u8 type, u8 code, int inner_offset, __be32);
 int raw6_local_deliver(struct sk_buff *, int);
 
 extern int                     rawv6_rcv(struct sock *sk,
index 9f80a766828923a8b41ad0588d91b40fcf12a8be..d16a304cbed4fb74b9de069d5eb41788c7a13d0d 100644 (file)
@@ -448,6 +448,7 @@ static inline void sctp_skb_set_owner_r(struct sk_buff *skb, struct sock *sk)
 {
        struct sctp_ulpevent *event = sctp_skb2event(skb);
 
+       skb_orphan(skb);
        skb->sk = sk;
        skb->destructor = sctp_sock_rfree;
        atomic_add(event->rmem_len, &sk->sk_rmem_alloc);
index 07133c5e986867cd3ab7affbb1a37dd85cb4801c..2c0da9239b95971b1fe4bd1aaa675fba7f4a50a9 100644 (file)
@@ -54,6 +54,7 @@
 
 #include <linux/filter.h>
 #include <linux/rculist_nulls.h>
+#include <linux/poll.h>
 
 #include <asm/atomic.h>
 #include <net/dst.h>
@@ -1241,6 +1242,74 @@ static inline int sk_has_allocations(const struct sock *sk)
        return sk_wmem_alloc_get(sk) || sk_rmem_alloc_get(sk);
 }
 
+/**
+ * sk_has_sleeper - check if there are any waiting processes
+ * @sk: socket
+ *
+ * Returns true if socket has waiting processes
+ *
+ * The purpose of the sk_has_sleeper and sock_poll_wait is to wrap the memory
+ * barrier call. They were added due to the race found within the tcp code.
+ *
+ * Consider following tcp code paths:
+ *
+ * CPU1                  CPU2
+ *
+ * sys_select            receive packet
+ *   ...                 ...
+ *   __add_wait_queue    update tp->rcv_nxt
+ *   ...                 ...
+ *   tp->rcv_nxt check   sock_def_readable
+ *   ...                 {
+ *   schedule               ...
+ *                          if (sk->sk_sleep && waitqueue_active(sk->sk_sleep))
+ *                              wake_up_interruptible(sk->sk_sleep)
+ *                          ...
+ *                       }
+ *
+ * The race for tcp fires when the __add_wait_queue changes done by CPU1 stay
+ * in its cache, and so does the tp->rcv_nxt update on CPU2 side.  The CPU1
+ * could then endup calling schedule and sleep forever if there are no more
+ * data on the socket.
+ *
+ * The sk_has_sleeper is always called right after a call to read_lock, so we
+ * can use smp_mb__after_lock barrier.
+ */
+static inline int sk_has_sleeper(struct sock *sk)
+{
+       /*
+        * We need to be sure we are in sync with the
+        * add_wait_queue modifications to the wait queue.
+        *
+        * This memory barrier is paired in the sock_poll_wait.
+        */
+       smp_mb__after_lock();
+       return sk->sk_sleep && waitqueue_active(sk->sk_sleep);
+}
+
+/**
+ * sock_poll_wait - place memory barrier behind the poll_wait call.
+ * @filp:           file
+ * @wait_address:   socket wait queue
+ * @p:              poll_table
+ *
+ * See the comments in the sk_has_sleeper function.
+ */
+static inline void sock_poll_wait(struct file *filp,
+               wait_queue_head_t *wait_address, poll_table *p)
+{
+       if (p && wait_address) {
+               poll_wait(filp, wait_address, p);
+               /*
+                * We need to be sure we are in sync with the
+                * socket flags modification.
+                *
+                * This memory barrier is paired in the sk_has_sleeper.
+               */
+               smp_mb();
+       }
+}
+
 /*
  *     Queue a received datagram if it will fit. Stream and sequenced
  *     protocols can't normally use this as they need to fit buffers in
@@ -1252,6 +1321,7 @@ static inline int sk_has_allocations(const struct sock *sk)
 
 static inline void skb_set_owner_w(struct sk_buff *skb, struct sock *sk)
 {
+       skb_orphan(skb);
        skb->sk = sk;
        skb->destructor = sock_wfree;
        /*
@@ -1264,6 +1334,7 @@ static inline void skb_set_owner_w(struct sk_buff *skb, struct sock *sk)
 
 static inline void skb_set_owner_r(struct sk_buff *skb, struct sock *sk)
 {
+       skb_orphan(skb);
        skb->sk = sk;
        skb->destructor = sock_rfree;
        atomic_add(skb->truesize, &sk->sk_rmem_alloc);
index 736bca4508862c668675fff1f03e9d462cb08674..9e3a3f4c1f6041bb3447392695f308cfcc5b2cc0 100644 (file)
@@ -1274,7 +1274,7 @@ struct xfrm_tunnel {
 struct xfrm6_tunnel {
        int (*handler)(struct sk_buff *skb);
        int (*err_handler)(struct sk_buff *skb, struct inet6_skb_parm *opt,
-                          int type, int code, int offset, __be32 info);
+                          u8 type, u8 code, int offset, __be32 info);
        struct xfrm6_tunnel *next;
        int priority;
 };
index d6b05f42dd44d85e488eaa65c67a105e1e7ad36c..9a74b468a2291dd19e0ee3b8ad364943b3a8b4bb 100644 (file)
@@ -1,3 +1,6 @@
+#undef TRACE_SYSTEM
+#define TRACE_SYSTEM block
+
 #if !defined(_TRACE_BLOCK_H) || defined(TRACE_HEADER_MULTI_READ)
 #define _TRACE_BLOCK_H
 
@@ -5,9 +8,6 @@
 #include <linux/blkdev.h>
 #include <linux/tracepoint.h>
 
-#undef TRACE_SYSTEM
-#define TRACE_SYSTEM block
-
 TRACE_EVENT(block_rq_abort,
 
        TP_PROTO(struct request_queue *q, struct request *rq),
index acf4cc9cd36d015e877887e13b79802eb9e8590d..7d8b5bc741857401acf0ee81f8eaa9b98b52c1cd 100644 (file)
@@ -1,9 +1,9 @@
-#if !defined(_TRACE_EXT4_H) || defined(TRACE_HEADER_MULTI_READ)
-#define _TRACE_EXT4_H
-
 #undef TRACE_SYSTEM
 #define TRACE_SYSTEM ext4
 
+#if !defined(_TRACE_EXT4_H) || defined(TRACE_HEADER_MULTI_READ)
+#define _TRACE_EXT4_H
+
 #include <linux/writeback.h>
 #include "../../../fs/ext4/ext4.h"
 #include "../../../fs/ext4/mballoc.h"
@@ -34,7 +34,8 @@ TRACE_EVENT(ext4_free_inode,
 
        TP_printk("dev %s ino %lu mode %d uid %u gid %u blocks %llu",
                  jbd2_dev_to_name(__entry->dev), __entry->ino, __entry->mode,
-                 __entry->uid, __entry->gid, __entry->blocks)
+                 __entry->uid, __entry->gid,
+                 (unsigned long long) __entry->blocks)
 );
 
 TRACE_EVENT(ext4_request_inode,
@@ -189,7 +190,7 @@ TRACE_EVENT(ext4_journalled_write_end,
                  __entry->copied)
 );
 
-TRACE_EVENT(ext4_da_writepage,
+TRACE_EVENT(ext4_writepage,
        TP_PROTO(struct inode *inode, struct page *page),
 
        TP_ARGS(inode, page),
@@ -341,49 +342,6 @@ TRACE_EVENT(ext4_da_write_end,
                  __entry->copied)
 );
 
-TRACE_EVENT(ext4_normal_writepage,
-       TP_PROTO(struct inode *inode, struct page *page),
-
-       TP_ARGS(inode, page),
-
-       TP_STRUCT__entry(
-               __field(        dev_t,  dev                     )
-               __field(        ino_t,  ino                     )
-               __field(        pgoff_t, index                  )
-       ),
-
-       TP_fast_assign(
-               __entry->dev    = inode->i_sb->s_dev;
-               __entry->ino    = inode->i_ino;
-               __entry->index  = page->index;
-       ),
-
-       TP_printk("dev %s ino %lu page_index %lu",
-                 jbd2_dev_to_name(__entry->dev), __entry->ino, __entry->index)
-);
-
-TRACE_EVENT(ext4_journalled_writepage,
-       TP_PROTO(struct inode *inode, struct page *page),
-
-       TP_ARGS(inode, page),
-
-       TP_STRUCT__entry(
-               __field(        dev_t,  dev                     )
-               __field(        ino_t,  ino                     )
-               __field(        pgoff_t, index                  )
-
-       ),
-
-       TP_fast_assign(
-               __entry->dev    = inode->i_sb->s_dev;
-               __entry->ino    = inode->i_ino;
-               __entry->index  = page->index;
-       ),
-
-       TP_printk("dev %s ino %lu page_index %lu",
-                 jbd2_dev_to_name(__entry->dev), __entry->ino, __entry->index)
-);
-
 TRACE_EVENT(ext4_discard_blocks,
        TP_PROTO(struct super_block *sb, unsigned long long blk,
                        unsigned long long count),
index b0c7ede55eb156c0d4880dee2555dc4b35577887..1cb0c3aa11e613659a0a87cc9c72ea4d14f69a3f 100644 (file)
@@ -1,12 +1,12 @@
+#undef TRACE_SYSTEM
+#define TRACE_SYSTEM irq
+
 #if !defined(_TRACE_IRQ_H) || defined(TRACE_HEADER_MULTI_READ)
 #define _TRACE_IRQ_H
 
 #include <linux/tracepoint.h>
 #include <linux/interrupt.h>
 
-#undef TRACE_SYSTEM
-#define TRACE_SYSTEM irq
-
 #define softirq_name(sirq) { sirq##_SOFTIRQ, #sirq }
 #define show_softirq_name(val)                 \
        __print_symbolic(val,                   \
index 845b0b4b48fda1077b851f44a99042d79f2e7591..10813fa0c8d07b68035b3bdc287fe0e0304a7788 100644 (file)
@@ -1,12 +1,12 @@
+#undef TRACE_SYSTEM
+#define TRACE_SYSTEM jbd2
+
 #if !defined(_TRACE_JBD2_H) || defined(TRACE_HEADER_MULTI_READ)
 #define _TRACE_JBD2_H
 
 #include <linux/jbd2.h>
 #include <linux/tracepoint.h>
 
-#undef TRACE_SYSTEM
-#define TRACE_SYSTEM jbd2
-
 TRACE_EVENT(jbd2_checkpoint,
 
        TP_PROTO(journal_t *journal, int result),
index 9baba50d6512e594658485779244bbdde751916b..1493c541f9c44566a21553c5947aa1fa93fc702e 100644 (file)
@@ -1,12 +1,12 @@
+#undef TRACE_SYSTEM
+#define TRACE_SYSTEM kmem
+
 #if !defined(_TRACE_KMEM_H) || defined(TRACE_HEADER_MULTI_READ)
 #define _TRACE_KMEM_H
 
 #include <linux/types.h>
 #include <linux/tracepoint.h>
 
-#undef TRACE_SYSTEM
-#define TRACE_SYSTEM kmem
-
 /*
  * The order of these masks is important. Matching masks will be seen
  * first and the left over flags will end up showing by themselves.
index 0e956c9dfd7eed1676d049ab2f1c6375983ba556..bcf1d209a00dabf7838aae49c2e5edcc5fc6dde8 100644 (file)
@@ -1,12 +1,12 @@
+#undef TRACE_SYSTEM
+#define TRACE_SYSTEM lockdep
+
 #if !defined(_TRACE_LOCKDEP_H) || defined(TRACE_HEADER_MULTI_READ)
 #define _TRACE_LOCKDEP_H
 
 #include <linux/lockdep.h>
 #include <linux/tracepoint.h>
 
-#undef TRACE_SYSTEM
-#define TRACE_SYSTEM lockdep
-
 #ifdef CONFIG_LOCKDEP
 
 TRACE_EVENT(lock_acquire,
index 24ab5bcff7b2bfaebfe7ed4d544f286c43c416a3..8949bb7eb08278bbe30d6785a1e6c1902db8a99a 100644 (file)
@@ -1,12 +1,12 @@
+#undef TRACE_SYSTEM
+#define TRACE_SYSTEM sched
+
 #if !defined(_TRACE_SCHED_H) || defined(TRACE_HEADER_MULTI_READ)
 #define _TRACE_SCHED_H
 
 #include <linux/sched.h>
 #include <linux/tracepoint.h>
 
-#undef TRACE_SYSTEM
-#define TRACE_SYSTEM sched
-
 /*
  * Tracepoint for calling kthread_stop, performed to end a kthread:
  */
index 1e8fabb57c06e4db8f46704153642bf873f87f77..e499863b96693b108fef4c2bc5b07fd52624ba63 100644 (file)
@@ -1,12 +1,12 @@
+#undef TRACE_SYSTEM
+#define TRACE_SYSTEM skb
+
 #if !defined(_TRACE_SKB_H) || defined(TRACE_HEADER_MULTI_READ)
 #define _TRACE_SKB_H
 
 #include <linux/skbuff.h>
 #include <linux/tracepoint.h>
 
-#undef TRACE_SYSTEM
-#define TRACE_SYSTEM skb
-
 /*
  * Tracepoint for free an sk_buff:
  */
index 035f1bff288e66586c2d4697e1bc8d5e0ee9329e..fcfd9a1e4b9640a7c4d3e26c44f2aac38e3b6810 100644 (file)
@@ -1,3 +1,6 @@
+#undef TRACE_SYSTEM
+#define TRACE_SYSTEM workqueue
+
 #if !defined(_TRACE_WORKQUEUE_H) || defined(TRACE_HEADER_MULTI_READ)
 #define _TRACE_WORKQUEUE_H
 
@@ -5,9 +8,6 @@
 #include <linux/sched.h>
 #include <linux/tracepoint.h>
 
-#undef TRACE_SYSTEM
-#define TRACE_SYSTEM workqueue
-
 TRACE_EVENT(workqueue_insertion,
 
        TP_PROTO(struct task_struct *wq_thread, struct work_struct *work),
index 4870dfeb9ee57798abd057eb74a5ac11497ff097..2c5ade79eb81718702dd1fdf44e8b129e69f88a9 100644 (file)
@@ -24,6 +24,7 @@
 #include <linux/smp_lock.h>
 #include <linux/initrd.h>
 #include <linux/bootmem.h>
+#include <linux/acpi.h>
 #include <linux/tty.h>
 #include <linux/gfp.h>
 #include <linux/percpu.h>
@@ -88,11 +89,6 @@ extern void sbus_init(void);
 extern void prio_tree_init(void);
 extern void radix_tree_init(void);
 extern void free_initmem(void);
-#ifdef CONFIG_ACPI
-extern void acpi_early_init(void);
-#else
-static inline void acpi_early_init(void) { }
-#endif
 #ifndef CONFIG_DEBUG_RODATA
 static inline void mark_rodata_ro(void) { }
 #endif
index e35ba2c3a8d770abd7fa97403616dbd8289d26e3..c5e68adc673248b03758bb59d81a5b88f71ef561 100644 (file)
@@ -32,6 +32,7 @@
 #include <linux/nsproxy.h>
 #include <linux/pid.h>
 #include <linux/ipc_namespace.h>
+#include <linux/ima.h>
 
 #include <net/sock.h>
 #include "util.h"
@@ -733,6 +734,7 @@ SYSCALL_DEFINE4(mq_open, const char __user *, u_name, int, oflag, mode_t, mode,
                error = PTR_ERR(filp);
                goto out_putfd;
        }
+       ima_counts_get(filp);
 
        fd_install(fd, filp);
        goto out_upsem;
index 0630e293cd493b0f1a7aba2f0d513d3ff1572145..2093a691f1c25159ec9f13d58257b21b824cce04 100644 (file)
@@ -69,7 +69,7 @@ obj-$(CONFIG_IKCONFIG) += configs.o
 obj-$(CONFIG_RESOURCE_COUNTERS) += res_counter.o
 obj-$(CONFIG_STOP_MACHINE) += stop_machine.o
 obj-$(CONFIG_KPROBES_SANITY_TEST) += test_kprobes.o
-obj-$(CONFIG_AUDIT) += audit.o auditfilter.o
+obj-$(CONFIG_AUDIT) += audit.o auditfilter.o audit_watch.o
 obj-$(CONFIG_AUDITSYSCALL) += auditsc.o
 obj-$(CONFIG_GCOV_KERNEL) += gcov/
 obj-$(CONFIG_AUDIT_TREE) += audit_tree.o
index 7afa31564162d4acc03bd4ed34144ba459e11bdf..9f3391090b3e826d1d7cb935e58f7d01aa054b37 100644 (file)
@@ -215,6 +215,7 @@ static void acct_file_reopen(struct bsd_acct_struct *acct, struct file *file,
 static int acct_on(char *name)
 {
        struct file *file;
+       struct vfsmount *mnt;
        int error;
        struct pid_namespace *ns;
        struct bsd_acct_struct *acct = NULL;
@@ -256,11 +257,12 @@ static int acct_on(char *name)
                acct = NULL;
        }
 
-       mnt_pin(file->f_path.mnt);
+       mnt = file->f_path.mnt;
+       mnt_pin(mnt);
        acct_file_reopen(ns->bacct, file, ns);
        spin_unlock(&acct_lock);
 
-       mntput(file->f_path.mnt); /* it's pinned, now give up active reference */
+       mntput(mnt); /* it's pinned, now give up active reference */
        kfree(acct);
 
        return 0;
index 9442c3533ba9f8be398333d8ee7b74882b339ae0..defc2e6f1e3bc9742606d7efc0a0af4e79095b14 100644 (file)
@@ -115,9 +115,6 @@ static atomic_t    audit_lost = ATOMIC_INIT(0);
 /* The netlink socket. */
 static struct sock *audit_sock;
 
-/* Inotify handle. */
-struct inotify_handle *audit_ih;
-
 /* Hash for inode-based rules */
 struct list_head audit_inode_hash[AUDIT_INODE_BUCKETS];
 
@@ -136,7 +133,7 @@ static DECLARE_WAIT_QUEUE_HEAD(kauditd_wait);
 static DECLARE_WAIT_QUEUE_HEAD(audit_backlog_wait);
 
 /* Serialize requests from userspace. */
-static DEFINE_MUTEX(audit_cmd_mutex);
+DEFINE_MUTEX(audit_cmd_mutex);
 
 /* AUDIT_BUFSIZ is the size of the temporary buffer used for formatting
  * audit records.  Since printk uses a 1024 byte buffer, this buffer
@@ -375,6 +372,25 @@ static void audit_hold_skb(struct sk_buff *skb)
                kfree_skb(skb);
 }
 
+/*
+ * For one reason or another this nlh isn't getting delivered to the userspace
+ * audit daemon, just send it to printk.
+ */
+static void audit_printk_skb(struct sk_buff *skb)
+{
+       struct nlmsghdr *nlh = nlmsg_hdr(skb);
+       char *data = NLMSG_DATA(nlh);
+
+       if (nlh->nlmsg_type != AUDIT_EOE) {
+               if (printk_ratelimit())
+                       printk(KERN_NOTICE "type=%d %s\n", nlh->nlmsg_type, data);
+               else
+                       audit_log_lost("printk limit exceeded\n");
+       }
+
+       audit_hold_skb(skb);
+}
+
 static void kauditd_send_skb(struct sk_buff *skb)
 {
        int err;
@@ -427,14 +443,8 @@ static int kauditd_thread(void *dummy)
                if (skb) {
                        if (audit_pid)
                                kauditd_send_skb(skb);
-                       else {
-                               if (printk_ratelimit())
-                                       printk(KERN_NOTICE "%s\n", skb->data + NLMSG_SPACE(0));
-                               else
-                                       audit_log_lost("printk limit exceeded\n");
-
-                               audit_hold_skb(skb);
-                       }
+                       else
+                               audit_printk_skb(skb);
                } else {
                        DECLARE_WAITQUEUE(wait, current);
                        set_current_state(TASK_INTERRUPTIBLE);
@@ -495,42 +505,25 @@ int audit_send_list(void *_dest)
        return 0;
 }
 
-#ifdef CONFIG_AUDIT_TREE
-static int prune_tree_thread(void *unused)
-{
-       mutex_lock(&audit_cmd_mutex);
-       audit_prune_trees();
-       mutex_unlock(&audit_cmd_mutex);
-       return 0;
-}
-
-void audit_schedule_prune(void)
-{
-       kthread_run(prune_tree_thread, NULL, "audit_prune_tree");
-}
-#endif
-
 struct sk_buff *audit_make_reply(int pid, int seq, int type, int done,
                                 int multi, void *payload, int size)
 {
        struct sk_buff  *skb;
        struct nlmsghdr *nlh;
-       int             len = NLMSG_SPACE(size);
        void            *data;
        int             flags = multi ? NLM_F_MULTI : 0;
        int             t     = done  ? NLMSG_DONE  : type;
 
-       skb = alloc_skb(len, GFP_KERNEL);
+       skb = nlmsg_new(size, GFP_KERNEL);
        if (!skb)
                return NULL;
 
-       nlh              = NLMSG_PUT(skb, pid, seq, t, size);
-       nlh->nlmsg_flags = flags;
-       data             = NLMSG_DATA(nlh);
+       nlh     = NLMSG_NEW(skb, pid, seq, t, size, flags);
+       data    = NLMSG_DATA(nlh);
        memcpy(data, payload, size);
        return skb;
 
-nlmsg_failure:                 /* Used by NLMSG_PUT */
+nlmsg_failure:                 /* Used by NLMSG_NEW */
        if (skb)
                kfree_skb(skb);
        return NULL;
@@ -926,28 +919,29 @@ static int audit_receive_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
 }
 
 /*
- * Get message from skb (based on rtnetlink_rcv_skb).  Each message is
- * processed by audit_receive_msg.  Malformed skbs with wrong length are
- * discarded silently.
+ * Get message from skb.  Each message is processed by audit_receive_msg.
+ * Malformed skbs with wrong length are discarded silently.
  */
 static void audit_receive_skb(struct sk_buff *skb)
 {
-       int             err;
-       struct nlmsghdr *nlh;
-       u32             rlen;
+       struct nlmsghdr *nlh;
+       /*
+        * len MUST be signed for NLMSG_NEXT to be able to dec it below 0
+        * if the nlmsg_len was not aligned
+        */
+       int len;
+       int err;
 
-       while (skb->len >= NLMSG_SPACE(0)) {
-               nlh = nlmsg_hdr(skb);
-               if (nlh->nlmsg_len < sizeof(*nlh) || skb->len < nlh->nlmsg_len)
-                       return;
-               rlen = NLMSG_ALIGN(nlh->nlmsg_len);
-               if (rlen > skb->len)
-                       rlen = skb->len;
-               if ((err = audit_receive_msg(skb, nlh))) {
+       nlh = nlmsg_hdr(skb);
+       len = skb->len;
+
+       while (NLMSG_OK(nlh, len)) {
+               err = audit_receive_msg(skb, nlh);
+               /* if err or if this message says it wants a response */
+               if (err || (nlh->nlmsg_flags & NLM_F_ACK))
                        netlink_ack(skb, nlh, err);
-               } else if (nlh->nlmsg_flags & NLM_F_ACK)
-                       netlink_ack(skb, nlh, 0);
-               skb_pull(skb, rlen);
+
+               nlh = NLMSG_NEXT(nlh, len);
        }
 }
 
@@ -959,13 +953,6 @@ static void audit_receive(struct sk_buff  *skb)
        mutex_unlock(&audit_cmd_mutex);
 }
 
-#ifdef CONFIG_AUDITSYSCALL
-static const struct inotify_operations audit_inotify_ops = {
-       .handle_event   = audit_handle_ievent,
-       .destroy_watch  = audit_free_parent,
-};
-#endif
-
 /* Initialize audit support at boot time. */
 static int __init audit_init(void)
 {
@@ -991,12 +978,6 @@ static int __init audit_init(void)
 
        audit_log(NULL, GFP_KERNEL, AUDIT_KERNEL, "initialized");
 
-#ifdef CONFIG_AUDITSYSCALL
-       audit_ih = inotify_init(&audit_inotify_ops);
-       if (IS_ERR(audit_ih))
-               audit_panic("cannot initialize inotify handle");
-#endif
-
        for (i = 0; i < AUDIT_INODE_BUCKETS; i++)
                INIT_LIST_HEAD(&audit_inode_hash[i]);
 
@@ -1070,18 +1051,20 @@ static struct audit_buffer * audit_buffer_alloc(struct audit_context *ctx,
                        goto err;
        }
 
-       ab->skb = alloc_skb(AUDIT_BUFSIZ, gfp_mask);
-       if (!ab->skb)
-               goto err;
-
        ab->ctx = ctx;
        ab->gfp_mask = gfp_mask;
-       nlh = (struct nlmsghdr *)skb_put(ab->skb, NLMSG_SPACE(0));
-       nlh->nlmsg_type = type;
-       nlh->nlmsg_flags = 0;
-       nlh->nlmsg_pid = 0;
-       nlh->nlmsg_seq = 0;
+
+       ab->skb = nlmsg_new(AUDIT_BUFSIZ, gfp_mask);
+       if (!ab->skb)
+               goto nlmsg_failure;
+
+       nlh = NLMSG_NEW(ab->skb, 0, 0, type, 0, 0);
+
        return ab;
+
+nlmsg_failure:                  /* Used by NLMSG_NEW */
+       kfree_skb(ab->skb);
+       ab->skb = NULL;
 err:
        audit_buffer_free(ab);
        return NULL;
@@ -1452,6 +1435,15 @@ void audit_log_d_path(struct audit_buffer *ab, const char *prefix,
        kfree(pathname);
 }
 
+void audit_log_key(struct audit_buffer *ab, char *key)
+{
+       audit_log_format(ab, " key=");
+       if (key)
+               audit_log_untrustedstring(ab, key);
+       else
+               audit_log_format(ab, "(null)");
+}
+
 /**
  * audit_log_end - end one audit record
  * @ab: the audit_buffer
@@ -1475,15 +1467,7 @@ void audit_log_end(struct audit_buffer *ab)
                        skb_queue_tail(&audit_skb_queue, ab->skb);
                        wake_up_interruptible(&kauditd_wait);
                } else {
-                       if (nlh->nlmsg_type != AUDIT_EOE) {
-                               if (printk_ratelimit()) {
-                                       printk(KERN_NOTICE "type=%d %s\n",
-                                               nlh->nlmsg_type,
-                                               ab->skb->data + NLMSG_SPACE(0));
-                               } else
-                                       audit_log_lost("printk limit exceeded\n");
-                       }
-                       audit_hold_skb(ab->skb);
+                       audit_printk_skb(ab->skb);
                }
                ab->skb = NULL;
        }
index 16f18cac661b68261c20c551caa3a94333df3da0..208687be4f30c8a2ddb432e3c1b8594fb85d2e8e 100644 (file)
@@ -53,18 +53,7 @@ enum audit_state {
 };
 
 /* Rule lists */
-struct audit_parent;
-
-struct audit_watch {
-       atomic_t                count;  /* reference count */
-       char                    *path;  /* insertion path */
-       dev_t                   dev;    /* associated superblock device */
-       unsigned long           ino;    /* associated inode number */
-       struct audit_parent     *parent; /* associated parent */
-       struct list_head        wlist;  /* entry in parent->watches list */
-       struct list_head        rules;  /* associated rules */
-};
-
+struct audit_watch;
 struct audit_tree;
 struct audit_chunk;
 
@@ -108,19 +97,28 @@ struct audit_netlink_list {
 
 int audit_send_list(void *);
 
-struct inotify_watch;
-/* Inotify handle */
-extern struct inotify_handle *audit_ih;
-
-extern void audit_free_parent(struct inotify_watch *);
-extern void audit_handle_ievent(struct inotify_watch *, u32, u32, u32,
-                               const char *, struct inode *);
 extern int selinux_audit_rule_update(void);
 
 extern struct mutex audit_filter_mutex;
 extern void audit_free_rule_rcu(struct rcu_head *);
 extern struct list_head audit_filter_list[];
 
+/* audit watch functions */
+extern unsigned long audit_watch_inode(struct audit_watch *watch);
+extern dev_t audit_watch_dev(struct audit_watch *watch);
+extern void audit_put_watch(struct audit_watch *watch);
+extern void audit_get_watch(struct audit_watch *watch);
+extern int audit_to_watch(struct audit_krule *krule, char *path, int len, u32 op);
+extern int audit_add_watch(struct audit_krule *krule);
+extern void audit_remove_watch(struct audit_watch *watch);
+extern void audit_remove_watch_rule(struct audit_krule *krule, struct list_head *list);
+extern void audit_inotify_unregister(struct list_head *in_list);
+extern char *audit_watch_path(struct audit_watch *watch);
+extern struct list_head *audit_watch_rules(struct audit_watch *watch);
+
+extern struct audit_entry *audit_dupe_rule(struct audit_krule *old,
+                                          struct audit_watch *watch);
+
 #ifdef CONFIG_AUDIT_TREE
 extern struct audit_chunk *audit_tree_lookup(const struct inode *);
 extern void audit_put_chunk(struct audit_chunk *);
@@ -130,10 +128,9 @@ extern int audit_add_tree_rule(struct audit_krule *);
 extern int audit_remove_tree_rule(struct audit_krule *);
 extern void audit_trim_trees(void);
 extern int audit_tag_tree(char *old, char *new);
-extern void audit_schedule_prune(void);
-extern void audit_prune_trees(void);
 extern const char *audit_tree_path(struct audit_tree *);
 extern void audit_put_tree(struct audit_tree *);
+extern void audit_kill_trees(struct list_head *);
 #else
 #define audit_remove_tree_rule(rule) BUG()
 #define audit_add_tree_rule(rule) -EINVAL
@@ -142,6 +139,7 @@ extern void audit_put_tree(struct audit_tree *);
 #define audit_put_tree(tree) (void)0
 #define audit_tag_tree(old, new) -EINVAL
 #define audit_tree_path(rule) ""       /* never called */
+#define audit_kill_trees(list) BUG()
 #endif
 
 extern char *audit_unpack_string(void **, size_t *, size_t);
@@ -160,7 +158,10 @@ static inline int audit_signal_info(int sig, struct task_struct *t)
        return 0;
 }
 extern void audit_filter_inodes(struct task_struct *, struct audit_context *);
+extern struct list_head *audit_killed_trees(void);
 #else
 #define audit_signal_info(s,t) AUDIT_DISABLED
 #define audit_filter_inodes(t,c) AUDIT_DISABLED
 #endif
+
+extern struct mutex audit_cmd_mutex;
index 1f6396d766874b1f28577a44812b0d097106cf88..2451dc6f328211d173747865cde60fd49b6c9bbd 100644 (file)
@@ -2,6 +2,7 @@
 #include <linux/inotify.h>
 #include <linux/namei.h>
 #include <linux/mount.h>
+#include <linux/kthread.h>
 
 struct audit_tree;
 struct audit_chunk;
@@ -441,13 +442,11 @@ static void kill_rules(struct audit_tree *tree)
                if (rule->tree) {
                        /* not a half-baked one */
                        ab = audit_log_start(NULL, GFP_KERNEL, AUDIT_CONFIG_CHANGE);
-                       audit_log_format(ab, "op=remove rule dir=");
+                       audit_log_format(ab, "op=");
+                       audit_log_string(ab, "remove rule");
+                       audit_log_format(ab, " dir=");
                        audit_log_untrustedstring(ab, rule->tree->pathname);
-                       if (rule->filterkey) {
-                               audit_log_format(ab, " key=");
-                               audit_log_untrustedstring(ab, rule->filterkey);
-                       } else
-                               audit_log_format(ab, " key=(null)");
+                       audit_log_key(ab, rule->filterkey);
                        audit_log_format(ab, " list=%d res=1", rule->listnr);
                        audit_log_end(ab);
                        rule->tree = NULL;
@@ -519,6 +518,8 @@ static void trim_marked(struct audit_tree *tree)
        }
 }
 
+static void audit_schedule_prune(void);
+
 /* called with audit_filter_mutex */
 int audit_remove_tree_rule(struct audit_krule *rule)
 {
@@ -824,10 +825,11 @@ int audit_tag_tree(char *old, char *new)
 
 /*
  * That gets run when evict_chunk() ends up needing to kill audit_tree.
- * Runs from a separate thread, with audit_cmd_mutex held.
+ * Runs from a separate thread.
  */
-void audit_prune_trees(void)
+static int prune_tree_thread(void *unused)
 {
+       mutex_lock(&audit_cmd_mutex);
        mutex_lock(&audit_filter_mutex);
 
        while (!list_empty(&prune_list)) {
@@ -844,6 +846,40 @@ void audit_prune_trees(void)
        }
 
        mutex_unlock(&audit_filter_mutex);
+       mutex_unlock(&audit_cmd_mutex);
+       return 0;
+}
+
+static void audit_schedule_prune(void)
+{
+       kthread_run(prune_tree_thread, NULL, "audit_prune_tree");
+}
+
+/*
+ * ... and that one is done if evict_chunk() decides to delay until the end
+ * of syscall.  Runs synchronously.
+ */
+void audit_kill_trees(struct list_head *list)
+{
+       mutex_lock(&audit_cmd_mutex);
+       mutex_lock(&audit_filter_mutex);
+
+       while (!list_empty(list)) {
+               struct audit_tree *victim;
+
+               victim = list_entry(list->next, struct audit_tree, list);
+               kill_rules(victim);
+               list_del_init(&victim->list);
+
+               mutex_unlock(&audit_filter_mutex);
+
+               prune_one(victim);
+
+               mutex_lock(&audit_filter_mutex);
+       }
+
+       mutex_unlock(&audit_filter_mutex);
+       mutex_unlock(&audit_cmd_mutex);
 }
 
 /*
@@ -854,6 +890,8 @@ void audit_prune_trees(void)
 static void evict_chunk(struct audit_chunk *chunk)
 {
        struct audit_tree *owner;
+       struct list_head *postponed = audit_killed_trees();
+       int need_prune = 0;
        int n;
 
        if (chunk->dead)
@@ -869,15 +907,21 @@ static void evict_chunk(struct audit_chunk *chunk)
                owner->root = NULL;
                list_del_init(&owner->same_root);
                spin_unlock(&hash_lock);
-               kill_rules(owner);
-               list_move(&owner->list, &prune_list);
-               audit_schedule_prune();
+               if (!postponed) {
+                       kill_rules(owner);
+                       list_move(&owner->list, &prune_list);
+                       need_prune = 1;
+               } else {
+                       list_move(&owner->list, postponed);
+               }
                spin_lock(&hash_lock);
        }
        list_del_rcu(&chunk->hash);
        for (n = 0; n < chunk->count; n++)
                list_del_init(&chunk->owners[n].list);
        spin_unlock(&hash_lock);
+       if (need_prune)
+               audit_schedule_prune();
        mutex_unlock(&audit_filter_mutex);
 }
 
diff --git a/kernel/audit_watch.c b/kernel/audit_watch.c
new file mode 100644 (file)
index 0000000..0e96dbc
--- /dev/null
@@ -0,0 +1,543 @@
+/* audit_watch.c -- watching inodes
+ *
+ * Copyright 2003-2009 Red Hat, Inc.
+ * Copyright 2005 Hewlett-Packard Development Company, L.P.
+ * Copyright 2005 IBM Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include <linux/kernel.h>
+#include <linux/audit.h>
+#include <linux/kthread.h>
+#include <linux/mutex.h>
+#include <linux/fs.h>
+#include <linux/namei.h>
+#include <linux/netlink.h>
+#include <linux/sched.h>
+#include <linux/inotify.h>
+#include <linux/security.h>
+#include "audit.h"
+
+/*
+ * Reference counting:
+ *
+ * audit_parent: lifetime is from audit_init_parent() to receipt of an IN_IGNORED
+ *     event.  Each audit_watch holds a reference to its associated parent.
+ *
+ * audit_watch: if added to lists, lifetime is from audit_init_watch() to
+ *     audit_remove_watch().  Additionally, an audit_watch may exist
+ *     temporarily to assist in searching existing filter data.  Each
+ *     audit_krule holds a reference to its associated watch.
+ */
+
+struct audit_watch {
+       atomic_t                count;  /* reference count */
+       char                    *path;  /* insertion path */
+       dev_t                   dev;    /* associated superblock device */
+       unsigned long           ino;    /* associated inode number */
+       struct audit_parent     *parent; /* associated parent */
+       struct list_head        wlist;  /* entry in parent->watches list */
+       struct list_head        rules;  /* associated rules */
+};
+
+struct audit_parent {
+       struct list_head        ilist;  /* entry in inotify registration list */
+       struct list_head        watches; /* associated watches */
+       struct inotify_watch    wdata;  /* inotify watch data */
+       unsigned                flags;  /* status flags */
+};
+
+/* Inotify handle. */
+struct inotify_handle *audit_ih;
+
+/*
+ * audit_parent status flags:
+ *
+ * AUDIT_PARENT_INVALID - set anytime rules/watches are auto-removed due to
+ * a filesystem event to ensure we're adding audit watches to a valid parent.
+ * Technically not needed for IN_DELETE_SELF or IN_UNMOUNT events, as we cannot
+ * receive them while we have nameidata, but must be used for IN_MOVE_SELF which
+ * we can receive while holding nameidata.
+ */
+#define AUDIT_PARENT_INVALID   0x001
+
+/* Inotify events we care about. */
+#define AUDIT_IN_WATCH IN_MOVE|IN_CREATE|IN_DELETE|IN_DELETE_SELF|IN_MOVE_SELF
+
+static void audit_free_parent(struct inotify_watch *i_watch)
+{
+       struct audit_parent *parent;
+
+       parent = container_of(i_watch, struct audit_parent, wdata);
+       WARN_ON(!list_empty(&parent->watches));
+       kfree(parent);
+}
+
+void audit_get_watch(struct audit_watch *watch)
+{
+       atomic_inc(&watch->count);
+}
+
+void audit_put_watch(struct audit_watch *watch)
+{
+       if (atomic_dec_and_test(&watch->count)) {
+               WARN_ON(watch->parent);
+               WARN_ON(!list_empty(&watch->rules));
+               kfree(watch->path);
+               kfree(watch);
+       }
+}
+
+void audit_remove_watch(struct audit_watch *watch)
+{
+       list_del(&watch->wlist);
+       put_inotify_watch(&watch->parent->wdata);
+       watch->parent = NULL;
+       audit_put_watch(watch); /* match initial get */
+}
+
+char *audit_watch_path(struct audit_watch *watch)
+{
+       return watch->path;
+}
+
+struct list_head *audit_watch_rules(struct audit_watch *watch)
+{
+       return &watch->rules;
+}
+
+unsigned long audit_watch_inode(struct audit_watch *watch)
+{
+       return watch->ino;
+}
+
+dev_t audit_watch_dev(struct audit_watch *watch)
+{
+       return watch->dev;
+}
+
+/* Initialize a parent watch entry. */
+static struct audit_parent *audit_init_parent(struct nameidata *ndp)
+{
+       struct audit_parent *parent;
+       s32 wd;
+
+       parent = kzalloc(sizeof(*parent), GFP_KERNEL);
+       if (unlikely(!parent))
+               return ERR_PTR(-ENOMEM);
+
+       INIT_LIST_HEAD(&parent->watches);
+       parent->flags = 0;
+
+       inotify_init_watch(&parent->wdata);
+       /* grab a ref so inotify watch hangs around until we take audit_filter_mutex */
+       get_inotify_watch(&parent->wdata);
+       wd = inotify_add_watch(audit_ih, &parent->wdata,
+                              ndp->path.dentry->d_inode, AUDIT_IN_WATCH);
+       if (wd < 0) {
+               audit_free_parent(&parent->wdata);
+               return ERR_PTR(wd);
+       }
+
+       return parent;
+}
+
+/* Initialize a watch entry. */
+static struct audit_watch *audit_init_watch(char *path)
+{
+       struct audit_watch *watch;
+
+       watch = kzalloc(sizeof(*watch), GFP_KERNEL);
+       if (unlikely(!watch))
+               return ERR_PTR(-ENOMEM);
+
+       INIT_LIST_HEAD(&watch->rules);
+       atomic_set(&watch->count, 1);
+       watch->path = path;
+       watch->dev = (dev_t)-1;
+       watch->ino = (unsigned long)-1;
+
+       return watch;
+}
+
+/* Translate a watch string to kernel respresentation. */
+int audit_to_watch(struct audit_krule *krule, char *path, int len, u32 op)
+{
+       struct audit_watch *watch;
+
+       if (!audit_ih)
+               return -EOPNOTSUPP;
+
+       if (path[0] != '/' || path[len-1] == '/' ||
+           krule->listnr != AUDIT_FILTER_EXIT ||
+           op != Audit_equal ||
+           krule->inode_f || krule->watch || krule->tree)
+               return -EINVAL;
+
+       watch = audit_init_watch(path);
+       if (IS_ERR(watch))
+               return PTR_ERR(watch);
+
+       audit_get_watch(watch);
+       krule->watch = watch;
+
+       return 0;
+}
+
+/* Duplicate the given audit watch.  The new watch's rules list is initialized
+ * to an empty list and wlist is undefined. */
+static struct audit_watch *audit_dupe_watch(struct audit_watch *old)
+{
+       char *path;
+       struct audit_watch *new;
+
+       path = kstrdup(old->path, GFP_KERNEL);
+       if (unlikely(!path))
+               return ERR_PTR(-ENOMEM);
+
+       new = audit_init_watch(path);
+       if (IS_ERR(new)) {
+               kfree(path);
+               goto out;
+       }
+
+       new->dev = old->dev;
+       new->ino = old->ino;
+       get_inotify_watch(&old->parent->wdata);
+       new->parent = old->parent;
+
+out:
+       return new;
+}
+
+static void audit_watch_log_rule_change(struct audit_krule *r, struct audit_watch *w, char *op)
+{
+       if (audit_enabled) {
+               struct audit_buffer *ab;
+               ab = audit_log_start(NULL, GFP_NOFS, AUDIT_CONFIG_CHANGE);
+               audit_log_format(ab, "auid=%u ses=%u op=",
+                                audit_get_loginuid(current),
+                                audit_get_sessionid(current));
+               audit_log_string(ab, op);
+               audit_log_format(ab, " path=");
+               audit_log_untrustedstring(ab, w->path);
+               audit_log_key(ab, r->filterkey);
+               audit_log_format(ab, " list=%d res=1", r->listnr);
+               audit_log_end(ab);
+       }
+}
+
+/* Update inode info in audit rules based on filesystem event. */
+static void audit_update_watch(struct audit_parent *parent,
+                              const char *dname, dev_t dev,
+                              unsigned long ino, unsigned invalidating)
+{
+       struct audit_watch *owatch, *nwatch, *nextw;
+       struct audit_krule *r, *nextr;
+       struct audit_entry *oentry, *nentry;
+
+       mutex_lock(&audit_filter_mutex);
+       list_for_each_entry_safe(owatch, nextw, &parent->watches, wlist) {
+               if (audit_compare_dname_path(dname, owatch->path, NULL))
+                       continue;
+
+               /* If the update involves invalidating rules, do the inode-based
+                * filtering now, so we don't omit records. */
+               if (invalidating && current->audit_context)
+                       audit_filter_inodes(current, current->audit_context);
+
+               nwatch = audit_dupe_watch(owatch);
+               if (IS_ERR(nwatch)) {
+                       mutex_unlock(&audit_filter_mutex);
+                       audit_panic("error updating watch, skipping");
+                       return;
+               }
+               nwatch->dev = dev;
+               nwatch->ino = ino;
+
+               list_for_each_entry_safe(r, nextr, &owatch->rules, rlist) {
+
+                       oentry = container_of(r, struct audit_entry, rule);
+                       list_del(&oentry->rule.rlist);
+                       list_del_rcu(&oentry->list);
+
+                       nentry = audit_dupe_rule(&oentry->rule, nwatch);
+                       if (IS_ERR(nentry)) {
+                               list_del(&oentry->rule.list);
+                               audit_panic("error updating watch, removing");
+                       } else {
+                               int h = audit_hash_ino((u32)ino);
+                               list_add(&nentry->rule.rlist, &nwatch->rules);
+                               list_add_rcu(&nentry->list, &audit_inode_hash[h]);
+                               list_replace(&oentry->rule.list,
+                                            &nentry->rule.list);
+                       }
+
+                       audit_watch_log_rule_change(r, owatch, "updated rules");
+
+                       call_rcu(&oentry->rcu, audit_free_rule_rcu);
+               }
+
+               audit_remove_watch(owatch);
+               goto add_watch_to_parent; /* event applies to a single watch */
+       }
+       mutex_unlock(&audit_filter_mutex);
+       return;
+
+add_watch_to_parent:
+       list_add(&nwatch->wlist, &parent->watches);
+       mutex_unlock(&audit_filter_mutex);
+       return;
+}
+
+/* Remove all watches & rules associated with a parent that is going away. */
+static void audit_remove_parent_watches(struct audit_parent *parent)
+{
+       struct audit_watch *w, *nextw;
+       struct audit_krule *r, *nextr;
+       struct audit_entry *e;
+
+       mutex_lock(&audit_filter_mutex);
+       parent->flags |= AUDIT_PARENT_INVALID;
+       list_for_each_entry_safe(w, nextw, &parent->watches, wlist) {
+               list_for_each_entry_safe(r, nextr, &w->rules, rlist) {
+                       e = container_of(r, struct audit_entry, rule);
+                       audit_watch_log_rule_change(r, w, "remove rule");
+                       list_del(&r->rlist);
+                       list_del(&r->list);
+                       list_del_rcu(&e->list);
+                       call_rcu(&e->rcu, audit_free_rule_rcu);
+               }
+               audit_remove_watch(w);
+       }
+       mutex_unlock(&audit_filter_mutex);
+}
+
+/* Unregister inotify watches for parents on in_list.
+ * Generates an IN_IGNORED event. */
+void audit_inotify_unregister(struct list_head *in_list)
+{
+       struct audit_parent *p, *n;
+
+       list_for_each_entry_safe(p, n, in_list, ilist) {
+               list_del(&p->ilist);
+               inotify_rm_watch(audit_ih, &p->wdata);
+               /* the unpin matching the pin in audit_do_del_rule() */
+               unpin_inotify_watch(&p->wdata);
+       }
+}
+
+/* Get path information necessary for adding watches. */
+static int audit_get_nd(char *path, struct nameidata **ndp, struct nameidata **ndw)
+{
+       struct nameidata *ndparent, *ndwatch;
+       int err;
+
+       ndparent = kmalloc(sizeof(*ndparent), GFP_KERNEL);
+       if (unlikely(!ndparent))
+               return -ENOMEM;
+
+       ndwatch = kmalloc(sizeof(*ndwatch), GFP_KERNEL);
+       if (unlikely(!ndwatch)) {
+               kfree(ndparent);
+               return -ENOMEM;
+       }
+
+       err = path_lookup(path, LOOKUP_PARENT, ndparent);
+       if (err) {
+               kfree(ndparent);
+               kfree(ndwatch);
+               return err;
+       }
+
+       err = path_lookup(path, 0, ndwatch);
+       if (err) {
+               kfree(ndwatch);
+               ndwatch = NULL;
+       }
+
+       *ndp = ndparent;
+       *ndw = ndwatch;
+
+       return 0;
+}
+
+/* Release resources used for watch path information. */
+static void audit_put_nd(struct nameidata *ndp, struct nameidata *ndw)
+{
+       if (ndp) {
+               path_put(&ndp->path);
+               kfree(ndp);
+       }
+       if (ndw) {
+               path_put(&ndw->path);
+               kfree(ndw);
+       }
+}
+
+/* Associate the given rule with an existing parent inotify_watch.
+ * Caller must hold audit_filter_mutex. */
+static void audit_add_to_parent(struct audit_krule *krule,
+                               struct audit_parent *parent)
+{
+       struct audit_watch *w, *watch = krule->watch;
+       int watch_found = 0;
+
+       list_for_each_entry(w, &parent->watches, wlist) {
+               if (strcmp(watch->path, w->path))
+                       continue;
+
+               watch_found = 1;
+
+               /* put krule's and initial refs to temporary watch */
+               audit_put_watch(watch);
+               audit_put_watch(watch);
+
+               audit_get_watch(w);
+               krule->watch = watch = w;
+               break;
+       }
+
+       if (!watch_found) {
+               get_inotify_watch(&parent->wdata);
+               watch->parent = parent;
+
+               list_add(&watch->wlist, &parent->watches);
+       }
+       list_add(&krule->rlist, &watch->rules);
+}
+
+/* Find a matching watch entry, or add this one.
+ * Caller must hold audit_filter_mutex. */
+int audit_add_watch(struct audit_krule *krule)
+{
+       struct audit_watch *watch = krule->watch;
+       struct inotify_watch *i_watch;
+       struct audit_parent *parent;
+       struct nameidata *ndp = NULL, *ndw = NULL;
+       int ret = 0;
+
+       mutex_unlock(&audit_filter_mutex);
+
+       /* Avoid calling path_lookup under audit_filter_mutex. */
+       ret = audit_get_nd(watch->path, &ndp, &ndw);
+       if (ret) {
+               /* caller expects mutex locked */
+               mutex_lock(&audit_filter_mutex);
+               goto error;
+       }
+
+       /* update watch filter fields */
+       if (ndw) {
+               watch->dev = ndw->path.dentry->d_inode->i_sb->s_dev;
+               watch->ino = ndw->path.dentry->d_inode->i_ino;
+       }
+
+       /* The audit_filter_mutex must not be held during inotify calls because
+        * we hold it during inotify event callback processing.  If an existing
+        * inotify watch is found, inotify_find_watch() grabs a reference before
+        * returning.
+        */
+       if (inotify_find_watch(audit_ih, ndp->path.dentry->d_inode,
+                              &i_watch) < 0) {
+               parent = audit_init_parent(ndp);
+               if (IS_ERR(parent)) {
+                       /* caller expects mutex locked */
+                       mutex_lock(&audit_filter_mutex);
+                       ret = PTR_ERR(parent);
+                       goto error;
+               }
+       } else
+               parent = container_of(i_watch, struct audit_parent, wdata);
+
+       mutex_lock(&audit_filter_mutex);
+
+       /* parent was moved before we took audit_filter_mutex */
+       if (parent->flags & AUDIT_PARENT_INVALID)
+               ret = -ENOENT;
+       else
+               audit_add_to_parent(krule, parent);
+
+       /* match get in audit_init_parent or inotify_find_watch */
+       put_inotify_watch(&parent->wdata);
+
+error:
+       audit_put_nd(ndp, ndw);         /* NULL args OK */
+       return ret;
+
+}
+
+void audit_remove_watch_rule(struct audit_krule *krule, struct list_head *list)
+{
+       struct audit_watch *watch = krule->watch;
+       struct audit_parent *parent = watch->parent;
+
+       list_del(&krule->rlist);
+
+       if (list_empty(&watch->rules)) {
+               audit_remove_watch(watch);
+
+               if (list_empty(&parent->watches)) {
+                       /* Put parent on the inotify un-registration
+                        * list.  Grab a reference before releasing
+                        * audit_filter_mutex, to be released in
+                        * audit_inotify_unregister().
+                        * If filesystem is going away, just leave
+                        * the sucker alone, eviction will take
+                        * care of it. */
+                       if (pin_inotify_watch(&parent->wdata))
+                               list_add(&parent->ilist, list);
+               }
+       }
+}
+
+/* Update watch data in audit rules based on inotify events. */
+static void audit_handle_ievent(struct inotify_watch *i_watch, u32 wd, u32 mask,
+                        u32 cookie, const char *dname, struct inode *inode)
+{
+       struct audit_parent *parent;
+
+       parent = container_of(i_watch, struct audit_parent, wdata);
+
+       if (mask & (IN_CREATE|IN_MOVED_TO) && inode)
+               audit_update_watch(parent, dname, inode->i_sb->s_dev,
+                                  inode->i_ino, 0);
+       else if (mask & (IN_DELETE|IN_MOVED_FROM))
+               audit_update_watch(parent, dname, (dev_t)-1, (unsigned long)-1, 1);
+       /* inotify automatically removes the watch and sends IN_IGNORED */
+       else if (mask & (IN_DELETE_SELF|IN_UNMOUNT))
+               audit_remove_parent_watches(parent);
+       /* inotify does not remove the watch, so remove it manually */
+       else if(mask & IN_MOVE_SELF) {
+               audit_remove_parent_watches(parent);
+               inotify_remove_watch_locked(audit_ih, i_watch);
+       } else if (mask & IN_IGNORED)
+               put_inotify_watch(i_watch);
+}
+
+static const struct inotify_operations audit_inotify_ops = {
+       .handle_event   = audit_handle_ievent,
+       .destroy_watch  = audit_free_parent,
+};
+
+static int __init audit_watch_init(void)
+{
+       audit_ih = inotify_init(&audit_inotify_ops);
+       if (IS_ERR(audit_ih))
+               audit_panic("cannot initialize inotify handle");
+       return 0;
+}
+subsys_initcall(audit_watch_init);
index 713098ee5a0243c61a30e946f6c34be44de653ca..a70604047f3c9061e81622a3b399b085fe5ac815 100644 (file)
@@ -27,7 +27,6 @@
 #include <linux/namei.h>
 #include <linux/netlink.h>
 #include <linux/sched.h>
-#include <linux/inotify.h>
 #include <linux/security.h>
 #include "audit.h"
 
  *             be written directly provided audit_filter_mutex is held.
  */
 
-/*
- * Reference counting:
- *
- * audit_parent: lifetime is from audit_init_parent() to receipt of an IN_IGNORED
- *     event.  Each audit_watch holds a reference to its associated parent.
- *
- * audit_watch: if added to lists, lifetime is from audit_init_watch() to
- *     audit_remove_watch().  Additionally, an audit_watch may exist
- *     temporarily to assist in searching existing filter data.  Each
- *     audit_krule holds a reference to its associated watch.
- */
-
-struct audit_parent {
-       struct list_head        ilist;  /* entry in inotify registration list */
-       struct list_head        watches; /* associated watches */
-       struct inotify_watch    wdata;  /* inotify watch data */
-       unsigned                flags;  /* status flags */
-};
-
-/*
- * audit_parent status flags:
- *
- * AUDIT_PARENT_INVALID - set anytime rules/watches are auto-removed due to
- * a filesystem event to ensure we're adding audit watches to a valid parent.
- * Technically not needed for IN_DELETE_SELF or IN_UNMOUNT events, as we cannot
- * receive them while we have nameidata, but must be used for IN_MOVE_SELF which
- * we can receive while holding nameidata.
- */
-#define AUDIT_PARENT_INVALID   0x001
-
 /* Audit filter lists, defined in <linux/audit.h> */
 struct list_head audit_filter_list[AUDIT_NR_FILTERS] = {
        LIST_HEAD_INIT(audit_filter_list[0]),
@@ -97,41 +66,6 @@ static struct list_head audit_rules_list[AUDIT_NR_FILTERS] = {
 
 DEFINE_MUTEX(audit_filter_mutex);
 
-/* Inotify events we care about. */
-#define AUDIT_IN_WATCH IN_MOVE|IN_CREATE|IN_DELETE|IN_DELETE_SELF|IN_MOVE_SELF
-
-void audit_free_parent(struct inotify_watch *i_watch)
-{
-       struct audit_parent *parent;
-
-       parent = container_of(i_watch, struct audit_parent, wdata);
-       WARN_ON(!list_empty(&parent->watches));
-       kfree(parent);
-}
-
-static inline void audit_get_watch(struct audit_watch *watch)
-{
-       atomic_inc(&watch->count);
-}
-
-static void audit_put_watch(struct audit_watch *watch)
-{
-       if (atomic_dec_and_test(&watch->count)) {
-               WARN_ON(watch->parent);
-               WARN_ON(!list_empty(&watch->rules));
-               kfree(watch->path);
-               kfree(watch);
-       }
-}
-
-static void audit_remove_watch(struct audit_watch *watch)
-{
-       list_del(&watch->wlist);
-       put_inotify_watch(&watch->parent->wdata);
-       watch->parent = NULL;
-       audit_put_watch(watch); /* match initial get */
-}
-
 static inline void audit_free_rule(struct audit_entry *e)
 {
        int i;
@@ -156,50 +90,6 @@ void audit_free_rule_rcu(struct rcu_head *head)
        audit_free_rule(e);
 }
 
-/* Initialize a parent watch entry. */
-static struct audit_parent *audit_init_parent(struct nameidata *ndp)
-{
-       struct audit_parent *parent;
-       s32 wd;
-
-       parent = kzalloc(sizeof(*parent), GFP_KERNEL);
-       if (unlikely(!parent))
-               return ERR_PTR(-ENOMEM);
-
-       INIT_LIST_HEAD(&parent->watches);
-       parent->flags = 0;
-
-       inotify_init_watch(&parent->wdata);
-       /* grab a ref so inotify watch hangs around until we take audit_filter_mutex */
-       get_inotify_watch(&parent->wdata);
-       wd = inotify_add_watch(audit_ih, &parent->wdata,
-                              ndp->path.dentry->d_inode, AUDIT_IN_WATCH);
-       if (wd < 0) {
-               audit_free_parent(&parent->wdata);
-               return ERR_PTR(wd);
-       }
-
-       return parent;
-}
-
-/* Initialize a watch entry. */
-static struct audit_watch *audit_init_watch(char *path)
-{
-       struct audit_watch *watch;
-
-       watch = kzalloc(sizeof(*watch), GFP_KERNEL);
-       if (unlikely(!watch))
-               return ERR_PTR(-ENOMEM);
-
-       INIT_LIST_HEAD(&watch->rules);
-       atomic_set(&watch->count, 1);
-       watch->path = path;
-       watch->dev = (dev_t)-1;
-       watch->ino = (unsigned long)-1;
-
-       return watch;
-}
-
 /* Initialize an audit filterlist entry. */
 static inline struct audit_entry *audit_init_entry(u32 field_count)
 {
@@ -260,31 +150,6 @@ static inline int audit_to_inode(struct audit_krule *krule,
        return 0;
 }
 
-/* Translate a watch string to kernel respresentation. */
-static int audit_to_watch(struct audit_krule *krule, char *path, int len,
-                         u32 op)
-{
-       struct audit_watch *watch;
-
-       if (!audit_ih)
-               return -EOPNOTSUPP;
-
-       if (path[0] != '/' || path[len-1] == '/' ||
-           krule->listnr != AUDIT_FILTER_EXIT ||
-           op != Audit_equal ||
-           krule->inode_f || krule->watch || krule->tree)
-               return -EINVAL;
-
-       watch = audit_init_watch(path);
-       if (IS_ERR(watch))
-               return PTR_ERR(watch);
-
-       audit_get_watch(watch);
-       krule->watch = watch;
-
-       return 0;
-}
-
 static __u32 *classes[AUDIT_SYSCALL_CLASSES];
 
 int __init audit_register_class(int class, unsigned *list)
@@ -766,7 +631,8 @@ static struct audit_rule_data *audit_krule_to_data(struct audit_krule *krule)
                        break;
                case AUDIT_WATCH:
                        data->buflen += data->values[i] =
-                               audit_pack_string(&bufp, krule->watch->path);
+                               audit_pack_string(&bufp,
+                                                 audit_watch_path(krule->watch));
                        break;
                case AUDIT_DIR:
                        data->buflen += data->values[i] =
@@ -818,7 +684,8 @@ static int audit_compare_rule(struct audit_krule *a, struct audit_krule *b)
                                return 1;
                        break;
                case AUDIT_WATCH:
-                       if (strcmp(a->watch->path, b->watch->path))
+                       if (strcmp(audit_watch_path(a->watch),
+                                  audit_watch_path(b->watch)))
                                return 1;
                        break;
                case AUDIT_DIR:
@@ -844,32 +711,6 @@ static int audit_compare_rule(struct audit_krule *a, struct audit_krule *b)
        return 0;
 }
 
-/* Duplicate the given audit watch.  The new watch's rules list is initialized
- * to an empty list and wlist is undefined. */
-static struct audit_watch *audit_dupe_watch(struct audit_watch *old)
-{
-       char *path;
-       struct audit_watch *new;
-
-       path = kstrdup(old->path, GFP_KERNEL);
-       if (unlikely(!path))
-               return ERR_PTR(-ENOMEM);
-
-       new = audit_init_watch(path);
-       if (IS_ERR(new)) {
-               kfree(path);
-               goto out;
-       }
-
-       new->dev = old->dev;
-       new->ino = old->ino;
-       get_inotify_watch(&old->parent->wdata);
-       new->parent = old->parent;
-
-out:
-       return new;
-}
-
 /* Duplicate LSM field information.  The lsm_rule is opaque, so must be
  * re-initialized. */
 static inline int audit_dupe_lsm_field(struct audit_field *df,
@@ -904,8 +745,8 @@ static inline int audit_dupe_lsm_field(struct audit_field *df,
  * rule with the new rule in the filterlist, then free the old rule.
  * The rlist element is undefined; list manipulations are handled apart from
  * the initial copy. */
-static struct audit_entry *audit_dupe_rule(struct audit_krule *old,
-                                          struct audit_watch *watch)
+struct audit_entry *audit_dupe_rule(struct audit_krule *old,
+                                   struct audit_watch *watch)
 {
        u32 fcount = old->field_count;
        struct audit_entry *entry;
@@ -977,137 +818,6 @@ static struct audit_entry *audit_dupe_rule(struct audit_krule *old,
        return entry;
 }
 
-/* Update inode info in audit rules based on filesystem event. */
-static void audit_update_watch(struct audit_parent *parent,
-                              const char *dname, dev_t dev,
-                              unsigned long ino, unsigned invalidating)
-{
-       struct audit_watch *owatch, *nwatch, *nextw;
-       struct audit_krule *r, *nextr;
-       struct audit_entry *oentry, *nentry;
-
-       mutex_lock(&audit_filter_mutex);
-       list_for_each_entry_safe(owatch, nextw, &parent->watches, wlist) {
-               if (audit_compare_dname_path(dname, owatch->path, NULL))
-                       continue;
-
-               /* If the update involves invalidating rules, do the inode-based
-                * filtering now, so we don't omit records. */
-               if (invalidating && current->audit_context)
-                       audit_filter_inodes(current, current->audit_context);
-
-               nwatch = audit_dupe_watch(owatch);
-               if (IS_ERR(nwatch)) {
-                       mutex_unlock(&audit_filter_mutex);
-                       audit_panic("error updating watch, skipping");
-                       return;
-               }
-               nwatch->dev = dev;
-               nwatch->ino = ino;
-
-               list_for_each_entry_safe(r, nextr, &owatch->rules, rlist) {
-
-                       oentry = container_of(r, struct audit_entry, rule);
-                       list_del(&oentry->rule.rlist);
-                       list_del_rcu(&oentry->list);
-
-                       nentry = audit_dupe_rule(&oentry->rule, nwatch);
-                       if (IS_ERR(nentry)) {
-                               list_del(&oentry->rule.list);
-                               audit_panic("error updating watch, removing");
-                       } else {
-                               int h = audit_hash_ino((u32)ino);
-                               list_add(&nentry->rule.rlist, &nwatch->rules);
-                               list_add_rcu(&nentry->list, &audit_inode_hash[h]);
-                               list_replace(&oentry->rule.list,
-                                            &nentry->rule.list);
-                       }
-
-                       call_rcu(&oentry->rcu, audit_free_rule_rcu);
-               }
-
-               if (audit_enabled) {
-                       struct audit_buffer *ab;
-                       ab = audit_log_start(NULL, GFP_NOFS,
-                               AUDIT_CONFIG_CHANGE);
-                       audit_log_format(ab, "auid=%u ses=%u",
-                               audit_get_loginuid(current),
-                               audit_get_sessionid(current));
-                       audit_log_format(ab,
-                               " op=updated rules specifying path=");
-                       audit_log_untrustedstring(ab, owatch->path);
-                       audit_log_format(ab, " with dev=%u ino=%lu\n",
-                                dev, ino);
-                       audit_log_format(ab, " list=%d res=1", r->listnr);
-                       audit_log_end(ab);
-               }
-               audit_remove_watch(owatch);
-               goto add_watch_to_parent; /* event applies to a single watch */
-       }
-       mutex_unlock(&audit_filter_mutex);
-       return;
-
-add_watch_to_parent:
-       list_add(&nwatch->wlist, &parent->watches);
-       mutex_unlock(&audit_filter_mutex);
-       return;
-}
-
-/* Remove all watches & rules associated with a parent that is going away. */
-static void audit_remove_parent_watches(struct audit_parent *parent)
-{
-       struct audit_watch *w, *nextw;
-       struct audit_krule *r, *nextr;
-       struct audit_entry *e;
-
-       mutex_lock(&audit_filter_mutex);
-       parent->flags |= AUDIT_PARENT_INVALID;
-       list_for_each_entry_safe(w, nextw, &parent->watches, wlist) {
-               list_for_each_entry_safe(r, nextr, &w->rules, rlist) {
-                       e = container_of(r, struct audit_entry, rule);
-                       if (audit_enabled) {
-                               struct audit_buffer *ab;
-                               ab = audit_log_start(NULL, GFP_NOFS,
-                                       AUDIT_CONFIG_CHANGE);
-                               audit_log_format(ab, "auid=%u ses=%u",
-                                       audit_get_loginuid(current),
-                                       audit_get_sessionid(current));
-                               audit_log_format(ab, " op=remove rule path=");
-                               audit_log_untrustedstring(ab, w->path);
-                               if (r->filterkey) {
-                                       audit_log_format(ab, " key=");
-                                       audit_log_untrustedstring(ab,
-                                                       r->filterkey);
-                               } else
-                                       audit_log_format(ab, " key=(null)");
-                               audit_log_format(ab, " list=%d res=1",
-                                       r->listnr);
-                               audit_log_end(ab);
-                       }
-                       list_del(&r->rlist);
-                       list_del(&r->list);
-                       list_del_rcu(&e->list);
-                       call_rcu(&e->rcu, audit_free_rule_rcu);
-               }
-               audit_remove_watch(w);
-       }
-       mutex_unlock(&audit_filter_mutex);
-}
-
-/* Unregister inotify watches for parents on in_list.
- * Generates an IN_IGNORED event. */
-static void audit_inotify_unregister(struct list_head *in_list)
-{
-       struct audit_parent *p, *n;
-
-       list_for_each_entry_safe(p, n, in_list, ilist) {
-               list_del(&p->ilist);
-               inotify_rm_watch(audit_ih, &p->wdata);
-               /* the unpin matching the pin in audit_do_del_rule() */
-               unpin_inotify_watch(&p->wdata);
-       }
-}
-
 /* Find an existing audit rule.
  * Caller must hold audit_filter_mutex to prevent stale rule data. */
 static struct audit_entry *audit_find_rule(struct audit_entry *entry,
@@ -1145,134 +855,6 @@ out:
        return found;
 }
 
-/* Get path information necessary for adding watches. */
-static int audit_get_nd(char *path, struct nameidata **ndp,
-                       struct nameidata **ndw)
-{
-       struct nameidata *ndparent, *ndwatch;
-       int err;
-
-       ndparent = kmalloc(sizeof(*ndparent), GFP_KERNEL);
-       if (unlikely(!ndparent))
-               return -ENOMEM;
-
-       ndwatch = kmalloc(sizeof(*ndwatch), GFP_KERNEL);
-       if (unlikely(!ndwatch)) {
-               kfree(ndparent);
-               return -ENOMEM;
-       }
-
-       err = path_lookup(path, LOOKUP_PARENT, ndparent);
-       if (err) {
-               kfree(ndparent);
-               kfree(ndwatch);
-               return err;
-       }
-
-       err = path_lookup(path, 0, ndwatch);
-       if (err) {
-               kfree(ndwatch);
-               ndwatch = NULL;
-       }
-
-       *ndp = ndparent;
-       *ndw = ndwatch;
-
-       return 0;
-}
-
-/* Release resources used for watch path information. */
-static void audit_put_nd(struct nameidata *ndp, struct nameidata *ndw)
-{
-       if (ndp) {
-               path_put(&ndp->path);
-               kfree(ndp);
-       }
-       if (ndw) {
-               path_put(&ndw->path);
-               kfree(ndw);
-       }
-}
-
-/* Associate the given rule with an existing parent inotify_watch.
- * Caller must hold audit_filter_mutex. */
-static void audit_add_to_parent(struct audit_krule *krule,
-                               struct audit_parent *parent)
-{
-       struct audit_watch *w, *watch = krule->watch;
-       int watch_found = 0;
-
-       list_for_each_entry(w, &parent->watches, wlist) {
-               if (strcmp(watch->path, w->path))
-                       continue;
-
-               watch_found = 1;
-
-               /* put krule's and initial refs to temporary watch */
-               audit_put_watch(watch);
-               audit_put_watch(watch);
-
-               audit_get_watch(w);
-               krule->watch = watch = w;
-               break;
-       }
-
-       if (!watch_found) {
-               get_inotify_watch(&parent->wdata);
-               watch->parent = parent;
-
-               list_add(&watch->wlist, &parent->watches);
-       }
-       list_add(&krule->rlist, &watch->rules);
-}
-
-/* Find a matching watch entry, or add this one.
- * Caller must hold audit_filter_mutex. */
-static int audit_add_watch(struct audit_krule *krule, struct nameidata *ndp,
-                          struct nameidata *ndw)
-{
-       struct audit_watch *watch = krule->watch;
-       struct inotify_watch *i_watch;
-       struct audit_parent *parent;
-       int ret = 0;
-
-       /* update watch filter fields */
-       if (ndw) {
-               watch->dev = ndw->path.dentry->d_inode->i_sb->s_dev;
-               watch->ino = ndw->path.dentry->d_inode->i_ino;
-       }
-
-       /* The audit_filter_mutex must not be held during inotify calls because
-        * we hold it during inotify event callback processing.  If an existing
-        * inotify watch is found, inotify_find_watch() grabs a reference before
-        * returning.
-        */
-       mutex_unlock(&audit_filter_mutex);
-
-       if (inotify_find_watch(audit_ih, ndp->path.dentry->d_inode,
-                              &i_watch) < 0) {
-               parent = audit_init_parent(ndp);
-               if (IS_ERR(parent)) {
-                       /* caller expects mutex locked */
-                       mutex_lock(&audit_filter_mutex);
-                       return PTR_ERR(parent);
-               }
-       } else
-               parent = container_of(i_watch, struct audit_parent, wdata);
-
-       mutex_lock(&audit_filter_mutex);
-
-       /* parent was moved before we took audit_filter_mutex */
-       if (parent->flags & AUDIT_PARENT_INVALID)
-               ret = -ENOENT;
-       else
-               audit_add_to_parent(krule, parent);
-
-       /* match get in audit_init_parent or inotify_find_watch */
-       put_inotify_watch(&parent->wdata);
-       return ret;
-}
-
 static u64 prio_low = ~0ULL/2;
 static u64 prio_high = ~0ULL/2 - 1;
 
@@ -1282,7 +864,6 @@ static inline int audit_add_rule(struct audit_entry *entry)
        struct audit_entry *e;
        struct audit_watch *watch = entry->rule.watch;
        struct audit_tree *tree = entry->rule.tree;
-       struct nameidata *ndp = NULL, *ndw = NULL;
        struct list_head *list;
        int h, err;
 #ifdef CONFIG_AUDITSYSCALL
@@ -1296,8 +877,8 @@ static inline int audit_add_rule(struct audit_entry *entry)
 
        mutex_lock(&audit_filter_mutex);
        e = audit_find_rule(entry, &list);
-       mutex_unlock(&audit_filter_mutex);
        if (e) {
+               mutex_unlock(&audit_filter_mutex);
                err = -EEXIST;
                /* normally audit_add_tree_rule() will free it on failure */
                if (tree)
@@ -1305,22 +886,16 @@ static inline int audit_add_rule(struct audit_entry *entry)
                goto error;
        }
 
-       /* Avoid calling path_lookup under audit_filter_mutex. */
-       if (watch) {
-               err = audit_get_nd(watch->path, &ndp, &ndw);
-               if (err)
-                       goto error;
-       }
-
-       mutex_lock(&audit_filter_mutex);
        if (watch) {
                /* audit_filter_mutex is dropped and re-taken during this call */
-               err = audit_add_watch(&entry->rule, ndp, ndw);
+               err = audit_add_watch(&entry->rule);
                if (err) {
                        mutex_unlock(&audit_filter_mutex);
                        goto error;
                }
-               h = audit_hash_ino((u32)watch->ino);
+               /* entry->rule.watch may have changed during audit_add_watch() */
+               watch = entry->rule.watch;
+               h = audit_hash_ino((u32)audit_watch_inode(watch));
                list = &audit_inode_hash[h];
        }
        if (tree) {
@@ -1358,11 +933,9 @@ static inline int audit_add_rule(struct audit_entry *entry)
 #endif
        mutex_unlock(&audit_filter_mutex);
 
-       audit_put_nd(ndp, ndw);         /* NULL args OK */
        return 0;
 
 error:
-       audit_put_nd(ndp, ndw);         /* NULL args OK */
        if (watch)
                audit_put_watch(watch); /* tmp watch, matches initial get */
        return err;
@@ -1372,7 +945,7 @@ error:
 static inline int audit_del_rule(struct audit_entry *entry)
 {
        struct audit_entry  *e;
-       struct audit_watch *watch, *tmp_watch = entry->rule.watch;
+       struct audit_watch *watch = entry->rule.watch;
        struct audit_tree *tree = entry->rule.tree;
        struct list_head *list;
        LIST_HEAD(inotify_list);
@@ -1394,29 +967,8 @@ static inline int audit_del_rule(struct audit_entry *entry)
                goto out;
        }
 
-       watch = e->rule.watch;
-       if (watch) {
-               struct audit_parent *parent = watch->parent;
-
-               list_del(&e->rule.rlist);
-
-               if (list_empty(&watch->rules)) {
-                       audit_remove_watch(watch);
-
-                       if (list_empty(&parent->watches)) {
-                               /* Put parent on the inotify un-registration
-                                * list.  Grab a reference before releasing
-                                * audit_filter_mutex, to be released in
-                                * audit_inotify_unregister().
-                                * If filesystem is going away, just leave
-                                * the sucker alone, eviction will take
-                                * care of it.
-                                */
-                               if (pin_inotify_watch(&parent->wdata))
-                                       list_add(&parent->ilist, &inotify_list);
-                       }
-               }
-       }
+       if (e->rule.watch)
+               audit_remove_watch_rule(&e->rule, &inotify_list);
 
        if (e->rule.tree)
                audit_remove_tree_rule(&e->rule);
@@ -1438,8 +990,8 @@ static inline int audit_del_rule(struct audit_entry *entry)
                audit_inotify_unregister(&inotify_list);
 
 out:
-       if (tmp_watch)
-               audit_put_watch(tmp_watch); /* match initial get */
+       if (watch)
+               audit_put_watch(watch); /* match initial get */
        if (tree)
                audit_put_tree(tree);   /* that's the temporary one */
 
@@ -1527,11 +1079,9 @@ static void audit_log_rule_change(uid_t loginuid, u32 sessionid, u32 sid,
                        security_release_secctx(ctx, len);
                }
        }
-       audit_log_format(ab, " op=%s rule key=", action);
-       if (rule->filterkey)
-               audit_log_untrustedstring(ab, rule->filterkey);
-       else
-               audit_log_format(ab, "(null)");
+       audit_log_format(ab, " op=");
+       audit_log_string(ab, action);
+       audit_log_key(ab, rule->filterkey);
        audit_log_format(ab, " list=%d res=%d", rule->listnr, res);
        audit_log_end(ab);
 }
@@ -1595,7 +1145,7 @@ int audit_receive_filter(int type, int pid, int uid, int seq, void *data,
                        return PTR_ERR(entry);
 
                err = audit_add_rule(entry);
-               audit_log_rule_change(loginuid, sessionid, sid, "add",
+               audit_log_rule_change(loginuid, sessionid, sid, "add rule",
                                      &entry->rule, !err);
 
                if (err)
@@ -1611,7 +1161,7 @@ int audit_receive_filter(int type, int pid, int uid, int seq, void *data,
                        return PTR_ERR(entry);
 
                err = audit_del_rule(entry);
-               audit_log_rule_change(loginuid, sessionid, sid, "remove",
+               audit_log_rule_change(loginuid, sessionid, sid, "remove rule",
                                      &entry->rule, !err);
 
                audit_free_rule(entry);
@@ -1793,7 +1343,7 @@ static int update_lsm_rule(struct audit_krule *r)
                list_del(&r->list);
        } else {
                if (watch) {
-                       list_add(&nentry->rule.rlist, &watch->rules);
+                       list_add(&nentry->rule.rlist, audit_watch_rules(watch));
                        list_del(&r->rlist);
                } else if (tree)
                        list_replace_init(&r->rlist, &nentry->rule.rlist);
@@ -1829,27 +1379,3 @@ int audit_update_lsm_rules(void)
 
        return err;
 }
-
-/* Update watch data in audit rules based on inotify events. */
-void audit_handle_ievent(struct inotify_watch *i_watch, u32 wd, u32 mask,
-                        u32 cookie, const char *dname, struct inode *inode)
-{
-       struct audit_parent *parent;
-
-       parent = container_of(i_watch, struct audit_parent, wdata);
-
-       if (mask & (IN_CREATE|IN_MOVED_TO) && inode)
-               audit_update_watch(parent, dname, inode->i_sb->s_dev,
-                                  inode->i_ino, 0);
-       else if (mask & (IN_DELETE|IN_MOVED_FROM))
-               audit_update_watch(parent, dname, (dev_t)-1, (unsigned long)-1, 1);
-       /* inotify automatically removes the watch and sends IN_IGNORED */
-       else if (mask & (IN_DELETE_SELF|IN_UNMOUNT))
-               audit_remove_parent_watches(parent);
-       /* inotify does not remove the watch, so remove it manually */
-       else if(mask & IN_MOVE_SELF) {
-               audit_remove_parent_watches(parent);
-               inotify_remove_watch_locked(audit_ih, i_watch);
-       } else if (mask & IN_IGNORED)
-               put_inotify_watch(i_watch);
-}
index 7d6ac7c1f414479ada4a58af0c4b9e241051062e..68d3c6a0ecd635bbeba49c5de2d3e89b50315897 100644 (file)
@@ -199,6 +199,7 @@ struct audit_context {
 
        struct audit_tree_refs *trees, *first_trees;
        int tree_count;
+       struct list_head killed_trees;
 
        int type;
        union {
@@ -548,9 +549,9 @@ static int audit_filter_rules(struct task_struct *tsk,
                        }
                        break;
                case AUDIT_WATCH:
-                       if (name && rule->watch->ino != (unsigned long)-1)
-                               result = (name->dev == rule->watch->dev &&
-                                         name->ino == rule->watch->ino);
+                       if (name && audit_watch_inode(rule->watch) != (unsigned long)-1)
+                               result = (name->dev == audit_watch_dev(rule->watch) &&
+                                         name->ino == audit_watch_inode(rule->watch));
                        break;
                case AUDIT_DIR:
                        if (ctx)
@@ -853,6 +854,7 @@ static inline struct audit_context *audit_alloc_context(enum audit_state state)
        if (!(context = kmalloc(sizeof(*context), GFP_KERNEL)))
                return NULL;
        audit_zero_context(context, state);
+       INIT_LIST_HEAD(&context->killed_trees);
        return context;
 }
 
@@ -1024,8 +1026,8 @@ static int audit_log_single_execve_arg(struct audit_context *context,
 {
        char arg_num_len_buf[12];
        const char __user *tmp_p = p;
-       /* how many digits are in arg_num? 3 is the length of " a=" */
-       size_t arg_num_len = snprintf(arg_num_len_buf, 12, "%d", arg_num) + 3;
+       /* how many digits are in arg_num? 5 is the length of ' a=""' */
+       size_t arg_num_len = snprintf(arg_num_len_buf, 12, "%d", arg_num) + 5;
        size_t len, len_left, to_send;
        size_t max_execve_audit_len = MAX_EXECVE_AUDIT_LEN;
        unsigned int i, has_cntl = 0, too_long = 0;
@@ -1137,7 +1139,7 @@ static int audit_log_single_execve_arg(struct audit_context *context,
                if (has_cntl)
                        audit_log_n_hex(*ab, buf, to_send);
                else
-                       audit_log_format(*ab, "\"%s\"", buf);
+                       audit_log_string(*ab, buf);
 
                p += to_send;
                len_left -= to_send;
@@ -1372,11 +1374,7 @@ static void audit_log_exit(struct audit_context *context, struct task_struct *ts
 
 
        audit_log_task_info(ab, tsk);
-       if (context->filterkey) {
-               audit_log_format(ab, " key=");
-               audit_log_untrustedstring(ab, context->filterkey);
-       } else
-               audit_log_format(ab, " key=(null)");
+       audit_log_key(ab, context->filterkey);
        audit_log_end(ab);
 
        for (aux = context->aux; aux; aux = aux->next) {
@@ -1549,6 +1547,8 @@ void audit_free(struct task_struct *tsk)
        /* that can happen only if we are called from do_exit() */
        if (context->in_syscall && context->current_state == AUDIT_RECORD_CONTEXT)
                audit_log_exit(context, tsk);
+       if (!list_empty(&context->killed_trees))
+               audit_kill_trees(&context->killed_trees);
 
        audit_free_context(context);
 }
@@ -1692,6 +1692,9 @@ void audit_syscall_exit(int valid, long return_code)
        context->in_syscall = 0;
        context->prio = context->state == AUDIT_RECORD_CONTEXT ? ~0ULL : 0;
 
+       if (!list_empty(&context->killed_trees))
+               audit_kill_trees(&context->killed_trees);
+
        if (context->previous) {
                struct audit_context *new_context = context->previous;
                context->previous  = NULL;
@@ -2525,3 +2528,11 @@ void audit_core_dumps(long signr)
        audit_log_format(ab, " sig=%ld", signr);
        audit_log_end(ab);
 }
+
+struct list_head *audit_killed_trees(void)
+{
+       struct audit_context *ctx = current->audit_context;
+       if (likely(!ctx || !ctx->in_syscall))
+               return NULL;
+       return &ctx->killed_trees;
+}
index 628d41f0dd54ed163e32f2d4d2e9ec6909ccd2ab..869dc221733e27701c275a0bdf283404507108f6 100644 (file)
@@ -12,7 +12,6 @@
 #include <linux/completion.h>
 #include <linux/personality.h>
 #include <linux/tty.h>
-#include <linux/mnt_namespace.h>
 #include <linux/iocontext.h>
 #include <linux/key.h>
 #include <linux/security.h>
index 467746b3f0aa2eec5970c42f56a71d8ae1583b7f..bd2959228871d05926dbb0ddfc3b5fe4f54c59d9 100644 (file)
@@ -17,7 +17,6 @@
 #include <linux/module.h>
 #include <linux/vmalloc.h>
 #include <linux/completion.h>
-#include <linux/mnt_namespace.h>
 #include <linux/personality.h>
 #include <linux/mempolicy.h>
 #include <linux/sem.h>
index 80b5ce716596a95b797a00c417b5a514f9d5d2a2..0672ff88f159f3041206750b3427fdd68aa0afc1 100644 (file)
@@ -247,6 +247,7 @@ again:
        if (err < 0)
                return err;
 
+       page = compound_head(page);
        lock_page(page);
        if (!page->mapping) {
                unlock_page(page);
@@ -284,6 +285,25 @@ void put_futex_key(int fshared, union futex_key *key)
        drop_futex_key_refs(key);
 }
 
+/*
+ * fault_in_user_writeable - fault in user address and verify RW access
+ * @uaddr:     pointer to faulting user space address
+ *
+ * Slow path to fixup the fault we just took in the atomic write
+ * access to @uaddr.
+ *
+ * We have no generic implementation of a non destructive write to the
+ * user address. We know that we faulted in the atomic pagefault
+ * disabled section so we can as well avoid the #PF overhead by
+ * calling get_user_pages() right away.
+ */
+static int fault_in_user_writeable(u32 __user *uaddr)
+{
+       int ret = get_user_pages(current, current->mm, (unsigned long)uaddr,
+                                1, 1, 0, NULL, NULL);
+       return ret < 0 ? ret : 0;
+}
+
 /**
  * futex_top_waiter() - Return the highest priority waiter on a futex
  * @hb:     the hash bucket the futex_q's reside in
@@ -896,7 +916,6 @@ retry:
 retry_private:
        op_ret = futex_atomic_op_inuser(op, uaddr2);
        if (unlikely(op_ret < 0)) {
-               u32 dummy;
 
                double_unlock_hb(hb1, hb2);
 
@@ -914,7 +933,7 @@ retry_private:
                        goto out_put_keys;
                }
 
-               ret = get_user(dummy, uaddr2);
+               ret = fault_in_user_writeable(uaddr2);
                if (ret)
                        goto out_put_keys;
 
@@ -1204,7 +1223,7 @@ retry_private:
                        double_unlock_hb(hb1, hb2);
                        put_futex_key(fshared, &key2);
                        put_futex_key(fshared, &key1);
-                       ret = get_user(curval2, uaddr2);
+                       ret = fault_in_user_writeable(uaddr2);
                        if (!ret)
                                goto retry;
                        goto out;
@@ -1482,7 +1501,7 @@ retry:
 handle_fault:
        spin_unlock(q->lock_ptr);
 
-       ret = get_user(uval, uaddr);
+       ret = fault_in_user_writeable(uaddr);
 
        spin_lock(q->lock_ptr);
 
@@ -1807,7 +1826,6 @@ static int futex_lock_pi(u32 __user *uaddr, int fshared,
 {
        struct hrtimer_sleeper timeout, *to = NULL;
        struct futex_hash_bucket *hb;
-       u32 uval;
        struct futex_q q;
        int res, ret;
 
@@ -1909,16 +1927,9 @@ out:
        return ret != -EINTR ? ret : -ERESTARTNOINTR;
 
 uaddr_faulted:
-       /*
-        * We have to r/w  *(int __user *)uaddr, and we have to modify it
-        * atomically.  Therefore, if we continue to fault after get_user()
-        * below, we need to handle the fault ourselves, while still holding
-        * the mmap_sem.  This can occur if the uaddr is under contention as
-        * we have to drop the mmap_sem in order to call get_user().
-        */
        queue_unlock(&q, hb);
 
-       ret = get_user(uval, uaddr);
+       ret = fault_in_user_writeable(uaddr);
        if (ret)
                goto out_put_key;
 
@@ -2013,17 +2024,10 @@ out:
        return ret;
 
 pi_faulted:
-       /*
-        * We have to r/w  *(int __user *)uaddr, and we have to modify it
-        * atomically.  Therefore, if we continue to fault after get_user()
-        * below, we need to handle the fault ourselves, while still holding
-        * the mmap_sem.  This can occur if the uaddr is under contention as
-        * we have to drop the mmap_sem in order to call get_user().
-        */
        spin_unlock(&hb->lock);
        put_futex_key(fshared, &key);
 
-       ret = get_user(uval, uaddr);
+       ret = fault_in_user_writeable(uaddr);
        if (!ret)
                goto retry;
 
index 9002958a96e70ef0f8acc70ceeccac5327efae9e..49da79ab8486df682bc7f252674b4a01b810c108 100644 (file)
@@ -191,6 +191,46 @@ struct hrtimer_clock_base *lock_hrtimer_base(const struct hrtimer *timer,
        }
 }
 
+
+/*
+ * Get the preferred target CPU for NOHZ
+ */
+static int hrtimer_get_target(int this_cpu, int pinned)
+{
+#ifdef CONFIG_NO_HZ
+       if (!pinned && get_sysctl_timer_migration() && idle_cpu(this_cpu)) {
+               int preferred_cpu = get_nohz_load_balancer();
+
+               if (preferred_cpu >= 0)
+                       return preferred_cpu;
+       }
+#endif
+       return this_cpu;
+}
+
+/*
+ * With HIGHRES=y we do not migrate the timer when it is expiring
+ * before the next event on the target cpu because we cannot reprogram
+ * the target cpu hardware and we would cause it to fire late.
+ *
+ * Called with cpu_base->lock of target cpu held.
+ */
+static int
+hrtimer_check_target(struct hrtimer *timer, struct hrtimer_clock_base *new_base)
+{
+#ifdef CONFIG_HIGH_RES_TIMERS
+       ktime_t expires;
+
+       if (!new_base->cpu_base->hres_active)
+               return 0;
+
+       expires = ktime_sub(hrtimer_get_expires(timer), new_base->offset);
+       return expires.tv64 <= new_base->cpu_base->expires_next.tv64;
+#else
+       return 0;
+#endif
+}
+
 /*
  * Switch the timer base to the current CPU when possible.
  */
@@ -200,16 +240,8 @@ switch_hrtimer_base(struct hrtimer *timer, struct hrtimer_clock_base *base,
 {
        struct hrtimer_clock_base *new_base;
        struct hrtimer_cpu_base *new_cpu_base;
-       int cpu, preferred_cpu = -1;
-
-       cpu = smp_processor_id();
-#if defined(CONFIG_NO_HZ) && defined(CONFIG_SMP)
-       if (!pinned && get_sysctl_timer_migration() && idle_cpu(cpu)) {
-               preferred_cpu = get_nohz_load_balancer();
-               if (preferred_cpu >= 0)
-                       cpu = preferred_cpu;
-       }
-#endif
+       int this_cpu = smp_processor_id();
+       int cpu = hrtimer_get_target(this_cpu, pinned);
 
 again:
        new_cpu_base = &per_cpu(hrtimer_bases, cpu);
@@ -217,7 +249,7 @@ again:
 
        if (base != new_base) {
                /*
-                * We are trying to schedule the timer on the local CPU.
+                * We are trying to move timer to new_base.
                 * However we can't change timer's base while it is running,
                 * so we keep it on the same CPU. No hassle vs. reprogramming
                 * the event source in the high resolution case. The softirq
@@ -233,38 +265,12 @@ again:
                spin_unlock(&base->cpu_base->lock);
                spin_lock(&new_base->cpu_base->lock);
 
-               /* Optimized away for NOHZ=n SMP=n */
-               if (cpu == preferred_cpu) {
-                       /* Calculate clock monotonic expiry time */
-#ifdef CONFIG_HIGH_RES_TIMERS
-                       ktime_t expires = ktime_sub(hrtimer_get_expires(timer),
-                                                       new_base->offset);
-#else
-                       ktime_t expires = hrtimer_get_expires(timer);
-#endif
-
-                       /*
-                        * Get the next event on target cpu from the
-                        * clock events layer.
-                        * This covers the highres=off nohz=on case as well.
-                        */
-                       ktime_t next = clockevents_get_next_event(cpu);
-
-                       ktime_t delta = ktime_sub(expires, next);
-
-                       /*
-                        * We do not migrate the timer when it is expiring
-                        * before the next event on the target cpu because
-                        * we cannot reprogram the target cpu hardware and
-                        * we would cause it to fire late.
-                        */
-                       if (delta.tv64 < 0) {
-                               cpu = smp_processor_id();
-                               spin_unlock(&new_base->cpu_base->lock);
-                               spin_lock(&base->cpu_base->lock);
-                               timer->base = base;
-                               goto again;
-                       }
+               if (cpu != this_cpu && hrtimer_check_target(timer, new_base)) {
+                       cpu = this_cpu;
+                       spin_unlock(&new_base->cpu_base->lock);
+                       spin_lock(&base->cpu_base->lock);
+                       timer->base = base;
+                       goto again;
                }
                timer->base = new_base;
        }
@@ -1276,14 +1282,22 @@ void hrtimer_interrupt(struct clock_event_device *dev)
 
        expires_next.tv64 = KTIME_MAX;
 
+       spin_lock(&cpu_base->lock);
+       /*
+        * We set expires_next to KTIME_MAX here with cpu_base->lock
+        * held to prevent that a timer is enqueued in our queue via
+        * the migration code. This does not affect enqueueing of
+        * timers which run their callback and need to be requeued on
+        * this CPU.
+        */
+       cpu_base->expires_next.tv64 = KTIME_MAX;
+
        base = cpu_base->clock_base;
 
        for (i = 0; i < HRTIMER_MAX_CLOCK_BASES; i++) {
                ktime_t basenow;
                struct rb_node *node;
 
-               spin_lock(&cpu_base->lock);
-
                basenow = ktime_add(now, base->offset);
 
                while ((node = base->first)) {
@@ -1316,11 +1330,15 @@ void hrtimer_interrupt(struct clock_event_device *dev)
 
                        __run_hrtimer(timer);
                }
-               spin_unlock(&cpu_base->lock);
                base++;
        }
 
+       /*
+        * Store the new expiry value so the migration code can verify
+        * against it.
+        */
        cpu_base->expires_next = expires_next;
+       spin_unlock(&cpu_base->lock);
 
        /* Reprogramming necessary ? */
        if (expires_next.tv64 != KTIME_MAX) {
index 7e95bedb2bfc19bc1d10eaed1337cd02c1ffdb1c..385c31a1bdbf3118b3d82d44b6720af727738bcb 100644 (file)
@@ -24,7 +24,6 @@
 #include <linux/unistd.h>
 #include <linux/kmod.h>
 #include <linux/slab.h>
-#include <linux/mnt_namespace.h>
 #include <linux/completion.h>
 #include <linux/file.h>
 #include <linux/fdtable.h>
index 38928fcaff2bcb517375c3e6b19d398e4d423c05..0a049837008e6b77d416659dfd0588fed37b00b5 100644 (file)
@@ -2451,9 +2451,9 @@ SYSCALL_DEFINE3(init_module, void __user *, umod,
                return ret;
        }
        if (ret > 0) {
-               printk(KERN_WARNING "%s: '%s'->init suspiciously returned %d, "
-                                   "it should follow 0/-E convention\n"
-                      KERN_WARNING "%s: loading module anyway...\n",
+               printk(KERN_WARNING
+"%s: '%s'->init suspiciously returned %d, it should follow 0/-E convention\n"
+"%s: loading module anyway...\n",
                       __func__, mod->name, ret,
                       __func__);
                dump_stack();
index 1a933a221ea4a299922f4db98d62de86c7e5ea0b..a641eb753b8cc92b664966e3a6932c595f07b111 100644 (file)
@@ -236,6 +236,8 @@ list_add_counter(struct perf_counter *counter, struct perf_counter_context *ctx)
 
        list_add_rcu(&counter->event_entry, &ctx->event_list);
        ctx->nr_counters++;
+       if (counter->attr.inherit_stat)
+               ctx->nr_stat++;
 }
 
 /*
@@ -250,6 +252,8 @@ list_del_counter(struct perf_counter *counter, struct perf_counter_context *ctx)
        if (list_empty(&counter->list_entry))
                return;
        ctx->nr_counters--;
+       if (counter->attr.inherit_stat)
+               ctx->nr_stat--;
 
        list_del_init(&counter->list_entry);
        list_del_rcu(&counter->event_entry);
@@ -1006,6 +1010,81 @@ static int context_equiv(struct perf_counter_context *ctx1,
                && !ctx1->pin_count && !ctx2->pin_count;
 }
 
+static void __perf_counter_read(void *counter);
+
+static void __perf_counter_sync_stat(struct perf_counter *counter,
+                                    struct perf_counter *next_counter)
+{
+       u64 value;
+
+       if (!counter->attr.inherit_stat)
+               return;
+
+       /*
+        * Update the counter value, we cannot use perf_counter_read()
+        * because we're in the middle of a context switch and have IRQs
+        * disabled, which upsets smp_call_function_single(), however
+        * we know the counter must be on the current CPU, therefore we
+        * don't need to use it.
+        */
+       switch (counter->state) {
+       case PERF_COUNTER_STATE_ACTIVE:
+               __perf_counter_read(counter);
+               break;
+
+       case PERF_COUNTER_STATE_INACTIVE:
+               update_counter_times(counter);
+               break;
+
+       default:
+               break;
+       }
+
+       /*
+        * In order to keep per-task stats reliable we need to flip the counter
+        * values when we flip the contexts.
+        */
+       value = atomic64_read(&next_counter->count);
+       value = atomic64_xchg(&counter->count, value);
+       atomic64_set(&next_counter->count, value);
+
+       swap(counter->total_time_enabled, next_counter->total_time_enabled);
+       swap(counter->total_time_running, next_counter->total_time_running);
+
+       /*
+        * Since we swizzled the values, update the user visible data too.
+        */
+       perf_counter_update_userpage(counter);
+       perf_counter_update_userpage(next_counter);
+}
+
+#define list_next_entry(pos, member) \
+       list_entry(pos->member.next, typeof(*pos), member)
+
+static void perf_counter_sync_stat(struct perf_counter_context *ctx,
+                                  struct perf_counter_context *next_ctx)
+{
+       struct perf_counter *counter, *next_counter;
+
+       if (!ctx->nr_stat)
+               return;
+
+       counter = list_first_entry(&ctx->event_list,
+                                  struct perf_counter, event_entry);
+
+       next_counter = list_first_entry(&next_ctx->event_list,
+                                       struct perf_counter, event_entry);
+
+       while (&counter->event_entry != &ctx->event_list &&
+              &next_counter->event_entry != &next_ctx->event_list) {
+
+               __perf_counter_sync_stat(counter, next_counter);
+
+               counter = list_next_entry(counter, event_entry);
+               next_counter = list_next_entry(counter, event_entry);
+       }
+}
+
 /*
  * Called from scheduler to remove the counters of the current task,
  * with interrupts disabled.
@@ -1061,6 +1140,8 @@ void perf_counter_task_sched_out(struct task_struct *task,
                        ctx->task = next;
                        next_ctx->task = task;
                        do_switch = 0;
+
+                       perf_counter_sync_stat(ctx, next_ctx);
                }
                spin_unlock(&next_ctx->lock);
                spin_unlock(&ctx->lock);
@@ -1347,10 +1428,57 @@ void perf_counter_task_tick(struct task_struct *curr, int cpu)
                perf_counter_task_sched_in(curr, cpu);
 }
 
+/*
+ * Enable all of a task's counters that have been marked enable-on-exec.
+ * This expects task == current.
+ */
+static void perf_counter_enable_on_exec(struct task_struct *task)
+{
+       struct perf_counter_context *ctx;
+       struct perf_counter *counter;
+       unsigned long flags;
+       int enabled = 0;
+
+       local_irq_save(flags);
+       ctx = task->perf_counter_ctxp;
+       if (!ctx || !ctx->nr_counters)
+               goto out;
+
+       __perf_counter_task_sched_out(ctx);
+
+       spin_lock(&ctx->lock);
+
+       list_for_each_entry(counter, &ctx->counter_list, list_entry) {
+               if (!counter->attr.enable_on_exec)
+                       continue;
+               counter->attr.enable_on_exec = 0;
+               if (counter->state >= PERF_COUNTER_STATE_INACTIVE)
+                       continue;
+               counter->state = PERF_COUNTER_STATE_INACTIVE;
+               counter->tstamp_enabled =
+                       ctx->time - counter->total_time_enabled;
+               enabled = 1;
+       }
+
+       /*
+        * Unclone this context if we enabled any counter.
+        */
+       if (enabled && ctx->parent_ctx) {
+               put_ctx(ctx->parent_ctx);
+               ctx->parent_ctx = NULL;
+       }
+
+       spin_unlock(&ctx->lock);
+
+       perf_counter_task_sched_in(task, smp_processor_id());
+ out:
+       local_irq_restore(flags);
+}
+
 /*
  * Cross CPU call to read the hardware counter
  */
-static void __read(void *info)
+static void __perf_counter_read(void *info)
 {
        struct perf_counter *counter = info;
        struct perf_counter_context *ctx = counter->ctx;
@@ -1372,7 +1500,7 @@ static u64 perf_counter_read(struct perf_counter *counter)
         */
        if (counter->state == PERF_COUNTER_STATE_ACTIVE) {
                smp_call_function_single(counter->oncpu,
-                                        __read, counter, 1);
+                                        __perf_counter_read, counter, 1);
        } else if (counter->state == PERF_COUNTER_STATE_INACTIVE) {
                update_counter_times(counter);
        }
@@ -1508,11 +1636,13 @@ static void free_counter(struct perf_counter *counter)
 {
        perf_pending_sync(counter);
 
-       atomic_dec(&nr_counters);
-       if (counter->attr.mmap)
-               atomic_dec(&nr_mmap_counters);
-       if (counter->attr.comm)
-               atomic_dec(&nr_comm_counters);
+       if (!counter->parent) {
+               atomic_dec(&nr_counters);
+               if (counter->attr.mmap)
+                       atomic_dec(&nr_mmap_counters);
+               if (counter->attr.comm)
+                       atomic_dec(&nr_comm_counters);
+       }
 
        if (counter->destroy)
                counter->destroy(counter);
@@ -1751,6 +1881,14 @@ int perf_counter_task_disable(void)
        return 0;
 }
 
+static int perf_counter_index(struct perf_counter *counter)
+{
+       if (counter->state != PERF_COUNTER_STATE_ACTIVE)
+               return 0;
+
+       return counter->hw.idx + 1 - PERF_COUNTER_INDEX_OFFSET;
+}
+
 /*
  * Callers need to ensure there can be no nesting of this function, otherwise
  * the seqlock logic goes bad. We can not serialize this because the arch
@@ -1775,11 +1913,17 @@ void perf_counter_update_userpage(struct perf_counter *counter)
        preempt_disable();
        ++userpg->lock;
        barrier();
-       userpg->index = counter->hw.idx;
+       userpg->index = perf_counter_index(counter);
        userpg->offset = atomic64_read(&counter->count);
        if (counter->state == PERF_COUNTER_STATE_ACTIVE)
                userpg->offset -= atomic64_read(&counter->hw.prev_count);
 
+       userpg->time_enabled = counter->total_time_enabled +
+                       atomic64_read(&counter->child_total_time_enabled);
+
+       userpg->time_running = counter->total_time_running +
+                       atomic64_read(&counter->child_total_time_running);
+
        barrier();
        ++userpg->lock;
        preempt_enable();
@@ -1876,7 +2020,7 @@ fail:
 
 static void perf_mmap_free_page(unsigned long addr)
 {
-       struct page *page = virt_to_page(addr);
+       struct page *page = virt_to_page((void *)addr);
 
        page->mapping = NULL;
        __free_page(page);
@@ -2483,15 +2627,14 @@ static void perf_counter_output(struct perf_counter *counter, int nmi,
                u32 cpu, reserved;
        } cpu_entry;
 
-       header.type = 0;
+       header.type = PERF_EVENT_SAMPLE;
        header.size = sizeof(header);
 
-       header.misc = PERF_EVENT_MISC_OVERFLOW;
+       header.misc = 0;
        header.misc |= perf_misc_flags(data->regs);
 
        if (sample_type & PERF_SAMPLE_IP) {
                ip = perf_instruction_pointer(data->regs);
-               header.type |= PERF_SAMPLE_IP;
                header.size += sizeof(ip);
        }
 
@@ -2500,7 +2643,6 @@ static void perf_counter_output(struct perf_counter *counter, int nmi,
                tid_entry.pid = perf_counter_pid(counter, current);
                tid_entry.tid = perf_counter_tid(counter, current);
 
-               header.type |= PERF_SAMPLE_TID;
                header.size += sizeof(tid_entry);
        }
 
@@ -2510,34 +2652,25 @@ static void perf_counter_output(struct perf_counter *counter, int nmi,
                 */
                time = sched_clock();
 
-               header.type |= PERF_SAMPLE_TIME;
                header.size += sizeof(u64);
        }
 
-       if (sample_type & PERF_SAMPLE_ADDR) {
-               header.type |= PERF_SAMPLE_ADDR;
+       if (sample_type & PERF_SAMPLE_ADDR)
                header.size += sizeof(u64);
-       }
 
-       if (sample_type & PERF_SAMPLE_ID) {
-               header.type |= PERF_SAMPLE_ID;
+       if (sample_type & PERF_SAMPLE_ID)
                header.size += sizeof(u64);
-       }
 
        if (sample_type & PERF_SAMPLE_CPU) {
-               header.type |= PERF_SAMPLE_CPU;
                header.size += sizeof(cpu_entry);
 
                cpu_entry.cpu = raw_smp_processor_id();
        }
 
-       if (sample_type & PERF_SAMPLE_PERIOD) {
-               header.type |= PERF_SAMPLE_PERIOD;
+       if (sample_type & PERF_SAMPLE_PERIOD)
                header.size += sizeof(u64);
-       }
 
        if (sample_type & PERF_SAMPLE_GROUP) {
-               header.type |= PERF_SAMPLE_GROUP;
                header.size += sizeof(u64) +
                        counter->nr_siblings * sizeof(group_entry);
        }
@@ -2547,10 +2680,9 @@ static void perf_counter_output(struct perf_counter *counter, int nmi,
 
                if (callchain) {
                        callchain_size = (1 + callchain->nr) * sizeof(u64);
-
-                       header.type |= PERF_SAMPLE_CALLCHAIN;
                        header.size += callchain_size;
-               }
+               } else
+                       header.size += sizeof(u64);
        }
 
        ret = perf_output_begin(&handle, counter, header.size, nmi, 1);
@@ -2601,12 +2733,78 @@ static void perf_counter_output(struct perf_counter *counter, int nmi,
                }
        }
 
-       if (callchain)
-               perf_output_copy(&handle, callchain, callchain_size);
+       if (sample_type & PERF_SAMPLE_CALLCHAIN) {
+               if (callchain)
+                       perf_output_copy(&handle, callchain, callchain_size);
+               else {
+                       u64 nr = 0;
+                       perf_output_put(&handle, nr);
+               }
+       }
 
        perf_output_end(&handle);
 }
 
+/*
+ * read event
+ */
+
+struct perf_read_event {
+       struct perf_event_header        header;
+
+       u32                             pid;
+       u32                             tid;
+       u64                             value;
+       u64                             format[3];
+};
+
+static void
+perf_counter_read_event(struct perf_counter *counter,
+                       struct task_struct *task)
+{
+       struct perf_output_handle handle;
+       struct perf_read_event event = {
+               .header = {
+                       .type = PERF_EVENT_READ,
+                       .misc = 0,
+                       .size = sizeof(event) - sizeof(event.format),
+               },
+               .pid = perf_counter_pid(counter, task),
+               .tid = perf_counter_tid(counter, task),
+               .value = atomic64_read(&counter->count),
+       };
+       int ret, i = 0;
+
+       if (counter->attr.read_format & PERF_FORMAT_TOTAL_TIME_ENABLED) {
+               event.header.size += sizeof(u64);
+               event.format[i++] = counter->total_time_enabled;
+       }
+
+       if (counter->attr.read_format & PERF_FORMAT_TOTAL_TIME_RUNNING) {
+               event.header.size += sizeof(u64);
+               event.format[i++] = counter->total_time_running;
+       }
+
+       if (counter->attr.read_format & PERF_FORMAT_ID) {
+               u64 id;
+
+               event.header.size += sizeof(u64);
+               if (counter->parent)
+                       id = counter->parent->id;
+               else
+                       id = counter->id;
+
+               event.format[i++] = id;
+       }
+
+       ret = perf_output_begin(&handle, counter, event.header.size, 0, 0);
+       if (ret)
+               return;
+
+       perf_output_copy(&handle, &event, event.header.size);
+       perf_output_end(&handle);
+}
+
 /*
  * fork tracking
  */
@@ -2798,6 +2996,9 @@ void perf_counter_comm(struct task_struct *task)
 {
        struct perf_comm_event comm_event;
 
+       if (task->perf_counter_ctxp)
+               perf_counter_enable_on_exec(task);
+
        if (!atomic_read(&nr_comm_counters))
                return;
 
@@ -3317,8 +3518,8 @@ out:
        put_cpu_var(perf_cpu_context);
 }
 
-void
-perf_swcounter_event(u32 event, u64 nr, int nmi, struct pt_regs *regs, u64 addr)
+void __perf_swcounter_event(u32 event, u64 nr, int nmi,
+                           struct pt_regs *regs, u64 addr)
 {
        struct perf_sample_data data = {
                .regs = regs,
@@ -3509,9 +3710,21 @@ static const struct pmu *tp_perf_counter_init(struct perf_counter *counter)
 }
 #endif
 
+atomic_t perf_swcounter_enabled[PERF_COUNT_SW_MAX];
+
+static void sw_perf_counter_destroy(struct perf_counter *counter)
+{
+       u64 event = counter->attr.config;
+
+       WARN_ON(counter->parent);
+
+       atomic_dec(&perf_swcounter_enabled[event]);
+}
+
 static const struct pmu *sw_perf_counter_init(struct perf_counter *counter)
 {
        const struct pmu *pmu = NULL;
+       u64 event = counter->attr.config;
 
        /*
         * Software counters (currently) can't in general distinguish
@@ -3520,7 +3733,7 @@ static const struct pmu *sw_perf_counter_init(struct perf_counter *counter)
         * to be kernel events, and page faults are never hypervisor
         * events.
         */
-       switch (counter->attr.config) {
+       switch (event) {
        case PERF_COUNT_SW_CPU_CLOCK:
                pmu = &perf_ops_cpu_clock;
 
@@ -3541,6 +3754,10 @@ static const struct pmu *sw_perf_counter_init(struct perf_counter *counter)
        case PERF_COUNT_SW_PAGE_FAULTS_MAJ:
        case PERF_COUNT_SW_CONTEXT_SWITCHES:
        case PERF_COUNT_SW_CPU_MIGRATIONS:
+               if (!counter->parent) {
+                       atomic_inc(&perf_swcounter_enabled[event]);
+                       counter->destroy = sw_perf_counter_destroy;
+               }
                pmu = &perf_ops_generic;
                break;
        }
@@ -3556,6 +3773,7 @@ perf_counter_alloc(struct perf_counter_attr *attr,
                   int cpu,
                   struct perf_counter_context *ctx,
                   struct perf_counter *group_leader,
+                  struct perf_counter *parent_counter,
                   gfp_t gfpflags)
 {
        const struct pmu *pmu;
@@ -3591,6 +3809,8 @@ perf_counter_alloc(struct perf_counter_attr *attr,
        counter->ctx            = ctx;
        counter->oncpu          = -1;
 
+       counter->parent         = parent_counter;
+
        counter->ns             = get_pid_ns(current->nsproxy->pid_ns);
        counter->id             = atomic64_inc_return(&perf_counter_id);
 
@@ -3648,11 +3868,13 @@ done:
 
        counter->pmu = pmu;
 
-       atomic_inc(&nr_counters);
-       if (counter->attr.mmap)
-               atomic_inc(&nr_mmap_counters);
-       if (counter->attr.comm)
-               atomic_inc(&nr_comm_counters);
+       if (!counter->parent) {
+               atomic_inc(&nr_counters);
+               if (counter->attr.mmap)
+                       atomic_inc(&nr_mmap_counters);
+               if (counter->attr.comm)
+                       atomic_inc(&nr_comm_counters);
+       }
 
        return counter;
 }
@@ -3815,7 +4037,7 @@ SYSCALL_DEFINE5(perf_counter_open,
        }
 
        counter = perf_counter_alloc(&attr, cpu, ctx, group_leader,
-                                    GFP_KERNEL);
+                                    NULL, GFP_KERNEL);
        ret = PTR_ERR(counter);
        if (IS_ERR(counter))
                goto err_put_context;
@@ -3881,7 +4103,8 @@ inherit_counter(struct perf_counter *parent_counter,
 
        child_counter = perf_counter_alloc(&parent_counter->attr,
                                           parent_counter->cpu, child_ctx,
-                                          group_leader, GFP_KERNEL);
+                                          group_leader, parent_counter,
+                                          GFP_KERNEL);
        if (IS_ERR(child_counter))
                return child_counter;
        get_ctx(child_ctx);
@@ -3904,12 +4127,6 @@ inherit_counter(struct perf_counter *parent_counter,
         */
        add_counter_to_ctx(child_counter, child_ctx);
 
-       child_counter->parent = parent_counter;
-       /*
-        * inherit into child's child as well:
-        */
-       child_counter->attr.inherit = 1;
-
        /*
         * Get a reference to the parent filp - we will fput it
         * when the child counter exits. This is safe to do because
@@ -3953,10 +4170,14 @@ static int inherit_group(struct perf_counter *parent_counter,
 }
 
 static void sync_child_counter(struct perf_counter *child_counter,
-                              struct perf_counter *parent_counter)
+                              struct task_struct *child)
 {
+       struct perf_counter *parent_counter = child_counter->parent;
        u64 child_val;
 
+       if (child_counter->attr.inherit_stat)
+               perf_counter_read_event(child_counter, child);
+
        child_val = atomic64_read(&child_counter->count);
 
        /*
@@ -3985,7 +4206,8 @@ static void sync_child_counter(struct perf_counter *child_counter,
 
 static void
 __perf_counter_exit_task(struct perf_counter *child_counter,
-                        struct perf_counter_context *child_ctx)
+                        struct perf_counter_context *child_ctx,
+                        struct task_struct *child)
 {
        struct perf_counter *parent_counter;
 
@@ -3999,7 +4221,7 @@ __perf_counter_exit_task(struct perf_counter *child_counter,
         * counters need to be zapped - but otherwise linger.
         */
        if (parent_counter) {
-               sync_child_counter(child_counter, parent_counter);
+               sync_child_counter(child_counter, child);
                free_counter(child_counter);
        }
 }
@@ -4061,7 +4283,7 @@ void perf_counter_exit_task(struct task_struct *child)
 again:
        list_for_each_entry_safe(child_counter, tmp, &child_ctx->counter_list,
                                 list_entry)
-               __perf_counter_exit_task(child_counter, child_ctx);
+               __perf_counter_exit_task(child_counter, child_ctx, child);
 
        /*
         * If the last counter was a group counter, it will have appended all
index ed97375daae9326ecf2b4864ff9368f1491f642a..bf0014d6a5f0972a1b2352d35a09eb82296164d1 100644 (file)
@@ -23,7 +23,6 @@
 #include <linux/console.h>
 #include <linux/cpu.h>
 #include <linux/freezer.h>
-#include <linux/smp_lock.h>
 #include <scsi/scsi_scan.h>
 
 #include <asm/uaccess.h>
index 61c78b2c07baefd768aed903f482ea08d9672200..082c320e4dbf0a4538b064f55814c72246852877 100644 (file)
@@ -181,8 +181,8 @@ int ptrace_attach(struct task_struct *task)
         * interference; SUID, SGID and LSM creds get determined differently
         * under ptrace.
         */
-       retval = mutex_lock_interruptible(&task->cred_guard_mutex);
-       if (retval < 0)
+       retval = -ERESTARTNOINTR;
+       if (mutex_lock_interruptible(&task->cred_guard_mutex))
                goto out;
 
        task_lock(task);
index 0dccfbba6d267ad59b62314d665a3a91b3104252..7717b95c202782d2af38837fc09dc475a5f845bb 100644 (file)
@@ -1533,7 +1533,7 @@ void __init __rcu_init(void)
        int j;
        struct rcu_node *rnp;
 
-       printk(KERN_WARNING "Experimental hierarchical RCU implementation.\n");
+       printk(KERN_INFO "Hierarchical RCU implementation.\n");
 #ifdef CONFIG_RCU_CPU_STALL_DETECTOR
        printk(KERN_INFO "RCU-based detection of stalled CPUs is enabled.\n");
 #endif /* #ifdef CONFIG_RCU_CPU_STALL_DETECTOR */
@@ -1546,7 +1546,6 @@ void __init __rcu_init(void)
                rcu_cpu_notify(&rcu_nb, CPU_UP_PREPARE, (void *)(long)i);
        /* Register notifier for non-boot CPUs */
        register_cpu_notifier(&rcu_nb);
-       printk(KERN_WARNING "Experimental hierarchical RCU init done.\n");
 }
 
 module_param(blimit, int, 0);
index ac5f3a36923fccf5abaee447a2ab6db6bbe71a4d..78b087221c156640f901b8eb59a9ad716155bc7b 100644 (file)
@@ -787,7 +787,7 @@ static int __init reserve_setup(char *str)
        static struct resource reserve[MAXRESERVE];
 
        for (;;) {
-               int io_start, io_num;
+               unsigned int io_start, io_num;
                int x = reserved;
 
                if (get_option (&str, &io_start) != 2)
index 7c9098d186e6f8e398c0cb9500c1efa2120293e2..98972d366fdc5bd8c2bf6232ee212e90d20be5cb 100644 (file)
@@ -493,6 +493,7 @@ struct rt_rq {
 #endif
 #ifdef CONFIG_SMP
        unsigned long rt_nr_migratory;
+       unsigned long rt_nr_total;
        int overloaded;
        struct plist_head pushable_tasks;
 #endif
@@ -2571,15 +2572,37 @@ static void __sched_fork(struct task_struct *p)
        p->se.avg_wakeup                = sysctl_sched_wakeup_granularity;
 
 #ifdef CONFIG_SCHEDSTATS
-       p->se.wait_start                = 0;
-       p->se.sum_sleep_runtime         = 0;
-       p->se.sleep_start               = 0;
-       p->se.block_start               = 0;
-       p->se.sleep_max                 = 0;
-       p->se.block_max                 = 0;
-       p->se.exec_max                  = 0;
-       p->se.slice_max                 = 0;
-       p->se.wait_max                  = 0;
+       p->se.wait_start                        = 0;
+       p->se.wait_max                          = 0;
+       p->se.wait_count                        = 0;
+       p->se.wait_sum                          = 0;
+
+       p->se.sleep_start                       = 0;
+       p->se.sleep_max                         = 0;
+       p->se.sum_sleep_runtime                 = 0;
+
+       p->se.block_start                       = 0;
+       p->se.block_max                         = 0;
+       p->se.exec_max                          = 0;
+       p->se.slice_max                         = 0;
+
+       p->se.nr_migrations_cold                = 0;
+       p->se.nr_failed_migrations_affine       = 0;
+       p->se.nr_failed_migrations_running      = 0;
+       p->se.nr_failed_migrations_hot          = 0;
+       p->se.nr_forced_migrations              = 0;
+       p->se.nr_forced2_migrations             = 0;
+
+       p->se.nr_wakeups                        = 0;
+       p->se.nr_wakeups_sync                   = 0;
+       p->se.nr_wakeups_migrate                = 0;
+       p->se.nr_wakeups_local                  = 0;
+       p->se.nr_wakeups_remote                 = 0;
+       p->se.nr_wakeups_affine                 = 0;
+       p->se.nr_wakeups_affine_attempts        = 0;
+       p->se.nr_wakeups_passive                = 0;
+       p->se.nr_wakeups_idle                   = 0;
+
 #endif
 
        INIT_LIST_HEAD(&p->rt.run_list);
@@ -6541,6 +6564,11 @@ SYSCALL_DEFINE0(sched_yield)
        return 0;
 }
 
+static inline int should_resched(void)
+{
+       return need_resched() && !(preempt_count() & PREEMPT_ACTIVE);
+}
+
 static void __cond_resched(void)
 {
 #ifdef CONFIG_DEBUG_SPINLOCK_SLEEP
@@ -6560,8 +6588,7 @@ static void __cond_resched(void)
 
 int __sched _cond_resched(void)
 {
-       if (need_resched() && !(preempt_count() & PREEMPT_ACTIVE) &&
-                                       system_state == SYSTEM_RUNNING) {
+       if (should_resched()) {
                __cond_resched();
                return 1;
        }
@@ -6579,12 +6606,12 @@ EXPORT_SYMBOL(_cond_resched);
  */
 int cond_resched_lock(spinlock_t *lock)
 {
-       int resched = need_resched() && system_state == SYSTEM_RUNNING;
+       int resched = should_resched();
        int ret = 0;
 
        if (spin_needbreak(lock) || resched) {
                spin_unlock(lock);
-               if (resched && need_resched())
+               if (resched)
                        __cond_resched();
                else
                        cpu_relax();
@@ -6599,7 +6626,7 @@ int __sched cond_resched_softirq(void)
 {
        BUG_ON(!in_softirq());
 
-       if (need_resched() && system_state == SYSTEM_RUNNING) {
+       if (should_resched()) {
                local_bh_enable();
                __cond_resched();
                local_bh_disable();
@@ -9070,7 +9097,7 @@ static void init_rt_rq(struct rt_rq *rt_rq, struct rq *rq)
 #ifdef CONFIG_SMP
        rt_rq->rt_nr_migratory = 0;
        rt_rq->overloaded = 0;
-       plist_head_init(&rq->rt.pushable_tasks, &rq->lock);
+       plist_head_init(&rt_rq->pushable_tasks, &rq->lock);
 #endif
 
        rt_rq->rt_time = 0;
index ba7fd6e9556f892dd941ecdd9e77be225929c251..7c248dc30f4199c5f945ace89b286808153d22bf 100644 (file)
@@ -687,7 +687,8 @@ place_entity(struct cfs_rq *cfs_rq, struct sched_entity *se, int initial)
                         * all of which have the same weight.
                         */
                        if (sched_feat(NORMALIZED_SLEEPER) &&
-                                       task_of(se)->policy != SCHED_IDLE)
+                                       (!entity_is_task(se) ||
+                                        task_of(se)->policy != SCHED_IDLE))
                                thresh = calc_delta_fair(thresh, se);
 
                        vruntime -= thresh;
index 9bf0d2a7304569a87ba4aa0c919bbb2531c39c06..3918e01994e0a92bd734d22eebef7047e0a17a57 100644 (file)
@@ -10,6 +10,8 @@ static inline struct task_struct *rt_task_of(struct sched_rt_entity *rt_se)
 
 #ifdef CONFIG_RT_GROUP_SCHED
 
+#define rt_entity_is_task(rt_se) (!(rt_se)->my_q)
+
 static inline struct rq *rq_of_rt_rq(struct rt_rq *rt_rq)
 {
        return rt_rq->rq;
@@ -22,6 +24,8 @@ static inline struct rt_rq *rt_rq_of_se(struct sched_rt_entity *rt_se)
 
 #else /* CONFIG_RT_GROUP_SCHED */
 
+#define rt_entity_is_task(rt_se) (1)
+
 static inline struct rq *rq_of_rt_rq(struct rt_rq *rt_rq)
 {
        return container_of(rt_rq, struct rq, rt);
@@ -73,7 +77,7 @@ static inline void rt_clear_overload(struct rq *rq)
 
 static void update_rt_migration(struct rt_rq *rt_rq)
 {
-       if (rt_rq->rt_nr_migratory && (rt_rq->rt_nr_running > 1)) {
+       if (rt_rq->rt_nr_migratory && rt_rq->rt_nr_total > 1) {
                if (!rt_rq->overloaded) {
                        rt_set_overload(rq_of_rt_rq(rt_rq));
                        rt_rq->overloaded = 1;
@@ -86,6 +90,12 @@ static void update_rt_migration(struct rt_rq *rt_rq)
 
 static void inc_rt_migration(struct sched_rt_entity *rt_se, struct rt_rq *rt_rq)
 {
+       if (!rt_entity_is_task(rt_se))
+               return;
+
+       rt_rq = &rq_of_rt_rq(rt_rq)->rt;
+
+       rt_rq->rt_nr_total++;
        if (rt_se->nr_cpus_allowed > 1)
                rt_rq->rt_nr_migratory++;
 
@@ -94,6 +104,12 @@ static void inc_rt_migration(struct sched_rt_entity *rt_se, struct rt_rq *rt_rq)
 
 static void dec_rt_migration(struct sched_rt_entity *rt_se, struct rt_rq *rt_rq)
 {
+       if (!rt_entity_is_task(rt_se))
+               return;
+
+       rt_rq = &rq_of_rt_rq(rt_rq)->rt;
+
+       rt_rq->rt_nr_total--;
        if (rt_se->nr_cpus_allowed > 1)
                rt_rq->rt_nr_migratory--;
 
index 62e4ff9968b5fe64a06c9f8735af10d3b6a304b9..98e02328c67de053dc55bdee746ca381e526660e 100644 (file)
@@ -335,7 +335,10 @@ static struct ctl_table kern_table[] = {
                .data           = &sysctl_timer_migration,
                .maxlen         = sizeof(unsigned int),
                .mode           = 0644,
-               .proc_handler   = &proc_dointvec,
+               .proc_handler   = &proc_dointvec_minmax,
+               .strategy       = &sysctl_intvec,
+               .extra1         = &zero,
+               .extra2         = &one,
        },
 #endif
        {
@@ -743,6 +746,14 @@ static struct ctl_table kern_table[] = {
                .mode           = 0644,
                .proc_handler   = &proc_dointvec,
        },
+       {
+               .ctl_name       = CTL_UNNUMBERED,
+               .procname       = "panic_on_io_nmi",
+               .data           = &panic_on_io_nmi,
+               .maxlen         = sizeof(int),
+               .mode           = 0644,
+               .proc_handler   = &proc_dointvec,
+       },
        {
                .ctl_name       = KERN_BOOTLOADER_TYPE,
                .procname       = "bootloader_type",
index 1ad6dd46111920d10c5d83f2f90c1aeeb81ca66d..a6dcd67b041d200fc61f2b2de06890e8a5c65443 100644 (file)
@@ -254,15 +254,4 @@ void clockevents_notify(unsigned long reason, void *arg)
        spin_unlock(&clockevents_lock);
 }
 EXPORT_SYMBOL_GPL(clockevents_notify);
-
-ktime_t clockevents_get_next_event(int cpu)
-{
-       struct tick_device *td;
-       struct clock_event_device *dev;
-
-       td = &per_cpu(tick_cpu_device, cpu);
-       dev = td->evtdev;
-
-       return dev->next_event;
-}
 #endif
index c994530d166da4fde2bed268f7a3ecfe661e93a8..4cde8b9c716f39b778ab7dfe5ead8985c0eb2c97 100644 (file)
@@ -96,7 +96,7 @@ static DEFINE_MUTEX(show_mutex);
 /*
  * Collection status, active/inactive:
  */
-static int __read_mostly active;
+int __read_mostly timer_stats_active;
 
 /*
  * Beginning/end timestamps of measurement:
@@ -242,7 +242,7 @@ void timer_stats_update_stats(void *timer, pid_t pid, void *startf,
        struct entry *entry, input;
        unsigned long flags;
 
-       if (likely(!active))
+       if (likely(!timer_stats_active))
                return;
 
        lock = &per_cpu(lookup_lock, raw_smp_processor_id());
@@ -254,7 +254,7 @@ void timer_stats_update_stats(void *timer, pid_t pid, void *startf,
        input.timer_flag = timer_flag;
 
        spin_lock_irqsave(lock, flags);
-       if (!active)
+       if (!timer_stats_active)
                goto out_unlock;
 
        entry = tstat_lookup(&input, comm);
@@ -290,7 +290,7 @@ static int tstats_show(struct seq_file *m, void *v)
        /*
         * If still active then calculate up to now:
         */
-       if (active)
+       if (timer_stats_active)
                time_stop = ktime_get();
 
        time = ktime_sub(time_stop, time_start);
@@ -368,18 +368,18 @@ static ssize_t tstats_write(struct file *file, const char __user *buf,
        mutex_lock(&show_mutex);
        switch (ctl[0]) {
        case '0':
-               if (active) {
-                       active = 0;
+               if (timer_stats_active) {
+                       timer_stats_active = 0;
                        time_stop = ktime_get();
                        sync_access();
                }
                break;
        case '1':
-               if (!active) {
+               if (!timer_stats_active) {
                        reset_entries();
                        time_start = ktime_get();
                        smp_mb();
-                       active = 1;
+                       timer_stats_active = 1;
                }
                break;
        default:
index 54d3912f8cadd497d09546ad8b9b1ba42369634d..0b36b9e5cc8b4e27f6adf89de403885cfe8a6687 100644 (file)
@@ -380,6 +380,8 @@ static void timer_stats_account_timer(struct timer_list *timer)
 {
        unsigned int flag = 0;
 
+       if (likely(!timer->start_site))
+               return;
        if (unlikely(tbase_get_deferrable(timer->base)))
                flag |= TIMER_STATS_FLAG_DEFERRABLE;
 
index 39af8af6fc302c981226ab8c8f277026b319ca4a..1090b0aed9bac6135d359e0cb07317085e6145d6 100644 (file)
@@ -22,6 +22,7 @@
 #include <linux/init.h>
 #include <linux/mutex.h>
 #include <linux/debugfs.h>
+#include <linux/smp_lock.h>
 #include <linux/time.h>
 #include <linux/uaccess.h>
 
index 80a97a51442d20eb9a8e177223b9bca33c64ca51..6227dc806377b98dfa64498f0af75416412d671c 100644 (file)
@@ -768,7 +768,7 @@ static struct tracer_stat function_stats __initdata = {
        .stat_show      = function_stat_show
 };
 
-static void ftrace_profile_debugfs(struct dentry *d_tracer)
+static __init void ftrace_profile_debugfs(struct dentry *d_tracer)
 {
        struct ftrace_profile_stat *stat;
        struct dentry *entry;
@@ -786,7 +786,6 @@ static void ftrace_profile_debugfs(struct dentry *d_tracer)
                         * The files created are permanent, if something happens
                         * we still do not free memory.
                         */
-                       kfree(stat);
                        WARN(1,
                             "Could not allocate stat file for cpu %d\n",
                             cpu);
@@ -813,7 +812,7 @@ static void ftrace_profile_debugfs(struct dentry *d_tracer)
 }
 
 #else /* CONFIG_FUNCTION_PROFILER */
-static void ftrace_profile_debugfs(struct dentry *d_tracer)
+static __init void ftrace_profile_debugfs(struct dentry *d_tracer)
 {
 }
 #endif /* CONFIG_FUNCTION_PROFILER */
index b591f7a1bd7b883ef2c4a4a2dc76d7e0d305c899..60a49488b791befc8bd6f7f3ee9875d4dcdc3251 100644 (file)
@@ -17,6 +17,7 @@
 #include <linux/writeback.h>
 #include <linux/kallsyms.h>
 #include <linux/seq_file.h>
+#include <linux/smp_lock.h>
 #include <linux/notifier.h>
 #include <linux/irqflags.h>
 #include <linux/debugfs.h>
index b53dc994dfb622040635d325aec2190d06de33d1..5b01b94518fcf15cc36646b6d2b859ed64a072e6 100644 (file)
@@ -361,7 +361,7 @@ ftrace_trace_onoff_callback(char *glob, char *cmd, char *param, int enable)
  out_reg:
        ret = register_ftrace_function_probe(glob, ops, count);
 
-       return ret;
+       return ret < 0 ? ret : 0;
 }
 
 static struct ftrace_func_command ftrace_traceon_cmd = {
index 7938f3ae93e3dbe9d898e037c47027c4908a8d94..e0c2545622e8f7617b3e32bcb8c3df235aa3a929 100644 (file)
@@ -27,8 +27,7 @@ void trace_print_seq(struct seq_file *m, struct trace_seq *s)
 {
        int len = s->len >= PAGE_SIZE ? PAGE_SIZE - 1 : s->len;
 
-       s->buffer[len] = 0;
-       seq_puts(m, s->buffer);
+       seq_write(m, s->buffer, len);
 
        trace_seq_init(s);
 }
index 4c32b1a1a06e393ad5d8844cdbefa00994965c2a..12327b2bb785c256a59cb864a2c2b8976c33e5aa 100644 (file)
@@ -359,6 +359,18 @@ config DEBUG_KMEMLEAK
          In order to access the kmemleak file, debugfs needs to be
          mounted (usually at /sys/kernel/debug).
 
+config DEBUG_KMEMLEAK_EARLY_LOG_SIZE
+       int "Maximum kmemleak early log entries"
+       depends on DEBUG_KMEMLEAK
+       range 200 2000
+       default 400
+       help
+         Kmemleak must track all the memory allocations to avoid
+         reporting false positives. Since memory may be allocated or
+         freed before kmemleak is initialised, an early log buffer is
+         used to store these actions. If kmemleak reports "early log
+         buffer exceeded", please increase this value.
+
 config DEBUG_KMEMLEAK_TEST
        tristate "Simple test for the kernel memory leak detector"
        depends on DEBUG_KMEMLEAK
index 3b93129a968c73b1d6eeff421abb76b38bc668dd..65b0d99b6d0aa8f7219741e731394d1514b1706e 100644 (file)
@@ -716,7 +716,7 @@ void dma_debug_init(u32 num_entries)
 
        for (i = 0; i < HASH_SIZE; ++i) {
                INIT_LIST_HEAD(&dma_entry_hash[i].list);
-               dma_entry_hash[i].lock = SPIN_LOCK_UNLOCKED;
+               spin_lock_init(&dma_entry_hash[i].lock);
        }
 
        if (dma_debug_fs_init() != 0) {
@@ -856,22 +856,21 @@ static void check_for_stack(struct device *dev, void *addr)
                                "stack [addr=%p]\n", addr);
 }
 
-static inline bool overlap(void *addr, u64 size, void *start, void *end)
+static inline bool overlap(void *addr, unsigned long len, void *start, void *end)
 {
-       void *addr2 = (char *)addr + size;
+       unsigned long a1 = (unsigned long)addr;
+       unsigned long b1 = a1 + len;
+       unsigned long a2 = (unsigned long)start;
+       unsigned long b2 = (unsigned long)end;
 
-       return ((addr >= start && addr < end) ||
-               (addr2 >= start && addr2 < end) ||
-               ((addr < start) && (addr2 >= end)));
+       return !(b1 <= a2 || a1 >= b2);
 }
 
-static void check_for_illegal_area(struct device *dev, void *addr, u64 size)
+static void check_for_illegal_area(struct device *dev, void *addr, unsigned long len)
 {
-       if (overlap(addr, size, _text, _etext) ||
-           overlap(addr, size, __start_rodata, __end_rodata))
-               err_printk(dev, NULL, "DMA-API: device driver maps "
-                               "memory from kernel text or rodata "
-                               "[addr=%p] [size=%llu]\n", addr, size);
+       if (overlap(addr, len, _text, _etext) ||
+           overlap(addr, len, __start_rodata, __end_rodata))
+               err_printk(dev, NULL, "DMA-API: device driver maps memory from kernel text or rodata [addr=%p] [len=%lu]\n", addr, len);
 }
 
 static void check_sync(struct device *dev,
@@ -969,7 +968,8 @@ void debug_dma_map_page(struct device *dev, struct page *page, size_t offset,
                entry->type = dma_debug_single;
 
        if (!PageHighMem(page)) {
-               void *addr = ((char *)page_address(page)) + offset;
+               void *addr = page_address(page) + offset;
+
                check_for_stack(dev, addr);
                check_for_illegal_area(dev, addr, size);
        }
index 493b468a503541fd65b64872eece6fb7228e36fa..c86edd2442944ec2532bdde3e2087b56519a224d 100644 (file)
@@ -283,7 +283,6 @@ static wait_queue_head_t congestion_wqh[2] = {
                __WAIT_QUEUE_HEAD_INITIALIZER(congestion_wqh[1])
        };
 
-
 void clear_bdi_congested(struct backing_dev_info *bdi, int sync)
 {
        enum bdi_state bit;
@@ -308,18 +307,18 @@ EXPORT_SYMBOL(set_bdi_congested);
 
 /**
  * congestion_wait - wait for a backing_dev to become uncongested
- * @rw: READ or WRITE
+ * @sync: SYNC or ASYNC IO
  * @timeout: timeout in jiffies
  *
  * Waits for up to @timeout jiffies for a backing_dev (any backing_dev) to exit
  * write congestion.  If no backing_devs are congested then just wait for the
  * next write to be completed.
  */
-long congestion_wait(int rw, long timeout)
+long congestion_wait(int sync, long timeout)
 {
        long ret;
        DEFINE_WAIT(wait);
-       wait_queue_head_t *wqh = &congestion_wqh[rw];
+       wait_queue_head_t *wqh = &congestion_wqh[sync];
 
        prepare_to_wait(wqh, &wait, TASK_UNINTERRUPTIBLE);
        ret = io_schedule_timeout(timeout);
index d2a9ce952768fbcb88f559077d9878cb15e1d03c..701740c9e81bdf967062b340e53cff8b7913427a 100644 (file)
@@ -12,6 +12,7 @@
 #include <linux/pfn.h>
 #include <linux/bootmem.h>
 #include <linux/module.h>
+#include <linux/kmemleak.h>
 
 #include <asm/bug.h>
 #include <asm/io.h>
@@ -335,6 +336,8 @@ void __init free_bootmem_node(pg_data_t *pgdat, unsigned long physaddr,
 {
        unsigned long start, end;
 
+       kmemleak_free_part(__va(physaddr), size);
+
        start = PFN_UP(physaddr);
        end = PFN_DOWN(physaddr + size);
 
@@ -354,6 +357,8 @@ void __init free_bootmem(unsigned long addr, unsigned long size)
 {
        unsigned long start, end;
 
+       kmemleak_free_part(__va(addr), size);
+
        start = PFN_UP(addr);
        end = PFN_DOWN(addr + size);
 
@@ -516,6 +521,7 @@ find_block:
                region = phys_to_virt(PFN_PHYS(bdata->node_min_pfn) +
                                start_off);
                memset(region, 0, size);
+               kmemleak_alloc(region, size, 1, 0);
                return region;
        }
 
index b1f0885dda2275b09baa7d82205f6529efd093b1..3df063706f53e6d579ec0acabace3503a471ba29 100644 (file)
@@ -86,10 +86,12 @@ show_pools(struct device *dev, struct device_attribute *attr, char *buf)
                unsigned pages = 0;
                unsigned blocks = 0;
 
+               spin_lock_irq(&pool->lock);
                list_for_each_entry(page, &pool->page_list, page_list) {
                        pages++;
                        blocks += page->in_use;
                }
+               spin_unlock_irq(&pool->lock);
 
                /* per-pool info, no real statistics yet */
                temp = scnprintf(next, size, "%-16s %4u %4Zu %4Zu %2u\n",
index 22396713feb9684647aa5c90a3b18e6661b2f798..ccea3b665c12571ac32d6d936b3862e103f7b995 100644 (file)
@@ -2272,6 +2272,7 @@ again:
                pagefault_enable();
                flush_dcache_page(page);
 
+               mark_page_accessed(page);
                status = a_ops->write_end(file, mapping, pos, bytes, copied,
                                                page, fsdata);
                if (unlikely(status < 0))
index c96f2c8700aa687f5726eaed2e26a5ccd9d35d87..5aabd41ffb8fafbea9fd3a507d9ac5ef6a679e25 100644 (file)
  *   scanned. This list is only modified during a scanning episode when the
  *   scan_mutex is held. At the end of a scan, the gray_list is always empty.
  *   Note that the kmemleak_object.use_count is incremented when an object is
- *   added to the gray_list and therefore cannot be freed
- * - kmemleak_mutex (mutex): prevents multiple users of the "kmemleak" debugfs
- *   file together with modifications to the memory scanning parameters
- *   including the scan_thread pointer
+ *   added to the gray_list and therefore cannot be freed. This mutex also
+ *   prevents multiple users of the "kmemleak" debugfs file together with
+ *   modifications to the memory scanning parameters including the scan_thread
+ *   pointer
  *
  * The kmemleak_object structures have a use_count incremented or decremented
  * using the get_object()/put_object() functions. When the use_count becomes
  * Kmemleak configuration and common defines.
  */
 #define MAX_TRACE              16      /* stack trace length */
-#define REPORTS_NR             50      /* maximum number of reported leaks */
 #define MSECS_MIN_AGE          5000    /* minimum object age for reporting */
-#define MSECS_SCAN_YIELD       10      /* CPU yielding period */
 #define SECS_FIRST_SCAN                60      /* delay before the first scan */
 #define SECS_SCAN_WAIT         600     /* subsequent auto scanning delay */
+#define GRAY_LIST_PASSES       25      /* maximum number of gray list scans */
 
 #define BYTES_PER_POINTER      sizeof(void *)
 
@@ -159,6 +158,8 @@ struct kmemleak_object {
 #define OBJECT_REPORTED                (1 << 1)
 /* flag set to not scan the object */
 #define OBJECT_NO_SCAN         (1 << 2)
+/* flag set on newly allocated objects */
+#define OBJECT_NEW             (1 << 3)
 
 /* the list of all allocated objects */
 static LIST_HEAD(object_list);
@@ -186,22 +187,16 @@ static atomic_t kmemleak_error = ATOMIC_INIT(0);
 static unsigned long min_addr = ULONG_MAX;
 static unsigned long max_addr;
 
-/* used for yielding the CPU to other tasks during scanning */
-static unsigned long next_scan_yield;
 static struct task_struct *scan_thread;
-static unsigned long jiffies_scan_yield;
+/* used to avoid reporting of recently allocated objects */
 static unsigned long jiffies_min_age;
+static unsigned long jiffies_last_scan;
 /* delay between automatic memory scannings */
 static signed long jiffies_scan_wait;
 /* enables or disables the task stacks scanning */
-static int kmemleak_stack_scan;
-/* mutex protecting the memory scanning */
+static int kmemleak_stack_scan = 1;
+/* protects the memory scanning, parameters and debug/kmemleak file access */
 static DEFINE_MUTEX(scan_mutex);
-/* mutex protecting the access to the /sys/kernel/debug/kmemleak file */
-static DEFINE_MUTEX(kmemleak_mutex);
-
-/* number of leaks reported (for limitation purposes) */
-static int reported_leaks;
 
 /*
  * Early object allocation/freeing logging. Kmemleak is initialized after the
@@ -215,6 +210,7 @@ static int reported_leaks;
 enum {
        KMEMLEAK_ALLOC,
        KMEMLEAK_FREE,
+       KMEMLEAK_FREE_PART,
        KMEMLEAK_NOT_LEAK,
        KMEMLEAK_IGNORE,
        KMEMLEAK_SCAN_AREA,
@@ -235,7 +231,7 @@ struct early_log {
 };
 
 /* early logging buffer and current position */
-static struct early_log early_log[200];
+static struct early_log early_log[CONFIG_DEBUG_KMEMLEAK_EARLY_LOG_SIZE];
 static int crt_early_log;
 
 static void kmemleak_disable(void);
@@ -278,13 +274,9 @@ static int color_gray(const struct kmemleak_object *object)
        return object->min_count != -1 && object->count >= object->min_count;
 }
 
-/*
- * Objects are considered referenced if their color is gray and they have not
- * been deleted.
- */
-static int referenced_object(struct kmemleak_object *object)
+static int color_black(const struct kmemleak_object *object)
 {
-       return (object->flags & OBJECT_ALLOCATED) && color_gray(object);
+       return object->min_count == -1;
 }
 
 /*
@@ -295,42 +287,28 @@ static int referenced_object(struct kmemleak_object *object)
 static int unreferenced_object(struct kmemleak_object *object)
 {
        return (object->flags & OBJECT_ALLOCATED) && color_white(object) &&
-               time_is_before_eq_jiffies(object->jiffies + jiffies_min_age);
+               time_before_eq(object->jiffies + jiffies_min_age,
+                              jiffies_last_scan);
 }
 
 /*
- * Printing of the (un)referenced objects information, either to the seq file
- * or to the kernel log. The print_referenced/print_unreferenced functions
- * must be called with the object->lock held.
+ * Printing of the unreferenced objects information to the seq file. The
+ * print_unreferenced function must be called with the object->lock held.
  */
-#define print_helper(seq, x...)        do {    \
-       struct seq_file *s = (seq);     \
-       if (s)                          \
-               seq_printf(s, x);       \
-       else                            \
-               pr_info(x);             \
-} while (0)
-
-static void print_referenced(struct kmemleak_object *object)
-{
-       pr_info("referenced object 0x%08lx (size %zu)\n",
-               object->pointer, object->size);
-}
-
 static void print_unreferenced(struct seq_file *seq,
                               struct kmemleak_object *object)
 {
        int i;
 
-       print_helper(seq, "unreferenced object 0x%08lx (size %zu):\n",
-                    object->pointer, object->size);
-       print_helper(seq, "  comm \"%s\", pid %d, jiffies %lu\n",
-                    object->comm, object->pid, object->jiffies);
-       print_helper(seq, "  backtrace:\n");
+       seq_printf(seq, "unreferenced object 0x%08lx (size %zu):\n",
+                  object->pointer, object->size);
+       seq_printf(seq, "  comm \"%s\", pid %d, jiffies %lu\n",
+                  object->comm, object->pid, object->jiffies);
+       seq_printf(seq, "  backtrace:\n");
 
        for (i = 0; i < object->trace_len; i++) {
                void *ptr = (void *)object->trace[i];
-               print_helper(seq, "    [<%p>] %pS\n", ptr, ptr);
+               seq_printf(seq, "    [<%p>] %pS\n", ptr, ptr);
        }
 }
 
@@ -478,7 +456,7 @@ static void create_object(unsigned long ptr, size_t size, int min_count,
        INIT_HLIST_HEAD(&object->area_list);
        spin_lock_init(&object->lock);
        atomic_set(&object->use_count, 1);
-       object->flags = OBJECT_ALLOCATED;
+       object->flags = OBJECT_ALLOCATED | OBJECT_NEW;
        object->pointer = ptr;
        object->size = size;
        object->min_count = min_count;
@@ -546,38 +524,86 @@ out:
  * Remove the metadata (struct kmemleak_object) for a memory block from the
  * object_list and object_tree_root and decrement its use_count.
  */
-static void delete_object(unsigned long ptr)
+static void __delete_object(struct kmemleak_object *object)
 {
        unsigned long flags;
-       struct kmemleak_object *object;
 
        write_lock_irqsave(&kmemleak_lock, flags);
-       object = lookup_object(ptr, 0);
-       if (!object) {
-               kmemleak_warn("Freeing unknown object at 0x%08lx\n",
-                             ptr);
-               write_unlock_irqrestore(&kmemleak_lock, flags);
-               return;
-       }
        prio_tree_remove(&object_tree_root, &object->tree_node);
        list_del_rcu(&object->object_list);
        write_unlock_irqrestore(&kmemleak_lock, flags);
 
        WARN_ON(!(object->flags & OBJECT_ALLOCATED));
-       WARN_ON(atomic_read(&object->use_count) < 1);
+       WARN_ON(atomic_read(&object->use_count) < 2);
 
        /*
         * Locking here also ensures that the corresponding memory block
         * cannot be freed when it is being scanned.
         */
        spin_lock_irqsave(&object->lock, flags);
-       if (object->flags & OBJECT_REPORTED)
-               print_referenced(object);
        object->flags &= ~OBJECT_ALLOCATED;
        spin_unlock_irqrestore(&object->lock, flags);
        put_object(object);
 }
 
+/*
+ * Look up the metadata (struct kmemleak_object) corresponding to ptr and
+ * delete it.
+ */
+static void delete_object_full(unsigned long ptr)
+{
+       struct kmemleak_object *object;
+
+       object = find_and_get_object(ptr, 0);
+       if (!object) {
+#ifdef DEBUG
+               kmemleak_warn("Freeing unknown object at 0x%08lx\n",
+                             ptr);
+#endif
+               return;
+       }
+       __delete_object(object);
+       put_object(object);
+}
+
+/*
+ * Look up the metadata (struct kmemleak_object) corresponding to ptr and
+ * delete it. If the memory block is partially freed, the function may create
+ * additional metadata for the remaining parts of the block.
+ */
+static void delete_object_part(unsigned long ptr, size_t size)
+{
+       struct kmemleak_object *object;
+       unsigned long start, end;
+
+       object = find_and_get_object(ptr, 1);
+       if (!object) {
+#ifdef DEBUG
+               kmemleak_warn("Partially freeing unknown object at 0x%08lx "
+                             "(size %zu)\n", ptr, size);
+#endif
+               return;
+       }
+       __delete_object(object);
+
+       /*
+        * Create one or two objects that may result from the memory block
+        * split. Note that partial freeing is only done by free_bootmem() and
+        * this happens before kmemleak_init() is called. The path below is
+        * only executed during early log recording in kmemleak_init(), so
+        * GFP_KERNEL is enough.
+        */
+       start = object->pointer;
+       end = object->pointer + object->size;
+       if (ptr > start)
+               create_object(start, ptr - start, object->min_count,
+                             GFP_KERNEL);
+       if (ptr + size < end)
+               create_object(ptr + size, end - ptr - size, object->min_count,
+                             GFP_KERNEL);
+
+       put_object(object);
+}
 /*
  * Make a object permanently as gray-colored so that it can no longer be
  * reported as a leak. This is used in general to mark a false positive.
@@ -696,7 +722,8 @@ static void log_early(int op_type, const void *ptr, size_t size,
        struct early_log *log;
 
        if (crt_early_log >= ARRAY_SIZE(early_log)) {
-               kmemleak_stop("Early log buffer exceeded\n");
+               pr_warning("Early log buffer exceeded\n");
+               kmemleak_disable();
                return;
        }
 
@@ -741,12 +768,27 @@ void kmemleak_free(const void *ptr)
        pr_debug("%s(0x%p)\n", __func__, ptr);
 
        if (atomic_read(&kmemleak_enabled) && ptr && !IS_ERR(ptr))
-               delete_object((unsigned long)ptr);
+               delete_object_full((unsigned long)ptr);
        else if (atomic_read(&kmemleak_early_log))
                log_early(KMEMLEAK_FREE, ptr, 0, 0, 0, 0);
 }
 EXPORT_SYMBOL_GPL(kmemleak_free);
 
+/*
+ * Partial memory freeing function callback. This function is usually called
+ * from bootmem allocator when (part of) a memory block is freed.
+ */
+void kmemleak_free_part(const void *ptr, size_t size)
+{
+       pr_debug("%s(0x%p)\n", __func__, ptr);
+
+       if (atomic_read(&kmemleak_enabled) && ptr && !IS_ERR(ptr))
+               delete_object_part((unsigned long)ptr, size);
+       else if (atomic_read(&kmemleak_early_log))
+               log_early(KMEMLEAK_FREE_PART, ptr, size, 0, 0, 0);
+}
+EXPORT_SYMBOL_GPL(kmemleak_free_part);
+
 /*
  * Mark an already allocated memory block as a false positive. This will cause
  * the block to no longer be reported as leak and always be scanned.
@@ -807,21 +849,6 @@ void kmemleak_no_scan(const void *ptr)
 }
 EXPORT_SYMBOL(kmemleak_no_scan);
 
-/*
- * Yield the CPU so that other tasks get a chance to run.  The yielding is
- * rate-limited to avoid excessive number of calls to the schedule() function
- * during memory scanning.
- */
-static void scan_yield(void)
-{
-       might_sleep();
-
-       if (time_is_before_eq_jiffies(next_scan_yield)) {
-               schedule();
-               next_scan_yield = jiffies + jiffies_scan_yield;
-       }
-}
-
 /*
  * Memory scanning is a long process and it needs to be interruptable. This
  * function checks whether such interrupt condition occured.
@@ -848,7 +875,7 @@ static int scan_should_stop(void)
  * found to the gray list.
  */
 static void scan_block(void *_start, void *_end,
-                      struct kmemleak_object *scanned)
+                      struct kmemleak_object *scanned, int allow_resched)
 {
        unsigned long *ptr;
        unsigned long *start = PTR_ALIGN(_start, BYTES_PER_POINTER);
@@ -859,18 +886,11 @@ static void scan_block(void *_start, void *_end,
                unsigned long pointer = *ptr;
                struct kmemleak_object *object;
 
+               if (allow_resched)
+                       cond_resched();
                if (scan_should_stop())
                        break;
 
-               /*
-                * When scanning a memory block with a corresponding
-                * kmemleak_object, the CPU yielding is handled in the calling
-                * code since it holds the object->lock to avoid the block
-                * freeing.
-                */
-               if (!scanned)
-                       scan_yield();
-
                object = find_and_get_object(pointer, 1);
                if (!object)
                        continue;
@@ -931,12 +951,12 @@ static void scan_object(struct kmemleak_object *object)
                goto out;
        if (hlist_empty(&object->area_list))
                scan_block((void *)object->pointer,
-                          (void *)(object->pointer + object->size), object);
+                          (void *)(object->pointer + object->size), object, 0);
        else
                hlist_for_each_entry(area, elem, &object->area_list, node)
                        scan_block((void *)(object->pointer + area->offset),
                                   (void *)(object->pointer + area->offset
-                                           + area->length), object);
+                                           + area->length), object, 0);
 out:
        spin_unlock_irqrestore(&object->lock, flags);
 }
@@ -952,6 +972,10 @@ static void kmemleak_scan(void)
        struct kmemleak_object *object, *tmp;
        struct task_struct *task;
        int i;
+       int new_leaks = 0;
+       int gray_list_pass = 0;
+
+       jiffies_last_scan = jiffies;
 
        /* prepare the kmemleak_object's */
        rcu_read_lock();
@@ -970,6 +994,7 @@ static void kmemleak_scan(void)
 #endif
                /* reset the reference count (whiten the object) */
                object->count = 0;
+               object->flags &= ~OBJECT_NEW;
                if (color_gray(object) && get_object(object))
                        list_add_tail(&object->gray_list, &gray_list);
 
@@ -978,14 +1003,14 @@ static void kmemleak_scan(void)
        rcu_read_unlock();
 
        /* data/bss scanning */
-       scan_block(_sdata, _edata, NULL);
-       scan_block(__bss_start, __bss_stop, NULL);
+       scan_block(_sdata, _edata, NULL, 1);
+       scan_block(__bss_start, __bss_stop, NULL, 1);
 
 #ifdef CONFIG_SMP
        /* per-cpu sections scanning */
        for_each_possible_cpu(i)
                scan_block(__per_cpu_start + per_cpu_offset(i),
-                          __per_cpu_end + per_cpu_offset(i), NULL);
+                          __per_cpu_end + per_cpu_offset(i), NULL, 1);
 #endif
 
        /*
@@ -1007,7 +1032,7 @@ static void kmemleak_scan(void)
                        /* only scan if page is in use */
                        if (page_count(page) == 0)
                                continue;
-                       scan_block(page, page + 1, NULL);
+                       scan_block(page, page + 1, NULL, 1);
                }
        }
 
@@ -1019,7 +1044,8 @@ static void kmemleak_scan(void)
                read_lock(&tasklist_lock);
                for_each_process(task)
                        scan_block(task_stack_page(task),
-                                  task_stack_page(task) + THREAD_SIZE, NULL);
+                                  task_stack_page(task) + THREAD_SIZE,
+                                  NULL, 0);
                read_unlock(&tasklist_lock);
        }
 
@@ -1031,9 +1057,10 @@ static void kmemleak_scan(void)
         * kmemleak objects cannot be freed from outside the loop because their
         * use_count was increased.
         */
+repeat:
        object = list_entry(gray_list.next, typeof(*object), gray_list);
        while (&object->gray_list != &gray_list) {
-               scan_yield();
+               cond_resched();
 
                /* may add new objects to the list */
                if (!scan_should_stop())
@@ -1048,7 +1075,59 @@ static void kmemleak_scan(void)
 
                object = tmp;
        }
+
+       if (scan_should_stop() || ++gray_list_pass >= GRAY_LIST_PASSES)
+               goto scan_end;
+
+       /*
+        * Check for new objects allocated during this scanning and add them
+        * to the gray list.
+        */
+       rcu_read_lock();
+       list_for_each_entry_rcu(object, &object_list, object_list) {
+               spin_lock_irqsave(&object->lock, flags);
+               if ((object->flags & OBJECT_NEW) && !color_black(object) &&
+                   get_object(object)) {
+                       object->flags &= ~OBJECT_NEW;
+                       list_add_tail(&object->gray_list, &gray_list);
+               }
+               spin_unlock_irqrestore(&object->lock, flags);
+       }
+       rcu_read_unlock();
+
+       if (!list_empty(&gray_list))
+               goto repeat;
+
+scan_end:
        WARN_ON(!list_empty(&gray_list));
+
+       /*
+        * If scanning was stopped or new objects were being allocated at a
+        * higher rate than gray list scanning, do not report any new
+        * unreferenced objects.
+        */
+       if (scan_should_stop() || gray_list_pass >= GRAY_LIST_PASSES)
+               return;
+
+       /*
+        * Scanning result reporting.
+        */
+       rcu_read_lock();
+       list_for_each_entry_rcu(object, &object_list, object_list) {
+               spin_lock_irqsave(&object->lock, flags);
+               if (unreferenced_object(object) &&
+                   !(object->flags & OBJECT_REPORTED)) {
+                       object->flags |= OBJECT_REPORTED;
+                       new_leaks++;
+               }
+               spin_unlock_irqrestore(&object->lock, flags);
+       }
+       rcu_read_unlock();
+
+       if (new_leaks)
+               pr_info("%d new suspected memory leaks (see "
+                       "/sys/kernel/debug/kmemleak)\n", new_leaks);
+
 }
 
 /*
@@ -1060,6 +1139,7 @@ static int kmemleak_scan_thread(void *arg)
        static int first_run = 1;
 
        pr_info("Automatic memory scanning thread started\n");
+       set_user_nice(current, 10);
 
        /*
         * Wait before the first scan to allow the system to fully initialize.
@@ -1070,36 +1150,12 @@ static int kmemleak_scan_thread(void *arg)
        }
 
        while (!kthread_should_stop()) {
-               struct kmemleak_object *object;
                signed long timeout = jiffies_scan_wait;
 
                mutex_lock(&scan_mutex);
-
                kmemleak_scan();
-               reported_leaks = 0;
-
-               rcu_read_lock();
-               list_for_each_entry_rcu(object, &object_list, object_list) {
-                       unsigned long flags;
-
-                       if (reported_leaks >= REPORTS_NR)
-                               break;
-                       spin_lock_irqsave(&object->lock, flags);
-                       if (!(object->flags & OBJECT_REPORTED) &&
-                           unreferenced_object(object)) {
-                               print_unreferenced(NULL, object);
-                               object->flags |= OBJECT_REPORTED;
-                               reported_leaks++;
-                       } else if ((object->flags & OBJECT_REPORTED) &&
-                                  referenced_object(object)) {
-                               print_referenced(object);
-                               object->flags &= ~OBJECT_REPORTED;
-                       }
-                       spin_unlock_irqrestore(&object->lock, flags);
-               }
-               rcu_read_unlock();
-
                mutex_unlock(&scan_mutex);
+
                /* wait before the next scan */
                while (timeout && !kthread_should_stop())
                        timeout = schedule_timeout_interruptible(timeout);
@@ -1112,7 +1168,7 @@ static int kmemleak_scan_thread(void *arg)
 
 /*
  * Start the automatic memory scanning thread. This function must be called
- * with the kmemleak_mutex held.
+ * with the scan_mutex held.
  */
 void start_scan_thread(void)
 {
@@ -1127,7 +1183,7 @@ void start_scan_thread(void)
 
 /*
  * Stop the automatic memory scanning thread. This function must be called
- * with the kmemleak_mutex held.
+ * with the scan_mutex held.
  */
 void stop_scan_thread(void)
 {
@@ -1146,13 +1202,11 @@ static void *kmemleak_seq_start(struct seq_file *seq, loff_t *pos)
 {
        struct kmemleak_object *object;
        loff_t n = *pos;
+       int err;
 
-       if (!n) {
-               kmemleak_scan();
-               reported_leaks = 0;
-       }
-       if (reported_leaks >= REPORTS_NR)
-               return NULL;
+       err = mutex_lock_interruptible(&scan_mutex);
+       if (err < 0)
+               return ERR_PTR(err);
 
        rcu_read_lock();
        list_for_each_entry_rcu(object, &object_list, object_list) {
@@ -1178,8 +1232,6 @@ static void *kmemleak_seq_next(struct seq_file *seq, void *v, loff_t *pos)
        struct list_head *n = &prev_obj->object_list;
 
        ++(*pos);
-       if (reported_leaks >= REPORTS_NR)
-               goto out;
 
        rcu_read_lock();
        list_for_each_continue_rcu(n, &object_list) {
@@ -1188,7 +1240,7 @@ static void *kmemleak_seq_next(struct seq_file *seq, void *v, loff_t *pos)
                        break;
        }
        rcu_read_unlock();
-out:
+
        put_object(prev_obj);
        return next_obj;
 }
@@ -1198,8 +1250,15 @@ out:
  */
 static void kmemleak_seq_stop(struct seq_file *seq, void *v)
 {
-       if (v)
-               put_object(v);
+       if (!IS_ERR(v)) {
+               /*
+                * kmemleak_seq_start may return ERR_PTR if the scan_mutex
+                * waiting was interrupted, so only release it if !IS_ERR.
+                */
+               mutex_unlock(&scan_mutex);
+               if (v)
+                       put_object(v);
+       }
 }
 
 /*
@@ -1211,11 +1270,8 @@ static int kmemleak_seq_show(struct seq_file *seq, void *v)
        unsigned long flags;
 
        spin_lock_irqsave(&object->lock, flags);
-       if (!unreferenced_object(object))
-               goto out;
-       print_unreferenced(seq, object);
-       reported_leaks++;
-out:
+       if ((object->flags & OBJECT_REPORTED) && unreferenced_object(object))
+               print_unreferenced(seq, object);
        spin_unlock_irqrestore(&object->lock, flags);
        return 0;
 }
@@ -1229,43 +1285,15 @@ static const struct seq_operations kmemleak_seq_ops = {
 
 static int kmemleak_open(struct inode *inode, struct file *file)
 {
-       int ret = 0;
-
        if (!atomic_read(&kmemleak_enabled))
                return -EBUSY;
 
-       ret = mutex_lock_interruptible(&kmemleak_mutex);
-       if (ret < 0)
-               goto out;
-       if (file->f_mode & FMODE_READ) {
-               ret = mutex_lock_interruptible(&scan_mutex);
-               if (ret < 0)
-                       goto kmemleak_unlock;
-               ret = seq_open(file, &kmemleak_seq_ops);
-               if (ret < 0)
-                       goto scan_unlock;
-       }
-       return ret;
-
-scan_unlock:
-       mutex_unlock(&scan_mutex);
-kmemleak_unlock:
-       mutex_unlock(&kmemleak_mutex);
-out:
-       return ret;
+       return seq_open(file, &kmemleak_seq_ops);
 }
 
 static int kmemleak_release(struct inode *inode, struct file *file)
 {
-       int ret = 0;
-
-       if (file->f_mode & FMODE_READ) {
-               seq_release(inode, file);
-               mutex_unlock(&scan_mutex);
-       }
-       mutex_unlock(&kmemleak_mutex);
-
-       return ret;
+       return seq_release(inode, file);
 }
 
 /*
@@ -1278,21 +1306,24 @@ static int kmemleak_release(struct inode *inode, struct file *file)
  *   scan=off  - stop the automatic memory scanning thread
  *   scan=...  - set the automatic memory scanning period in seconds (0 to
  *               disable it)
+ *   scan      - trigger a memory scan
  */
 static ssize_t kmemleak_write(struct file *file, const char __user *user_buf,
                              size_t size, loff_t *ppos)
 {
        char buf[64];
        int buf_size;
-
-       if (!atomic_read(&kmemleak_enabled))
-               return -EBUSY;
+       int ret;
 
        buf_size = min(size, (sizeof(buf) - 1));
        if (strncpy_from_user(buf, user_buf, buf_size) < 0)
                return -EFAULT;
        buf[buf_size] = 0;
 
+       ret = mutex_lock_interruptible(&scan_mutex);
+       if (ret < 0)
+               return ret;
+
        if (strncmp(buf, "off", 3) == 0)
                kmemleak_disable();
        else if (strncmp(buf, "stack=on", 8) == 0)
@@ -1305,18 +1336,24 @@ static ssize_t kmemleak_write(struct file *file, const char __user *user_buf,
                stop_scan_thread();
        else if (strncmp(buf, "scan=", 5) == 0) {
                unsigned long secs;
-               int err;
 
-               err = strict_strtoul(buf + 5, 0, &secs);
-               if (err < 0)
-                       return err;
+               ret = strict_strtoul(buf + 5, 0, &secs);
+               if (ret < 0)
+                       goto out;
                stop_scan_thread();
                if (secs) {
                        jiffies_scan_wait = msecs_to_jiffies(secs * 1000);
                        start_scan_thread();
                }
-       } else
-               return -EINVAL;
+       } else if (strncmp(buf, "scan", 4) == 0)
+               kmemleak_scan();
+       else
+               ret = -EINVAL;
+
+out:
+       mutex_unlock(&scan_mutex);
+       if (ret < 0)
+               return ret;
 
        /* ignore the rest of the buffer, only one command at a time */
        *ppos += size;
@@ -1340,14 +1377,12 @@ static int kmemleak_cleanup_thread(void *arg)
 {
        struct kmemleak_object *object;
 
-       mutex_lock(&kmemleak_mutex);
+       mutex_lock(&scan_mutex);
        stop_scan_thread();
-       mutex_unlock(&kmemleak_mutex);
 
-       mutex_lock(&scan_mutex);
        rcu_read_lock();
        list_for_each_entry_rcu(object, &object_list, object_list)
-               delete_object(object->pointer);
+               delete_object_full(object->pointer);
        rcu_read_unlock();
        mutex_unlock(&scan_mutex);
 
@@ -1411,7 +1446,6 @@ void __init kmemleak_init(void)
        int i;
        unsigned long flags;
 
-       jiffies_scan_yield = msecs_to_jiffies(MSECS_SCAN_YIELD);
        jiffies_min_age = msecs_to_jiffies(MSECS_MIN_AGE);
        jiffies_scan_wait = msecs_to_jiffies(SECS_SCAN_WAIT * 1000);
 
@@ -1443,6 +1477,9 @@ void __init kmemleak_init(void)
                case KMEMLEAK_FREE:
                        kmemleak_free(log->ptr);
                        break;
+               case KMEMLEAK_FREE_PART:
+                       kmemleak_free_part(log->ptr, log->size);
+                       break;
                case KMEMLEAK_NOT_LEAK:
                        kmemleak_not_leak(log->ptr);
                        break;
@@ -1486,9 +1523,9 @@ static int __init kmemleak_late_init(void)
                                     &kmemleak_fops);
        if (!dentry)
                pr_warning("Failed to create the debugfs kmemleak file\n");
-       mutex_lock(&kmemleak_mutex);
+       mutex_lock(&scan_mutex);
        start_scan_thread();
-       mutex_unlock(&kmemleak_mutex);
+       mutex_unlock(&scan_mutex);
 
        pr_info("Kernel memory leak detector initialized\n");
 
index e2fa20dadf408e2d38e6b5a4a61ed4fb9febd3a1..e717964cb5a0cc2e73ddc520a5d76d726cb6593a 100644 (file)
@@ -1973,7 +1973,7 @@ try_to_free:
                if (!progress) {
                        nr_retries--;
                        /* maybe some writeback is necessary */
-                       congestion_wait(WRITE, HZ/10);
+                       congestion_wait(BLK_RW_ASYNC, HZ/10);
                }
 
        }
index f46ac18ba2311e7e63de8d61b2b7353b283f7b72..65216194eb8daec69843ef672d73725eeb37e0ca 100644 (file)
@@ -1207,8 +1207,8 @@ static inline int use_zero_page(struct vm_area_struct *vma)
 
 
 int __get_user_pages(struct task_struct *tsk, struct mm_struct *mm,
-                    unsigned long start, int len, int flags,
-               struct page **pages, struct vm_area_struct **vmas)
+                    unsigned long start, int nr_pages, int flags,
+                    struct page **pages, struct vm_area_struct **vmas)
 {
        int i;
        unsigned int vm_flags = 0;
@@ -1217,7 +1217,7 @@ int __get_user_pages(struct task_struct *tsk, struct mm_struct *mm,
        int ignore = !!(flags & GUP_FLAGS_IGNORE_VMA_PERMISSIONS);
        int ignore_sigkill = !!(flags & GUP_FLAGS_IGNORE_SIGKILL);
 
-       if (len <= 0)
+       if (nr_pages <= 0)
                return 0;
        /* 
         * Require read or write permissions.
@@ -1269,7 +1269,7 @@ int __get_user_pages(struct task_struct *tsk, struct mm_struct *mm,
                                vmas[i] = gate_vma;
                        i++;
                        start += PAGE_SIZE;
-                       len--;
+                       nr_pages--;
                        continue;
                }
 
@@ -1280,7 +1280,7 @@ int __get_user_pages(struct task_struct *tsk, struct mm_struct *mm,
 
                if (is_vm_hugetlb_page(vma)) {
                        i = follow_hugetlb_page(mm, vma, pages, vmas,
-                                               &start, &len, i, write);
+                                               &start, &nr_pages, i, write);
                        continue;
                }
 
@@ -1357,9 +1357,9 @@ int __get_user_pages(struct task_struct *tsk, struct mm_struct *mm,
                                vmas[i] = vma;
                        i++;
                        start += PAGE_SIZE;
-                       len--;
-               } while (len && start < vma->vm_end);
-       } while (len);
+                       nr_pages--;
+               } while (nr_pages && start < vma->vm_end);
+       } while (nr_pages);
        return i;
 }
 
@@ -1368,7 +1368,7 @@ int __get_user_pages(struct task_struct *tsk, struct mm_struct *mm,
  * @tsk:       task_struct of target task
  * @mm:                mm_struct of target mm
  * @start:     starting user address
- * @len:       number of pages from start to pin
+ * @nr_pages:  number of pages from start to pin
  * @write:     whether pages will be written to by the caller
  * @force:     whether to force write access even if user mapping is
  *             readonly. This will result in the page being COWed even
@@ -1380,7 +1380,7 @@ int __get_user_pages(struct task_struct *tsk, struct mm_struct *mm,
  *             Or NULL if the caller does not require them.
  *
  * Returns number of pages pinned. This may be fewer than the number
- * requested. If len is 0 or negative, returns 0. If no pages
+ * requested. If nr_pages is 0 or negative, returns 0. If no pages
  * were pinned, returns -errno. Each page returned must be released
  * with a put_page() call when it is finished with. vmas will only
  * remain valid while mmap_sem is held.
@@ -1414,7 +1414,7 @@ int __get_user_pages(struct task_struct *tsk, struct mm_struct *mm,
  * See also get_user_pages_fast, for performance critical applications.
  */
 int get_user_pages(struct task_struct *tsk, struct mm_struct *mm,
-               unsigned long start, int len, int write, int force,
+               unsigned long start, int nr_pages, int write, int force,
                struct page **pages, struct vm_area_struct **vmas)
 {
        int flags = 0;
@@ -1424,9 +1424,7 @@ int get_user_pages(struct task_struct *tsk, struct mm_struct *mm,
        if (force)
                flags |= GUP_FLAGS_FORCE;
 
-       return __get_user_pages(tsk, mm,
-                               start, len, flags,
-                               pages, vmas);
+       return __get_user_pages(tsk, mm, start, nr_pages, flags, pages, vmas);
 }
 
 EXPORT_SYMBOL(get_user_pages);
index 2fd2ad5da98e5d82e751b76f4e6369c57f20e6db..53cab10fece40a3f5835604e62754818de0e1e7c 100644 (file)
@@ -173,8 +173,8 @@ unsigned int kobjsize(const void *objp)
 }
 
 int __get_user_pages(struct task_struct *tsk, struct mm_struct *mm,
-                    unsigned long start, int len, int flags,
-               struct page **pages, struct vm_area_struct **vmas)
+                    unsigned long start, int nr_pages, int flags,
+                    struct page **pages, struct vm_area_struct **vmas)
 {
        struct vm_area_struct *vma;
        unsigned long vm_flags;
@@ -189,7 +189,7 @@ int __get_user_pages(struct task_struct *tsk, struct mm_struct *mm,
        vm_flags  = write ? (VM_WRITE | VM_MAYWRITE) : (VM_READ | VM_MAYREAD);
        vm_flags &= force ? (VM_MAYREAD | VM_MAYWRITE) : (VM_READ | VM_WRITE);
 
-       for (i = 0; i < len; i++) {
+       for (i = 0; i < nr_pages; i++) {
                vma = find_vma(mm, start);
                if (!vma)
                        goto finish_or_fault;
@@ -224,7 +224,7 @@ finish_or_fault:
  * - don't permit access to VMAs that don't support it, such as I/O mappings
  */
 int get_user_pages(struct task_struct *tsk, struct mm_struct *mm,
-       unsigned long start, int len, int write, int force,
+       unsigned long start, int nr_pages, int write, int force,
        struct page **pages, struct vm_area_struct **vmas)
 {
        int flags = 0;
@@ -234,12 +234,31 @@ int get_user_pages(struct task_struct *tsk, struct mm_struct *mm,
        if (force)
                flags |= GUP_FLAGS_FORCE;
 
-       return __get_user_pages(tsk, mm,
-                               start, len, flags,
-                               pages, vmas);
+       return __get_user_pages(tsk, mm, start, nr_pages, flags, pages, vmas);
 }
 EXPORT_SYMBOL(get_user_pages);
 
+/**
+ * follow_pfn - look up PFN at a user virtual address
+ * @vma: memory mapping
+ * @address: user virtual address
+ * @pfn: location to store found PFN
+ *
+ * Only IO mappings and raw PFN mappings are allowed.
+ *
+ * Returns zero and the pfn at @pfn on success, -ve otherwise.
+ */
+int follow_pfn(struct vm_area_struct *vma, unsigned long address,
+       unsigned long *pfn)
+{
+       if (!(vma->vm_flags & (VM_IO | VM_PFNMAP)))
+               return -EINVAL;
+
+       *pfn = address >> PAGE_SHIFT;
+       return 0;
+}
+EXPORT_SYMBOL(follow_pfn);
+
 DEFINE_RWLOCK(vmlist_lock);
 struct vm_struct *vmlist;
 
index 7b0dcea4935bea292730ce7d1926fc0ea00df062..81627ebcd313fcd5ee3545a0996d2802fab36085 100644 (file)
@@ -541,8 +541,11 @@ static void balance_dirty_pages(struct address_space *mapping)
                 * filesystems (i.e. NFS) in which data may have been
                 * written to the server's write cache, but has not yet
                 * been flushed to permanent storage.
+                * Only move pages to writeback if this bdi is over its
+                * threshold otherwise wait until the disk writes catch
+                * up.
                 */
-               if (bdi_nr_reclaimable) {
+               if (bdi_nr_reclaimable > bdi_thresh) {
                        writeback_inodes(&wbc);
                        pages_written += write_chunk - wbc.nr_to_write;
                        get_dirty_limits(&background_thresh, &dirty_thresh,
@@ -572,7 +575,7 @@ static void balance_dirty_pages(struct address_space *mapping)
                if (pages_written >= write_chunk)
                        break;          /* We've done our duty */
 
-               congestion_wait(WRITE, HZ/10);
+               congestion_wait(BLK_RW_ASYNC, HZ/10);
        }
 
        if (bdi_nr_reclaimable + bdi_nr_writeback < bdi_thresh &&
@@ -666,7 +669,7 @@ void throttle_vm_writeout(gfp_t gfp_mask)
                 if (global_page_state(NR_UNSTABLE_NFS) +
                        global_page_state(NR_WRITEBACK) <= dirty_thresh)
                                break;
-                congestion_wait(WRITE, HZ/10);
+                congestion_wait(BLK_RW_ASYNC, HZ/10);
 
                /*
                 * The caller might hold locks which can prevent IO completion
@@ -712,7 +715,7 @@ static void background_writeout(unsigned long _min_pages)
                if (wbc.nr_to_write > 0 || wbc.pages_skipped > 0) {
                        /* Wrote less than expected */
                        if (wbc.encountered_congestion || wbc.more_io)
-                               congestion_wait(WRITE, HZ/10);
+                               congestion_wait(BLK_RW_ASYNC, HZ/10);
                        else
                                break;
                }
@@ -784,7 +787,7 @@ static void wb_kupdate(unsigned long arg)
                writeback_inodes(&wbc);
                if (wbc.nr_to_write > 0) {
                        if (wbc.encountered_congestion || wbc.more_io)
-                               congestion_wait(WRITE, HZ/10);
+                               congestion_wait(BLK_RW_ASYNC, HZ/10);
                        else
                                break;  /* All the old data is written */
                }
index aecc9cdfdfce9111ef55de91a38afb164d6fad87..caa92689aac951e5d6c08c89993526898bc695d1 100644 (file)
@@ -1153,10 +1153,10 @@ again:
                         * properly detect and handle allocation failures.
                         *
                         * We most definitely don't want callers attempting to
-                        * allocate greater than single-page units with
+                        * allocate greater than order-1 page units with
                         * __GFP_NOFAIL.
                         */
-                       WARN_ON_ONCE(order > 0);
+                       WARN_ON_ONCE(order > 1);
                }
                spin_lock_irqsave(&zone->lock, flags);
                page = __rmqueue(zone, order, migratetype);
@@ -1666,7 +1666,7 @@ __alloc_pages_high_priority(gfp_t gfp_mask, unsigned int order,
                        preferred_zone, migratetype);
 
                if (!page && gfp_mask & __GFP_NOFAIL)
-                       congestion_wait(WRITE, HZ/50);
+                       congestion_wait(BLK_RW_ASYNC, HZ/50);
        } while (!page && (gfp_mask & __GFP_NOFAIL));
 
        return page;
@@ -1831,7 +1831,7 @@ rebalance:
        pages_reclaimed += did_some_progress;
        if (should_alloc_retry(gfp_mask, order, pages_reclaimed)) {
                /* Wait for some write requests to complete then retry */
-               congestion_wait(WRITE, HZ/50);
+               congestion_wait(BLK_RW_ASYNC, HZ/50);
                goto rebalance;
        }
 
@@ -1983,7 +1983,7 @@ void *alloc_pages_exact(size_t size, gfp_t gfp_mask)
                unsigned long alloc_end = addr + (PAGE_SIZE << order);
                unsigned long used = addr + PAGE_ALIGN(size);
 
-               split_page(virt_to_page(addr), order);
+               split_page(virt_to_page((void *)addr), order);
                while (used < alloc_end) {
                        free_page(used);
                        used += PAGE_SIZE;
@@ -4032,6 +4032,8 @@ static void __init find_zone_movable_pfns_for_nodes(unsigned long *movable_pfn)
        int i, nid;
        unsigned long usable_startpfn;
        unsigned long kernelcore_node, kernelcore_remaining;
+       /* save the state before borrow the nodemask */
+       nodemask_t saved_node_state = node_states[N_HIGH_MEMORY];
        unsigned long totalpages = early_calculate_totalpages();
        int usable_nodes = nodes_weight(node_states[N_HIGH_MEMORY]);
 
@@ -4059,7 +4061,7 @@ static void __init find_zone_movable_pfns_for_nodes(unsigned long *movable_pfn)
 
        /* If kernelcore was not specified, there is no ZONE_MOVABLE */
        if (!required_kernelcore)
-               return;
+               goto out;
 
        /* usable_startpfn is the lowest possible pfn ZONE_MOVABLE can be at */
        find_usable_zone_for_movable();
@@ -4158,6 +4160,10 @@ restart:
        for (nid = 0; nid < MAX_NUMNODES; nid++)
                zone_movable_pfn[nid] =
                        roundup(zone_movable_pfn[nid], MAX_ORDER_NR_PAGES);
+
+out:
+       /* restore the node_state */
+       node_states[N_HIGH_MEMORY] = saved_node_state;
 }
 
 /* Any regular memory on that node ? */
@@ -4242,11 +4248,6 @@ void __init free_area_init_nodes(unsigned long *max_zone_pfn)
                                                early_node_map[i].start_pfn,
                                                early_node_map[i].end_pfn);
 
-       /*
-        * find_zone_movable_pfns_for_nodes/early_calculate_totalpages init
-        * that node_mask, clear it at first
-        */
-       nodes_clear(node_states[N_HIGH_MEMORY]);
        /* Initialise every node */
        mminit_verify_pageflags_layout();
        setup_nr_node_ids();
@@ -4744,8 +4745,10 @@ void *__init alloc_large_system_hash(const char *tablename,
                         * some pages at the end of hash table which
                         * alloc_pages_exact() automatically does
                         */
-                       if (get_order(size) < MAX_ORDER)
+                       if (get_order(size) < MAX_ORDER) {
                                table = alloc_pages_exact(size, GFP_ATOMIC);
+                               kmemleak_alloc(table, size, 1, GFP_ATOMIC);
+                       }
                }
        } while (!table && size > PAGE_SIZE && --log2qty);
 
@@ -4763,16 +4766,6 @@ void *__init alloc_large_system_hash(const char *tablename,
        if (_hash_mask)
                *_hash_mask = (1 << log2qty) - 1;
 
-       /*
-        * If hashdist is set, the table allocation is done with __vmalloc()
-        * which invokes the kmemleak_alloc() callback. This function may also
-        * be called before the slab and kmemleak are initialised when
-        * kmemleak simply buffers the request to be executed later
-        * (GFP_ATOMIC flag ignored in this case).
-        */
-       if (!hashdist)
-               kmemleak_alloc(table, size, 1, GFP_ATOMIC);
-
        return table;
 }
 
index c0b2c1a76e81c280398b27ed310b1e03500e3a23..b70f2acd88535a63c0c6ffd9f41dff6e0b51da9d 100644 (file)
@@ -549,14 +549,14 @@ static void pcpu_free_area(struct pcpu_chunk *chunk, int freeme)
  * @chunk: chunk of interest
  * @page_start: page index of the first page to unmap
  * @page_end: page index of the last page to unmap + 1
- * @flush: whether to flush cache and tlb or not
+ * @flush_tlb: whether to flush tlb or not
  *
  * For each cpu, unmap pages [@page_start,@page_end) out of @chunk.
  * If @flush is true, vcache is flushed before unmapping and tlb
  * after.
  */
 static void pcpu_unmap(struct pcpu_chunk *chunk, int page_start, int page_end,
-                      bool flush)
+                      bool flush_tlb)
 {
        unsigned int last = num_possible_cpus() - 1;
        unsigned int cpu;
@@ -569,9 +569,8 @@ static void pcpu_unmap(struct pcpu_chunk *chunk, int page_start, int page_end,
         * the whole region at once rather than doing it for each cpu.
         * This could be an overkill but is more scalable.
         */
-       if (flush)
-               flush_cache_vunmap(pcpu_chunk_addr(chunk, 0, page_start),
-                                  pcpu_chunk_addr(chunk, last, page_end));
+       flush_cache_vunmap(pcpu_chunk_addr(chunk, 0, page_start),
+                          pcpu_chunk_addr(chunk, last, page_end));
 
        for_each_possible_cpu(cpu)
                unmap_kernel_range_noflush(
@@ -579,7 +578,7 @@ static void pcpu_unmap(struct pcpu_chunk *chunk, int page_start, int page_end,
                                (page_end - page_start) << PAGE_SHIFT);
 
        /* ditto as flush_cache_vunmap() */
-       if (flush)
+       if (flush_tlb)
                flush_tlb_kernel_range(pcpu_chunk_addr(chunk, 0, page_start),
                                       pcpu_chunk_addr(chunk, last, page_end));
 }
@@ -1234,6 +1233,7 @@ static struct page * __init pcpue_get_page(unsigned int cpu, int pageno)
 ssize_t __init pcpu_embed_first_chunk(size_t static_size, size_t reserved_size,
                                      ssize_t dyn_size, ssize_t unit_size)
 {
+       size_t chunk_size;
        unsigned int cpu;
 
        /* determine parameters and allocate */
@@ -1248,11 +1248,15 @@ ssize_t __init pcpu_embed_first_chunk(size_t static_size, size_t reserved_size,
        } else
                pcpue_unit_size = max_t(size_t, pcpue_size, PCPU_MIN_UNIT_SIZE);
 
-       pcpue_ptr = __alloc_bootmem_nopanic(
-                                       num_possible_cpus() * pcpue_unit_size,
-                                       PAGE_SIZE, __pa(MAX_DMA_ADDRESS));
-       if (!pcpue_ptr)
+       chunk_size = pcpue_unit_size * num_possible_cpus();
+
+       pcpue_ptr = __alloc_bootmem_nopanic(chunk_size, PAGE_SIZE,
+                                           __pa(MAX_DMA_ADDRESS));
+       if (!pcpue_ptr) {
+               pr_warning("PERCPU: failed to allocate %zu bytes for "
+                          "embedding\n", chunk_size);
                return -ENOMEM;
+       }
 
        /* return the leftover and copy */
        for_each_possible_cpu(cpu) {
index e89d7ec18eda46d42abf68c3994db0e33cfded06..d713239ce2ce72be6097a1ad478ce1b04798773d 100644 (file)
@@ -1558,6 +1558,7 @@ static struct inode *shmem_get_inode(struct super_block *sb, int mode,
                spin_lock_init(&info->lock);
                info->flags = flags & VM_NORESERVE;
                INIT_LIST_HEAD(&info->swaplist);
+               cache_no_acl(inode);
 
                switch (mode & S_IFMT) {
                default:
@@ -2388,7 +2389,6 @@ static void shmem_destroy_inode(struct inode *inode)
                /* only struct inode is valid if it's an inline symlink */
                mpol_free_shared_policy(&SHMEM_I(inode)->policy);
        }
-       shmem_acl_destroy_inode(inode);
        kmem_cache_free(shmem_inode_cachep, SHMEM_I(inode));
 }
 
@@ -2397,10 +2397,6 @@ static void init_once(void *foo)
        struct shmem_inode_info *p = (struct shmem_inode_info *) foo;
 
        inode_init_once(&p->vfs_inode);
-#ifdef CONFIG_TMPFS_POSIX_ACL
-       p->i_acl = NULL;
-       p->i_default_acl = NULL;
-#endif
 }
 
 static int init_inodecache(void)
index 8e5aadd7dcd6aef09f581d3ff925072cc494b0c0..606a8e757a422e83d2c714dfb9423c4f40b727dd 100644 (file)
@@ -22,11 +22,11 @@ shmem_get_acl(struct inode *inode, int type)
        spin_lock(&inode->i_lock);
        switch(type) {
                case ACL_TYPE_ACCESS:
-                       acl = posix_acl_dup(SHMEM_I(inode)->i_acl);
+                       acl = posix_acl_dup(inode->i_acl);
                        break;
 
                case ACL_TYPE_DEFAULT:
-                       acl = posix_acl_dup(SHMEM_I(inode)->i_default_acl);
+                       acl = posix_acl_dup(inode->i_default_acl);
                        break;
        }
        spin_unlock(&inode->i_lock);
@@ -45,13 +45,13 @@ shmem_set_acl(struct inode *inode, int type, struct posix_acl *acl)
        spin_lock(&inode->i_lock);
        switch(type) {
                case ACL_TYPE_ACCESS:
-                       free = SHMEM_I(inode)->i_acl;
-                       SHMEM_I(inode)->i_acl = posix_acl_dup(acl);
+                       free = inode->i_acl;
+                       inode->i_acl = posix_acl_dup(acl);
                        break;
 
                case ACL_TYPE_DEFAULT:
-                       free = SHMEM_I(inode)->i_default_acl;
-                       SHMEM_I(inode)->i_default_acl = posix_acl_dup(acl);
+                       free = inode->i_default_acl;
+                       inode->i_default_acl = posix_acl_dup(acl);
                        break;
        }
        spin_unlock(&inode->i_lock);
@@ -154,23 +154,6 @@ shmem_acl_init(struct inode *inode, struct inode *dir)
        return generic_acl_init(inode, dir, &shmem_acl_ops);
 }
 
-/**
- * shmem_acl_destroy_inode  -  destroy acls hanging off the in-memory inode
- *
- * This is done before destroying the actual inode.
- */
-
-void
-shmem_acl_destroy_inode(struct inode *inode)
-{
-       if (SHMEM_I(inode)->i_acl)
-               posix_acl_release(SHMEM_I(inode)->i_acl);
-       SHMEM_I(inode)->i_acl = NULL;
-       if (SHMEM_I(inode)->i_default_acl)
-               posix_acl_release(SHMEM_I(inode)->i_default_acl);
-       SHMEM_I(inode)->i_default_acl = NULL;
-}
-
 /**
  * shmem_check_acl  -  check_acl() callback for generic_permission()
  */
index e74a16e4ced605111bd0f84154273c038bb0d9e3..7b5d4deacfcd96f79460e3e91d159f22b47dec5f 100644 (file)
--- a/mm/slab.c
+++ b/mm/slab.c
@@ -1544,9 +1544,6 @@ void __init kmem_cache_init(void)
        }
 
        g_cpucache_up = EARLY;
-
-       /* Annotate slab for lockdep -- annotate the malloc caches */
-       init_lock_keys();
 }
 
 void __init kmem_cache_init_late(void)
@@ -1563,6 +1560,9 @@ void __init kmem_cache_init_late(void)
        /* Done! */
        g_cpucache_up = FULL;
 
+       /* Annotate slab for lockdep -- annotate the malloc caches */
+       init_lock_keys();
+
        /*
         * Register a cpu startup notifier callback that initializes
         * cpu_cache_get for all new cpus
@@ -2547,7 +2547,7 @@ void kmem_cache_destroy(struct kmem_cache *cachep)
        }
 
        if (unlikely(cachep->flags & SLAB_DESTROY_BY_RCU))
-               synchronize_rcu();
+               rcu_barrier();
 
        __kmem_cache_destroy(cachep);
        mutex_unlock(&cache_chain_mutex);
index c78742defdc6477ef7474ebc1fc8117173aaabfc..9641da3d5e58dfca1d7c79dbef99760364fa98b2 100644 (file)
--- a/mm/slob.c
+++ b/mm/slob.c
@@ -595,6 +595,8 @@ EXPORT_SYMBOL(kmem_cache_create);
 void kmem_cache_destroy(struct kmem_cache *c)
 {
        kmemleak_free(c);
+       if (c->flags & SLAB_DESTROY_BY_RCU)
+               rcu_barrier();
        slob_free(c, sizeof(struct kmem_cache));
 }
 EXPORT_SYMBOL(kmem_cache_destroy);
index ce62b770e2fc5399e53dcc9c91ec5220820fc977..b9f1491a58a184e80769fc541d3d2958cb4919ed 100644 (file)
--- a/mm/slub.c
+++ b/mm/slub.c
@@ -21,7 +21,6 @@
 #include <linux/kmemcheck.h>
 #include <linux/cpu.h>
 #include <linux/cpuset.h>
-#include <linux/kmemleak.h>
 #include <linux/mempolicy.h>
 #include <linux/ctype.h>
 #include <linux/debugobjects.h>
@@ -1085,11 +1084,17 @@ static struct page *allocate_slab(struct kmem_cache *s, gfp_t flags, int node)
 {
        struct page *page;
        struct kmem_cache_order_objects oo = s->oo;
+       gfp_t alloc_gfp;
 
        flags |= s->allocflags;
 
-       page = alloc_slab_page(flags | __GFP_NOWARN | __GFP_NORETRY, node,
-                                                                       oo);
+       /*
+        * Let the initial higher-order allocation fail under memory pressure
+        * so we fall-back to the minimum order allocation.
+        */
+       alloc_gfp = (flags | __GFP_NOWARN | __GFP_NORETRY) & ~__GFP_NOFAIL;
+
+       page = alloc_slab_page(alloc_gfp, node, oo);
        if (unlikely(!page)) {
                oo = s->min;
                /*
@@ -2589,6 +2594,8 @@ static inline int kmem_cache_close(struct kmem_cache *s)
  */
 void kmem_cache_destroy(struct kmem_cache *s)
 {
+       if (s->flags & SLAB_DESTROY_BY_RCU)
+               rcu_barrier();
        down_write(&slub_lock);
        s->refcount--;
        if (!s->refcount) {
@@ -2827,13 +2834,15 @@ EXPORT_SYMBOL(__kmalloc);
 static void *kmalloc_large_node(size_t size, gfp_t flags, int node)
 {
        struct page *page;
+       void *ptr = NULL;
 
        flags |= __GFP_COMP | __GFP_NOTRACK;
        page = alloc_pages_node(node, flags, get_order(size));
        if (page)
-               return page_address(page);
-       else
-               return NULL;
+               ptr = page_address(page);
+
+       kmemleak_alloc(ptr, size, 1, flags);
+       return ptr;
 }
 
 #ifdef CONFIG_NUMA
@@ -2918,6 +2927,7 @@ void kfree(const void *x)
        page = virt_to_head_page(x);
        if (unlikely(!PageSlab(page))) {
                BUG_ON(!PageCompound(page));
+               kmemleak_free(x);
                put_page(page);
                return;
        }
index 54155268dfcae49634dc016bb168845600a866a0..dea7abd310980daea1fa6c5a0c850a972fe37a21 100644 (file)
@@ -1104,7 +1104,7 @@ static unsigned long shrink_inactive_list(unsigned long max_scan,
                 */
                if (nr_freed < nr_taken && !current_is_kswapd() &&
                    lumpy_reclaim) {
-                       congestion_wait(WRITE, HZ/10);
+                       congestion_wait(BLK_RW_ASYNC, HZ/10);
 
                        /*
                         * The attempt at page out may have made some
@@ -1721,7 +1721,7 @@ static unsigned long do_try_to_free_pages(struct zonelist *zonelist,
 
                /* Take a nap, wait for some writeback to complete */
                if (sc->nr_scanned && priority < DEF_PRIORITY - 2)
-                       congestion_wait(WRITE, HZ/10);
+                       congestion_wait(BLK_RW_ASYNC, HZ/10);
        }
        /* top priority shrink_zones still had more to do? don't OOM, then */
        if (!sc->all_unreclaimable && scanning_global_lru(sc))
@@ -1960,7 +1960,7 @@ loop_again:
                 * another pass across the zones.
                 */
                if (total_scanned && priority < DEF_PRIORITY - 2)
-                       congestion_wait(WRITE, HZ/10);
+                       congestion_wait(BLK_RW_ASYNC, HZ/10);
 
                /*
                 * We do this so kswapd doesn't build up large priorities for
@@ -2233,7 +2233,7 @@ unsigned long shrink_all_memory(unsigned long nr_pages)
                                goto out;
 
                        if (sc.nr_scanned && prio < DEF_PRIORITY - 2)
-                               congestion_wait(WRITE, HZ / 10);
+                               congestion_wait(BLK_RW_ASYNC, HZ / 10);
                }
        }
 
index a2a1814c7a8d639d6ccd76e9fdd966b7a6431fa6..8c2588e4edc0e3bf4d329661873e1875044cade1 100644 (file)
@@ -735,12 +735,14 @@ static int parse_opts(char *params, struct p9_fd_opts *opts)
                if (!*p)
                        continue;
                token = match_token(p, tokens, args);
-               r = match_int(&args[0], &option);
-               if (r < 0) {
-                       P9_DPRINTK(P9_DEBUG_ERROR,
-                        "integer field, but no integer?\n");
-                       ret = r;
-                       continue;
+               if (token != Opt_err) {
+                       r = match_int(&args[0], &option);
+                       if (r < 0) {
+                               P9_DPRINTK(P9_DEBUG_ERROR,
+                               "integer field, but no integer?\n");
+                               ret = r;
+                               continue;
+                       }
                }
                switch (token) {
                case Opt_port:
index 590b8396362237e62b82965b2f6e95fb1c167591..bfbe13786bb468acfeedb888e8ee4a209c34b2e2 100644 (file)
@@ -54,6 +54,7 @@
 #include <linux/capability.h>
 #include <linux/module.h>
 #include <linux/if_arp.h>
+#include <linux/smp_lock.h>
 #include <linux/termios.h>     /* For TIOCOUTQ/INQ */
 #include <net/datalink.h>
 #include <net/psnap.h>
index c1c97936192c730d8f68431a782f8695c43504a3..8c4d843eb17f46bbec50847aa1352580adcd1c26 100644 (file)
@@ -92,7 +92,7 @@ static void vcc_sock_destruct(struct sock *sk)
 static void vcc_def_wakeup(struct sock *sk)
 {
        read_lock(&sk->sk_callback_lock);
-       if (sk->sk_sleep && waitqueue_active(sk->sk_sleep))
+       if (sk_has_sleeper(sk))
                wake_up(sk->sk_sleep);
        read_unlock(&sk->sk_callback_lock);
 }
@@ -110,7 +110,7 @@ static void vcc_write_space(struct sock *sk)
        read_lock(&sk->sk_callback_lock);
 
        if (vcc_writable(sk)) {
-               if (sk->sk_sleep && waitqueue_active(sk->sk_sleep))
+               if (sk_has_sleeper(sk))
                        wake_up_interruptible(sk->sk_sleep);
 
                sk_wake_async(sk, SOCK_WAKE_SPACE, POLL_OUT);
@@ -594,7 +594,7 @@ unsigned int vcc_poll(struct file *file, struct socket *sock, poll_table *wait)
        struct atm_vcc *vcc;
        unsigned int mask;
 
-       poll_wait(file, sk->sk_sleep, wait);
+       sock_poll_wait(file, sk->sk_sleep, wait);
        mask = 0;
 
        vcc = ATM_SD(sock);
index 5f1d2107a1dd70f7628f18d7649d92e2a1bd9d76..de56d3983de098b11d64f8971d85b8ded8187bf2 100644 (file)
@@ -437,8 +437,7 @@ free:
 int ax25_kiss_rcv(struct sk_buff *skb, struct net_device *dev,
                  struct packet_type *ptype, struct net_device *orig_dev)
 {
-       skb->sk = NULL;         /* Initially we don't know who it's for */
-       skb->destructor = NULL; /* Who initializes this, dammit?! */
+       skb_orphan(skb);
 
        if (!net_eq(dev_net(dev), &init_net)) {
                kfree_skb(skb);
index 9aac5213105aaf031e5ca1fcc993a051800e1475..e1241c76239a96fb3e4d027ba071b640c2904ceb 100644 (file)
@@ -93,7 +93,7 @@ static void __exit br_deinit(void)
 
        unregister_pernet_subsys(&br_net_ops);
 
-       synchronize_net();
+       rcu_barrier(); /* Wait for completion of call_rcu()'s */
 
        br_netfilter_fini();
 #if defined(CONFIG_ATM_LANE) || defined(CONFIG_ATM_LANE_MODULE)
index 58abee1f1df1b044514079f9245dc7c1b96978a3..b0fe69211eefef1e18224fa123d2b13498bffefa 100644 (file)
@@ -712,7 +712,7 @@ unsigned int datagram_poll(struct file *file, struct socket *sock,
        struct sock *sk = sock->sk;
        unsigned int mask;
 
-       poll_wait(file, sk->sk_sleep, wait);
+       sock_poll_wait(file, sk->sk_sleep, wait);
        mask = 0;
 
        /* exceptional events? */
index baf2dc13a34a402aa22af5091bf87d2e1c9f1f16..70c27e0c7c3235a8df94d27f6080248d6b000239 100644 (file)
@@ -2310,8 +2310,6 @@ ncls:
        if (!skb)
                goto out;
 
-       skb_orphan(skb);
-
        type = skb->protocol;
        list_for_each_entry_rcu(ptype,
                        &ptype_base[ntohs(type) & PTYPE_HASH_MASK], list) {
@@ -2825,9 +2823,11 @@ static void net_rx_action(struct softirq_action *h)
                 * move the instance around on the list at-will.
                 */
                if (unlikely(work == weight)) {
-                       if (unlikely(napi_disable_pending(n)))
-                               __napi_complete(n);
-                       else
+                       if (unlikely(napi_disable_pending(n))) {
+                               local_irq_enable();
+                               napi_complete(n);
+                               local_irq_disable();
+                       } else
                                list_move_tail(&n->poll_list, list);
                }
 
index 9675f312830dd762bcd530eee90569de5a89b320..df30feb2fc725b047ef744273e7c506714bbac61 100644 (file)
@@ -740,7 +740,7 @@ int netpoll_setup(struct netpoll *np)
                                       np->name);
                                break;
                        }
-                       cond_resched();
+                       msleep(1);
                }
 
                /* If carrier appears to come up instantly, we don't
index b0ba569bc97361dec5b2619a46ffbeab50331dc2..ba5d2116aea1b4eadb7e72736e8e40b63ff6aa09 100644 (file)
@@ -939,8 +939,23 @@ static struct sock *sk_prot_alloc(struct proto *prot, gfp_t priority,
        struct kmem_cache *slab;
 
        slab = prot->slab;
-       if (slab != NULL)
-               sk = kmem_cache_alloc(slab, priority);
+       if (slab != NULL) {
+               sk = kmem_cache_alloc(slab, priority & ~__GFP_ZERO);
+               if (!sk)
+                       return sk;
+               if (priority & __GFP_ZERO) {
+                       /*
+                        * caches using SLAB_DESTROY_BY_RCU should let
+                        * sk_node.next un-modified. Special care is taken
+                        * when initializing object to zero.
+                        */
+                       if (offsetof(struct sock, sk_node.next) != 0)
+                               memset(sk, 0, offsetof(struct sock, sk_node.next));
+                       memset(&sk->sk_node.pprev, 0,
+                              prot->obj_size - offsetof(struct sock,
+                                                        sk_node.pprev));
+               }
+       }
        else
                sk = kmalloc(prot->obj_size, priority);
 
@@ -1715,7 +1730,7 @@ EXPORT_SYMBOL(sock_no_sendpage);
 static void sock_def_wakeup(struct sock *sk)
 {
        read_lock(&sk->sk_callback_lock);
-       if (sk->sk_sleep && waitqueue_active(sk->sk_sleep))
+       if (sk_has_sleeper(sk))
                wake_up_interruptible_all(sk->sk_sleep);
        read_unlock(&sk->sk_callback_lock);
 }
@@ -1723,7 +1738,7 @@ static void sock_def_wakeup(struct sock *sk)
 static void sock_def_error_report(struct sock *sk)
 {
        read_lock(&sk->sk_callback_lock);
-       if (sk->sk_sleep && waitqueue_active(sk->sk_sleep))
+       if (sk_has_sleeper(sk))
                wake_up_interruptible_poll(sk->sk_sleep, POLLERR);
        sk_wake_async(sk, SOCK_WAKE_IO, POLL_ERR);
        read_unlock(&sk->sk_callback_lock);
@@ -1732,7 +1747,7 @@ static void sock_def_error_report(struct sock *sk)
 static void sock_def_readable(struct sock *sk, int len)
 {
        read_lock(&sk->sk_callback_lock);
-       if (sk->sk_sleep && waitqueue_active(sk->sk_sleep))
+       if (sk_has_sleeper(sk))
                wake_up_interruptible_sync_poll(sk->sk_sleep, POLLIN |
                                                POLLRDNORM | POLLRDBAND);
        sk_wake_async(sk, SOCK_WAKE_WAITD, POLL_IN);
@@ -1747,7 +1762,7 @@ static void sock_def_write_space(struct sock *sk)
         * progress.  --DaveM
         */
        if ((atomic_read(&sk->sk_wmem_alloc) << 1) <= sk->sk_sndbuf) {
-               if (sk->sk_sleep && waitqueue_active(sk->sk_sleep))
+               if (sk_has_sleeper(sk))
                        wake_up_interruptible_sync_poll(sk->sk_sleep, POLLOUT |
                                                POLLWRNORM | POLLWRBAND);
 
index 05ea7440d9e51b6f40e29b7335277c4853b8ca7d..3e70faab29897370b815447f6ab937dee12101b9 100644 (file)
@@ -85,7 +85,7 @@ static inline __u32 dccp_v6_init_sequence(struct sk_buff *skb)
 }
 
 static void dccp_v6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
-                       int type, int code, int offset, __be32 info)
+                       u8 type, u8 code, int offset, __be32 info)
 {
        struct ipv6hdr *hdr = (struct ipv6hdr *)skb->data;
        const struct dccp_hdr *dh = (struct dccp_hdr *)(skb->data + offset);
index c0e88c16d0888b5222ca250c01a27bf3078a7e2a..c96119fda6885fd6b6bdc5487ff5cca7d2dd1574 100644 (file)
@@ -196,7 +196,7 @@ void dccp_write_space(struct sock *sk)
 {
        read_lock(&sk->sk_callback_lock);
 
-       if (sk->sk_sleep && waitqueue_active(sk->sk_sleep))
+       if (sk_has_sleeper(sk))
                wake_up_interruptible(sk->sk_sleep);
        /* Should agree with poll, otherwise some programs break */
        if (sock_writeable(sk))
index 314a1b5c033c88950ddf73eccf30a34bcaf60191..94ca8eaace7d05988059838bd5477831d643b65f 100644 (file)
@@ -311,7 +311,7 @@ unsigned int dccp_poll(struct file *file, struct socket *sock,
        unsigned int mask;
        struct sock *sk = sock->sk;
 
-       poll_wait(file, sk->sk_sleep, wait);
+       sock_poll_wait(file, sk->sk_sleep, wait);
        if (sk->sk_state == DCCP_LISTEN)
                return inet_csk_listen_poll(sk);
 
index d351b8db0df5ceac6f6c566bb82cb9a700d78d2a..77d40289653cf0e739e5893e0e053c2145d6156a 100644 (file)
@@ -2413,6 +2413,8 @@ static void __exit decnet_exit(void)
        proc_net_remove(&init_net, "decnet");
 
        proto_unregister(&dn_proto);
+
+       rcu_barrier_bh(); /* Wait for completion of call_rcu_bh()'s */
 }
 module_exit(decnet_exit);
 #endif
index 4e4d8b5ad03d3b58fe6c0e353e147b2b78fa5144..efe661a9def4db3644d0e8402e2b00295a3cd0c6 100644 (file)
@@ -418,7 +418,7 @@ static int mv88e6xxx_stats_wait(struct dsa_switch *ds)
        int i;
 
        for (i = 0; i < 10; i++) {
-               ret = REG_READ(REG_GLOBAL2, 0x1d);
+               ret = REG_READ(REG_GLOBAL, 0x1d);
                if ((ret & 0x8000) == 0)
                        return 0;
        }
index 105ad10876afe3dc06d2a5d2002900b297601879..27eda9fdf3c207f371864fa7ee81c2480f6999e9 100644 (file)
@@ -276,6 +276,9 @@ static struct net_device *ieee802154_nl_get_dev(struct genl_info *info)
        else
                return NULL;
 
+       if (!dev)
+               return NULL;
+
        if (dev->type != ARPHRD_IEEE802154) {
                dev_put(dev);
                return NULL;
@@ -521,3 +524,6 @@ static void __exit ieee802154_nl_exit(void)
 }
 module_exit(ieee802154_nl_exit);
 
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("ieee 802.15.4 configuration interface");
+
index 8a3881e28aca42d5066970276085bfdbe1535499..c29d75d8f1b124ee7706da2e145189eaf7c5b65e 100644 (file)
@@ -801,11 +801,8 @@ static int arp_process(struct sk_buff *skb)
  *  cache.
  */
 
-       /*
-        *  Special case: IPv4 duplicate address detection packet (RFC2131)
-        *  and Gratuitous ARP/ARP Announce. (RFC3927, Section 2.4)
-        */
-       if (sip == 0 || tip == sip) {
+       /* Special case: IPv4 duplicate address detection packet (RFC2131) */
+       if (sip == 0) {
                if (arp->ar_op == htons(ARPOP_REQUEST) &&
                    inet_addr_type(net, tip) == RTN_LOCAL &&
                    !arp_ignore(in_dev, sip, tip))
index 012cf5a685814bdff7c538ccbdc8805519ed0939..63c2fa7b68c4b922840fe883bd9bdf0e9a6c21c7 100644 (file)
@@ -316,8 +316,8 @@ static inline void check_tnode(const struct tnode *tn)
 
 static const int halve_threshold = 25;
 static const int inflate_threshold = 50;
-static const int halve_threshold_root = 8;
-static const int inflate_threshold_root = 15;
+static const int halve_threshold_root = 15;
+static const int inflate_threshold_root = 25;
 
 
 static void __alias_free_mem(struct rcu_head *head)
@@ -1021,6 +1021,9 @@ static void trie_rebalance(struct trie *t, struct tnode *tn)
                                      (struct node *)tn, wasfull);
 
                tp = node_parent((struct node *) tn);
+               if (!tp)
+                       rcu_assign_pointer(t->trie, (struct node *)tn);
+
                tnode_free_flush();
                if (!tp)
                        break;
index 44e2a3d2359afd99da1324022c221e811d83a0a9..cb4a0f4bd5e5654b465ddee4f32a42504711d5d3 100644 (file)
@@ -735,10 +735,10 @@ static int ipgre_tunnel_xmit(struct sk_buff *skb, struct net_device *dev)
        }
 
        tos = tiph->tos;
-       if (tos&1) {
+       if (tos == 1) {
+               tos = 0;
                if (skb->protocol == htons(ETH_P_IP))
                        tos = old_iph->tos;
-               tos &= ~1;
        }
 
        {
index 490ce20faf38b8bbe47aa60d1c7b1b1847fe1059..db46b4b5b2b9429db018b1abcadaf26d92316048 100644 (file)
@@ -440,6 +440,9 @@ int ip_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt,
        /* Remove any debris in the socket control block */
        memset(IPCB(skb), 0, sizeof(struct inet_skb_parm));
 
+       /* Must drop socket now because of tproxy. */
+       skb_orphan(skb);
+
        return NF_HOOK(PF_INET, NF_INET_PRE_ROUTING, skb, dev, NULL,
                       ip_rcv_finish);
 
index 2470262826694d122b5457d6ef4144b66429d7a2..7d08210547291b74bc15d001e55eacdb8dd34281 100644 (file)
@@ -1243,7 +1243,6 @@ int ip_push_pending_frames(struct sock *sk)
                skb->len += tmp_skb->len;
                skb->data_len += tmp_skb->len;
                skb->truesize += tmp_skb->truesize;
-               __sock_put(tmp_skb->sk);
                tmp_skb->destructor = NULL;
                tmp_skb->sk = NULL;
        }
index 155c008626c825729e5ac09fa45740e0bd8486c8..09172a65d9b61ea8de3cd52301e5c1e064d5b123 100644 (file)
@@ -191,7 +191,8 @@ nf_nat_mangle_tcp_packet(struct sk_buff *skb,
                                    ct, ctinfo);
                /* Tell TCP window tracking about seq change */
                nf_conntrack_tcp_update(skb, ip_hdrlen(skb),
-                                       ct, CTINFO2DIR(ctinfo));
+                                       ct, CTINFO2DIR(ctinfo),
+                                       (int)rep_len - (int)match_len);
 
                nf_conntrack_event_cache(IPCT_NATSEQADJ, ct);
        }
@@ -377,6 +378,7 @@ nf_nat_seq_adjust(struct sk_buff *skb,
        struct tcphdr *tcph;
        int dir;
        __be32 newseq, newack;
+       s16 seqoff, ackoff;
        struct nf_conn_nat *nat = nfct_nat(ct);
        struct nf_nat_seq *this_way, *other_way;
 
@@ -390,15 +392,18 @@ nf_nat_seq_adjust(struct sk_buff *skb,
 
        tcph = (void *)skb->data + ip_hdrlen(skb);
        if (after(ntohl(tcph->seq), this_way->correction_pos))
-               newseq = htonl(ntohl(tcph->seq) + this_way->offset_after);
+               seqoff = this_way->offset_after;
        else
-               newseq = htonl(ntohl(tcph->seq) + this_way->offset_before);
+               seqoff = this_way->offset_before;
 
        if (after(ntohl(tcph->ack_seq) - other_way->offset_before,
                  other_way->correction_pos))
-               newack = htonl(ntohl(tcph->ack_seq) - other_way->offset_after);
+               ackoff = other_way->offset_after;
        else
-               newack = htonl(ntohl(tcph->ack_seq) - other_way->offset_before);
+               ackoff = other_way->offset_before;
+
+       newseq = htonl(ntohl(tcph->seq) + seqoff);
+       newack = htonl(ntohl(tcph->ack_seq) - ackoff);
 
        inet_proto_csum_replace4(&tcph->check, skb, tcph->seq, newseq, 0);
        inet_proto_csum_replace4(&tcph->check, skb, tcph->ack_seq, newack, 0);
@@ -413,7 +418,7 @@ nf_nat_seq_adjust(struct sk_buff *skb,
        if (!nf_nat_sack_adjust(skb, tcph, ct, ctinfo))
                return 0;
 
-       nf_conntrack_tcp_update(skb, ip_hdrlen(skb), ct, dir);
+       nf_conntrack_tcp_update(skb, ip_hdrlen(skb), ct, dir, seqoff);
 
        return 1;
 }
index 65b3a8b11a6c3e6699ab426dce59e356da220670..278f46f5011beb2ab85747543f84dfd3ce7c6d1c 100644 (file)
@@ -1093,8 +1093,27 @@ restart:
                 * If we drop it here, the callers have no way to resolve routes
                 * when we're not caching.  Instead, just point *rp at rt, so
                 * the caller gets a single use out of the route
+                * Note that we do rt_free on this new route entry, so that
+                * once its refcount hits zero, we are still able to reap it
+                * (Thanks Alexey)
+                * Note also the rt_free uses call_rcu.  We don't actually
+                * need rcu protection here, this is just our path to get
+                * on the route gc list.
                 */
-               goto report_and_exit;
+
+               if (rt->rt_type == RTN_UNICAST || rt->fl.iif == 0) {
+                       int err = arp_bind_neighbour(&rt->u.dst);
+                       if (err) {
+                               if (net_ratelimit())
+                                       printk(KERN_WARNING
+                                           "Neighbour table failure & not caching routes.\n");
+                               rt_drop(rt);
+                               return err;
+                       }
+               }
+
+               rt_free(rt);
+               goto skip_hashing;
        }
 
        rthp = &rt_hash_table[hash].chain;
@@ -1211,7 +1230,8 @@ restart:
 #if RT_CACHE_DEBUG >= 2
        if (rt->u.dst.rt_next) {
                struct rtable *trt;
-               printk(KERN_DEBUG "rt_cache @%02x: %pI4", hash, &rt->rt_dst);
+               printk(KERN_DEBUG "rt_cache @%02x: %pI4",
+                      hash, &rt->rt_dst);
                for (trt = rt->u.dst.rt_next; trt; trt = trt->u.dst.rt_next)
                        printk(" . %pI4", &trt->rt_dst);
                printk("\n");
@@ -1226,7 +1246,7 @@ restart:
 
        spin_unlock_bh(rt_hash_lock_addr(hash));
 
-report_and_exit:
+skip_hashing:
        if (rp)
                *rp = rt;
        else
index 17b89c523f9d1ac590dbc575c8d6be7664851cbb..91145244ea630777e7e4a2e7f112f3c31bc7f90e 100644 (file)
@@ -339,7 +339,7 @@ unsigned int tcp_poll(struct file *file, struct socket *sock, poll_table *wait)
        struct sock *sk = sock->sk;
        struct tcp_sock *tp = tcp_sk(sk);
 
-       poll_wait(file, sk->sk_sleep, wait);
+       sock_poll_wait(file, sk->sk_sleep, wait);
        if (sk->sk_state == TCP_LISTEN)
                return inet_csk_listen_poll(sk);
 
@@ -903,13 +903,17 @@ int tcp_sendmsg(struct kiocb *iocb, struct socket *sock, struct msghdr *msg,
                iov++;
 
                while (seglen > 0) {
-                       int copy;
+                       int copy = 0;
+                       int max = size_goal;
 
                        skb = tcp_write_queue_tail(sk);
+                       if (tcp_send_head(sk)) {
+                               if (skb->ip_summed == CHECKSUM_NONE)
+                                       max = mss_now;
+                               copy = max - skb->len;
+                       }
 
-                       if (!tcp_send_head(sk) ||
-                           (copy = size_goal - skb->len) <= 0) {
-
+                       if (copy <= 0) {
 new_segment:
                                /* Allocate new segment. If the interface is SG,
                                 * allocate skb fitting to single page.
@@ -930,6 +934,7 @@ new_segment:
 
                                skb_entail(sk, skb);
                                copy = size_goal;
+                               max = size_goal;
                        }
 
                        /* Try to append data to the end of skb. */
@@ -1028,7 +1033,7 @@ new_segment:
                        if ((seglen -= copy) == 0 && iovlen == 0)
                                goto out;
 
-                       if (skb->len < size_goal || (flags & MSG_OOB))
+                       if (skb->len < max || (flags & MSG_OOB))
                                continue;
 
                        if (forced_push(tp)) {
index 43bbba7926ee40be929849921a7c950e27e10e5a..f8d67ccc64f3254c1080008df83b234e3853d976 100644 (file)
@@ -128,7 +128,8 @@ tcp_timewait_state_process(struct inet_timewait_sock *tw, struct sk_buff *skb,
                        goto kill_with_rst;
 
                /* Dup ACK? */
-               if (!after(TCP_SKB_CB(skb)->end_seq, tcptw->tw_rcv_nxt) ||
+               if (!th->ack ||
+                   !after(TCP_SKB_CB(skb)->end_seq, tcptw->tw_rcv_nxt) ||
                    TCP_SKB_CB(skb)->end_seq == TCP_SKB_CB(skb)->seq) {
                        inet_twsk_put(tw);
                        return TCP_TW_SUCCESS;
index 416fc4c2e7ebdc7367959407ef99c386d6428c20..5bdf08d312d9b9b13a824673da237001679c0bff 100644 (file)
@@ -725,7 +725,8 @@ static void tcp_queue_skb(struct sock *sk, struct sk_buff *skb)
 static void tcp_set_skb_tso_segs(struct sock *sk, struct sk_buff *skb,
                                 unsigned int mss_now)
 {
-       if (skb->len <= mss_now || !sk_can_gso(sk)) {
+       if (skb->len <= mss_now || !sk_can_gso(sk) ||
+           skb->ip_summed == CHECKSUM_NONE) {
                /* Avoid the costly divide in the normal
                 * non-TSO case.
                 */
index 60d918c96a4fff19c0d4062558ea8c594fa9bef2..0071ee6f441f1236d953f6a2f0f6b3cd8d67e758 100644 (file)
@@ -136,7 +136,8 @@ _decode_session4(struct sk_buff *skb, struct flowi *fl, int reverse)
                case IPPROTO_TCP:
                case IPPROTO_SCTP:
                case IPPROTO_DCCP:
-                       if (pskb_may_pull(skb, xprth + 4 - skb->data)) {
+                       if (xprth + 4 < skb->data ||
+                           pskb_may_pull(skb, xprth + 4 - skb->data)) {
                                __be16 *ports = (__be16 *)xprth;
 
                                fl->fl_ip_sport = ports[!!reverse];
index 8c1e86afbbf5208c4eeadee48ce407dbf3b0016f..43b3c9f89c12c5dfac56d70eac73b8718ea73650 100644 (file)
@@ -1916,8 +1916,32 @@ ok:
                                        update_lft = 1;
                                else if (stored_lft <= MIN_VALID_LIFETIME) {
                                        /* valid_lft <= stored_lft is always true */
-                                       /* XXX: IPsec */
-                                       update_lft = 0;
+                                       /*
+                                        * RFC 4862 Section 5.5.3e:
+                                        * "Note that the preferred lifetime of
+                                        *  the corresponding address is always
+                                        *  reset to the Preferred Lifetime in
+                                        *  the received Prefix Information
+                                        *  option, regardless of whether the
+                                        *  valid lifetime is also reset or
+                                        *  ignored."
+                                        *
+                                        *  So if the preferred lifetime in
+                                        *  this advertisement is different
+                                        *  than what we have stored, but the
+                                        *  valid lifetime is invalid, just
+                                        *  reset prefered_lft.
+                                        *
+                                        *  We must set the valid lifetime
+                                        *  to the stored lifetime since we'll
+                                        *  be updating the timestamp below,
+                                        *  else we'll set it back to the
+                                        *  minumum.
+                                        */
+                                       if (prefered_lft != ifp->prefered_lft) {
+                                               valid_lft = stored_lft;
+                                               update_lft = 1;
+                                       }
                                } else {
                                        valid_lft = MIN_VALID_LIFETIME;
                                        if (valid_lft < prefered_lft)
@@ -3085,7 +3109,7 @@ restart:
                                spin_unlock(&ifp->lock);
                                continue;
                        } else if (age >= ifp->prefered_lft) {
-                               /* jiffies - ifp->tsamp > age >= ifp->prefered_lft */
+                               /* jiffies - ifp->tstamp > age >= ifp->prefered_lft */
                                int deprecate = 0;
 
                                if (!(ifp->flags&IFA_F_DEPRECATED)) {
@@ -3362,7 +3386,10 @@ static int inet6_fill_ifaddr(struct sk_buff *skb, struct inet6_ifaddr *ifa,
                valid = ifa->valid_lft;
                if (preferred != INFINITY_LIFE_TIME) {
                        long tval = (jiffies - ifa->tstamp)/HZ;
-                       preferred -= tval;
+                       if (preferred > tval)
+                               preferred -= tval;
+                       else
+                               preferred = 0;
                        if (valid != INFINITY_LIFE_TIME)
                                valid -= tval;
                }
index 85b3d0036afdeff08efc32d1179dbabf7a58f9b3..caa0278d30a9dbedb6ca0dc172144c7992e2e485 100644 (file)
@@ -1284,6 +1284,8 @@ static void __exit inet6_exit(void)
        proto_unregister(&udplitev6_prot);
        proto_unregister(&udpv6_prot);
        proto_unregister(&tcpv6_prot);
+
+       rcu_barrier(); /* Wait for completion of call_rcu()'s */
 }
 module_exit(inet6_exit);
 
index 52449f7a1b715cf830fb4d051cb31ebd10cc3350..86f42a288c4bb487237ffa6da9944e20d0456efb 100644 (file)
@@ -405,7 +405,7 @@ out:
 }
 
 static void ah6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
-                   int type, int code, int offset, __be32 info)
+                   u8 type, u8 code, int offset, __be32 info)
 {
        struct net *net = dev_net(skb->dev);
        struct ipv6hdr *iph = (struct ipv6hdr*)skb->data;
index c2f250150db10a6d1c68c6904404e258860fc30d..678bb95b1525716f2120db6abe3332a7c4e5edab 100644 (file)
@@ -354,7 +354,7 @@ static u32 esp6_get_mtu(struct xfrm_state *x, int mtu)
 }
 
 static void esp6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
-                    int type, int code, int offset, __be32 info)
+                    u8 type, u8 code, int offset, __be32 info)
 {
        struct net *net = dev_net(skb->dev);
        struct ipv6hdr *iph = (struct ipv6hdr*)skb->data;
index 36dff8807183c81741baba329cea9d637ff6ebcd..eab62a7a8f06e54fd7e161b8312565f8da59ed60 100644 (file)
@@ -117,7 +117,7 @@ static __inline__ void icmpv6_xmit_unlock(struct sock *sk)
 /*
  * Slightly more convenient version of icmpv6_send.
  */
-void icmpv6_param_prob(struct sk_buff *skb, int code, int pos)
+void icmpv6_param_prob(struct sk_buff *skb, u8 code, int pos)
 {
        icmpv6_send(skb, ICMPV6_PARAMPROB, code, pos, skb->dev);
        kfree_skb(skb);
@@ -161,7 +161,7 @@ static int is_ineligible(struct sk_buff *skb)
 /*
  * Check the ICMP output rate limit
  */
-static inline int icmpv6_xrlim_allow(struct sock *sk, int type,
+static inline int icmpv6_xrlim_allow(struct sock *sk, u8 type,
                                     struct flowi *fl)
 {
        struct dst_entry *dst;
@@ -305,7 +305,7 @@ static inline void mip6_addr_swap(struct sk_buff *skb) {}
 /*
  *     Send an ICMP message in response to a packet in error
  */
-void icmpv6_send(struct sk_buff *skb, int type, int code, __u32 info,
+void icmpv6_send(struct sk_buff *skb, u8 type, u8 code, __u32 info,
                 struct net_device *dev)
 {
        struct net *net = dev_net(skb->dev);
@@ -590,7 +590,7 @@ out:
        icmpv6_xmit_unlock(sk);
 }
 
-static void icmpv6_notify(struct sk_buff *skb, int type, int code, __be32 info)
+static void icmpv6_notify(struct sk_buff *skb, u8 type, u8 code, __be32 info)
 {
        struct inet6_protocol *ipprot;
        int inner_offset;
@@ -643,7 +643,7 @@ static int icmpv6_rcv(struct sk_buff *skb)
        struct in6_addr *saddr, *daddr;
        struct ipv6hdr *orig_hdr;
        struct icmp6hdr *hdr;
-       int type;
+       u8 type;
 
        if (!xfrm6_policy_check(NULL, XFRM_POLICY_IN, skb)) {
                struct sec_path *sp = skb_sec_path(skb);
@@ -914,7 +914,7 @@ static const struct icmp6_err {
        },
 };
 
-int icmpv6_err_convert(int type, int code, int *err)
+int icmpv6_err_convert(u8 type, u8 code, int *err)
 {
        int fatal = 0;
 
index c3a07d75b5f50bafb987a7359c168f504ac81828..6d6a4277c67728f0e25a27f854904686f2eb1156 100644 (file)
@@ -139,6 +139,9 @@ int ipv6_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt
 
        rcu_read_unlock();
 
+       /* Must drop socket now because of tproxy. */
+       skb_orphan(skb);
+
        return NF_HOOK(PF_INET6, NF_INET_PRE_ROUTING, skb, dev, NULL,
                       ip6_rcv_finish);
 err:
index 7c76e3d1821551c42acc16d3e2210404a553b4d0..87f8419a68fdf888b37a2643345d89b85005671d 100644 (file)
@@ -1484,7 +1484,6 @@ int ip6_push_pending_frames(struct sock *sk)
                skb->len += tmp_skb->len;
                skb->data_len += tmp_skb->len;
                skb->truesize += tmp_skb->truesize;
-               __sock_put(tmp_skb->sk);
                tmp_skb->destructor = NULL;
                tmp_skb->sk = NULL;
        }
index 404d16a97d5c9d85c119f1853ce23e509c924ed5..51f410e7775a2880981e909817ce9ae5eba68d1f 100644 (file)
@@ -394,13 +394,13 @@ parse_tlv_tnl_enc_lim(struct sk_buff *skb, __u8 * raw)
 
 static int
 ip6_tnl_err(struct sk_buff *skb, __u8 ipproto, struct inet6_skb_parm *opt,
-           int *type, int *code, int *msg, __u32 *info, int offset)
+           u8 *type, u8 *code, int *msg, __u32 *info, int offset)
 {
        struct ipv6hdr *ipv6h = (struct ipv6hdr *) skb->data;
        struct ip6_tnl *t;
        int rel_msg = 0;
-       int rel_type = ICMPV6_DEST_UNREACH;
-       int rel_code = ICMPV6_ADDR_UNREACH;
+       u8 rel_type = ICMPV6_DEST_UNREACH;
+       u8 rel_code = ICMPV6_ADDR_UNREACH;
        __u32 rel_info = 0;
        __u16 len;
        int err = -ENOENT;
@@ -488,11 +488,11 @@ out:
 
 static int
 ip4ip6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
-          int type, int code, int offset, __be32 info)
+          u8 type, u8 code, int offset, __be32 info)
 {
        int rel_msg = 0;
-       int rel_type = type;
-       int rel_code = code;
+       u8 rel_type = type;
+       u8 rel_code = code;
        __u32 rel_info = ntohl(info);
        int err;
        struct sk_buff *skb2;
@@ -586,11 +586,11 @@ out:
 
 static int
 ip6ip6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
-          int type, int code, int offset, __be32 info)
+          u8 type, u8 code, int offset, __be32 info)
 {
        int rel_msg = 0;
-       int rel_type = type;
-       int rel_code = code;
+       u8 rel_type = type;
+       u8 rel_code = code;
        __u32 rel_info = ntohl(info);
        int err;
 
index 3a0b3be7ece525d6d7230c2fd2c79340a025c4f2..79c172f1ff012d6b7f577ea20febae037ec96dad 100644 (file)
@@ -51,7 +51,7 @@
 #include <linux/mutex.h>
 
 static void ipcomp6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
-                               int type, int code, int offset, __be32 info)
+                               u8 type, u8 code, int offset, __be32 info)
 {
        __be32 spi;
        struct ipv6hdr *iph = (struct ipv6hdr*)skb->data;
index f995e19c87a96d29995d7de530e0f996160ff980..f797e8c6f3b36de616de064616e43c22fa70a536 100644 (file)
@@ -54,7 +54,7 @@ static inline void *mip6_padn(__u8 *data, __u8 padlen)
        return data + padlen;
 }
 
-static inline void mip6_param_prob(struct sk_buff *skb, int code, int pos)
+static inline void mip6_param_prob(struct sk_buff *skb, u8 code, int pos)
 {
        icmpv6_send(skb, ICMPV6_PARAMPROB, code, pos, skb->dev);
 }
index 8b0b6f948063607d8d60ec18bde103a36369bc2a..d6c3c1c34b2d0cf1eac94211675800fce65be843 100644 (file)
@@ -310,7 +310,7 @@ out:
 
 static void rawv6_err(struct sock *sk, struct sk_buff *skb,
               struct inet6_skb_parm *opt,
-              int type, int code, int offset, __be32 info)
+              u8 type, u8 code, int offset, __be32 info)
 {
        struct inet_sock *inet = inet_sk(sk);
        struct ipv6_pinfo *np = inet6_sk(sk);
@@ -343,7 +343,7 @@ static void rawv6_err(struct sock *sk, struct sk_buff *skb,
 }
 
 void raw6_icmp_error(struct sk_buff *skb, int nexthdr,
-               int type, int code, int inner_offset, __be32 info)
+               u8 type, u8 code, int inner_offset, __be32 info)
 {
        struct sock *sk;
        int hash;
index 658293ea05ba736d143947ceca915cacdf4e5f89..1473ee0a1f5135d02cd9cc2bab8ae5c8b37e1e88 100644 (file)
@@ -1865,7 +1865,7 @@ int ipv6_route_ioctl(struct net *net, unsigned int cmd, void __user *arg)
  *     Drop the packet on the floor
  */
 
-static int ip6_pkt_drop(struct sk_buff *skb, int code, int ipstats_mib_noroutes)
+static int ip6_pkt_drop(struct sk_buff *skb, u8 code, int ipstats_mib_noroutes)
 {
        int type;
        struct dst_entry *dst = skb_dst(skb);
index 68e52308e5520f7180e22c0230aea51133fad265..98b7327d0949aa993751411f6512ebdf304f326f 100644 (file)
@@ -1018,6 +1018,7 @@ static void ipip6_tunnel_setup(struct net_device *dev)
        dev->hard_header_len    = LL_MAX_HEADER + sizeof(struct iphdr);
        dev->mtu                = ETH_DATA_LEN - sizeof(struct iphdr);
        dev->flags              = IFF_NOARP;
+       dev->priv_flags        &= ~IFF_XMIT_DST_RELEASE;
        dev->iflink             = 0;
        dev->addr_len           = 4;
        dev->features           |= NETIF_F_NETNS_LOCAL;
index 53b6a4192b161eae3f44b226395e02a691ad120c..58810c65b6359524b171fa9ca0678b9a6a21241c 100644 (file)
@@ -317,7 +317,7 @@ failure:
 }
 
 static void tcp_v6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
-               int type, int code, int offset, __be32 info)
+               u8 type, u8 code, int offset, __be32 info)
 {
        struct ipv6hdr *hdr = (struct ipv6hdr*)skb->data;
        const struct tcphdr *th = (struct tcphdr *)(skb->data+offset);
index 669f280989c351ce6c9b2e29ed934e1c3d02a937..633ad789effc12d0000c9ec3bb2c76192bfcee6e 100644 (file)
@@ -124,7 +124,7 @@ drop:
 }
 
 static void tunnel6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
-                       int type, int code, int offset, __be32 info)
+                       u8 type, u8 code, int offset, __be32 info)
 {
        struct xfrm6_tunnel *handler;
 
index 023beda6b22445f52f75e13fc3e0000b78d42342..33b59bd92c4dc18667a6f0bf94fc7ac4282b4323 100644 (file)
@@ -312,7 +312,7 @@ csum_copy_err:
 }
 
 void __udp6_lib_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
-                   int type, int code, int offset, __be32 info,
+                   u8 type, u8 code, int offset, __be32 info,
                    struct udp_table *udptable)
 {
        struct ipv6_pinfo *np;
@@ -346,8 +346,8 @@ out:
 }
 
 static __inline__ void udpv6_err(struct sk_buff *skb,
-                                struct inet6_skb_parm *opt, int type,
-                                int code, int offset, __be32 info     )
+                                struct inet6_skb_parm *opt, u8 type,
+                                u8 code, int offset, __be32 info     )
 {
        __udp6_lib_err(skb, opt, type, code, offset, info, &udp_table);
 }
index 23779208c334e90aa1bad9100a1d8c84f6b452df..6bb303471e204ade2e31d025cb9d3ec1b80fbd60 100644 (file)
@@ -9,7 +9,7 @@
 
 extern int     __udp6_lib_rcv(struct sk_buff *, struct udp_table *, int );
 extern void    __udp6_lib_err(struct sk_buff *, struct inet6_skb_parm *,
-                              int , int , int , __be32 , struct udp_table *);
+                              u8 , u8 , int , __be32 , struct udp_table *);
 
 extern int     udp_v6_get_port(struct sock *sk, unsigned short snum);
 
index ba162a824585b8fcecd2c1022c0c64d09faa68bc..4818c48688f210b31932329204b9c47159c5e44c 100644 (file)
@@ -20,7 +20,7 @@ static int udplitev6_rcv(struct sk_buff *skb)
 
 static void udplitev6_err(struct sk_buff *skb,
                          struct inet6_skb_parm *opt,
-                         int type, int code, int offset, __be32 info)
+                         u8 type, u8 code, int offset, __be32 info)
 {
        __udp6_lib_err(skb, opt, type, code, offset, info, &udplite_table);
 }
index b4b16a43f2771bd62558a2cd8ca3af60b0d99808..3a3c677bc0f2571b9679e5b9015ec15c6951e3b2 100644 (file)
@@ -157,7 +157,8 @@ _decode_session6(struct sk_buff *skb, struct flowi *fl, int reverse)
        ipv6_addr_copy(&fl->fl6_dst, reverse ? &hdr->saddr : &hdr->daddr);
        ipv6_addr_copy(&fl->fl6_src, reverse ? &hdr->daddr : &hdr->saddr);
 
-       while (pskb_may_pull(skb, nh + offset + 1 - skb->data)) {
+       while (nh + offset + 1 < skb->data ||
+              pskb_may_pull(skb, nh + offset + 1 - skb->data)) {
                nh = skb_network_header(skb);
                exthdr = (struct ipv6_opt_hdr *)(nh + offset);
 
@@ -177,7 +178,8 @@ _decode_session6(struct sk_buff *skb, struct flowi *fl, int reverse)
                case IPPROTO_TCP:
                case IPPROTO_SCTP:
                case IPPROTO_DCCP:
-                       if (!onlyproto && pskb_may_pull(skb, nh + offset + 4 - skb->data)) {
+                       if (!onlyproto && (nh + offset + 4 < skb->data ||
+                            pskb_may_pull(skb, nh + offset + 4 - skb->data))) {
                                __be16 *ports = (__be16 *)exthdr;
 
                                fl->fl_ip_sport = ports[!!reverse];
index 80193db224d9070e2ca57982122fdf8384ba5d9f..81a95c00e50355855cd7fdf22ac207b7e7dc1d91 100644 (file)
@@ -262,7 +262,7 @@ static int xfrm6_tunnel_rcv(struct sk_buff *skb)
 }
 
 static int xfrm6_tunnel_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
-                           int type, int code, int offset, __be32 info)
+                           u8 type, u8 code, int offset, __be32 info)
 {
        /* xfrm6_tunnel native err handling */
        switch (type) {
index 417b0e30949551de04cc6e1f8087ca9a7809da08..f1118d92a191dc07acd9bfda34ce81c7df8613f0 100644 (file)
@@ -41,6 +41,7 @@
 #include <linux/netdevice.h>
 #include <linux/uio.h>
 #include <linux/skbuff.h>
+#include <linux/smp_lock.h>
 #include <linux/socket.h>
 #include <linux/sockios.h>
 #include <linux/string.h>
index 5922febe25c42dc9a602378a600db8d8da674f85..80cf29aae0967a8935646ecda366b94168449a1a 100644 (file)
@@ -45,6 +45,7 @@
 #include <linux/capability.h>
 #include <linux/module.h>
 #include <linux/types.h>
+#include <linux/smp_lock.h>
 #include <linux/socket.h>
 #include <linux/sockios.h>
 #include <linux/init.h>
@@ -913,9 +914,6 @@ static int irda_accept(struct socket *sock, struct socket *newsock, int flags)
        /* Clean up the original one to keep it in listen state */
        irttp_listen(self->tsap);
 
-       /* Wow ! What is that ? Jean II */
-       skb->sk = NULL;
-       skb->destructor = NULL;
        kfree_skb(skb);
        sk->sk_ack_backlog--;
 
index 67c99d20857fab4e2e078e9c1d5d4a9ee6bbc952..7ba96618660e349de2253473d6701ab8bbad9613 100644 (file)
@@ -196,6 +196,7 @@ static int ircomm_lmp_data_request(struct ircomm_cb *self,
        /* Don't forget to refcount it - see ircomm_tty_do_softint() */
        skb_get(skb);
 
+       skb_orphan(skb);
        skb->destructor = ircomm_lmp_flow_control;
 
        if ((self->pkt_count++ > 7) && (self->flow_status == FLOW_START)) {
index bccf4d0059f0a6a629bbd5913015b0453caaa5e9..b001c361ad30976ff3a1de5bfe80fe2f0142b6f9 100644 (file)
 #include <linux/module.h>
 
 #include <linux/kernel.h>
-#include <linux/smp_lock.h>
 #include <linux/skbuff.h>
 #include <linux/tty.h>
 #include <linux/proc_fs.h>
index 6d8ae03c14f5b8e3dc12af9906a14e1b0ae3b666..68cbcb19cbd8a084dc0121997c2701f970c99aa1 100644 (file)
@@ -13,6 +13,7 @@
  *     2) as a control channel (write commands, read events)
  */
 
+#include <linux/smp_lock.h>
 #include "irnet_ppp.h"         /* Private header */
 /* Please put other headers in irnet.h - Thanks */
 
index 6be5f92d10943d383ce252242233e61770b2e528..49c15b48408e5617a5405ba396f1f9b9e427dd5d 100644 (file)
@@ -306,7 +306,7 @@ static inline int iucv_below_msglim(struct sock *sk)
 static void iucv_sock_wake_msglim(struct sock *sk)
 {
        read_lock(&sk->sk_callback_lock);
-       if (sk->sk_sleep && waitqueue_active(sk->sk_sleep))
+       if (sk_has_sleeper(sk))
                wake_up_interruptible_all(sk->sk_sleep);
        sk_wake_async(sk, SOCK_WAKE_SPACE, POLL_OUT);
        read_unlock(&sk->sk_callback_lock);
@@ -1256,7 +1256,7 @@ unsigned int iucv_sock_poll(struct file *file, struct socket *sock,
        struct sock *sk = sock->sk;
        unsigned int mask = 0;
 
-       poll_wait(file, sk->sk_sleep, wait);
+       sock_poll_wait(file, sk->sk_sleep, wait);
 
        if (sk->sk_state == IUCV_LISTEN)
                return iucv_accept_poll(sk);
index fc712e60705da4b8a8785b305cec79300be955c7..11cf45bce38a36cf17c4592b5b0991a489a28c5e 100644 (file)
@@ -494,7 +494,7 @@ void ieee80211_stop_mesh(struct ieee80211_sub_if_data *sdata)
         * should it be using the interface and enqueuing
         * frames at this very time on another CPU.
         */
-       synchronize_rcu();
+       rcu_barrier(); /* Wait for RX path and call_rcu()'s */
        skb_queue_purge(&sdata->u.mesh.skb_queue);
 }
 
index 003cb470ac8478c84329bf29a0687484a2e6acb1..f49ef288e2e28841a2e6308c2ab94e83cf2d1717 100644 (file)
@@ -637,7 +637,7 @@ static void mesh_queue_preq(struct mesh_path *mpath, u8 flags)
        struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
        struct mesh_preq_queue *preq_node;
 
-       preq_node = kmalloc(sizeof(struct mesh_preq_queue), GFP_KERNEL);
+       preq_node = kmalloc(sizeof(struct mesh_preq_queue), GFP_ATOMIC);
        if (!preq_node) {
                printk(KERN_DEBUG "Mesh HWMP: could not allocate PREQ node\n");
                return;
index b218b98fba7fbeb573d420ca0829af99f47584c5..37771abd8f5a5bcd85d9d94fa558f0e69649defb 100644 (file)
@@ -66,7 +66,7 @@ rix_to_ndx(struct minstrel_sta_info *mi, int rix)
        for (i = rix; i >= 0; i--)
                if (mi->r[i].rix == rix)
                        break;
-       WARN_ON(mi->r[i].rix != rix);
+       WARN_ON(i < 0);
        return i;
 }
 
@@ -181,6 +181,9 @@ minstrel_tx_status(void *priv, struct ieee80211_supported_band *sband,
                        break;
 
                ndx = rix_to_ndx(mi, ar[i].idx);
+               if (ndx < 0)
+                       continue;
+
                mi->r[ndx].attempts += ar[i].count;
 
                if ((i != IEEE80211_TX_MAX_RATES - 1) && (ar[i + 1].idx < 0))
index 5f72b94b4918745f3491b48ba06cbc1714890280..7508f11c5b3952a05ed9b41682f50d7827b3c4e6 100644 (file)
@@ -335,7 +335,8 @@ begin:
        h = __nf_conntrack_find(net, tuple);
        if (h) {
                ct = nf_ct_tuplehash_to_ctrack(h);
-               if (unlikely(!atomic_inc_not_zero(&ct->ct_general.use)))
+               if (unlikely(nf_ct_is_dying(ct) ||
+                            !atomic_inc_not_zero(&ct->ct_general.use)))
                        h = NULL;
                else {
                        if (unlikely(!nf_ct_tuple_equal(tuple, &h->tuple))) {
@@ -425,7 +426,6 @@ __nf_conntrack_confirm(struct sk_buff *skb)
        /* Remove from unconfirmed list */
        hlist_nulls_del_rcu(&ct->tuplehash[IP_CT_DIR_ORIGINAL].hnnode);
 
-       __nf_conntrack_hash_insert(ct, hash, repl_hash);
        /* Timer relative to confirmation time, not original
           setting time, otherwise we'd get timer wrap in
           weird delay cases. */
@@ -433,8 +433,16 @@ __nf_conntrack_confirm(struct sk_buff *skb)
        add_timer(&ct->timeout);
        atomic_inc(&ct->ct_general.use);
        set_bit(IPS_CONFIRMED_BIT, &ct->status);
+
+       /* Since the lookup is lockless, hash insertion must be done after
+        * starting the timer and setting the CONFIRMED bit. The RCU barriers
+        * guarantee that no other CPU can find the conntrack before the above
+        * stores are visible.
+        */
+       __nf_conntrack_hash_insert(ct, hash, repl_hash);
        NF_CT_STAT_INC(net, insert);
        spin_unlock_bh(&nf_conntrack_lock);
+
        help = nfct_help(ct);
        if (help && help->helper)
                nf_conntrack_event_cache(IPCT_HELPER, ct);
@@ -503,7 +511,8 @@ static noinline int early_drop(struct net *net, unsigned int hash)
                        cnt++;
                }
 
-               if (ct && unlikely(!atomic_inc_not_zero(&ct->ct_general.use)))
+               if (ct && unlikely(nf_ct_is_dying(ct) ||
+                                  !atomic_inc_not_zero(&ct->ct_general.use)))
                        ct = NULL;
                if (ct || cnt >= NF_CT_EVICTION_RANGE)
                        break;
@@ -1267,13 +1276,19 @@ err_cache:
        return ret;
 }
 
+/*
+ * We need to use special "null" values, not used in hash table
+ */
+#define UNCONFIRMED_NULLS_VAL  ((1<<30)+0)
+#define DYING_NULLS_VAL                ((1<<30)+1)
+
 static int nf_conntrack_init_net(struct net *net)
 {
        int ret;
 
        atomic_set(&net->ct.count, 0);
-       INIT_HLIST_NULLS_HEAD(&net->ct.unconfirmed, 0);
-       INIT_HLIST_NULLS_HEAD(&net->ct.dying, 0);
+       INIT_HLIST_NULLS_HEAD(&net->ct.unconfirmed, UNCONFIRMED_NULLS_VAL);
+       INIT_HLIST_NULLS_HEAD(&net->ct.dying, DYING_NULLS_VAL);
        net->ct.stat = alloc_percpu(struct ip_conntrack_stat);
        if (!net->ct.stat) {
                ret = -ENOMEM;
index afde8f991646eadfa6afc72d6390fb27b5ecaf61..2032dfe25ca85a64daab1760fb1ce6b01fc96c7e 100644 (file)
@@ -617,8 +617,10 @@ err1:
 void nf_conntrack_expect_fini(struct net *net)
 {
        exp_proc_remove(net);
-       if (net_eq(net, &init_net))
+       if (net_eq(net, &init_net)) {
+               rcu_barrier(); /* Wait for call_rcu() before destroy */
                kmem_cache_destroy(nf_ct_expect_cachep);
+       }
        nf_ct_free_hashtable(net->ct.expect_hash, net->ct.expect_vmalloc,
                             nf_ct_expect_hsize);
 }
index 4b2c769d555fce4d6131b08f5aac6d53b3a48be6..fef95be334bd8b834335afe8bbef0cdb9f62dc37 100644 (file)
@@ -186,6 +186,6 @@ void nf_ct_extend_unregister(struct nf_ct_ext_type *type)
        rcu_assign_pointer(nf_ct_ext_types[type->id], NULL);
        update_alloc_size(type);
        mutex_unlock(&nf_ct_ext_type_mutex);
-       synchronize_rcu();
+       rcu_barrier(); /* Wait for completion of call_rcu()'s */
 }
 EXPORT_SYMBOL_GPL(nf_ct_extend_unregister);
index 33fc0a443f3de755772f5be4f686c1f44adf9cb1..97a82ba75376aff182fecb1ac37b97e6ca1bf021 100644 (file)
@@ -720,8 +720,8 @@ static bool tcp_in_window(const struct nf_conn *ct,
 /* Caller must linearize skb at tcp header. */
 void nf_conntrack_tcp_update(const struct sk_buff *skb,
                             unsigned int dataoff,
-                            struct nf_conn *ct,
-                            int dir)
+                            struct nf_conn *ct, int dir,
+                            s16 offset)
 {
        const struct tcphdr *tcph = (const void *)skb->data + dataoff;
        const struct ip_ct_tcp_state *sender = &ct->proto.tcp.seen[dir];
@@ -734,7 +734,7 @@ void nf_conntrack_tcp_update(const struct sk_buff *skb,
        /*
         * We have to worry for the ack in the reply packet only...
         */
-       if (after(end, ct->proto.tcp.seen[dir].td_end))
+       if (ct->proto.tcp.seen[dir].td_end + offset == end)
                ct->proto.tcp.seen[dir].td_end = end;
        ct->proto.tcp.last_end = end;
        spin_unlock_bh(&ct->lock);
index 2fefe147750a09b2f8d94f0e78f3b5f35e5b08b0..4e620305f28c765548c5c5b35b1a5b833034bf30 100644 (file)
@@ -47,7 +47,6 @@ int nf_log_register(u_int8_t pf, struct nf_logger *logger)
        mutex_lock(&nf_log_mutex);
 
        if (pf == NFPROTO_UNSPEC) {
-               int i;
                for (i = NFPROTO_UNSPEC; i < NFPROTO_NUMPROTO; i++)
                        list_add_tail(&(logger->list[i]), &(nf_loggers_l[i]));
        } else {
@@ -216,7 +215,7 @@ static const struct file_operations nflog_file_ops = {
 #endif /* PROC_FS */
 
 #ifdef CONFIG_SYSCTL
-struct ctl_path nf_log_sysctl_path[] = {
+static struct ctl_path nf_log_sysctl_path[] = {
        { .procname = "net", .ctl_name = CTL_NET, },
        { .procname = "netfilter", .ctl_name = NET_NETFILTER, },
        { .procname = "nf_log", .ctl_name = CTL_UNNUMBERED, },
@@ -228,19 +227,26 @@ static struct ctl_table nf_log_sysctl_table[NFPROTO_NUMPROTO+1];
 static struct ctl_table_header *nf_log_dir_header;
 
 static int nf_log_proc_dostring(ctl_table *table, int write, struct file *filp,
-                        void *buffer, size_t *lenp, loff_t *ppos)
+                        void __user *buffer, size_t *lenp, loff_t *ppos)
 {
        const struct nf_logger *logger;
+       char buf[NFLOGGER_NAME_LEN];
+       size_t size = *lenp;
        int r = 0;
        int tindex = (unsigned long)table->extra1;
 
        if (write) {
-               if (!strcmp(buffer, "NONE")) {
+               if (size > sizeof(buf))
+                       size = sizeof(buf);
+               if (copy_from_user(buf, buffer, size))
+                       return -EFAULT;
+
+               if (!strcmp(buf, "NONE")) {
                        nf_log_unbind_pf(tindex);
                        return 0;
                }
                mutex_lock(&nf_log_mutex);
-               logger = __find_logger(tindex, buffer);
+               logger = __find_logger(tindex, buf);
                if (logger == NULL) {
                        mutex_unlock(&nf_log_mutex);
                        return -ENOENT;
index 498b45101df7f820e8bd97d6612406811d59afaf..f28f6a5fc02d96aa79acce6e57a8968026250387 100644 (file)
@@ -40,12 +40,12 @@ nfqueue_tg(struct sk_buff *skb, const struct xt_target_param *par)
 static u32 hash_v4(const struct sk_buff *skb)
 {
        const struct iphdr *iph = ip_hdr(skb);
-       u32 ipaddr;
+       __be32 ipaddr;
 
        /* packets in either direction go into same queue */
        ipaddr = iph->saddr ^ iph->daddr;
 
-       return jhash_2words(ipaddr, iph->protocol, jhash_initval);
+       return jhash_2words((__force u32)ipaddr, iph->protocol, jhash_initval);
 }
 
 static unsigned int
@@ -63,14 +63,14 @@ nfqueue_tg4_v1(struct sk_buff *skb, const struct xt_target_param *par)
 static u32 hash_v6(const struct sk_buff *skb)
 {
        const struct ipv6hdr *ip6h = ipv6_hdr(skb);
-       u32 addr[4];
+       __be32 addr[4];
 
        addr[0] = ip6h->saddr.s6_addr32[0] ^ ip6h->daddr.s6_addr32[0];
        addr[1] = ip6h->saddr.s6_addr32[1] ^ ip6h->daddr.s6_addr32[1];
        addr[2] = ip6h->saddr.s6_addr32[2] ^ ip6h->daddr.s6_addr32[2];
        addr[3] = ip6h->saddr.s6_addr32[3] ^ ip6h->daddr.s6_addr32[3];
 
-       return jhash2(addr, ARRAY_SIZE(addr), jhash_initval);
+       return jhash2((__force u32 *)addr, ARRAY_SIZE(addr), jhash_initval);
 }
 
 static unsigned int
index 69a639f354031ffa3288e1e8c6a7929fce784762..225ee3ecd69d63152489a0f47ae76d5cbacb7b8f 100644 (file)
 #include <net/netfilter/nf_conntrack.h>
 #include <linux/netfilter/xt_cluster.h>
 
-static inline u_int32_t nf_ct_orig_ipv4_src(const struct nf_conn *ct)
+static inline u32 nf_ct_orig_ipv4_src(const struct nf_conn *ct)
 {
-       return ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.u3.ip;
+       return (__force u32)ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.u3.ip;
 }
 
-static inline const void *nf_ct_orig_ipv6_src(const struct nf_conn *ct)
+static inline const u32 *nf_ct_orig_ipv6_src(const struct nf_conn *ct)
 {
-       return ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.u3.ip6;
+       return (__force u32 *)ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.u3.ip6;
 }
 
 static inline u_int32_t
index 0b7139f3dd786b3b4fa9ac416ca20fb9fbfe47c4..fc581800698e6885ee9c6ccb71ccc4be6eb9f594 100644 (file)
@@ -129,7 +129,7 @@ conntrack_addrcmp(const union nf_inet_addr *kaddr,
 
 static inline bool
 conntrack_mt_origsrc(const struct nf_conn *ct,
-                     const struct xt_conntrack_mtinfo1 *info,
+                     const struct xt_conntrack_mtinfo2 *info,
                     u_int8_t family)
 {
        return conntrack_addrcmp(&ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.u3,
@@ -138,7 +138,7 @@ conntrack_mt_origsrc(const struct nf_conn *ct,
 
 static inline bool
 conntrack_mt_origdst(const struct nf_conn *ct,
-                     const struct xt_conntrack_mtinfo1 *info,
+                     const struct xt_conntrack_mtinfo2 *info,
                     u_int8_t family)
 {
        return conntrack_addrcmp(&ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.u3,
@@ -147,7 +147,7 @@ conntrack_mt_origdst(const struct nf_conn *ct,
 
 static inline bool
 conntrack_mt_replsrc(const struct nf_conn *ct,
-                     const struct xt_conntrack_mtinfo1 *info,
+                     const struct xt_conntrack_mtinfo2 *info,
                     u_int8_t family)
 {
        return conntrack_addrcmp(&ct->tuplehash[IP_CT_DIR_REPLY].tuple.src.u3,
@@ -156,7 +156,7 @@ conntrack_mt_replsrc(const struct nf_conn *ct,
 
 static inline bool
 conntrack_mt_repldst(const struct nf_conn *ct,
-                     const struct xt_conntrack_mtinfo1 *info,
+                     const struct xt_conntrack_mtinfo2 *info,
                     u_int8_t family)
 {
        return conntrack_addrcmp(&ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.u3,
@@ -164,7 +164,7 @@ conntrack_mt_repldst(const struct nf_conn *ct,
 }
 
 static inline bool
-ct_proto_port_check(const struct xt_conntrack_mtinfo1 *info,
+ct_proto_port_check(const struct xt_conntrack_mtinfo2 *info,
                     const struct nf_conn *ct)
 {
        const struct nf_conntrack_tuple *tuple;
@@ -204,7 +204,7 @@ ct_proto_port_check(const struct xt_conntrack_mtinfo1 *info,
 static bool
 conntrack_mt(const struct sk_buff *skb, const struct xt_match_param *par)
 {
-       const struct xt_conntrack_mtinfo1 *info = par->matchinfo;
+       const struct xt_conntrack_mtinfo2 *info = par->matchinfo;
        enum ip_conntrack_info ctinfo;
        const struct nf_conn *ct;
        unsigned int statebit;
@@ -278,6 +278,16 @@ conntrack_mt(const struct sk_buff *skb, const struct xt_match_param *par)
        return true;
 }
 
+static bool
+conntrack_mt_v1(const struct sk_buff *skb, const struct xt_match_param *par)
+{
+       const struct xt_conntrack_mtinfo2 *const *info = par->matchinfo;
+       struct xt_match_param newpar = *par;
+
+       newpar.matchinfo = *info;
+       return conntrack_mt(skb, &newpar);
+}
+
 static bool conntrack_mt_check(const struct xt_mtchk_param *par)
 {
        if (nf_ct_l3proto_try_module_get(par->family) < 0) {
@@ -288,11 +298,45 @@ static bool conntrack_mt_check(const struct xt_mtchk_param *par)
        return true;
 }
 
+static bool conntrack_mt_check_v1(const struct xt_mtchk_param *par)
+{
+       struct xt_conntrack_mtinfo1 *info = par->matchinfo;
+       struct xt_conntrack_mtinfo2 *up;
+       int ret = conntrack_mt_check(par);
+
+       if (ret < 0)
+               return ret;
+
+       up = kmalloc(sizeof(*up), GFP_KERNEL);
+       if (up == NULL) {
+               nf_ct_l3proto_module_put(par->family);
+               return -ENOMEM;
+       }
+
+       /*
+        * The strategy here is to minimize the overhead of v1 matching,
+        * by prebuilding a v2 struct and putting the pointer into the
+        * v1 dataspace.
+        */
+       memcpy(up, info, offsetof(typeof(*info), state_mask));
+       up->state_mask  = info->state_mask;
+       up->status_mask = info->status_mask;
+       *(void **)info  = up;
+       return true;
+}
+
 static void conntrack_mt_destroy(const struct xt_mtdtor_param *par)
 {
        nf_ct_l3proto_module_put(par->family);
 }
 
+static void conntrack_mt_destroy_v1(const struct xt_mtdtor_param *par)
+{
+       struct xt_conntrack_mtinfo2 **info = par->matchinfo;
+       kfree(*info);
+       conntrack_mt_destroy(par);
+}
+
 #ifdef CONFIG_COMPAT
 struct compat_xt_conntrack_info
 {
@@ -363,6 +407,16 @@ static struct xt_match conntrack_mt_reg[] __read_mostly = {
                .revision   = 1,
                .family     = NFPROTO_UNSPEC,
                .matchsize  = sizeof(struct xt_conntrack_mtinfo1),
+               .match      = conntrack_mt_v1,
+               .checkentry = conntrack_mt_check_v1,
+               .destroy    = conntrack_mt_destroy_v1,
+               .me         = THIS_MODULE,
+       },
+       {
+               .name       = "conntrack",
+               .revision   = 2,
+               .family     = NFPROTO_UNSPEC,
+               .matchsize  = sizeof(struct xt_conntrack_mtinfo2),
                .match      = conntrack_mt,
                .checkentry = conntrack_mt_check,
                .destroy    = conntrack_mt_destroy,
index 01dd07b764ec46de6d82baec2625500bee2c714d..98fc190e8f0eed8683e9836b6be1567ecea74382 100644 (file)
@@ -54,6 +54,7 @@ static bool quota_mt_check(const struct xt_mtchk_param *par)
        if (q->master == NULL)
                return -ENOMEM;
 
+       q->master->quota = q->quota;
        return true;
 }
 
index 220a1d588ee0e89813127dc87381accb21b36f88..4fc6a917f6de5b30d55de8dba82531be03e67826 100644 (file)
@@ -66,7 +66,7 @@ xt_rateest_mt(const struct sk_buff *skb, const struct xt_match_param *par)
                if (info->flags & XT_RATEEST_MATCH_BPS)
                        ret &= bps1 == bps2;
                if (info->flags & XT_RATEEST_MATCH_PPS)
-                       ret &= pps2 == pps2;
+                       ret &= pps1 == pps2;
                break;
        }
 
index 80a322d77909ac0d96000486580f20d2946fcbd3..b0d6ddd82a9da1b20ce14bf2b76099cdf72362bc 100644 (file)
@@ -69,10 +69,27 @@ static struct phonet_device *__phonet_get(struct net_device *dev)
        return NULL;
 }
 
-static void __phonet_device_free(struct phonet_device *pnd)
+static void phonet_device_destroy(struct net_device *dev)
 {
-       list_del(&pnd->list);
-       kfree(pnd);
+       struct phonet_device_list *pndevs = phonet_device_list(dev_net(dev));
+       struct phonet_device *pnd;
+
+       ASSERT_RTNL();
+
+       spin_lock_bh(&pndevs->lock);
+       pnd = __phonet_get(dev);
+       if (pnd)
+               list_del(&pnd->list);
+       spin_unlock_bh(&pndevs->lock);
+
+       if (pnd) {
+               u8 addr;
+
+               for (addr = find_first_bit(pnd->addrs, 64); addr < 64;
+                       addr = find_next_bit(pnd->addrs, 64, 1+addr))
+                       phonet_address_notify(RTM_DELADDR, dev, addr);
+               kfree(pnd);
+       }
 }
 
 struct net_device *phonet_device_get(struct net *net)
@@ -126,8 +143,10 @@ int phonet_address_del(struct net_device *dev, u8 addr)
        pnd = __phonet_get(dev);
        if (!pnd || !test_and_clear_bit(addr >> 2, pnd->addrs))
                err = -EADDRNOTAVAIL;
-       else if (bitmap_empty(pnd->addrs, 64))
-               __phonet_device_free(pnd);
+       else if (bitmap_empty(pnd->addrs, 64)) {
+               list_del(&pnd->list);
+               kfree(pnd);
+       }
        spin_unlock_bh(&pndevs->lock);
        return err;
 }
@@ -181,18 +200,8 @@ static int phonet_device_notify(struct notifier_block *me, unsigned long what,
 {
        struct net_device *dev = arg;
 
-       if (what == NETDEV_UNREGISTER) {
-               struct phonet_device_list *pndevs;
-               struct phonet_device *pnd;
-
-               /* Destroy phonet-specific device data */
-               pndevs = phonet_device_list(dev_net(dev));
-               spin_lock_bh(&pndevs->lock);
-               pnd = __phonet_get(dev);
-               if (pnd)
-                       __phonet_device_free(pnd);
-               spin_unlock_bh(&pndevs->lock);
-       }
+       if (what == NETDEV_UNREGISTER)
+               phonet_device_destroy(dev);
        return 0;
 
 }
@@ -218,11 +227,12 @@ static int phonet_init_net(struct net *net)
 static void phonet_exit_net(struct net *net)
 {
        struct phonet_net *pnn = net_generic(net, phonet_net_id);
-       struct phonet_device *pnd, *n;
-
-       list_for_each_entry_safe(pnd, n, &pnn->pndevs.list, list)
-               __phonet_device_free(pnd);
+       struct net_device *dev;
 
+       rtnl_lock();
+       for_each_netdev(net, dev)
+               phonet_device_destroy(dev);
+       rtnl_unlock();
        kfree(pnn);
 }
 
index cec4e59516817ecc0b64a8fdaa04c11de52aa0b2..f8b4cee434c232614665523ac4608cbed543f86b 100644 (file)
@@ -32,7 +32,7 @@
 static int fill_addr(struct sk_buff *skb, struct net_device *dev, u8 addr,
                     u32 pid, u32 seq, int event);
 
-static void rtmsg_notify(int event, struct net_device *dev, u8 addr)
+void phonet_address_notify(int event, struct net_device *dev, u8 addr)
 {
        struct sk_buff *skb;
        int err = -ENOBUFS;
@@ -94,7 +94,7 @@ static int addr_doit(struct sk_buff *skb, struct nlmsghdr *nlh, void *attr)
        else
                err = phonet_address_del(dev, pnaddr);
        if (!err)
-               rtmsg_notify(nlh->nlmsg_type, dev, pnaddr);
+               phonet_address_notify(nlh->nlmsg_type, dev, pnaddr);
        return err;
 }
 
index eac5e7bb73659c3b951bd7fc9f564e7d380e4d9b..bfe493ebf27c36a7a82974af5a596ee8f75528c9 100644 (file)
@@ -63,7 +63,7 @@ static void rxrpc_write_space(struct sock *sk)
        _enter("%p", sk);
        read_lock(&sk->sk_callback_lock);
        if (rxrpc_writable(sk)) {
-               if (sk->sk_sleep && waitqueue_active(sk->sk_sleep))
+               if (sk_has_sleeper(sk))
                        wake_up_interruptible(sk->sk_sleep);
                sk_wake_async(sk, SOCK_WAKE_SPACE, POLL_OUT);
        }
@@ -588,7 +588,7 @@ static unsigned int rxrpc_poll(struct file *file, struct socket *sock,
        unsigned int mask;
        struct sock *sk = sock->sk;
 
-       poll_wait(file, sk->sk_sleep, wait);
+       sock_poll_wait(file, sk->sk_sleep, wait);
        mask = 0;
 
        /* the socket is readable if there are any messages waiting on the Rx
index a63de3f7f1859ccf839893f69b4b7db4ee84b431..6a4b19094143653ab79a43de52d916fd8ed2a0f0 100644 (file)
@@ -133,7 +133,7 @@ static struct notifier_block sctp_inet6addr_notifier = {
 
 /* ICMP error handler. */
 SCTP_STATIC void sctp_v6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
-                            int type, int code, int offset, __be32 info)
+                            u8 type, u8 code, int offset, __be32 info)
 {
        struct inet6_dev *idev;
        struct sock *sk;
index b764114445156dc69146856c118cbf1a725addca..b94c2119056661aaa61073a29bd429f069f7923f 100644 (file)
@@ -407,7 +407,7 @@ int sctp_packet_transmit(struct sctp_packet *packet)
        }
        dst = dst_clone(tp->dst);
        skb_dst_set(nskb, dst);
-       if (dst)
+       if (!dst)
                goto no_route;
 
        /* Build the SCTP header.  */
index 35ba035970a2ace360d9e5498a35e02a7f8a68e6..971890dbfea020be8f75b72269bcf34456abc102 100644 (file)
@@ -6652,21 +6652,6 @@ static void sctp_wait_for_close(struct sock *sk, long timeout)
        finish_wait(sk->sk_sleep, &wait);
 }
 
-static void sctp_sock_rfree_frag(struct sk_buff *skb)
-{
-       struct sk_buff *frag;
-
-       if (!skb->data_len)
-               goto done;
-
-       /* Don't forget the fragments. */
-       skb_walk_frags(skb, frag)
-               sctp_sock_rfree_frag(frag);
-
-done:
-       sctp_sock_rfree(skb);
-}
-
 static void sctp_skb_set_owner_r_frag(struct sk_buff *skb, struct sock *sk)
 {
        struct sk_buff *frag;
@@ -6776,7 +6761,6 @@ static void sctp_sock_migrate(struct sock *oldsk, struct sock *newsk,
        sctp_skb_for_each(skb, &oldsk->sk_receive_queue, tmp) {
                event = sctp_skb2event(skb);
                if (event->asoc == assoc) {
-                       sctp_sock_rfree_frag(skb);
                        __skb_unlink(skb, &oldsk->sk_receive_queue);
                        __skb_queue_tail(&newsk->sk_receive_queue, skb);
                        sctp_skb_set_owner_r_frag(skb, newsk);
@@ -6807,7 +6791,6 @@ static void sctp_sock_migrate(struct sock *oldsk, struct sock *newsk,
                sctp_skb_for_each(skb, &oldsp->pd_lobby, tmp) {
                        event = sctp_skb2event(skb);
                        if (event->asoc == assoc) {
-                               sctp_sock_rfree_frag(skb);
                                __skb_unlink(skb, &oldsp->pd_lobby);
                                __skb_queue_tail(queue, skb);
                                sctp_skb_set_owner_r_frag(skb, newsk);
@@ -6822,15 +6805,11 @@ static void sctp_sock_migrate(struct sock *oldsk, struct sock *newsk,
 
        }
 
-       sctp_skb_for_each(skb, &assoc->ulpq.reasm, tmp) {
-               sctp_sock_rfree_frag(skb);
+       sctp_skb_for_each(skb, &assoc->ulpq.reasm, tmp)
                sctp_skb_set_owner_r_frag(skb, newsk);
-       }
 
-       sctp_skb_for_each(skb, &assoc->ulpq.lobby, tmp) {
-               sctp_sock_rfree_frag(skb);
+       sctp_skb_for_each(skb, &assoc->ulpq.lobby, tmp)
                sctp_skb_set_owner_r_frag(skb, newsk);
-       }
 
        /* Set the type of socket to indicate that it is peeled off from the
         * original UDP-style socket or created with the accept() call on a
index 5bc2f45bddf0051a90f73274707b2697cc53b5d0..ebfcf9b8990918d65db492add437ae46fa259e30 100644 (file)
@@ -28,7 +28,6 @@
 #include <linux/kallsyms.h>
 #include <linux/mm.h>
 #include <linux/slab.h>
-#include <linux/smp_lock.h>
 #include <linux/utsname.h>
 #include <linux/workqueue.h>
 #include <linux/in6.h>
index 1102ce1251f7b61ad7d6a70a7df8826ce2a420c2..8f459abe97cff614525775560ec355f9d4c69246 100644 (file)
@@ -16,7 +16,6 @@
 #include <linux/slab.h>
 #include <linux/mempool.h>
 #include <linux/smp.h>
-#include <linux/smp_lock.h>
 #include <linux/spinlock.h>
 #include <linux/mutex.h>
 
index 843629f557630d07b0b4b0e29eb5a6f9feddce88..adaa81982f7469a31c0aa4af418ea74014312f9e 100644 (file)
@@ -66,6 +66,7 @@ cleanup_sunrpc(void)
 #ifdef CONFIG_PROC_FS
        rpc_proc_exit();
 #endif
+       rcu_barrier(); /* Wait for completion of call_rcu()'s */
 }
 MODULE_LICENSE("GPL");
 module_init(init_sunrpc);
index 6f33d33cc064e0f39f3232c910aff09fd53b3a67..27d44332f0175968c0729646ae4641321104bbd6 100644 (file)
@@ -5,6 +5,7 @@
  */
 
 #include <linux/sched.h>
+#include <linux/smp_lock.h>
 #include <linux/errno.h>
 #include <linux/freezer.h>
 #include <linux/kthread.h>
index 36d4e44d62334275ffbfaa8e3b837e95bcdace5f..fc3ebb906911b955b33b39af1a6a2e729d4695c9 100644 (file)
@@ -315,7 +315,7 @@ static void unix_write_space(struct sock *sk)
 {
        read_lock(&sk->sk_callback_lock);
        if (unix_writable(sk)) {
-               if (sk->sk_sleep && waitqueue_active(sk->sk_sleep))
+               if (sk_has_sleeper(sk))
                        wake_up_interruptible_sync(sk->sk_sleep);
                sk_wake_async(sk, SOCK_WAKE_SPACE, POLL_OUT);
        }
@@ -1985,7 +1985,7 @@ static unsigned int unix_poll(struct file *file, struct socket *sock, poll_table
        struct sock *sk = sock->sk;
        unsigned int mask;
 
-       poll_wait(file, sk->sk_sleep, wait);
+       sock_poll_wait(file, sk->sk_sleep, wait);
        mask = 0;
 
        /* exceptional events? */
@@ -2022,7 +2022,7 @@ static unsigned int unix_dgram_poll(struct file *file, struct socket *sock,
        struct sock *sk = sock->sk, *other;
        unsigned int mask, writable;
 
-       poll_wait(file, sk->sk_sleep, wait);
+       sock_poll_wait(file, sk->sk_sleep, wait);
        mask = 0;
 
        /* exceptional events? */
@@ -2053,7 +2053,7 @@ static unsigned int unix_dgram_poll(struct file *file, struct socket *sock,
                other = unix_peer_get(sk);
                if (other) {
                        if (unix_peer(other) != sk) {
-                               poll_wait(file, &unix_sk(other)->peer_wait,
+                               sock_poll_wait(file, &unix_sk(other)->peer_wait,
                                          wait);
                                if (unix_recvq_full(other))
                                        writable = 0;
index 466e2d22d256de7151551575607999ff6f1e95a9..258daa80ad926d80d86abcf06aaeb177514d1791 100644 (file)
@@ -48,6 +48,7 @@
 #include <linux/kernel.h>
 #include <linux/module.h>      /* support for loadable modules */
 #include <linux/slab.h>                /* kmalloc(), kfree() */
+#include <linux/smp_lock.h>
 #include <linux/mm.h>
 #include <linux/string.h>      /* inline mem*, str* functions */
 
index 241bddd0b4f19b2bb17009a295bf023345bfdc7c..43bdb1372caee29772f63397dd7ce1f7e7edd963 100644 (file)
@@ -447,6 +447,7 @@ static int nl80211_set_wiphy(struct sk_buff *skb, struct genl_info *info)
 
        rdev = __cfg80211_drv_from_info(info);
        if (IS_ERR(rdev)) {
+               mutex_unlock(&cfg80211_mutex);
                result = PTR_ERR(rdev);
                goto unlock;
        }
index e95b638b919f5dba4203a0959c0437fd612f239e..f8e71b300001e3a6ef5bde1f774d3c44e47ff2a0 100644 (file)
@@ -366,7 +366,6 @@ cfg80211_bss_update(struct cfg80211_registered_device *dev,
        found = rb_find_bss(dev, res);
 
        if (found) {
-               kref_get(&found->ref);
                found->pub.beacon_interval = res->pub.beacon_interval;
                found->pub.tsf = res->pub.tsf;
                found->pub.signal = res->pub.signal;
index 21cdc872004edbb4acba70070eadaa0ad8102e27..5e6c072c64d3d8b3380cc68247565fa291237952 100644 (file)
@@ -40,6 +40,7 @@
 #include <linux/errno.h>
 #include <linux/kernel.h>
 #include <linux/sched.h>
+#include <linux/smp_lock.h>
 #include <linux/timer.h>
 #include <linux/string.h>
 #include <linux/net.h>
index d31ccb487730b174a44ae0cc15d53d7fe9106822..faf54c6bf96bed9a25402d4ab728a21af120a207 100644 (file)
@@ -292,8 +292,8 @@ static struct xfrm_algo_desc ealg_list[] = {
        }
 },
 {
-       .name = "cbc(cast128)",
-       .compat = "cast128",
+       .name = "cbc(cast5)",
+       .compat = "cast5",
 
        .uinfo = {
                .encr = {
index 5f1f86565f162e4bccf4bcc215ef78a8272bbae3..f2f7c638083e321b8500e449f9a84c19bf903d97 100644 (file)
@@ -668,22 +668,10 @@ static struct xfrm_state *__xfrm_state_lookup(struct net *net, xfrm_address_t *d
        hlist_for_each_entry(x, entry, net->xfrm.state_byspi+h, byspi) {
                if (x->props.family != family ||
                    x->id.spi       != spi ||
-                   x->id.proto     != proto)
+                   x->id.proto     != proto ||
+                   xfrm_addr_cmp(&x->id.daddr, daddr, family))
                        continue;
 
-               switch (family) {
-               case AF_INET:
-                       if (x->id.daddr.a4 != daddr->a4)
-                               continue;
-                       break;
-               case AF_INET6:
-                       if (!ipv6_addr_equal((struct in6_addr *)daddr,
-                                            (struct in6_addr *)
-                                            x->id.daddr.a6))
-                               continue;
-                       break;
-               }
-
                xfrm_state_hold(x);
                return x;
        }
@@ -699,26 +687,11 @@ static struct xfrm_state *__xfrm_state_lookup_byaddr(struct net *net, xfrm_addre
 
        hlist_for_each_entry(x, entry, net->xfrm.state_bysrc+h, bysrc) {
                if (x->props.family != family ||
-                   x->id.proto     != proto)
+                   x->id.proto     != proto ||
+                   xfrm_addr_cmp(&x->id.daddr, daddr, family) ||
+                   xfrm_addr_cmp(&x->props.saddr, saddr, family))
                        continue;
 
-               switch (family) {
-               case AF_INET:
-                       if (x->id.daddr.a4 != daddr->a4 ||
-                           x->props.saddr.a4 != saddr->a4)
-                               continue;
-                       break;
-               case AF_INET6:
-                       if (!ipv6_addr_equal((struct in6_addr *)daddr,
-                                            (struct in6_addr *)
-                                            x->id.daddr.a6) ||
-                           !ipv6_addr_equal((struct in6_addr *)saddr,
-                                            (struct in6_addr *)
-                                            x->props.saddr.a6))
-                               continue;
-                       break;
-               }
-
                xfrm_state_hold(x);
                return x;
        }
@@ -1001,25 +974,11 @@ static struct xfrm_state *__find_acq_core(struct net *net, unsigned short family
                    x->props.family != family ||
                    x->km.state     != XFRM_STATE_ACQ ||
                    x->id.spi       != 0 ||
-                   x->id.proto     != proto)
+                   x->id.proto     != proto ||
+                   xfrm_addr_cmp(&x->id.daddr, daddr, family) ||
+                   xfrm_addr_cmp(&x->props.saddr, saddr, family))
                        continue;
 
-               switch (family) {
-               case AF_INET:
-                       if (x->id.daddr.a4    != daddr->a4 ||
-                           x->props.saddr.a4 != saddr->a4)
-                               continue;
-                       break;
-               case AF_INET6:
-                       if (!ipv6_addr_equal((struct in6_addr *)x->id.daddr.a6,
-                                            (struct in6_addr *)daddr) ||
-                           !ipv6_addr_equal((struct in6_addr *)
-                                            x->props.saddr.a6,
-                                            (struct in6_addr *)saddr))
-                               continue;
-                       break;
-               }
-
                xfrm_state_hold(x);
                return x;
        }
index 9977a756fb32102dae7b7e4eedf3130c20546e6f..f24ae370e514f77f04342c78d0d180e89e4001f4 100644 (file)
@@ -1,20 +1,3 @@
-/*
- * Notice that this file is not protected like a normal header.
- * We also must allow for rereading of this file. The
- *
- *  || defined(TRACE_HEADER_MULTI_READ)
- *
- * serves this purpose.
- */
-#if !defined(_TRACE_EVENT_SAMPLE_H) || defined(TRACE_HEADER_MULTI_READ)
-#define _TRACE_EVENT_SAMPLE_H
-
-/*
- * All trace headers should include tracepoint.h, until we finally
- * make it into a standard header.
- */
-#include <linux/tracepoint.h>
-
 /*
  * If TRACE_SYSTEM is defined, that will be the directory created
  * in the ftrace directory under /debugfs/tracing/events/<system>
  * #define TRACE_INCLUDE_FILE trace-events-sample
  *
  * As we do an the bottom of this file.
+ *
+ * Notice that TRACE_SYSTEM should be defined outside of #if
+ * protection, just like TRACE_INCLUDE_FILE.
  */
 #undef TRACE_SYSTEM
 #define TRACE_SYSTEM sample
 
+/*
+ * Notice that this file is not protected like a normal header.
+ * We also must allow for rereading of this file. The
+ *
+ *  || defined(TRACE_HEADER_MULTI_READ)
+ *
+ * serves this purpose.
+ */
+#if !defined(_TRACE_EVENT_SAMPLE_H) || defined(TRACE_HEADER_MULTI_READ)
+#define _TRACE_EVENT_SAMPLE_H
+
+/*
+ * All trace headers should include tracepoint.h, until we finally
+ * make it into a standard header.
+ */
+#include <linux/tracepoint.h>
+
 /*
  * The TRACE_EVENT macro is broken up into 5 parts.
  *
index b939fbd0119539f38b6c4f34e211223d9d8b4a45..52cab46ae35a3be5a6a1869ce2b01aa9c4e06190 100644 (file)
@@ -7,3 +7,4 @@ pnmtologo
 bin2c
 unifdef
 binoffset
+ihex2fw
diff --git a/scripts/dtc/.gitignore b/scripts/dtc/.gitignore
new file mode 100644 (file)
index 0000000..095acb4
--- /dev/null
@@ -0,0 +1,5 @@
+dtc
+dtc-lexer.lex.c
+dtc-parser.tab.c
+dtc-parser.tab.h
+
index ed591e9b7d1de8945040bef790bb2a540bcc09d2..b52d340d759da1123b94cdc441feb83e9458b3c0 100755 (executable)
@@ -1426,6 +1426,8 @@ sub dump_struct($$) {
        # strip comments:
        $members =~ s/\/\*.*?\*\///gos;
        $nested =~ s/\/\*.*?\*\///gos;
+       # strip kmemcheck_bitfield_{begin,end}.*;
+       $members =~ s/kmemcheck_bitfield_.*?;//gos;
 
        create_parameterlist($members, ';', $file);
        check_sections($file, $declaration_name, "struct", $sectcheck, $struct_actual, $nested);
@@ -1468,8 +1470,6 @@ sub dump_enum($$) {
            }
 
        }
-       # strip kmemcheck_bitfield_{begin,end}.*;
-       $members =~ s/kmemcheck_bitfield_.*?;//gos;
 
        output_declaration($declaration_name,
                           'enum',
index 01c2d13dd0204367b9655ee1c202f0a437ed2398..b19f1f4962e3dfdb852a4059bf3d1c6122963779 100644 (file)
@@ -16,6 +16,8 @@ create_package() {
        local pname="$1" pdir="$2"
 
        cp debian/copyright "$pdir/usr/share/doc/$pname/"
+       cp debian/changelog "$pdir/usr/share/doc/$pname/changelog.Debian"
+       gzip -9 "$pdir/usr/share/doc/$pname/changelog.Debian"
 
        # Fix ownership and permissions
        chown -R root:root "$pdir"
index 64f5ddb09ea626de131090d68aa5aeac10de060e..5c113123ed9f208840d5af7283e6df4769a4bc12 100644 (file)
@@ -237,7 +237,7 @@ static void write_header(void)
     fprintf(out, " *  Linux logo %s\n", logoname);
     fputs(" */\n\n", out);
     fputs("#include <linux/linux_logo.h>\n\n", out);
-    fprintf(out, "static const unsigned char %s_data[] __initconst = {\n",
+    fprintf(out, "static unsigned char %s_data[] __initdata = {\n",
            logoname);
 }
 
@@ -374,7 +374,7 @@ static void write_logo_clut224(void)
     fputs("\n};\n\n", out);
 
     /* write logo clut */
-    fprintf(out, "static const unsigned char %s_clut[] __initconst = {\n",
+    fprintf(out, "static unsigned char %s_clut[] __initdata = {\n",
            logoname);
     write_hex_cnt = 0;
     for (i = 0; i < logo_clutsize; i++) {
index 6f611874d10e9f7bbea81fab4fc537d68a711b75..101c512564ec60a850bf5c56163641c43f16b513 100644 (file)
@@ -238,7 +238,34 @@ out:
 }
 
 /*
- * ima_opens_get - increment file counts
+ * ima_counts_put - decrement file counts
+ *
+ * File counts are incremented in ima_path_check. On file open
+ * error, such as ETXTBSY, decrement the counts to prevent
+ * unnecessary imbalance messages.
+ */
+void ima_counts_put(struct path *path, int mask)
+{
+       struct inode *inode = path->dentry->d_inode;
+       struct ima_iint_cache *iint;
+
+       if (!ima_initialized || !S_ISREG(inode->i_mode))
+               return;
+       iint = ima_iint_find_insert_get(inode);
+       if (!iint)
+               return;
+
+       mutex_lock(&iint->mutex);
+       iint->opencount--;
+       if ((mask & MAY_WRITE) || (mask == 0))
+               iint->writecount--;
+       else if (mask & (MAY_READ | MAY_EXEC))
+               iint->readcount--;
+       mutex_unlock(&iint->mutex);
+}
+
+/*
+ * ima_counts_get - increment file counts
  *
  * - for IPC shm and shmat file.
  * - for nfsd exported files.
index 7ec94314ac0ca28126b7c051d8663bbd1319f9de..a0880e9c8e054695c757818b7991b2c37daf38ab 100644 (file)
@@ -134,7 +134,8 @@ int ima_add_template_entry(struct ima_template_entry *entry, int violation,
        }
 out:
        mutex_unlock(&ima_extend_list_mutex);
-       integrity_audit_msg(AUDIT_INTEGRITY_PCR, inode, entry->template_name,
+       integrity_audit_msg(AUDIT_INTEGRITY_PCR, inode,
+                           entry->template.file_name,
                            op, audit_cause, result, audit_info);
        return result;
 }
index 108b643229baecc3ec592eb300fbd4f332936c8c..6205f37d547ce80e0315be9d97fbc7ce7fa9ebe5 100644 (file)
@@ -75,7 +75,7 @@ int __pxa2xx_pcm_hw_free(struct snd_pcm_substream *substream)
 {
        struct pxa2xx_runtime_data *rtd = substream->runtime->private_data;
 
-       if (rtd && rtd->params)
+       if (rtd && rtd->params && rtd->params->drcmr)
                *rtd->params->drcmr = 0;
 
        snd_pcm_set_runtime_buffer(substream, NULL);
index de83608719ea23138a793e2c557444add2f4001e..3ee0269e5bd08376fa47bf94731459b9ac4e0d03 100644 (file)
@@ -338,7 +338,7 @@ static int __devinit snd_cmi8330_pnp(int dev, struct snd_cmi8330 *acard,
                return -EBUSY;
 
        acard->mpu = pnp_request_card_device(card, id->devs[2].id, NULL);
-       if (acard->play == NULL)
+       if (acard->mpu == NULL)
                return -EBUSY;
 
        pdev = acard->cap;
index c180598f1710498bf94ca0549622c798288fb675..89466b056be79c8f1515db39d517b3dede0d25c2 100644 (file)
@@ -199,7 +199,7 @@ MODULE_LICENSE("GPL");
  */
 
 static struct pci_device_id id_tbl[] = {
-       { PCI_VENDOR_ID_CYRIX, PCI_DEVICE_ID_CYRIX_5530_AUDIO, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
+       { PCI_VDEVICE(CYRIX, PCI_DEVICE_ID_CYRIX_5530_AUDIO), 0 },
        { }
 };
 
index 6c0a770ed0543d62bdc26203244c1e730a106110..1b2316f35b1f9b70cfab473913505e826ceb61ff 100644 (file)
@@ -926,31 +926,21 @@ static struct midi_operations mpu401_midi_operations[MAX_MIDI_DEV];
 static void mpu401_chk_version(int n, struct mpu_config *devc)
 {
        int tmp;
-       unsigned long flags;
 
        devc->version = devc->revision = 0;
 
-       spin_lock_irqsave(&devc->lock,flags);
-       if ((tmp = mpu_cmd(n, 0xAC, 0)) < 0)
-       {
-               spin_unlock_irqrestore(&devc->lock,flags);
+       tmp = mpu_cmd(n, 0xAC, 0);
+       if (tmp < 0)
                return;
-       }
        if ((tmp & 0xf0) > 0x20)        /* Why it's larger than 2.x ??? */
-       {
-               spin_unlock_irqrestore(&devc->lock,flags);
                return;
-       }
        devc->version = tmp;
 
-       if ((tmp = mpu_cmd(n, 0xAD, 0)) < 0)
-       {
+       if ((tmp = mpu_cmd(n, 0xAD, 0)) < 0) {
                devc->version = 0;
-               spin_unlock_irqrestore(&devc->lock,flags);
                return;
        }
        devc->revision = tmp;
-       spin_unlock_irqrestore(&devc->lock,flags);
 }
 
 int attach_mpu401(struct address_info *hw_config, struct module *owner)
index 71515ddb4593c71f75aa8f17d62d755034a4e181..d6752dff2a443df67a8b9cd3fa5a913e6dc7b68c 100644 (file)
@@ -287,10 +287,10 @@ struct atiixp {
 /*
  */
 static struct pci_device_id snd_atiixp_ids[] = {
-       { 0x1002, 0x4341, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, /* SB200 */
-       { 0x1002, 0x4361, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, /* SB300 */
-       { 0x1002, 0x4370, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, /* SB400 */
-       { 0x1002, 0x4382, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, /* SB600 */
+       { PCI_VDEVICE(ATI, 0x4341), 0 }, /* SB200 */
+       { PCI_VDEVICE(ATI, 0x4361), 0 }, /* SB300 */
+       { PCI_VDEVICE(ATI, 0x4370), 0 }, /* SB400 */
+       { PCI_VDEVICE(ATI, 0x4382), 0 }, /* SB600 */
        { 0, }
 };
 
index c3136cccc559e86f90f978d9bb922ae305c5d140..e7e147bf8eb2686cc98a629905f9589a0fb5357d 100644 (file)
@@ -262,8 +262,8 @@ struct atiixp_modem {
 /*
  */
 static struct pci_device_id snd_atiixp_ids[] = {
-       { 0x1002, 0x434d, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, /* SB200 */
-       { 0x1002, 0x4378, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, /* SB400 */
+       { PCI_VDEVICE(ATI, 0x434d), 0 }, /* SB200 */
+       { PCI_VDEVICE(ATI, 0x4378), 0 }, /* SB400 */
        { 0, }
 };
 
index fce22c7af0ea2a7d8c57af9910ae000d8f41db11..c0e8c6b295cb98df3fb8ef164f373cb35f81ba58 100644 (file)
@@ -1,8 +1,7 @@
 #include "au8810.h"
 #include "au88x0.h"
 static struct pci_device_id snd_vortex_ids[] = {
-       {PCI_VENDOR_ID_AUREAL, PCI_DEVICE_ID_AUREAL_ADVANTAGE,
-        PCI_ANY_ID, PCI_ANY_ID, 0, 0, 1,},
+       {PCI_VDEVICE(AUREAL, PCI_DEVICE_ID_AUREAL_ADVANTAGE), 1,},
        {0,}
 };
 
index d1fbcce0725731cc46d35b3946a17299acbf68ce..a6527330df584964b5b96b82632f747e22da89f2 100644 (file)
@@ -1,8 +1,7 @@
 #include "au8820.h"
 #include "au88x0.h"
 static struct pci_device_id snd_vortex_ids[] = {
-       {PCI_VENDOR_ID_AUREAL, PCI_DEVICE_ID_AUREAL_VORTEX_1,
-        PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0,},
+       {PCI_VDEVICE(AUREAL, PCI_DEVICE_ID_AUREAL_VORTEX_1), 0,},
        {0,}
 };
 
index d4f2717c14fb07a896c13cfd943c78b5a107bb32..6c702ad4352ad8198af4a062c75c9d93571f10fd 100644 (file)
@@ -1,8 +1,7 @@
 #include "au8830.h"
 #include "au88x0.h"
 static struct pci_device_id snd_vortex_ids[] = {
-       {PCI_VENDOR_ID_AUREAL, PCI_DEVICE_ID_AUREAL_VORTEX_2,
-        PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0,},
+       {PCI_VDEVICE(AUREAL, PCI_DEVICE_ID_AUREAL_VORTEX_2), 0,},
        {0,}
 };
 
index 57b992a5c05724c6b67e18668464e592d8b82660..f24bf1ecb36d1fa060fda9d817d17a872b11e774 100644 (file)
@@ -1876,7 +1876,7 @@ static int snd_ca0106_resume(struct pci_dev *pci)
 
 // PCI IDs
 static struct pci_device_id snd_ca0106_ids[] = {
-       { 0x1102, 0x0007, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },    /* Audigy LS or Live 24bit */
+       { PCI_VDEVICE(CREATIVE, 0x0007), 0 },   /* Audigy LS or Live 24bit */
        { 0, }
 };
 MODULE_DEVICE_TABLE(pci, snd_ca0106_ids);
index 449fe02f666e19288936295ebc8b5cc76c9d154b..ddcd4a9fd7e69f1cf63fcbc0d79adc8868c4237a 100644 (file)
@@ -2797,11 +2797,11 @@ static inline void snd_cmipci_proc_init(struct cmipci *cm) {}
 
 
 static struct pci_device_id snd_cmipci_ids[] = {
-       {PCI_VENDOR_ID_CMEDIA, PCI_DEVICE_ID_CMEDIA_CM8338A, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
-       {PCI_VENDOR_ID_CMEDIA, PCI_DEVICE_ID_CMEDIA_CM8338B, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
-       {PCI_VENDOR_ID_CMEDIA, PCI_DEVICE_ID_CMEDIA_CM8738, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
-       {PCI_VENDOR_ID_CMEDIA, PCI_DEVICE_ID_CMEDIA_CM8738B, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
-       {PCI_VENDOR_ID_AL, PCI_DEVICE_ID_CMEDIA_CM8738, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+       {PCI_VDEVICE(CMEDIA, PCI_DEVICE_ID_CMEDIA_CM8338A), 0},
+       {PCI_VDEVICE(CMEDIA, PCI_DEVICE_ID_CMEDIA_CM8338B), 0},
+       {PCI_VDEVICE(CMEDIA, PCI_DEVICE_ID_CMEDIA_CM8738), 0},
+       {PCI_VDEVICE(CMEDIA, PCI_DEVICE_ID_CMEDIA_CM8738B), 0},
+       {PCI_VDEVICE(AL, PCI_DEVICE_ID_CMEDIA_CM8738), 0},
        {0,},
 };
 
index f6286f84a2213c1b08314de7b74f2bcd6a2469fb..e2e0359bb0568ca98999f2512baeb83e67a55883 100644 (file)
@@ -495,7 +495,7 @@ struct cs4281 {
 static irqreturn_t snd_cs4281_interrupt(int irq, void *dev_id);
 
 static struct pci_device_id snd_cs4281_ids[] = {
-       { 0x1013, 0x6005, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, },   /* CS4281 */
+       { PCI_VDEVICE(CIRRUS, 0x6005), 0, },    /* CS4281 */
        { 0, }
 };
 
index c9b3e3d48cbcbf819e16e5d0a8535e8029310596..033aec430117ac698c50cfe7514e26b6b792bdbd 100644 (file)
@@ -65,9 +65,9 @@ module_param_array(mmap_valid, bool, NULL, 0444);
 MODULE_PARM_DESC(mmap_valid, "Support OSS mmap.");
 
 static struct pci_device_id snd_cs46xx_ids[] = {
-        { 0x1013, 0x6001, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, },   /* CS4280 */
-        { 0x1013, 0x6003, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, },   /* CS4612 */
-        { 0x1013, 0x6004, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, },   /* CS4615 */
+       { PCI_VDEVICE(CIRRUS, 0x6001), 0, },   /* CS4280 */
+       { PCI_VDEVICE(CIRRUS, 0x6003), 0, },   /* CS4612 */
+       { PCI_VDEVICE(CIRRUS, 0x6004), 0, },   /* CS4615 */
        { 0, }
 };
 
index c7f3b994101cef1f335fde62e09a5d53616e4152..168af67d938e1415993b29eb166763327ec0048b 100644 (file)
@@ -77,9 +77,9 @@ MODULE_PARM_DESC(subsystem, "Force card subsystem model.");
  * Class 0401: 1102:0008 (rev 00) Subsystem: 1102:1001 -> Audigy2 Value  Model:SB0400
  */
 static struct pci_device_id snd_emu10k1_ids[] = {
-       { 0x1102, 0x0002, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },    /* EMU10K1 */
-       { 0x1102, 0x0004, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 1 },    /* Audigy */
-       { 0x1102, 0x0008, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 1 },    /* Audigy 2 Value SB0400 */
+       { PCI_VDEVICE(CREATIVE, 0x0002), 0 },   /* EMU10K1 */
+       { PCI_VDEVICE(CREATIVE, 0x0004), 1 },   /* Audigy */
+       { PCI_VDEVICE(CREATIVE, 0x0008), 1 },   /* Audigy 2 Value SB0400 */
        { 0, }
 };
 
index 4d3ad793e98fb1618048ebf84d47374695604558..36e08bd2b3cc6ff8d2a4aa74e8f51e233bb62477 100644 (file)
@@ -1607,7 +1607,7 @@ static void __devexit snd_emu10k1x_remove(struct pci_dev *pci)
 
 // PCI IDs
 static struct pci_device_id snd_emu10k1x_ids[] = {
-       { 0x1102, 0x0006, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },    /* Dell OEM version (EMU10K1) */
+       { PCI_VDEVICE(CREATIVE, 0x0006), 0 },   /* Dell OEM version (EMU10K1) */
        { 0, }
 };
 MODULE_DEVICE_TABLE(pci, snd_emu10k1x_ids);
index e617acaf10e3300679b7ca0614183877bc654db9..61b8ab39800ff073cc9bf3c82bd4eb428a488350 100644 (file)
@@ -644,7 +644,7 @@ int __devinit snd_p16v_pcm(struct snd_emu10k1 *emu, int device, struct snd_pcm *
        int err;
         int capture=1;
   
-       /* snd_printk("KERN_DEBUG snd_p16v_pcm called. device=%d\n", device); */
+       /* snd_printk(KERN_DEBUG "snd_p16v_pcm called. device=%d\n", device); */
        emu->p16v_device_offset = device;
        if (rpcm)
                *rpcm = NULL;
index 18f4d1e98c46945c63c0a2c80c64e1fcc198bde8..2b82c5c723e159a1f393724dbca259f12d755050 100644 (file)
@@ -445,12 +445,12 @@ static irqreturn_t snd_audiopci_interrupt(int irq, void *dev_id);
 
 static struct pci_device_id snd_audiopci_ids[] = {
 #ifdef CHIP1370
-       { 0x1274, 0x5000, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, },   /* ES1370 */
+       { PCI_VDEVICE(ENSONIQ, 0x5000), 0, },   /* ES1370 */
 #endif
 #ifdef CHIP1371
-       { 0x1274, 0x1371, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, },   /* ES1371 */
-       { 0x1274, 0x5880, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, },   /* ES1373 - CT5880 */
-       { 0x1102, 0x8938, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, },   /* Ectiva EV1938 */
+       { PCI_VDEVICE(ENSONIQ, 0x1371), 0, },   /* ES1371 */
+       { PCI_VDEVICE(ENSONIQ, 0x5880), 0, },   /* ES1373 - CT5880 */
+       { PCI_VDEVICE(ECTIVA, 0x8938), 0, },    /* Ectiva EV1938 */
 #endif
        { 0, }
 };
index fbd2ac09aa34a667ef0220e9ac51bbd4a7072890..820318ee62c179872a2354e656b438e8ed74504d 100644 (file)
@@ -244,7 +244,7 @@ struct es1938 {
 static irqreturn_t snd_es1938_interrupt(int irq, void *dev_id);
 
 static struct pci_device_id snd_es1938_ids[] = {
-        { 0x125d, 0x1969, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, },   /* Solo-1 */
+       { PCI_VDEVICE(ESS, 0x1969), 0, },   /* Solo-1 */
        { 0, }
 };
 
index 29272f2e95a07945cf805e6c75867f0f1e2cb762..b0275a05087015aa0c7d8680cd23c03f63830d40 100644 (file)
@@ -50,19 +50,22 @@ static void snd_hda_generate_beep(struct work_struct *work)
  * The tone frequency of beep generator on IDT/STAC codecs is
  * defined from the 8bit tone parameter, in Hz,
  *    freq = 48000 * (257 - tone) / 1024
- * that is from 12kHz to 93.75kHz in step of 46.875 hz
+ * that is from 12kHz to 93.75Hz in steps of 46.875 Hz
  */
 static int beep_linear_tone(struct hda_beep *beep, int hz)
 {
+       if (hz <= 0)
+               return 0;
        hz *= 1000; /* fixed point */
-       hz = hz - DIGBEEP_HZ_MIN;
+       hz = hz - DIGBEEP_HZ_MIN
+               + DIGBEEP_HZ_STEP / 2; /* round to nearest step */
        if (hz < 0)
                hz = 0; /* turn off PC beep*/
        else if (hz >= (DIGBEEP_HZ_MAX - DIGBEEP_HZ_MIN))
-               hz = 0xff;
+               hz = 1; /* max frequency */
        else {
                hz /= DIGBEEP_HZ_STEP;
-               hz++;
+               hz = 255 - hz;
        }
        return hz;
 }
index 462e2cedaa6af6807fbee41fdc9f0fa6140389af..26d255de6bebb73b6fa51b39b740132b7c0b609c 100644 (file)
@@ -3470,10 +3470,16 @@ int snd_hda_multi_out_analog_open(struct hda_codec *codec,
                }
                mutex_lock(&codec->spdif_mutex);
                if (mout->share_spdif) {
-                       runtime->hw.rates &= mout->spdif_rates;
-                       runtime->hw.formats &= mout->spdif_formats;
-                       if (mout->spdif_maxbps < hinfo->maxbps)
-                               hinfo->maxbps = mout->spdif_maxbps;
+                       if ((runtime->hw.rates & mout->spdif_rates) &&
+                           (runtime->hw.formats & mout->spdif_formats)) {
+                               runtime->hw.rates &= mout->spdif_rates;
+                               runtime->hw.formats &= mout->spdif_formats;
+                               if (mout->spdif_maxbps < hinfo->maxbps)
+                                       hinfo->maxbps = mout->spdif_maxbps;
+                       } else {
+                               mout->share_spdif = 0;
+                               /* FIXME: need notify? */
+                       }
                }
                mutex_unlock(&codec->spdif_mutex);
        }
index 4e9ea70802701247ef09f6d1a6ce4a68164a216f..77c1b840ca8b081839bc9c5baad859d0cb8a8596 100644 (file)
@@ -1454,6 +1454,18 @@ static int azx_pcm_open(struct snd_pcm_substream *substream)
                mutex_unlock(&chip->open_mutex);
                return err;
        }
+       snd_pcm_limit_hw_rates(runtime);
+       /* sanity check */
+       if (snd_BUG_ON(!runtime->hw.channels_min) ||
+           snd_BUG_ON(!runtime->hw.channels_max) ||
+           snd_BUG_ON(!runtime->hw.formats) ||
+           snd_BUG_ON(!runtime->hw.rates)) {
+               azx_release_device(azx_dev);
+               hinfo->ops.close(hinfo, apcm->codec, substream);
+               snd_hda_power_down(apcm->codec);
+               mutex_unlock(&chip->open_mutex);
+               return -EINVAL;
+       }
        spin_lock_irqsave(&chip->reg_lock, flags);
        azx_dev->substream = substream;
        azx_dev->running = 0;
@@ -1462,7 +1474,6 @@ static int azx_pcm_open(struct snd_pcm_substream *substream)
        runtime->private_data = azx_dev;
        snd_pcm_set_sync(substream);
        mutex_unlock(&chip->open_mutex);
-
        return 0;
 }
 
@@ -2322,9 +2333,19 @@ static int __devinit azx_create(struct snd_card *card, struct pci_dev *pci,
        gcap = azx_readw(chip, GCAP);
        snd_printdd(SFX "chipset global capabilities = 0x%x\n", gcap);
 
-       /* ATI chips seems buggy about 64bit DMA addresses */
-       if (chip->driver_type == AZX_DRIVER_ATI)
-               gcap &= ~ICH6_GCAP_64OK;
+       /* disable SB600 64bit support for safety */
+       if ((chip->driver_type == AZX_DRIVER_ATI) ||
+           (chip->driver_type == AZX_DRIVER_ATIHDMI)) {
+               struct pci_dev *p_smbus;
+               p_smbus = pci_get_device(PCI_VENDOR_ID_ATI,
+                                        PCI_DEVICE_ID_ATI_SBX00_SMBUS,
+                                        NULL);
+               if (p_smbus) {
+                       if (p_smbus->revision < 0x30)
+                               gcap &= ~ICH6_GCAP_64OK;
+                       pci_dev_put(p_smbus);
+               }
+       }
 
        /* allow 64bit DMA address if supported by H/W */
        if ((gcap & ICH6_GCAP_64OK) && !pci_set_dma_mask(pci, DMA_BIT_MASK(64)))
index 84cc49ca91487d8535bde13aaf60139bb16c4fa7..be7d25fa7f35a3e164cf858aa7f5c4b67afd9ac6 100644 (file)
@@ -72,6 +72,7 @@ struct ad198x_spec {
        hda_nid_t private_dac_nids[AUTO_CFG_MAX_OUTS];
 
        unsigned int jack_present :1;
+       unsigned int inv_jack_detect:1;
 
 #ifdef CONFIG_SND_HDA_POWER_SAVE
        struct hda_loopback_check loopback;
@@ -669,39 +670,13 @@ static struct hda_input_mux ad1986a_automic_capture_source = {
        },
 };
 
-static struct snd_kcontrol_new ad1986a_laptop_eapd_mixers[] = {
+static struct snd_kcontrol_new ad1986a_laptop_master_mixers[] = {
        HDA_BIND_VOL("Master Playback Volume", &ad1986a_laptop_master_vol),
        HDA_BIND_SW("Master Playback Switch", &ad1986a_laptop_master_sw),
-       HDA_CODEC_VOLUME("PCM Playback Volume", 0x03, 0x0, HDA_OUTPUT),
-       HDA_CODEC_MUTE("PCM Playback Switch", 0x03, 0x0, HDA_OUTPUT),
-       HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x17, 0, HDA_OUTPUT),
-       HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x17, 0, HDA_OUTPUT),
-       HDA_CODEC_VOLUME("Mic Playback Volume", 0x13, 0x0, HDA_OUTPUT),
-       HDA_CODEC_MUTE("Mic Playback Switch", 0x13, 0x0, HDA_OUTPUT),
-       HDA_CODEC_VOLUME("Mic Boost", 0x0f, 0x0, HDA_OUTPUT),
-       HDA_CODEC_VOLUME("Capture Volume", 0x12, 0x0, HDA_OUTPUT),
-       HDA_CODEC_MUTE("Capture Switch", 0x12, 0x0, HDA_OUTPUT),
-       {
-               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-               .name = "Capture Source",
-               .info = ad198x_mux_enum_info,
-               .get = ad198x_mux_enum_get,
-               .put = ad198x_mux_enum_put,
-       },
-       {
-               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-               .name = "External Amplifier",
-               .info = ad198x_eapd_info,
-               .get = ad198x_eapd_get,
-               .put = ad198x_eapd_put,
-               .private_value = 0x1b | (1 << 8), /* port-D, inversed */
-       },
        { } /* end */
 };
 
-static struct snd_kcontrol_new ad1986a_samsung_mixers[] = {
-       HDA_BIND_VOL("Master Playback Volume", &ad1986a_laptop_master_vol),
-       HDA_BIND_SW("Master Playback Switch", &ad1986a_laptop_master_sw),
+static struct snd_kcontrol_new ad1986a_laptop_eapd_mixers[] = {
        HDA_CODEC_VOLUME("PCM Playback Volume", 0x03, 0x0, HDA_OUTPUT),
        HDA_CODEC_MUTE("PCM Playback Switch", 0x03, 0x0, HDA_OUTPUT),
        HDA_CODEC_VOLUME("Mic Playback Volume", 0x13, 0x0, HDA_OUTPUT),
@@ -727,6 +702,12 @@ static struct snd_kcontrol_new ad1986a_samsung_mixers[] = {
        { } /* end */
 };
 
+static struct snd_kcontrol_new ad1986a_laptop_intmic_mixers[] = {
+       HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x17, 0, HDA_OUTPUT),
+       HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x17, 0, HDA_OUTPUT),
+       { } /* end */
+};
+
 /* re-connect the mic boost input according to the jack sensing */
 static void ad1986a_automic(struct hda_codec *codec)
 {
@@ -776,8 +757,9 @@ static void ad1986a_hp_automute(struct hda_codec *codec)
        unsigned int present;
 
        present = snd_hda_codec_read(codec, 0x1a, 0, AC_VERB_GET_PIN_SENSE, 0);
-       /* Lenovo N100 seems to report the reversed bit for HP jack-sensing */
-       spec->jack_present = !(present & 0x80000000);
+       spec->jack_present = !!(present & 0x80000000);
+       if (spec->inv_jack_detect)
+               spec->jack_present = !spec->jack_present;
        ad1986a_update_hp(codec);
 }
 
@@ -816,7 +798,7 @@ static int ad1986a_hp_master_sw_put(struct snd_kcontrol *kcontrol,
        return change;
 }
 
-static struct snd_kcontrol_new ad1986a_laptop_automute_mixers[] = {
+static struct snd_kcontrol_new ad1986a_automute_master_mixers[] = {
        HDA_BIND_VOL("Master Playback Volume", &ad1986a_laptop_master_vol),
        {
                .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
@@ -826,33 +808,10 @@ static struct snd_kcontrol_new ad1986a_laptop_automute_mixers[] = {
                .put = ad1986a_hp_master_sw_put,
                .private_value = HDA_COMPOSE_AMP_VAL(0x1a, 3, 0, HDA_OUTPUT),
        },
-       HDA_CODEC_VOLUME("PCM Playback Volume", 0x03, 0x0, HDA_OUTPUT),
-       HDA_CODEC_MUTE("PCM Playback Switch", 0x03, 0x0, HDA_OUTPUT),
-       HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x17, 0x0, HDA_OUTPUT),
-       HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x17, 0x0, HDA_OUTPUT),
-       HDA_CODEC_VOLUME("Mic Playback Volume", 0x13, 0x0, HDA_OUTPUT),
-       HDA_CODEC_MUTE("Mic Playback Switch", 0x13, 0x0, HDA_OUTPUT),
-       HDA_CODEC_VOLUME("Mic Boost", 0x0f, 0x0, HDA_OUTPUT),
-       HDA_CODEC_VOLUME("Capture Volume", 0x12, 0x0, HDA_OUTPUT),
-       HDA_CODEC_MUTE("Capture Switch", 0x12, 0x0, HDA_OUTPUT),
-       {
-               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-               .name = "Capture Source",
-               .info = ad198x_mux_enum_info,
-               .get = ad198x_mux_enum_get,
-               .put = ad198x_mux_enum_put,
-       },
-       {
-               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-               .name = "External Amplifier",
-               .info = ad198x_eapd_info,
-               .get = ad198x_eapd_get,
-               .put = ad198x_eapd_put,
-               .private_value = 0x1b | (1 << 8), /* port-D, inversed */
-       },
        { } /* end */
 };
 
+
 /*
  * initialization verbs
  */
@@ -981,6 +940,27 @@ static struct hda_verb ad1986a_hp_init_verbs[] = {
        {}
 };
 
+static void ad1986a_samsung_p50_unsol_event(struct hda_codec *codec,
+                                           unsigned int res)
+{
+       switch (res >> 26) {
+       case AD1986A_HP_EVENT:
+               ad1986a_hp_automute(codec);
+               break;
+       case AD1986A_MIC_EVENT:
+               ad1986a_automic(codec);
+               break;
+       }
+}
+
+static int ad1986a_samsung_p50_init(struct hda_codec *codec)
+{
+       ad198x_init(codec);
+       ad1986a_hp_automute(codec);
+       ad1986a_automic(codec);
+       return 0;
+}
+
 
 /* models */
 enum {
@@ -991,6 +971,7 @@ enum {
        AD1986A_LAPTOP_AUTOMUTE,
        AD1986A_ULTRA,
        AD1986A_SAMSUNG,
+       AD1986A_SAMSUNG_P50,
        AD1986A_MODELS
 };
 
@@ -1002,6 +983,7 @@ static const char *ad1986a_models[AD1986A_MODELS] = {
        [AD1986A_LAPTOP_AUTOMUTE] = "laptop-automute",
        [AD1986A_ULTRA]         = "ultra",
        [AD1986A_SAMSUNG]       = "samsung",
+       [AD1986A_SAMSUNG_P50]   = "samsung-p50",
 };
 
 static struct snd_pci_quirk ad1986a_cfg_tbl[] = {
@@ -1024,6 +1006,7 @@ static struct snd_pci_quirk ad1986a_cfg_tbl[] = {
        SND_PCI_QUIRK(0x1179, 0xff40, "Toshiba", AD1986A_LAPTOP_EAPD),
        SND_PCI_QUIRK(0x144d, 0xb03c, "Samsung R55", AD1986A_3STACK),
        SND_PCI_QUIRK(0x144d, 0xc01e, "FSC V2060", AD1986A_LAPTOP),
+       SND_PCI_QUIRK(0x144d, 0xc024, "Samsung P50", AD1986A_SAMSUNG_P50),
        SND_PCI_QUIRK(0x144d, 0xc027, "Samsung Q1", AD1986A_ULTRA),
        SND_PCI_QUIRK_MASK(0x144d, 0xff00, 0xc000, "Samsung", AD1986A_SAMSUNG),
        SND_PCI_QUIRK(0x144d, 0xc504, "Samsung Q35", AD1986A_3STACK),
@@ -1111,7 +1094,10 @@ static int patch_ad1986a(struct hda_codec *codec)
                spec->multiout.dac_nids = ad1986a_laptop_dac_nids;
                break;
        case AD1986A_LAPTOP_EAPD:
-               spec->mixers[0] = ad1986a_laptop_eapd_mixers;
+               spec->num_mixers = 3;
+               spec->mixers[0] = ad1986a_laptop_master_mixers;
+               spec->mixers[1] = ad1986a_laptop_eapd_mixers;
+               spec->mixers[2] = ad1986a_laptop_intmic_mixers;
                spec->num_init_verbs = 2;
                spec->init_verbs[1] = ad1986a_eapd_init_verbs;
                spec->multiout.max_channels = 2;
@@ -1122,7 +1108,9 @@ static int patch_ad1986a(struct hda_codec *codec)
                spec->input_mux = &ad1986a_laptop_eapd_capture_source;
                break;
        case AD1986A_SAMSUNG:
-               spec->mixers[0] = ad1986a_samsung_mixers;
+               spec->num_mixers = 2;
+               spec->mixers[0] = ad1986a_laptop_master_mixers;
+               spec->mixers[1] = ad1986a_laptop_eapd_mixers;
                spec->num_init_verbs = 3;
                spec->init_verbs[1] = ad1986a_eapd_init_verbs;
                spec->init_verbs[2] = ad1986a_automic_verbs;
@@ -1135,8 +1123,28 @@ static int patch_ad1986a(struct hda_codec *codec)
                codec->patch_ops.unsol_event = ad1986a_automic_unsol_event;
                codec->patch_ops.init = ad1986a_automic_init;
                break;
+       case AD1986A_SAMSUNG_P50:
+               spec->num_mixers = 2;
+               spec->mixers[0] = ad1986a_automute_master_mixers;
+               spec->mixers[1] = ad1986a_laptop_eapd_mixers;
+               spec->num_init_verbs = 4;
+               spec->init_verbs[1] = ad1986a_eapd_init_verbs;
+               spec->init_verbs[2] = ad1986a_automic_verbs;
+               spec->init_verbs[3] = ad1986a_hp_init_verbs;
+               spec->multiout.max_channels = 2;
+               spec->multiout.num_dacs = 1;
+               spec->multiout.dac_nids = ad1986a_laptop_dac_nids;
+               if (!is_jack_available(codec, 0x25))
+                       spec->multiout.dig_out_nid = 0;
+               spec->input_mux = &ad1986a_automic_capture_source;
+               codec->patch_ops.unsol_event = ad1986a_samsung_p50_unsol_event;
+               codec->patch_ops.init = ad1986a_samsung_p50_init;
+               break;
        case AD1986A_LAPTOP_AUTOMUTE:
-               spec->mixers[0] = ad1986a_laptop_automute_mixers;
+               spec->num_mixers = 3;
+               spec->mixers[0] = ad1986a_automute_master_mixers;
+               spec->mixers[1] = ad1986a_laptop_eapd_mixers;
+               spec->mixers[2] = ad1986a_laptop_intmic_mixers;
                spec->num_init_verbs = 3;
                spec->init_verbs[1] = ad1986a_eapd_init_verbs;
                spec->init_verbs[2] = ad1986a_hp_init_verbs;
@@ -1148,6 +1156,10 @@ static int patch_ad1986a(struct hda_codec *codec)
                spec->input_mux = &ad1986a_laptop_eapd_capture_source;
                codec->patch_ops.unsol_event = ad1986a_hp_unsol_event;
                codec->patch_ops.init = ad1986a_hp_init;
+               /* Lenovo N100 seems to report the reversed bit
+                * for HP jack-sensing
+                */
+               spec->inv_jack_detect = 1;
                break;
        case AD1986A_ULTRA:
                spec->mixers[0] = ad1986a_laptop_eapd_mixers;
@@ -3734,9 +3746,30 @@ static struct snd_kcontrol_new ad1884a_laptop_mixers[] = {
        { } /* end */
 };
 
+static int ad1884a_mobile_master_sw_put(struct snd_kcontrol *kcontrol,
+                                       struct snd_ctl_elem_value *ucontrol)
+{
+       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+       int ret = snd_hda_mixer_amp_switch_put(kcontrol, ucontrol);
+       int mute = (!ucontrol->value.integer.value[0] &&
+                   !ucontrol->value.integer.value[1]);
+       /* toggle GPIO1 according to the mute state */
+       snd_hda_codec_write(codec, 0x01, 0, AC_VERB_SET_GPIO_DATA,
+                           mute ? 0x02 : 0x0);
+       return ret;
+}
+
 static struct snd_kcontrol_new ad1884a_mobile_mixers[] = {
        HDA_CODEC_VOLUME("Master Playback Volume", 0x21, 0x0, HDA_OUTPUT),
-       HDA_CODEC_MUTE("Master Playback Switch", 0x21, 0x0, HDA_OUTPUT),
+       /*HDA_CODEC_MUTE("Master Playback Switch", 0x21, 0x0, HDA_OUTPUT),*/
+       {
+               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+               .name = "Master Playback Switch",
+               .info = snd_hda_mixer_amp_switch_info,
+               .get = snd_hda_mixer_amp_switch_get,
+               .put = ad1884a_mobile_master_sw_put,
+               .private_value = HDA_COMPOSE_AMP_VAL(0x21, 3, 0, HDA_OUTPUT),
+       },
        HDA_CODEC_VOLUME("PCM Playback Volume", 0x20, 0x5, HDA_INPUT),
        HDA_CODEC_MUTE("PCM Playback Switch", 0x20, 0x5, HDA_INPUT),
        HDA_CODEC_VOLUME("Mic Capture Volume", 0x14, 0x0, HDA_INPUT),
@@ -3857,6 +3890,10 @@ static struct hda_verb ad1884a_mobile_verbs[] = {
        /* unsolicited event for pin-sense */
        {0x11, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | AD1884A_HP_EVENT},
        {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | AD1884A_MIC_EVENT},
+       /* allow to touch GPIO1 (for mute control) */
+       {0x01, AC_VERB_SET_GPIO_MASK, 0x02},
+       {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x02},
+       {0x01, AC_VERB_SET_GPIO_DATA, 0x02}, /* first muted */
        { } /* end */
 };
 
@@ -3966,6 +4003,7 @@ static struct snd_pci_quirk ad1884a_cfg_tbl[] = {
        SND_PCI_QUIRK(0x103c, 0x3037, "HP 2230s", AD1884A_LAPTOP),
        SND_PCI_QUIRK(0x103c, 0x3056, "HP", AD1884A_MOBILE),
        SND_PCI_QUIRK_MASK(0x103c, 0xfff0, 0x3070, "HP", AD1884A_MOBILE),
+       SND_PCI_QUIRK_MASK(0x103c, 0xfff0, 0x30d0, "HP laptop", AD1884A_LAPTOP),
        SND_PCI_QUIRK_MASK(0x103c, 0xfff0, 0x30e0, "HP laptop", AD1884A_LAPTOP),
        SND_PCI_QUIRK_MASK(0x103c, 0xff00, 0x3600, "HP laptop", AD1884A_LAPTOP),
        SND_PCI_QUIRK(0x17aa, 0x20ac, "Thinkpad X300", AD1884A_THINKPAD),
index 392d108c355878791fa1b21700e055203e7566a9..019ca7cb56d7d54631a425cb8f079099ef2ef11a 100644 (file)
@@ -510,7 +510,7 @@ static int ca0110_parse_auto_config(struct hda_codec *codec)
 }
 
 
-int patch_ca0110(struct hda_codec *codec)
+static int patch_ca0110(struct hda_codec *codec)
 {
        struct ca0110_spec *spec;
        int err;
index 33453319742508251d3b9a96d2ca1c26312cdcd8..7e99763ca527209ad3243e3b0f75228aeb440fce 100644 (file)
@@ -945,12 +945,13 @@ static void alc_fix_pll_init(struct hda_codec *codec, hda_nid_t nid,
 static void alc_automute_pin(struct hda_codec *codec)
 {
        struct alc_spec *spec = codec->spec;
-       unsigned int present;
+       unsigned int present, pincap;
        unsigned int nid = spec->autocfg.hp_pins[0];
        int i;
 
-       /* need to execute and sync at first */
-       snd_hda_codec_read(codec, nid, 0, AC_VERB_SET_PIN_SENSE, 0);
+       pincap = snd_hda_query_pin_caps(codec, nid);
+       if (pincap & AC_PINCAP_TRIG_REQ) /* need trigger? */
+               snd_hda_codec_read(codec, nid, 0, AC_VERB_SET_PIN_SENSE, 0);
        present = snd_hda_codec_read(codec, nid, 0,
                                     AC_VERB_GET_PIN_SENSE, 0);
        spec->jack_present = (present & AC_PINSENSE_PRESENCE) != 0;
@@ -1392,7 +1393,7 @@ static struct hda_verb alc888_fujitsu_xa3530_verbs[] = {
 static void alc_automute_amp(struct hda_codec *codec)
 {
        struct alc_spec *spec = codec->spec;
-       unsigned int val, mute;
+       unsigned int val, mute, pincap;
        hda_nid_t nid;
        int i;
 
@@ -1401,6 +1402,10 @@ static void alc_automute_amp(struct hda_codec *codec)
                nid = spec->autocfg.hp_pins[i];
                if (!nid)
                        break;
+               pincap = snd_hda_query_pin_caps(codec, nid);
+               if (pincap & AC_PINCAP_TRIG_REQ) /* need trigger? */
+                       snd_hda_codec_read(codec, nid, 0,
+                                          AC_VERB_SET_PIN_SENSE, 0);
                val = snd_hda_codec_read(codec, nid, 0,
                                         AC_VERB_GET_PIN_SENSE, 0);
                if (val & AC_PINSENSE_PRESENCE) {
@@ -1471,6 +1476,10 @@ static struct hda_verb alc888_acer_aspire_4930g_verbs[] = {
 static struct hda_verb alc888_acer_aspire_6530g_verbs[] = {
 /* Bias voltage on for external mic port */
        {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN | PIN_VREF80},
+/* Front Mic: set to PIN_IN (empty by default) */
+       {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
+/* Unselect Front Mic by default in input mixer 3 */
+       {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0xb)},
 /* Enable unsolicited event for HP jack */
        {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
 /* Enable speaker output */
@@ -1560,18 +1569,22 @@ static struct hda_input_mux alc888_2_capture_sources[2] = {
 static struct hda_input_mux alc888_acer_aspire_6530_sources[2] = {
        /* Interal mic only available on one ADC */
        {
-               .num_items = 3,
+               .num_items = 5,
                .items = {
                        { "Ext Mic", 0x0 },
+                       { "Line In", 0x2 },
                        { "CD", 0x4 },
+                       { "Input Mix", 0xa },
                        { "Int Mic", 0xb },
                },
        },
        {
-               .num_items = 2,
+               .num_items = 4,
                .items = {
                        { "Ext Mic", 0x0 },
+                       { "Line In", 0x2 },
                        { "CD", 0x4 },
+                       { "Input Mix", 0xa },
                },
        }
 };
@@ -1639,6 +1652,17 @@ static void alc888_acer_aspire_4930g_init_hook(struct hda_codec *codec)
        alc_automute_amp(codec);
 }
 
+static void alc888_acer_aspire_6530g_init_hook(struct hda_codec *codec)
+{
+       struct alc_spec *spec = codec->spec;
+
+       spec->autocfg.hp_pins[0] = 0x15;
+       spec->autocfg.speaker_pins[0] = 0x14;
+       spec->autocfg.speaker_pins[1] = 0x16;
+       spec->autocfg.speaker_pins[2] = 0x17;
+       alc_automute_amp(codec);
+}
+
 static void alc889_acer_aspire_8930g_init_hook(struct hda_codec *codec)
 {
        struct alc_spec *spec = codec->spec;
@@ -4481,6 +4505,12 @@ static int alc880_parse_auto_config(struct hda_codec *codec)
                                              &dig_nid, 1);
                if (err < 0)
                        continue;
+               if (dig_nid > 0x7f) {
+                       printk(KERN_ERR "alc880_auto: invalid dig_nid "
+                               "connection 0x%x for NID 0x%x\n", dig_nid,
+                               spec->autocfg.dig_out_pins[i]);
+                       continue;
+               }
                if (!i)
                        spec->multiout.dig_out_nid = dig_nid;
                else {
@@ -6895,9 +6925,6 @@ static struct hda_verb alc882_targa_verbs[] = {
        {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
 
        {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
-       {0x01, AC_VERB_SET_GPIO_MASK, 0x03},
-       {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x03},
-       {0x01, AC_VERB_SET_GPIO_DATA, 0x03},
        { } /* end */
 };
 
@@ -7217,7 +7244,8 @@ static struct alc_config_preset alc882_presets[] = {
        },
        [ALC882_TARGA] = {
                .mixers = { alc882_targa_mixer, alc882_chmode_mixer },
-               .init_verbs = { alc882_init_verbs, alc882_targa_verbs},
+               .init_verbs = { alc882_init_verbs, alc880_gpio3_init_verbs,
+                               alc882_targa_verbs},
                .num_dacs = ARRAY_SIZE(alc882_dac_nids),
                .dac_nids = alc882_dac_nids,
                .dig_out_nid = ALC882_DIGOUT_NID,
@@ -8189,6 +8217,8 @@ static struct snd_kcontrol_new alc888_acer_aspire_6530_mixer[] = {
        HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
        HDA_CODEC_VOLUME("LFE Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
        HDA_BIND_MUTE("LFE Playback Switch", 0x0f, 2, HDA_INPUT),
+       HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
+       HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
        HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
        HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
        HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
@@ -9064,7 +9094,7 @@ static struct snd_pci_quirk alc883_cfg_tbl[] = {
        SND_PCI_QUIRK(0x1025, 0x0157, "Acer X3200", ALC883_AUTO),
        SND_PCI_QUIRK(0x1025, 0x0158, "Acer AX1700-U3700A", ALC883_AUTO),
        SND_PCI_QUIRK(0x1025, 0x015e, "Acer Aspire 6930G",
-               ALC888_ACER_ASPIRE_4930G),
+               ALC888_ACER_ASPIRE_6530G),
        SND_PCI_QUIRK(0x1025, 0x0166, "Acer Aspire 6530G",
                ALC888_ACER_ASPIRE_6530G),
        /* default Acer -- disabled as it causes more problems.
@@ -9212,7 +9242,8 @@ static struct alc_config_preset alc883_presets[] = {
        },
        [ALC883_TARGA_DIG] = {
                .mixers = { alc883_targa_mixer, alc883_chmode_mixer },
-               .init_verbs = { alc883_init_verbs, alc883_targa_verbs},
+               .init_verbs = { alc883_init_verbs, alc880_gpio3_init_verbs,
+                               alc883_targa_verbs},
                .num_dacs = ARRAY_SIZE(alc883_dac_nids),
                .dac_nids = alc883_dac_nids,
                .dig_out_nid = ALC883_DIGOUT_NID,
@@ -9225,7 +9256,8 @@ static struct alc_config_preset alc883_presets[] = {
        },
        [ALC883_TARGA_2ch_DIG] = {
                .mixers = { alc883_targa_2ch_mixer},
-               .init_verbs = { alc883_init_verbs, alc883_targa_verbs},
+               .init_verbs = { alc883_init_verbs, alc880_gpio3_init_verbs,
+                               alc883_targa_verbs},
                .num_dacs = ARRAY_SIZE(alc883_dac_nids),
                .dac_nids = alc883_dac_nids,
                .adc_nids = alc883_adc_nids_alt,
@@ -9317,7 +9349,7 @@ static struct alc_config_preset alc883_presets[] = {
                        ARRAY_SIZE(alc888_2_capture_sources),
                .input_mux = alc888_acer_aspire_6530_sources,
                .unsol_event = alc_automute_amp_unsol_event,
-               .init_hook = alc888_acer_aspire_4930g_init_hook,
+               .init_hook = alc888_acer_aspire_6530g_init_hook,
        },
        [ALC888_ACER_ASPIRE_8930G] = {
                .mixers = { alc888_base_mixer,
@@ -12437,6 +12469,8 @@ static int alc268_parse_auto_config(struct hda_codec *codec)
        if (err < 0)
                return err;
 
+       alc_ssid_check(codec, 0x15, 0x1b, 0x14);
+
        return 1;
 }
 
@@ -12848,20 +12882,11 @@ static struct snd_kcontrol_new alc269_lifebook_mixer[] = {
        { }
 };
 
-/* bind volumes of both NID 0x0c and 0x0d */
-static struct hda_bind_ctls alc269_epc_bind_vol = {
-       .ops = &snd_hda_bind_vol,
-       .values = {
-               HDA_COMPOSE_AMP_VAL(0x02, 3, 0, HDA_OUTPUT),
-               HDA_COMPOSE_AMP_VAL(0x03, 3, 0, HDA_OUTPUT),
-               0
-       },
-};
-
 static struct snd_kcontrol_new alc269_eeepc_mixer[] = {
-       HDA_CODEC_MUTE("iSpeaker Playback Switch", 0x14, 0x0, HDA_OUTPUT),
-       HDA_BIND_VOL("LineOut Playback Volume", &alc269_epc_bind_vol),
-       HDA_CODEC_MUTE("LineOut Playback Switch", 0x15, 0x0, HDA_OUTPUT),
+       HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT),
+       HDA_CODEC_VOLUME("Speaker Playback Volume", 0x02, 0x0, HDA_OUTPUT),
+       HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
+       HDA_CODEC_VOLUME("Headphone Playback Volume", 0x03, 0x0, HDA_OUTPUT),
        { } /* end */
 };
 
@@ -12874,12 +12899,7 @@ static struct snd_kcontrol_new alc269_epc_capture_mixer[] = {
 };
 
 /* FSC amilo */
-static struct snd_kcontrol_new alc269_fujitsu_mixer[] = {
-       HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT),
-       HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
-       HDA_BIND_VOL("PCM Playback Volume", &alc269_epc_bind_vol),
-       { } /* end */
-};
+#define alc269_fujitsu_mixer   alc269_eeepc_mixer
 
 static struct hda_verb alc269_quanta_fl1_verbs[] = {
        {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
@@ -13345,6 +13365,8 @@ static int alc269_parse_auto_config(struct hda_codec *codec)
        if (!spec->cap_mixer && !spec->no_analog)
                set_capture_mixer(spec);
 
+       alc_ssid_check(codec, 0x15, 0x1b, 0x14);
+
        return 1;
 }
 
index 14f3c3e0f62dec7618b97b7d5872148da9d02ef3..41b5b3a18c1ee3efcdd910643aaea45e12f59ae1 100644 (file)
@@ -1590,8 +1590,6 @@ static struct snd_pci_quirk stac9200_cfg_tbl[] = {
        /* SigmaTel reference board */
        SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668,
                      "DFI LanParty", STAC_REF),
-       SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0xfb30,
-                     "SigmaTel",STAC_9205_REF),
        SND_PCI_QUIRK(PCI_VENDOR_ID_DFI, 0x3101,
                      "DFI LanParty", STAC_REF),
        /* Dell laptops have BIOS problem */
@@ -2344,6 +2342,8 @@ static struct snd_pci_quirk stac9205_cfg_tbl[] = {
        /* SigmaTel reference board */
        SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668,
                      "DFI LanParty", STAC_9205_REF),
+       SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0xfb30,
+                     "SigmaTel", STAC_9205_REF),
        SND_PCI_QUIRK(PCI_VENDOR_ID_DFI, 0x3101,
                      "DFI LanParty", STAC_9205_REF),
        /* Dell */
index 8e004fb6961add86847d11b2a128577488a7821b..9008b4b013aa7a6feddf45d52e55a8c994a5a45e 100644 (file)
@@ -210,7 +210,9 @@ struct via_spec {
        /* capture */
        unsigned int num_adc_nids;
        hda_nid_t *adc_nids;
+       hda_nid_t mux_nids[3];
        hda_nid_t dig_in_nid;
+       hda_nid_t dig_in_pin;
 
        /* capture source */
        const struct hda_input_mux *input_mux;
@@ -319,6 +321,9 @@ static void via_auto_set_output_and_unmute(struct hda_codec *codec,
                            pin_type);
        snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_AMP_GAIN_MUTE,
                            AMP_OUT_UNMUTE);
+       if (snd_hda_query_pin_caps(codec, nid) & AC_PINCAP_EAPD)
+               snd_hda_codec_write(codec, nid, 0, 
+                                   AC_VERB_SET_EAPD_BTLENABLE, 0x02);
 }
 
 
@@ -387,27 +392,12 @@ static int via_mux_enum_put(struct snd_kcontrol *kcontrol,
        struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
        struct via_spec *spec = codec->spec;
        unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
-       unsigned int vendor_id = codec->vendor_id;
-
-       /* AIW0  lydia 060801 add for correct sw0 input select */
-       if (IS_VT1708_VENDORID(vendor_id) && (adc_idx == 0))
-               return snd_hda_input_mux_put(codec, spec->input_mux, ucontrol,
-                                            0x18, &spec->cur_mux[adc_idx]);
-       else if ((IS_VT1709_10CH_VENDORID(vendor_id) ||
-                 IS_VT1709_6CH_VENDORID(vendor_id)) && (adc_idx == 0))
-               return snd_hda_input_mux_put(codec, spec->input_mux, ucontrol,
-                                            0x19, &spec->cur_mux[adc_idx]);
-       else if ((IS_VT1708B_8CH_VENDORID(vendor_id) ||
-                 IS_VT1708B_4CH_VENDORID(vendor_id)) && (adc_idx == 0))
-               return snd_hda_input_mux_put(codec, spec->input_mux, ucontrol,
-                                            0x17, &spec->cur_mux[adc_idx]);
-       else if (IS_VT1702_VENDORID(vendor_id) && (adc_idx == 0))
-               return snd_hda_input_mux_put(codec, spec->input_mux, ucontrol,
-                                            0x13, &spec->cur_mux[adc_idx]);
-       else
-               return snd_hda_input_mux_put(codec, spec->input_mux, ucontrol,
-                                            spec->adc_nids[adc_idx],
-                                            &spec->cur_mux[adc_idx]);
+
+       if (!spec->mux_nids[adc_idx])
+               return -EINVAL;
+       return snd_hda_input_mux_put(codec, spec->input_mux, ucontrol,
+                                    spec->mux_nids[adc_idx],
+                                    &spec->cur_mux[adc_idx]);
 }
 
 static int via_independent_hp_info(struct snd_kcontrol *kcontrol,
@@ -998,25 +988,11 @@ static int via_init(struct hda_codec *codec)
 
        /* Lydia Add for EAPD enable */
        if (!spec->dig_in_nid) { /* No Digital In connection */
-               if (IS_VT1708_VENDORID(codec->vendor_id)) {
-                       snd_hda_codec_write(codec, VT1708_DIGIN_PIN, 0,
-                                           AC_VERB_SET_PIN_WIDGET_CONTROL,
-                                           PIN_OUT);
-                       snd_hda_codec_write(codec, VT1708_DIGIN_PIN, 0,
-                                           AC_VERB_SET_EAPD_BTLENABLE, 0x02);
-               } else if (IS_VT1709_10CH_VENDORID(codec->vendor_id) ||
-                          IS_VT1709_6CH_VENDORID(codec->vendor_id)) {
-                       snd_hda_codec_write(codec, VT1709_DIGIN_PIN, 0,
+               if (spec->dig_in_pin) {
+                       snd_hda_codec_write(codec, spec->dig_in_pin, 0,
                                            AC_VERB_SET_PIN_WIDGET_CONTROL,
                                            PIN_OUT);
-                       snd_hda_codec_write(codec, VT1709_DIGIN_PIN, 0,
-                                           AC_VERB_SET_EAPD_BTLENABLE, 0x02);
-               } else if (IS_VT1708B_8CH_VENDORID(codec->vendor_id) ||
-                          IS_VT1708B_4CH_VENDORID(codec->vendor_id)) {
-                       snd_hda_codec_write(codec, VT1708B_DIGIN_PIN, 0,
-                                           AC_VERB_SET_PIN_WIDGET_CONTROL,
-                                           PIN_OUT);
-                       snd_hda_codec_write(codec, VT1708B_DIGIN_PIN, 0,
+                       snd_hda_codec_write(codec, spec->dig_in_pin, 0,
                                            AC_VERB_SET_EAPD_BTLENABLE, 0x02);
                }
        } else /* enable SPDIF-input pin */
@@ -1326,6 +1302,7 @@ static int vt1708_parse_auto_config(struct hda_codec *codec)
 
        if (spec->autocfg.dig_outs)
                spec->multiout.dig_out_nid = VT1708_DIGOUT_NID;
+       spec->dig_in_pin = VT1708_DIGIN_PIN;
        if (spec->autocfg.dig_in_pin)
                spec->dig_in_nid = VT1708_DIGIN_NID;
 
@@ -1352,6 +1329,34 @@ static int via_auto_init(struct hda_codec *codec)
        return 0;
 }
 
+static int get_mux_nids(struct hda_codec *codec)
+{
+       struct via_spec *spec = codec->spec;
+       hda_nid_t nid, conn[8];
+       unsigned int type;
+       int i, n;
+
+       for (i = 0; i < spec->num_adc_nids; i++) {
+               nid = spec->adc_nids[i];
+               while (nid) {
+                       type = (get_wcaps(codec, nid) & AC_WCAP_TYPE)
+                               >> AC_WCAP_TYPE_SHIFT;
+                       if (type == AC_WID_PIN)
+                               break;
+                       n = snd_hda_get_connections(codec, nid, conn,
+                                                   ARRAY_SIZE(conn));
+                       if (n <= 0)
+                               break;
+                       if (n > 1) {
+                               spec->mux_nids[i] = nid;
+                               break;
+                       }
+                       nid = conn[0];
+               }
+       }
+       return 0;
+}
+
 static int patch_vt1708(struct hda_codec *codec)
 {
        struct via_spec *spec;
@@ -1799,6 +1804,7 @@ static int vt1709_parse_auto_config(struct hda_codec *codec)
 
        if (spec->autocfg.dig_outs)
                spec->multiout.dig_out_nid = VT1709_DIGOUT_NID;
+       spec->dig_in_pin = VT1709_DIGIN_PIN;
        if (spec->autocfg.dig_in_pin)
                spec->dig_in_nid = VT1709_DIGIN_NID;
 
@@ -1859,6 +1865,7 @@ static int patch_vt1709_10ch(struct hda_codec *codec)
        if (!spec->adc_nids && spec->input_mux) {
                spec->adc_nids = vt1709_adc_nids;
                spec->num_adc_nids = ARRAY_SIZE(vt1709_adc_nids);
+               get_mux_nids(codec);
                spec->mixers[spec->num_mixers] = vt1709_capture_mixer;
                spec->num_mixers++;
        }
@@ -1952,6 +1959,7 @@ static int patch_vt1709_6ch(struct hda_codec *codec)
        if (!spec->adc_nids && spec->input_mux) {
                spec->adc_nids = vt1709_adc_nids;
                spec->num_adc_nids = ARRAY_SIZE(vt1709_adc_nids);
+               get_mux_nids(codec);
                spec->mixers[spec->num_mixers] = vt1709_capture_mixer;
                spec->num_mixers++;
        }
@@ -2344,6 +2352,7 @@ static int vt1708B_parse_auto_config(struct hda_codec *codec)
 
        if (spec->autocfg.dig_outs)
                spec->multiout.dig_out_nid = VT1708B_DIGOUT_NID;
+       spec->dig_in_pin = VT1708B_DIGIN_PIN;
        if (spec->autocfg.dig_in_pin)
                spec->dig_in_nid = VT1708B_DIGIN_NID;
 
@@ -2404,6 +2413,7 @@ static int patch_vt1708B_8ch(struct hda_codec *codec)
        if (!spec->adc_nids && spec->input_mux) {
                spec->adc_nids = vt1708B_adc_nids;
                spec->num_adc_nids = ARRAY_SIZE(vt1708B_adc_nids);
+               get_mux_nids(codec);
                spec->mixers[spec->num_mixers] = vt1708B_capture_mixer;
                spec->num_mixers++;
        }
@@ -2455,6 +2465,7 @@ static int patch_vt1708B_4ch(struct hda_codec *codec)
        if (!spec->adc_nids && spec->input_mux) {
                spec->adc_nids = vt1708B_adc_nids;
                spec->num_adc_nids = ARRAY_SIZE(vt1708B_adc_nids);
+               get_mux_nids(codec);
                spec->mixers[spec->num_mixers] = vt1708B_capture_mixer;
                spec->num_mixers++;
        }
@@ -2889,6 +2900,7 @@ static int patch_vt1708S(struct hda_codec *codec)
        if (!spec->adc_nids && spec->input_mux) {
                spec->adc_nids = vt1708S_adc_nids;
                spec->num_adc_nids = ARRAY_SIZE(vt1708S_adc_nids);
+               get_mux_nids(codec);
                spec->mixers[spec->num_mixers] = vt1708S_capture_mixer;
                spec->num_mixers++;
        }
@@ -3206,6 +3218,7 @@ static int patch_vt1702(struct hda_codec *codec)
        if (!spec->adc_nids && spec->input_mux) {
                spec->adc_nids = vt1702_adc_nids;
                spec->num_adc_nids = ARRAY_SIZE(vt1702_adc_nids);
+               get_mux_nids(codec);
                spec->mixers[spec->num_mixers] = vt1702_capture_mixer;
                spec->num_mixers++;
        }
index 0d0cdbdb44867e88d12e6c7cb088ac7b13a37a94..cecf1ffeeaaa448c50d499101fa890ce2a921db4 100644 (file)
@@ -107,7 +107,7 @@ MODULE_PARM_DESC(dxr_enable, "Enable DXR support for Terratec DMX6FIRE.");
 
 
 static const struct pci_device_id snd_ice1712_ids[] = {
-       { PCI_VENDOR_ID_ICE, PCI_DEVICE_ID_ICE_1712, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },   /* ICE1712 */
+       { PCI_VDEVICE(ICE, PCI_DEVICE_ID_ICE_1712), 0 },   /* ICE1712 */
        { 0, }
 };
 
index 36ade77cf37116216d6424dc3871e23377ee79cd..cc84a831eb21f19ee30099b6aece9e7f021c32d4 100644 (file)
@@ -93,7 +93,7 @@ MODULE_PARM_DESC(model, "Use the given board model.");
 
 /* Both VT1720 and VT1724 have the same PCI IDs */
 static const struct pci_device_id snd_vt1724_ids[] = {
-       { PCI_VENDOR_ID_ICE, PCI_DEVICE_ID_VT1724, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
+       { PCI_VDEVICE(ICE, PCI_DEVICE_ID_VT1724), 0 },
        { 0, }
 };
 
index 8aa5687f392a10abf1310015d8ddeb57e73d070a..171ada535209a2974c8151597b0e1ceb4489736c 100644 (file)
@@ -421,29 +421,29 @@ struct intel8x0 {
 };
 
 static struct pci_device_id snd_intel8x0_ids[] = {
-       { 0x8086, 0x2415, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DEVICE_INTEL }, /* 82801AA */
-       { 0x8086, 0x2425, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DEVICE_INTEL }, /* 82901AB */
-       { 0x8086, 0x2445, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DEVICE_INTEL }, /* 82801BA */
-       { 0x8086, 0x2485, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DEVICE_INTEL }, /* ICH3 */
-       { 0x8086, 0x24c5, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DEVICE_INTEL_ICH4 }, /* ICH4 */
-       { 0x8086, 0x24d5, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DEVICE_INTEL_ICH4 }, /* ICH5 */
-       { 0x8086, 0x25a6, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DEVICE_INTEL_ICH4 }, /* ESB */
-       { 0x8086, 0x266e, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DEVICE_INTEL_ICH4 }, /* ICH6 */
-       { 0x8086, 0x27de, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DEVICE_INTEL_ICH4 }, /* ICH7 */
-       { 0x8086, 0x2698, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DEVICE_INTEL_ICH4 }, /* ESB2 */
-       { 0x8086, 0x7195, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DEVICE_INTEL }, /* 440MX */
-       { 0x1039, 0x7012, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DEVICE_SIS },   /* SI7012 */
-       { 0x10de, 0x01b1, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DEVICE_NFORCE },        /* NFORCE */
-       { 0x10de, 0x003a, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DEVICE_NFORCE },        /* MCP04 */
-       { 0x10de, 0x006a, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DEVICE_NFORCE },        /* NFORCE2 */
-       { 0x10de, 0x0059, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DEVICE_NFORCE },        /* CK804 */
-       { 0x10de, 0x008a, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DEVICE_NFORCE },        /* CK8 */
-       { 0x10de, 0x00da, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DEVICE_NFORCE },        /* NFORCE3 */
-       { 0x10de, 0x00ea, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DEVICE_NFORCE },        /* CK8S */
-       { 0x10de, 0x026b, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DEVICE_NFORCE },        /* MCP51 */
-       { 0x1022, 0x746d, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DEVICE_INTEL }, /* AMD8111 */
-       { 0x1022, 0x7445, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DEVICE_INTEL }, /* AMD768 */
-       { 0x10b9, 0x5455, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DEVICE_ALI },   /* Ali5455 */
+       { PCI_VDEVICE(INTEL, 0x2415), DEVICE_INTEL },   /* 82801AA */
+       { PCI_VDEVICE(INTEL, 0x2425), DEVICE_INTEL },   /* 82901AB */
+       { PCI_VDEVICE(INTEL, 0x2445), DEVICE_INTEL },   /* 82801BA */
+       { PCI_VDEVICE(INTEL, 0x2485), DEVICE_INTEL },   /* ICH3 */
+       { PCI_VDEVICE(INTEL, 0x24c5), DEVICE_INTEL_ICH4 }, /* ICH4 */
+       { PCI_VDEVICE(INTEL, 0x24d5), DEVICE_INTEL_ICH4 }, /* ICH5 */
+       { PCI_VDEVICE(INTEL, 0x25a6), DEVICE_INTEL_ICH4 }, /* ESB */
+       { PCI_VDEVICE(INTEL, 0x266e), DEVICE_INTEL_ICH4 }, /* ICH6 */
+       { PCI_VDEVICE(INTEL, 0x27de), DEVICE_INTEL_ICH4 }, /* ICH7 */
+       { PCI_VDEVICE(INTEL, 0x2698), DEVICE_INTEL_ICH4 }, /* ESB2 */
+       { PCI_VDEVICE(INTEL, 0x7195), DEVICE_INTEL },   /* 440MX */
+       { PCI_VDEVICE(SI, 0x7012), DEVICE_SIS },        /* SI7012 */
+       { PCI_VDEVICE(NVIDIA, 0x01b1), DEVICE_NFORCE }, /* NFORCE */
+       { PCI_VDEVICE(NVIDIA, 0x003a), DEVICE_NFORCE }, /* MCP04 */
+       { PCI_VDEVICE(NVIDIA, 0x006a), DEVICE_NFORCE }, /* NFORCE2 */
+       { PCI_VDEVICE(NVIDIA, 0x0059), DEVICE_NFORCE }, /* CK804 */
+       { PCI_VDEVICE(NVIDIA, 0x008a), DEVICE_NFORCE }, /* CK8 */
+       { PCI_VDEVICE(NVIDIA, 0x00da), DEVICE_NFORCE }, /* NFORCE3 */
+       { PCI_VDEVICE(NVIDIA, 0x00ea), DEVICE_NFORCE }, /* CK8S */
+       { PCI_VDEVICE(NVIDIA, 0x026b), DEVICE_NFORCE }, /* MCP51 */
+       { PCI_VDEVICE(AMD, 0x746d), DEVICE_INTEL },     /* AMD8111 */
+       { PCI_VDEVICE(AMD, 0x7445), DEVICE_INTEL },     /* AMD768 */
+       { PCI_VDEVICE(AL, 0x5455), DEVICE_ALI },   /* Ali5455 */
        { 0, }
 };
 
index 6ec0fc50d6be16bf064b27ca83e61b172deb045e..9e7d12e7673f52abc3d02518da23a51c6d0ff59a 100644 (file)
@@ -220,24 +220,24 @@ struct intel8x0m {
 };
 
 static struct pci_device_id snd_intel8x0m_ids[] = {
-       { 0x8086, 0x2416, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DEVICE_INTEL }, /* 82801AA */
-       { 0x8086, 0x2426, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DEVICE_INTEL }, /* 82901AB */
-       { 0x8086, 0x2446, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DEVICE_INTEL }, /* 82801BA */
-       { 0x8086, 0x2486, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DEVICE_INTEL }, /* ICH3 */
-       { 0x8086, 0x24c6, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DEVICE_INTEL }, /* ICH4 */
-       { 0x8086, 0x24d6, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DEVICE_INTEL }, /* ICH5 */
-       { 0x8086, 0x266d, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DEVICE_INTEL }, /* ICH6 */
-       { 0x8086, 0x27dd, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DEVICE_INTEL }, /* ICH7 */
-       { 0x8086, 0x7196, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DEVICE_INTEL }, /* 440MX */
-       { 0x1022, 0x7446, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DEVICE_INTEL }, /* AMD768 */
-       { 0x1039, 0x7013, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DEVICE_SIS },   /* SI7013 */
-       { 0x10de, 0x01c1, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DEVICE_NFORCE }, /* NFORCE */
-       { 0x10de, 0x0069, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DEVICE_NFORCE }, /* NFORCE2 */
-       { 0x10de, 0x0089, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DEVICE_NFORCE }, /* NFORCE2s */
-       { 0x10de, 0x00d9, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DEVICE_NFORCE }, /* NFORCE3 */
+       { PCI_VDEVICE(INTEL, 0x2416), DEVICE_INTEL },   /* 82801AA */
+       { PCI_VDEVICE(INTEL, 0x2426), DEVICE_INTEL },   /* 82901AB */
+       { PCI_VDEVICE(INTEL, 0x2446), DEVICE_INTEL },   /* 82801BA */
+       { PCI_VDEVICE(INTEL, 0x2486), DEVICE_INTEL },   /* ICH3 */
+       { PCI_VDEVICE(INTEL, 0x24c6), DEVICE_INTEL }, /* ICH4 */
+       { PCI_VDEVICE(INTEL, 0x24d6), DEVICE_INTEL }, /* ICH5 */
+       { PCI_VDEVICE(INTEL, 0x266d), DEVICE_INTEL },   /* ICH6 */
+       { PCI_VDEVICE(INTEL, 0x27dd), DEVICE_INTEL },   /* ICH7 */
+       { PCI_VDEVICE(INTEL, 0x7196), DEVICE_INTEL },   /* 440MX */
+       { PCI_VDEVICE(AMD, 0x7446), DEVICE_INTEL },     /* AMD768 */
+       { PCI_VDEVICE(SI, 0x7013), DEVICE_SIS },        /* SI7013 */
+       { PCI_VDEVICE(NVIDIA, 0x01c1), DEVICE_NFORCE }, /* NFORCE */
+       { PCI_VDEVICE(NVIDIA, 0x0069), DEVICE_NFORCE }, /* NFORCE2 */
+       { PCI_VDEVICE(NVIDIA, 0x0089), DEVICE_NFORCE }, /* NFORCE2s */
+       { PCI_VDEVICE(NVIDIA, 0x00d9), DEVICE_NFORCE }, /* NFORCE3 */
 #if 0
-       { 0x1022, 0x746d, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DEVICE_INTEL }, /* AMD8111 */
-       { 0x10b9, 0x5455, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DEVICE_ALI },   /* Ali5455 */
+       { PCI_VDEVICE(AMD, 0x746d), DEVICE_INTEL },     /* AMD8111 */
+       { PCI_VDEVICE(AL, 0x5455), DEVICE_ALI },   /* Ali5455 */
 #endif
        { 0, }
 };
index 18da2ef04d097903a7ae3097e811632a1ba2774b..11b8c6514b3d8ecf5da061687d9c949e0d771d5a 100644 (file)
@@ -654,13 +654,12 @@ static int __devinit lx_init_ethersound_config(struct lx6464es *chip)
        int i;
        u32 orig_conf_es = lx_dsp_reg_read(chip, eReg_CONFES);
 
-       u32 default_conf_es = (64 << IOCR_OUTPUTS_OFFSET) |
+       /* configure 64 io channels */
+       u32 conf_es = (orig_conf_es & CONFES_READ_PART_MASK) |
                (64 << IOCR_INPUTS_OFFSET) |
+               (64 << IOCR_OUTPUTS_OFFSET) |
                (FREQ_RATIO_SINGLE_MODE << FREQ_RATIO_OFFSET);
 
-       u32 conf_es = (orig_conf_es & CONFES_READ_PART_MASK)
-               | (default_conf_es & CONFES_WRITE_PART_MASK);
-
        snd_printdd("->lx_init_ethersound\n");
 
        chip->freq_ratio = FREQ_RATIO_SINGLE_MODE;
index 82bc5b9e7629db8537e66af68624feb14e0d17e1..a83d1968a8450f49816add1bf2bbc2ffbba962c6 100644 (file)
@@ -61,7 +61,7 @@ MODULE_PARM_DESC(enable, "Enable Digigram " CARD_NAME " soundcard.");
  */
 
 static struct pci_device_id snd_mixart_ids[] = {
-       { 0x1057, 0x0003, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, }, /* MC8240 */
+       { PCI_VDEVICE(MOTOROLA, 0x0003), 0, }, /* MC8240 */
        { 0, }
 };
 
index 522a040855d41e7321414cfbd2b5c3e22b0d47a8..97a0731331a15f6ae2a4be6d16acce0f5e85915d 100644 (file)
@@ -263,9 +263,9 @@ struct nm256 {
  * PCI ids
  */
 static struct pci_device_id snd_nm256_ids[] = {
-       {PCI_VENDOR_ID_NEOMAGIC, PCI_DEVICE_ID_NEOMAGIC_NM256AV_AUDIO, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
-       {PCI_VENDOR_ID_NEOMAGIC, PCI_DEVICE_ID_NEOMAGIC_NM256ZX_AUDIO, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
-       {PCI_VENDOR_ID_NEOMAGIC, PCI_DEVICE_ID_NEOMAGIC_NM256XL_PLUS_AUDIO, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+       {PCI_VDEVICE(NEOMAGIC, PCI_DEVICE_ID_NEOMAGIC_NM256AV_AUDIO), 0},
+       {PCI_VDEVICE(NEOMAGIC, PCI_DEVICE_ID_NEOMAGIC_NM256ZX_AUDIO), 0},
+       {PCI_VDEVICE(NEOMAGIC, PCI_DEVICE_ID_NEOMAGIC_NM256XL_PLUS_AUDIO), 0},
        {0,},
 };
 
index 304da169bfdcbeacb669a338a25a5f4c12271de9..5401c547c4e33f75e3e8f5186b09d2129b16fc43 100644 (file)
@@ -575,8 +575,10 @@ static int ac97_switch_put(struct snd_kcontrol *ctl,
 static int ac97_volume_info(struct snd_kcontrol *ctl,
                            struct snd_ctl_elem_info *info)
 {
+       int stereo = (ctl->private_value >> 16) & 1;
+
        info->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
-       info->count = 2;
+       info->count = stereo ? 2 : 1;
        info->value.integer.min = 0;
        info->value.integer.max = 0x1f;
        return 0;
@@ -587,6 +589,7 @@ static int ac97_volume_get(struct snd_kcontrol *ctl,
 {
        struct oxygen *chip = ctl->private_data;
        unsigned int codec = (ctl->private_value >> 24) & 1;
+       int stereo = (ctl->private_value >> 16) & 1;
        unsigned int index = ctl->private_value & 0xff;
        u16 reg;
 
@@ -594,7 +597,8 @@ static int ac97_volume_get(struct snd_kcontrol *ctl,
        reg = oxygen_read_ac97(chip, codec, index);
        mutex_unlock(&chip->mutex);
        value->value.integer.value[0] = 31 - (reg & 0x1f);
-       value->value.integer.value[1] = 31 - ((reg >> 8) & 0x1f);
+       if (stereo)
+               value->value.integer.value[1] = 31 - ((reg >> 8) & 0x1f);
        return 0;
 }
 
@@ -603,6 +607,7 @@ static int ac97_volume_put(struct snd_kcontrol *ctl,
 {
        struct oxygen *chip = ctl->private_data;
        unsigned int codec = (ctl->private_value >> 24) & 1;
+       int stereo = (ctl->private_value >> 16) & 1;
        unsigned int index = ctl->private_value & 0xff;
        u16 oldreg, newreg;
        int change;
@@ -612,8 +617,11 @@ static int ac97_volume_put(struct snd_kcontrol *ctl,
        newreg = oldreg;
        newreg = (newreg & ~0x1f) |
                (31 - (value->value.integer.value[0] & 0x1f));
-       newreg = (newreg & ~0x1f00) |
-               ((31 - (value->value.integer.value[0] & 0x1f)) << 8);
+       if (stereo)
+               newreg = (newreg & ~0x1f00) |
+                       ((31 - (value->value.integer.value[1] & 0x1f)) << 8);
+       else
+               newreg = (newreg & ~0x1f00) | ((newreg & 0x1f) << 8);
        change = newreg != oldreg;
        if (change)
                oxygen_write_ac97(chip, codec, index, newreg);
@@ -673,7 +681,7 @@ static int ac97_fp_rec_volume_put(struct snd_kcontrol *ctl,
                .private_value = ((codec) << 24) | ((invert) << 16) | \
                                 ((bitnr) << 8) | (index), \
        }
-#define AC97_VOLUME(xname, codec, index) { \
+#define AC97_VOLUME(xname, codec, index, stereo) { \
                .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
                .name = xname, \
                .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | \
@@ -682,7 +690,7 @@ static int ac97_fp_rec_volume_put(struct snd_kcontrol *ctl,
                .get = ac97_volume_get, \
                .put = ac97_volume_put, \
                .tlv = { .p = ac97_db_scale, }, \
-               .private_value = ((codec) << 24) | (index), \
+               .private_value = ((codec) << 24) | ((stereo) << 16) | (index), \
        }
 
 static DECLARE_TLV_DB_SCALE(monitor_db_scale, -1000, 1000, 0);
@@ -882,18 +890,18 @@ static const struct {
 };
 
 static const struct snd_kcontrol_new ac97_controls[] = {
-       AC97_VOLUME("Mic Capture Volume", 0, AC97_MIC),
+       AC97_VOLUME("Mic Capture Volume", 0, AC97_MIC, 0),
        AC97_SWITCH("Mic Capture Switch", 0, AC97_MIC, 15, 1),
        AC97_SWITCH("Mic Boost (+20dB)", 0, AC97_MIC, 6, 0),
        AC97_SWITCH("Line Capture Switch", 0, AC97_LINE, 15, 1),
-       AC97_VOLUME("CD Capture Volume", 0, AC97_CD),
+       AC97_VOLUME("CD Capture Volume", 0, AC97_CD, 1),
        AC97_SWITCH("CD Capture Switch", 0, AC97_CD, 15, 1),
-       AC97_VOLUME("Aux Capture Volume", 0, AC97_AUX),
+       AC97_VOLUME("Aux Capture Volume", 0, AC97_AUX, 1),
        AC97_SWITCH("Aux Capture Switch", 0, AC97_AUX, 15, 1),
 };
 
 static const struct snd_kcontrol_new ac97_fp_controls[] = {
-       AC97_VOLUME("Front Panel Playback Volume", 1, AC97_HEADPHONE),
+       AC97_VOLUME("Front Panel Playback Volume", 1, AC97_HEADPHONE, 1),
        AC97_SWITCH("Front Panel Playback Switch", 1, AC97_HEADPHONE, 15, 1),
        {
                .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
index bf971f7cfdc652984d4824576306e96aaa88b4d6..6ebcb6bdd7129eb8dd04daf344aad880aabf8ce9 100644 (file)
@@ -635,6 +635,8 @@ static void xonar_d2_resume(struct oxygen *chip)
 
 static void xonar_d1_resume(struct oxygen *chip)
 {
+       oxygen_set_bits8(chip, OXYGEN_FUNCTION, OXYGEN_FUNCTION_RESET_CODEC);
+       msleep(1);
        cs43xx_init(chip);
        xonar_enable_output(chip);
 }
index 235a71e5ac8de6782f9d24027a347b5dc7852046..b5ca02e2038c9bb42c35c8a194c57974e15b6686 100644 (file)
@@ -2197,9 +2197,12 @@ static int __init alsa_card_riptide_init(void)
        if (err < 0)
                return err;
 #if defined(SUPPORT_JOYSTICK)
-       pci_register_driver(&joystick_driver);
+       err = pci_register_driver(&joystick_driver);
+       /* On failure unregister formerly registered audio driver */
+       if (err < 0)
+               pci_unregister_driver(&driver);
 #endif
-       return 0;
+       return err;
 }
 
 static void __exit alsa_card_riptide_exit(void)
index d7b966e7c4cf69270358a6070979e904e072f3d4..f977dba7cbd09462ac760219711c04dbb189ea0e 100644 (file)
@@ -227,12 +227,9 @@ struct rme32 {
 };
 
 static struct pci_device_id snd_rme32_ids[] = {
-       {PCI_VENDOR_ID_XILINX_RME, PCI_DEVICE_ID_RME_DIGI32,
-        PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0,},
-       {PCI_VENDOR_ID_XILINX_RME, PCI_DEVICE_ID_RME_DIGI32_8,
-        PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0,},
-       {PCI_VENDOR_ID_XILINX_RME, PCI_DEVICE_ID_RME_DIGI32_PRO,
-        PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0,},
+       {PCI_VDEVICE(XILINX_RME, PCI_DEVICE_ID_RME_DIGI32), 0,},
+       {PCI_VDEVICE(XILINX_RME, PCI_DEVICE_ID_RME_DIGI32_8), 0,},
+       {PCI_VDEVICE(XILINX_RME, PCI_DEVICE_ID_RME_DIGI32_PRO), 0,},
        {0,}
 };
 
index 55fb1c131f5809a1b2b62383c99c3ac6037e90c8..2ba5c0fd55dbb7adc590e568e0b78350124ffd91 100644 (file)
@@ -232,14 +232,10 @@ struct rme96 {
 };
 
 static struct pci_device_id snd_rme96_ids[] = {
-       { PCI_VENDOR_ID_XILINX, PCI_DEVICE_ID_RME_DIGI96,
-         PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, },
-       { PCI_VENDOR_ID_XILINX, PCI_DEVICE_ID_RME_DIGI96_8,
-         PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, },
-       { PCI_VENDOR_ID_XILINX, PCI_DEVICE_ID_RME_DIGI96_8_PRO,
-         PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, },
-       { PCI_VENDOR_ID_XILINX, PCI_DEVICE_ID_RME_DIGI96_8_PAD_OR_PST,
-         PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, }, 
+       { PCI_VDEVICE(XILINX, PCI_DEVICE_ID_RME_DIGI96), 0, },
+       { PCI_VDEVICE(XILINX, PCI_DEVICE_ID_RME_DIGI96_8), 0, },
+       { PCI_VDEVICE(XILINX, PCI_DEVICE_ID_RME_DIGI96_8_PRO), 0, },
+       { PCI_VDEVICE(XILINX, PCI_DEVICE_ID_RME_DIGI96_8_PAD_OR_PST), 0, },
        { 0, }
 };
 
index 7dc60ad4772e33b76027efe35265991ffa3ea8ef..1f6406c4534d455120efcdd0c1c6e9e3b98a9173 100644 (file)
@@ -243,7 +243,7 @@ struct sonicvibes {
 };
 
 static struct pci_device_id snd_sonic_ids[] = {
-       { 0x5333, 0xca00, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, },
+       { PCI_VDEVICE(S3, 0xca00), 0, },
         { 0, }
 };
 
index 949fcaf6b70ed9454ecd373ec052e8e7b7800fc9..acfa4760da49e3afb147b438897fbdb03b547239 100644 (file)
@@ -402,9 +402,9 @@ struct via82xx {
 
 static struct pci_device_id snd_via82xx_ids[] = {
        /* 0x1106, 0x3058 */
-       { PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C686_5, PCI_ANY_ID, PCI_ANY_ID, 0, 0, TYPE_CARD_VIA686, },     /* 686A */
+       { PCI_VDEVICE(VIA, PCI_DEVICE_ID_VIA_82C686_5), TYPE_CARD_VIA686, },    /* 686A */
        /* 0x1106, 0x3059 */
-       { PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8233_5, PCI_ANY_ID, PCI_ANY_ID, 0, 0, TYPE_CARD_VIA8233, },      /* VT8233 */
+       { PCI_VDEVICE(VIA, PCI_DEVICE_ID_VIA_8233_5), TYPE_CARD_VIA8233, },     /* VT8233 */
        { 0, }
 };
 
index 0d54e3503c1e6edc4ad80d23f246aa3b034aab12..47eb61561dfcad83b0bd7c22fe91f5ef9519856e 100644 (file)
@@ -261,7 +261,7 @@ struct via82xx_modem {
 };
 
 static struct pci_device_id snd_via82xx_modem_ids[] = {
-       { 0x1106, 0x3068, PCI_ANY_ID, PCI_ANY_ID, 0, 0, TYPE_CARD_VIA82XX_MODEM, },
+       { PCI_VDEVICE(VIA, 0x3068), TYPE_CARD_VIA82XX_MODEM, },
        { 0, }
 };
 
index 4af66661f9b020b83956559847848b51647fde97..e6b18b90d4510afa4393d700110cc84200c2f5ef 100644 (file)
@@ -67,12 +67,12 @@ module_param_array(rear_switch, bool, NULL, 0444);
 MODULE_PARM_DESC(rear_switch, "Enable shared rear/line-in switch");
 
 static struct pci_device_id snd_ymfpci_ids[] = {
-        { 0x1073, 0x0004, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, },   /* YMF724 */
-        { 0x1073, 0x000d, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, },   /* YMF724F */
-        { 0x1073, 0x000a, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, },   /* YMF740 */
-        { 0x1073, 0x000c, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, },   /* YMF740C */
-        { 0x1073, 0x0010, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, },   /* YMF744 */
-        { 0x1073, 0x0012, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, },   /* YMF754 */
+       { PCI_VDEVICE(YAMAHA, 0x0004), 0, },   /* YMF724 */
+       { PCI_VDEVICE(YAMAHA, 0x000d), 0, },   /* YMF724F */
+       { PCI_VDEVICE(YAMAHA, 0x000a), 0, },   /* YMF740 */
+       { PCI_VDEVICE(YAMAHA, 0x000c), 0, },   /* YMF740C */
+       { PCI_VDEVICE(YAMAHA, 0x0010), 0, },   /* YMF744 */
+       { PCI_VDEVICE(YAMAHA, 0x0012), 0, },   /* YMF754 */
        { 0, }
 };
 
index d28eeaceb8573a504f3c7c5471f9f2f296c5618c..49c4b2898aff50beaa33e82f1dfcb9c5ea615106 100644 (file)
@@ -79,7 +79,7 @@ static const u16 wm8753_reg[] = {
        0x0097, 0x0097, 0x0000, 0x0004,
        0x0000, 0x0083, 0x0024, 0x01ba,
        0x0000, 0x0083, 0x0024, 0x01ba,
-       0x0000, 0x0000
+       0x0000, 0x0000, 0x0000
 };
 
 /* codec private data */
@@ -1660,11 +1660,11 @@ static int wm8753_register(struct wm8753_priv *wm8753)
        codec->set_bias_level = wm8753_set_bias_level;
        codec->dai = wm8753_dai;
        codec->num_dai = 2;
-       codec->reg_cache_size = ARRAY_SIZE(wm8753->reg_cache);
+       codec->reg_cache_size = ARRAY_SIZE(wm8753->reg_cache) + 1;
        codec->reg_cache = &wm8753->reg_cache;
        codec->private_data = wm8753;
 
-       memcpy(codec->reg_cache, wm8753_reg, sizeof(codec->reg_cache));
+       memcpy(codec->reg_cache, wm8753_reg, sizeof(wm8753->reg_cache));
        INIT_DELAYED_WORK(&codec->delayed_work, wm8753_work);
 
        ret = wm8753_reset(codec);
index c05f71803aa8a30f07da731d70591800c5a844fe..8c0fdf84aac341bf3718d73f6255f714cd66cb47 100644 (file)
@@ -1037,14 +1037,14 @@ static int __devinit wm8988_spi_probe(struct spi_device *spi)
        codec->control_data = spi;
        codec->dev = &spi->dev;
 
-       spi->dev.driver_data = wm8988;
+       dev_set_drvdata(&spi->dev, wm8988);
 
        return wm8988_register(wm8988);
 }
 
 static int __devexit wm8988_spi_remove(struct spi_device *spi)
 {
-       struct wm8988_priv *wm8988 = spi->dev.driver_data;
+       struct wm8988_priv *wm8988 = dev_get_drvdata(&spi->dev);
 
        wm8988_unregister(wm8988);
 
index 5dbebf82249ca735776d942ed9e3335e7b300b09..8cb65ccad35fb8cfcf96caac60cd2b0e1adb468e 100644 (file)
@@ -33,7 +33,7 @@ config SND_SOC_MPC5200_I2S
 config SND_SOC_MPC5200_AC97
        tristate "Freescale MPC5200 PSC in AC97 mode driver"
        depends on PPC_MPC52xx && PPC_BESTCOMM
-       select AC97_BUS
+       select SND_SOC_AC97_BUS
        select SND_MPC52xx_DMA
        select PPC_BESTCOMM_GEN_BD
        help
@@ -41,7 +41,7 @@ config SND_SOC_MPC5200_AC97
 
 config SND_MPC52xx_SOC_PCM030
        tristate "SoC AC97 Audio support for Phytec pcm030 and WM9712"
-       depends on PPC_MPC5200_SIMPLE && BROKEN
+       depends on PPC_MPC5200_SIMPLE
        select SND_SOC_MPC5200_AC97
        select SND_SOC_WM9712
        help
@@ -50,7 +50,7 @@ config SND_MPC52xx_SOC_PCM030
 
 config SND_MPC52xx_SOC_EFIKA
        tristate "SoC AC97 Audio support for bbplan Efika and STAC9766"
-       depends on PPC_EFIKA && BROKEN
+       depends on PPC_EFIKA
        select SND_SOC_MPC5200_AC97
        select SND_SOC_STAC9766
        help
index efec33a1c5bddc443e56b0807f76aace8c58a569..f0a2d407199815fcbfc0cc0b2b3483d91e7d85e8 100644 (file)
@@ -456,6 +456,7 @@ int mpc5200_audio_dma_create(struct of_device *op)
                return -ENODEV;
 
        spin_lock_init(&psc_dma->lock);
+       mutex_init(&psc_dma->mutex);
        psc_dma->id = be32_to_cpu(*prop);
        psc_dma->irq = irq;
        psc_dma->psc_regs = regs;
index 2000803f06a721f236d7caae1104993cedbfeff7..8d396bb9d9fe405db9c10dc12d14e2dedabfaf58 100644 (file)
@@ -55,6 +55,7 @@ struct psc_dma {
        unsigned int irq;
        struct device *dev;
        spinlock_t lock;
+       struct mutex mutex;
        u32 sicr;
        uint sysclk;
        int imr;
index 794a247b3eb55ec758a55a9b21e43533cc25e891..7eb549985d490cef5bc1cd3a6717020bea2b5fb4 100644 (file)
@@ -34,13 +34,20 @@ static unsigned short psc_ac97_read(struct snd_ac97 *ac97, unsigned short reg)
        int status;
        unsigned int val;
 
+       mutex_lock(&psc_dma->mutex);
+
        /* Wait for command send status zero = ready */
        status = spin_event_timeout(!(in_be16(&psc_dma->psc_regs->sr_csr.status) &
                                MPC52xx_PSC_SR_CMDSEND), 100, 0);
        if (status == 0) {
                pr_err("timeout on ac97 bus (rdy)\n");
+               mutex_unlock(&psc_dma->mutex);
                return -ENODEV;
        }
+
+       /* Force clear the data valid bit */
+       in_be32(&psc_dma->psc_regs->ac97_data);
+
        /* Send the read */
        out_be32(&psc_dma->psc_regs->ac97_cmd, (1<<31) | ((reg & 0x7f) << 24));
 
@@ -50,16 +57,19 @@ static unsigned short psc_ac97_read(struct snd_ac97 *ac97, unsigned short reg)
        if (status == 0) {
                pr_err("timeout on ac97 read (val) %x\n",
                                in_be16(&psc_dma->psc_regs->sr_csr.status));
+               mutex_unlock(&psc_dma->mutex);
                return -ENODEV;
        }
        /* Get the data */
        val = in_be32(&psc_dma->psc_regs->ac97_data);
        if (((val >> 24) & 0x7f) != reg) {
                pr_err("reg echo error on ac97 read\n");
+               mutex_unlock(&psc_dma->mutex);
                return -ENODEV;
        }
        val = (val >> 8) & 0xffff;
 
+       mutex_unlock(&psc_dma->mutex);
        return (unsigned short) val;
 }
 
@@ -68,16 +78,21 @@ static void psc_ac97_write(struct snd_ac97 *ac97,
 {
        int status;
 
+       mutex_lock(&psc_dma->mutex);
+
        /* Wait for command status zero = ready */
        status = spin_event_timeout(!(in_be16(&psc_dma->psc_regs->sr_csr.status) &
                                MPC52xx_PSC_SR_CMDSEND), 100, 0);
        if (status == 0) {
                pr_err("timeout on ac97 bus (write)\n");
-               return;
+               goto out;
        }
        /* Write data */
        out_be32(&psc_dma->psc_regs->ac97_cmd,
                        ((reg & 0x7f) << 24) | (val << 8));
+
+ out:
+       mutex_unlock(&psc_dma->mutex);
 }
 
 static void psc_ac97_warm_reset(struct snd_ac97 *ac97)
index 6454e15f7d28cb274bf3e21abe76b9b1ee6f06ee..84a1950880ebc96143a749cd2c5c819b08575508 100644 (file)
@@ -216,12 +216,15 @@ static snd_pcm_uframes_t omap_pcm_pointer(struct snd_pcm_substream *substream)
        dma_addr_t ptr;
        snd_pcm_uframes_t offset;
 
-       if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
-               ptr = omap_get_dma_src_pos(prtd->dma_ch);
-       else
+       if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
                ptr = omap_get_dma_dst_pos(prtd->dma_ch);
+               offset = bytes_to_frames(runtime, ptr - runtime->dma_addr);
+       } else if (!(cpu_is_omap1510())) {
+               ptr = omap_get_dma_src_pos(prtd->dma_ch);
+               offset = bytes_to_frames(runtime, ptr - runtime->dma_addr);
+       } else
+               offset = prtd->period_index * runtime->period_size;
 
-       offset = bytes_to_frames(runtime, ptr - runtime->dma_addr);
        if (offset >= runtime->buffer_size)
                offset = 0;
 
index 4743e262895d9f1068260762ca6c4f64df5dd17d..6b8f655d1ad826d7556317b17e1f1074fa7e49f3 100644 (file)
@@ -167,6 +167,7 @@ static int pxa2xx_i2s_hw_params(struct snd_pcm_substream *substream,
 
        BUG_ON(IS_ERR(clk_i2s));
        clk_enable(clk_i2s);
+       dai->private_data = dai;
        pxa_i2s_wait();
 
        if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
@@ -255,7 +256,10 @@ static void pxa2xx_i2s_shutdown(struct snd_pcm_substream *substream,
        if ((SACR1 & (SACR1_DREC | SACR1_DRPL)) == (SACR1_DREC | SACR1_DRPL)) {
                SACR0 &= ~SACR0_ENB;
                pxa_i2s_wait();
-               clk_disable(clk_i2s);
+               if (dai->private_data != NULL) {
+                       clk_disable(clk_i2s);
+                       dai->private_data = NULL;
+               }
        }
 }
 
@@ -336,6 +340,7 @@ static int pxa2xx_i2s_probe(struct platform_device *dev)
                return PTR_ERR(clk_i2s);
 
        pxa_i2s_dai.dev = &dev->dev;
+       pxa_i2s_dai.private_data = NULL;
        ret = snd_soc_register_dai(&pxa_i2s_dai);
        if (ret != 0)
                clk_put(clk_i2s);
index 12522e6913d92d068676f4b3916571b03dae2d87..a41f8b127f49cceb1432183c4943482d6f61997f 100644 (file)
@@ -10,6 +10,8 @@
 #include <linux/module.h>
 #include <linux/device.h>
 #include <linux/err.h>
+#include <linux/kdev_t.h>
+#include <linux/major.h>
 #include <sound/core.h>
 
 #ifdef CONFIG_SOUND_OSS_CORE
@@ -29,6 +31,8 @@ MODULE_LICENSE("GPL");
 
 static char *sound_nodename(struct device *dev)
 {
+       if (MAJOR(dev->devt) == SOUND_MAJOR)
+               return NULL;
        return kasprintf(GFP_KERNEL, "snd/%s", dev_name(dev));
 }
 
@@ -104,7 +108,6 @@ module_exit(cleanup_soundcore);
 #include <linux/types.h>
 #include <linux/kernel.h>
 #include <linux/sound.h>
-#include <linux/major.h>
 #include <linux/kmod.h>
 
 #define SOUND_STEP 16
index 0e5db719de244c1ba6da224ac316b8a37106109c..de38108f0b283ab4653693cbe9ac77698de299a1 100644 (file)
@@ -35,7 +35,7 @@
 #include "input.h"
 
 MODULE_AUTHOR("Daniel Mack <daniel@caiaq.de>");
-MODULE_DESCRIPTION("caiaq USB audio, version 1.3.17");
+MODULE_DESCRIPTION("caiaq USB audio, version 1.3.18");
 MODULE_LICENSE("GPL");
 MODULE_SUPPORTED_DEVICE("{{Native Instruments, RigKontrol2},"
                         "{Native Instruments, RigKontrol3},"
@@ -349,7 +349,9 @@ static void __devinit setup_card(struct snd_usb_caiaqdev *dev)
                log("Unable to set up control system (ret=%d)\n", ret);
 }
 
-static int create_card(struct usb_device* usb_dev, struct snd_card **cardp)
+static int create_card(struct usb_device *usb_dev,
+                      struct usb_interface *intf,
+                      struct snd_card **cardp)
 {
        int devnum;
        int err;
@@ -374,7 +376,7 @@ static int create_card(struct usb_device* usb_dev, struct snd_card **cardp)
        dev->chip.usb_id = USB_ID(le16_to_cpu(usb_dev->descriptor.idVendor),
                                  le16_to_cpu(usb_dev->descriptor.idProduct));
        spin_lock_init(&dev->spinlock);
-       snd_card_set_dev(card, &usb_dev->dev);
+       snd_card_set_dev(card, &intf->dev);
 
        *cardp = card;
        return 0;
@@ -461,7 +463,7 @@ static int __devinit snd_probe(struct usb_interface *intf,
        struct snd_card *card;
        struct usb_device *device = interface_to_usbdev(intf);
 
-       ret = create_card(device, &card);
+       ret = create_card(device, intf, &card);
 
        if (ret < 0)
                return ret;
index c7b902358b7b268a3dd25178639f41009dedf125..44b9cdc8a83bae15856ca18fb7915acc7197757d 100644 (file)
@@ -2661,7 +2661,7 @@ static int parse_audio_endpoints(struct snd_usb_audio *chip, int iface_no)
        struct usb_interface_descriptor *altsd;
        int i, altno, err, stream;
        int format;
-       struct audioformat *fp;
+       struct audioformat *fp = NULL;
        unsigned char *fmt, *csep;
        int num;
 
@@ -2734,6 +2734,18 @@ static int parse_audio_endpoints(struct snd_usb_audio *chip, int iface_no)
                        continue;
                }
 
+               /*
+                * Blue Microphones workaround: The last altsetting is identical
+                * with the previous one, except for a larger packet size, but
+                * is actually a mislabeled two-channel setting; ignore it.
+                */
+               if (fmt[4] == 1 && fmt[5] == 2 && altno == 2 && num == 3 &&
+                   fp && fp->altsetting == 1 && fp->channels == 1 &&
+                   fp->format == SNDRV_PCM_FORMAT_S16_LE &&
+                   le16_to_cpu(get_endpoint(alts, 0)->wMaxPacketSize) ==
+                                                       fp->maxpacksize * 2)
+                       continue;
+
                csep = snd_usb_find_desc(alts->endpoint[0].extra, alts->endpoint[0].extralen, NULL, USB_DT_CS_ENDPOINT);
                /* Creamware Noah has this descriptor after the 2nd endpoint */
                if (!csep && altsd->bNumEndpoints >= 2)
index a5aae9d67f31707e585de8de10689d8099df5f1c..fd44946ce4b3a21aa4bae548144fcf6b66df676b 100644 (file)
@@ -514,7 +514,6 @@ static int usx2y_create_card(struct usb_device *device, struct snd_card **cardp)
                US122L(card)->chip.dev->bus->busnum,
                US122L(card)->chip.dev->devnum
                );
-       snd_card_set_dev(card, &device->dev);
        *cardp = card;
        return 0;
 }
@@ -531,6 +530,7 @@ static int us122l_usb_probe(struct usb_interface *intf,
        if (err < 0)
                return err;
 
+       snd_card_set_dev(card, &intf->dev);
        if (!us122l_create_card(card)) {
                snd_card_free(card);
                return -EINVAL;
index 5ce0da23ee96fd22752b53ffcab1d7f8057672b9..cb4bb8373ca2989732459c70b14df5e2d2ad423d 100644 (file)
@@ -364,7 +364,6 @@ static int usX2Y_create_card(struct usb_device *device, struct snd_card **cardp)
                0,//us428(card)->usbmidi.ifnum,
                usX2Y(card)->chip.dev->bus->busnum, usX2Y(card)->chip.dev->devnum
                );
-       snd_card_set_dev(card, &device->dev);
        *cardp = card;
        return 0;
 }
@@ -388,6 +387,7 @@ static int usX2Y_usb_probe(struct usb_device *device,
        err = usX2Y_create_card(device, &card);
        if (err < 0)
                return err;
+       snd_card_set_dev(card, &intf->dev);
        if ((err = usX2Y_hwdep_new(card, device)) < 0  ||
            (err = snd_card_register(card)) < 0) {
                snd_card_free(card);
index dd1ab6177840b039437d3b516794d23dd096fe23..9efd27f6b52f0ee7da14dda8777a050945c98086 100644 (file)
@@ -296,9 +296,10 @@ static void usX2Y_error_urb_status(struct usX2Ydev *usX2Y,
 static void usX2Y_error_sequence(struct usX2Ydev *usX2Y,
                                 struct snd_usX2Y_substream *subs, struct urb *urb)
 {
-       snd_printk(KERN_ERR "Sequence Error!(hcd_frame=%i ep=%i%s;wait=%i,frame=%i).\n"
-                  KERN_ERR "Most propably some urb of usb-frame %i is still missing.\n"
-                  KERN_ERR "Cause could be too long delays in usb-hcd interrupt handling.\n",
+       snd_printk(KERN_ERR
+"Sequence Error!(hcd_frame=%i ep=%i%s;wait=%i,frame=%i).\n"
+"Most propably some urb of usb-frame %i is still missing.\n"
+"Cause could be too long delays in usb-hcd interrupt handling.\n",
                   usb_get_current_frame_number(usX2Y->chip.dev),
                   subs->endpoint, usb_pipein(urb->pipe) ? "in" : "out",
                   usX2Y->wait_iso_frame, urb->start_frame, usX2Y->wait_iso_frame);
diff --git a/tools/perf/CREDITS b/tools/perf/CREDITS
new file mode 100644 (file)
index 0000000..c2ddcb3
--- /dev/null
@@ -0,0 +1,30 @@
+Most of the infrastructure that 'perf' uses here has been reused
+from the Git project, as of version:
+
+    66996ec: Sync with 1.6.2.4
+
+Here is an (incomplete!) list of main contributors to those files
+in util/* and elsewhere:
+
+ Alex Riesen
+ Christian Couder
+ Dmitry Potapov
+ Jeff King
+ Johannes Schindelin
+ Johannes Sixt
+ Junio C Hamano
+ Linus Torvalds
+ Matthias Kestenholz
+ Michal Ostrowski
+ Miklos Vajna
+ Petr Baudis
+ Pierre Habouzit
+ René Scharfe
+ Samuel Tardieu
+ Shawn O. Pearce
+ Steffen Prohaska
+ Steve Haslam
+
+Thanks guys!
+
+The full history of the files can be found in the upstream Git commits.
index 52d3fc6846a976e9947b7176a520273e639dfe6d..8aa3f8c88707f1ab9ea48f123833139ca8cc3ed7 100644 (file)
@@ -13,13 +13,25 @@ SYNOPSIS
 DESCRIPTION
 -----------
 This command displays the performance counter profile information recorded
-via perf report.
+via perf record.
 
 OPTIONS
 -------
 -i::
 --input=::
         Input file name. (default: perf.data)
+-d::
+--dsos=::
+       Only consider symbols in these dsos. CSV that understands
+       file://filename entries.
+-C::
+--comms=::
+       Only consider symbols in these comms. CSV that understands
+       file://filename entries.
+-S::
+--symbols=::
+       Only consider these symbols. CSV that understands
+       file://filename entries.
 
 SEE ALSO
 --------
index c368a72721d785b3836fe5c1e2a37bdcfc3082f5..0d74346d21abd6c032194a87fc4e0cc0697f6a09 100644 (file)
@@ -8,8 +8,8 @@ perf-stat - Run a command and gather performance counter statistics
 SYNOPSIS
 --------
 [verse]
-'perf stat' [-e <EVENT> | --event=EVENT] [-l] [-a] <command>
-'perf stat' [-e <EVENT> | --event=EVENT] [-l] [-a] -- <command> [<options>]
+'perf stat' [-e <EVENT> | --event=EVENT] [-S] [-a] <command>
+'perf stat' [-e <EVENT> | --event=EVENT] [-S] [-a] -- <command> [<options>]
 
 DESCRIPTION
 -----------
@@ -40,7 +40,7 @@ OPTIONS
 -a::
         system-wide collection
 
--l::
+-S::
         scale counter values
 
 EXAMPLES
index 36d7eef4991352e429480325542c23897ba6d194..7822b3d6baca22ea302a847a8a12d2ed3bde32a4 100644 (file)
@@ -164,7 +164,7 @@ endif
 
 # CFLAGS and LDFLAGS are for the users to override from the command line.
 
-CFLAGS = $(M64) -ggdb3 -Wall -Wstrict-prototypes -Wmissing-declarations -Wmissing-prototypes -std=gnu99 -Wdeclaration-after-statement -Werror -O6
+CFLAGS = $(M64) -ggdb3 -Wall -Wextra -Wstrict-prototypes -Wmissing-declarations -Wmissing-prototypes -std=gnu99 -Wdeclaration-after-statement -Werror -O6
 LDFLAGS = -lpthread -lrt -lelf -lm
 ALL_CFLAGS = $(CFLAGS)
 ALL_LDFLAGS = $(LDFLAGS)
@@ -223,7 +223,7 @@ SPARSE_FLAGS = -D__BIG_ENDIAN__ -D__powerpc__
 # Those must not be GNU-specific; they are shared with perl/ which may
 # be built by a different compiler. (Note that this is an artifact now
 # but it still might be nice to keep that distinction.)
-BASIC_CFLAGS =
+BASIC_CFLAGS = -Iutil/include
 BASIC_LDFLAGS =
 
 # Guard against environment variables
@@ -289,10 +289,11 @@ export PERL_PATH
 LIB_FILE=libperf.a
 
 LIB_H += ../../include/linux/perf_counter.h
+LIB_H += ../../include/linux/rbtree.h
+LIB_H += ../../include/linux/list.h
+LIB_H += util/include/linux/list.h
 LIB_H += perf.h
-LIB_H += types.h
-LIB_H += util/list.h
-LIB_H += util/rbtree.h
+LIB_H += util/types.h
 LIB_H += util/levenshtein.h
 LIB_H += util/parse-options.h
 LIB_H += util/parse-events.h
@@ -301,9 +302,11 @@ LIB_H += util/util.h
 LIB_H += util/help.h
 LIB_H += util/strbuf.h
 LIB_H += util/string.h
+LIB_H += util/strlist.h
 LIB_H += util/run-command.h
 LIB_H += util/sigchain.h
 LIB_H += util/symbol.h
+LIB_H += util/module.h
 LIB_H += util/color.h
 
 LIB_OBJS += util/abspath.o
@@ -322,12 +325,16 @@ LIB_OBJS += util/run-command.o
 LIB_OBJS += util/quote.o
 LIB_OBJS += util/strbuf.o
 LIB_OBJS += util/string.o
+LIB_OBJS += util/strlist.o
 LIB_OBJS += util/usage.o
 LIB_OBJS += util/wrapper.o
 LIB_OBJS += util/sigchain.o
 LIB_OBJS += util/symbol.o
+LIB_OBJS += util/module.o
 LIB_OBJS += util/color.o
 LIB_OBJS += util/pager.o
+LIB_OBJS += util/header.o
+LIB_OBJS += util/callchain.o
 
 BUILTIN_OBJS += builtin-annotate.o
 BUILTIN_OBJS += builtin-help.o
@@ -377,12 +384,6 @@ ifndef CC_LD_DYNPATH
        endif
 endif
 
-ifdef ZLIB_PATH
-       BASIC_CFLAGS += -I$(ZLIB_PATH)/include
-       EXTLIBS += -L$(ZLIB_PATH)/$(lib) $(CC_LD_DYNPATH)$(ZLIB_PATH)/$(lib)
-endif
-EXTLIBS += -lz
-
 ifdef NEEDS_SOCKET
        EXTLIBS += -lsocket
 endif
@@ -693,6 +694,9 @@ builtin-init-db.o: builtin-init-db.c PERF-CFLAGS
 util/config.o: util/config.c PERF-CFLAGS
        $(QUIET_CC)$(CC) -o $*.o -c $(ALL_CFLAGS) -DETC_PERFCONFIG='"$(ETC_PERFCONFIG_SQ)"' $<
 
+util/rbtree.o: ../../lib/rbtree.c PERF-CFLAGS
+       $(QUIET_CC)$(CC) -o util/rbtree.o -c $(ALL_CFLAGS) -DETC_PERFCONFIG='"$(ETC_PERFCONFIG_SQ)"' $<
+
 perf-%$X: %.o $(PERFLIBS)
        $(QUIET_LINK)$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $(filter %.o,$^) $(LIBS)
 
index 7e58e3ad1508053aa9cf92147caf15e1af80cee3..5f9eefecc5740b531460d0d63be520f9c73b63f4 100644 (file)
@@ -10,9 +10,9 @@
 #include "util/util.h"
 
 #include "util/color.h"
-#include "util/list.h"
+#include <linux/list.h>
 #include "util/cache.h"
-#include "util/rbtree.h"
+#include <linux/rbtree.h>
 #include "util/symbol.h"
 #include "util/string.h"
 
 #define SHOW_USER      2
 #define SHOW_HV                4
 
-#define MIN_GREEN              0.5
-#define MIN_RED                5.0
-
-
 static char            const *input_name = "perf.data";
 static char            *vmlinux = "vmlinux";
 
@@ -43,6 +39,10 @@ static int           dump_trace = 0;
 
 static int             verbose;
 
+static int             modules;
+
+static int             full_paths;
+
 static int             print_line;
 
 static unsigned long   page_size;
@@ -160,7 +160,7 @@ static void dsos__fprintf(FILE *fp)
 
 static struct symbol *vdso__find_symbol(struct dso *dso, u64 ip)
 {
-       return dso__find_symbol(kernel_dso, ip);
+       return dso__find_symbol(dso, ip);
 }
 
 static int load_kernel(void)
@@ -171,8 +171,8 @@ static int load_kernel(void)
        if (!kernel_dso)
                return -1;
 
-       err = dso__load_kernel(kernel_dso, vmlinux, NULL, verbose);
-       if (err) {
+       err = dso__load_kernel(kernel_dso, vmlinux, NULL, verbose, modules);
+       if (err <= 0) {
                dso__delete(kernel_dso);
                kernel_dso = NULL;
        } else
@@ -203,7 +203,7 @@ static u64 map__map_ip(struct map *map, u64 ip)
        return ip - map->start + map->pgoff;
 }
 
-static u64 vdso__map_ip(struct map *map, u64 ip)
+static u64 vdso__map_ip(struct map *map __used, u64 ip)
 {
        return ip;
 }
@@ -600,7 +600,7 @@ static LIST_HEAD(hist_entry__sort_list);
 
 static int sort_dimension__add(char *tok)
 {
-       int i;
+       unsigned int i;
 
        for (i = 0; i < ARRAY_SIZE(sort_dimensions); i++) {
                struct sort_dimension *sd = &sort_dimensions[i];
@@ -855,7 +855,7 @@ static unsigned long total = 0,
                     total_unknown = 0;
 
 static int
-process_overflow_event(event_t *event, unsigned long offset, unsigned long head)
+process_sample_event(event_t *event, unsigned long offset, unsigned long head)
 {
        char level;
        int show = 0;
@@ -1013,10 +1013,10 @@ process_period_event(event_t *event, unsigned long offset, unsigned long head)
 static int
 process_event(event_t *event, unsigned long offset, unsigned long head)
 {
-       if (event->header.misc & PERF_EVENT_MISC_OVERFLOW)
-               return process_overflow_event(event, offset, head);
-
        switch (event->header.type) {
+       case PERF_EVENT_SAMPLE:
+               return process_sample_event(event, offset, head);
+
        case PERF_EVENT_MMAP:
                return process_mmap_event(event, offset, head);
 
@@ -1043,24 +1043,6 @@ process_event(event_t *event, unsigned long offset, unsigned long head)
        return 0;
 }
 
-static char *get_color(double percent)
-{
-       char *color = PERF_COLOR_NORMAL;
-
-       /*
-        * We color high-overhead entries in red, mid-overhead
-        * entries in green - and keep the low overhead places
-        * normal:
-        */
-       if (percent >= MIN_RED)
-               color = PERF_COLOR_RED;
-       else {
-               if (percent > MIN_GREEN)
-                       color = PERF_COLOR_GREEN;
-       }
-       return color;
-}
-
 static int
 parse_line(FILE *file, struct symbol *sym, u64 start, u64 len)
 {
@@ -1069,7 +1051,7 @@ parse_line(FILE *file, struct symbol *sym, u64 start, u64 len)
        static const char *prev_color;
        unsigned int offset;
        size_t line_len;
-       u64 line_ip;
+       s64 line_ip;
        int ret;
        char *c;
 
@@ -1122,7 +1104,7 @@ parse_line(FILE *file, struct symbol *sym, u64 start, u64 len)
                } else if (sym->hist_sum)
                        percent = 100.0 * hits / sym->hist_sum;
 
-               color = get_color(percent);
+               color = get_percent_color(percent);
 
                /*
                 * Also color the filename and line if needed, with
@@ -1258,7 +1240,7 @@ static void print_summary(char *filename)
 
                sym_ext = rb_entry(node, struct sym_ext, node);
                percent = sym_ext->percent;
-               color = get_color(percent);
+               color = get_percent_color(percent);
                path = sym_ext->path;
 
                color_fprintf(stdout, color, " %7.2f %s", percent, path);
@@ -1268,19 +1250,25 @@ static void print_summary(char *filename)
 
 static void annotate_sym(struct dso *dso, struct symbol *sym)
 {
-       char *filename = dso->name;
+       char *filename = dso->name, *d_filename;
        u64 start, end, len;
        char command[PATH_MAX*2];
        FILE *file;
 
        if (!filename)
                return;
-       if (dso == kernel_dso)
+       if (sym->module)
+               filename = sym->module->path;
+       else if (dso == kernel_dso)
                filename = vmlinux;
 
        start = sym->obj_start;
        if (!start)
                start = sym->start;
+       if (full_paths)
+               d_filename = filename;
+       else
+               d_filename = basename(filename);
 
        end = start + sym->end - sym->start + 1;
        len = sym->end - sym->start;
@@ -1291,13 +1279,14 @@ static void annotate_sym(struct dso *dso, struct symbol *sym)
        }
 
        printf("\n\n------------------------------------------------\n");
-       printf(" Percent |      Source code & Disassembly of %s\n", filename);
+       printf(" Percent |      Source code & Disassembly of %s\n", d_filename);
        printf("------------------------------------------------\n");
 
        if (verbose >= 2)
                printf("annotating [%p] %30s : [%p] %30s\n", dso, dso->name, sym, sym->name);
 
-       sprintf(command, "objdump --start-address=0x%016Lx --stop-address=0x%016Lx -dS %s", (u64)start, (u64)end, filename);
+       sprintf(command, "objdump --start-address=0x%016Lx --stop-address=0x%016Lx -dS %s|grep -v %s",
+                       (u64)start, (u64)end, filename, filename);
 
        if (verbose >= 3)
                printf("doing: %s\n", command);
@@ -1428,7 +1417,7 @@ more:
 
        head += size;
 
-       if (offset + head < stat.st_size)
+       if (offset + head < (unsigned long)stat.st_size)
                goto more;
 
        rc = EXIT_SUCCESS;
@@ -1472,8 +1461,12 @@ static const struct option options[] = {
        OPT_BOOLEAN('D', "dump-raw-trace", &dump_trace,
                    "dump raw trace in ASCII"),
        OPT_STRING('k', "vmlinux", &vmlinux, "file", "vmlinux pathname"),
+       OPT_BOOLEAN('m', "modules", &modules,
+                   "load module symbols - WARNING: use only with -k and LIVE kernel"),
        OPT_BOOLEAN('l', "print-line", &print_line,
                    "print matching source lines (may be slow)"),
+       OPT_BOOLEAN('P', "full-paths", &full_paths,
+                   "Don't shorten the displayed pathnames"),
        OPT_END()
 };
 
@@ -1492,7 +1485,7 @@ static void setup_sorting(void)
        free(str);
 }
 
-int cmd_annotate(int argc, const char **argv, const char *prefix)
+int cmd_annotate(int argc, const char **argv, const char *prefix __used)
 {
        symbol__init();
 
index 0f32dc3f3c4c7a45b5d18bf8fac59aabedb8069f..2599d86a733b404db9be615519fec61b3517a1dd 100644 (file)
@@ -3,6 +3,7 @@
  *
  * Builtin help command
  */
+#include "perf.h"
 #include "util/cache.h"
 #include "builtin.h"
 #include "util/exec_cmd.h"
@@ -277,7 +278,7 @@ static struct cmdnames main_cmds, other_cmds;
 
 void list_common_cmds_help(void)
 {
-       int i, longest = 0;
+       unsigned int i, longest = 0;
 
        for (i = 0; i < ARRAY_SIZE(common_cmds); i++) {
                if (longest < strlen(common_cmds[i].name))
@@ -415,9 +416,10 @@ static void show_html_page(const char *perf_cmd)
        open_html(page_path.buf);
 }
 
-int cmd_help(int argc, const char **argv, const char *prefix)
+int cmd_help(int argc, const char **argv, const char *prefix __used)
 {
        const char *alias;
+
        load_command_list("perf-", &main_cmds, &other_cmds);
 
        perf_config(perf_help_config, NULL);
index fe60e37c96efc85e60e83d59d1cdb7127fe198c8..f990fa8a35c9d3312a20f3dcc1498203574c9407 100644 (file)
@@ -13,7 +13,7 @@
 #include "util/parse-options.h"
 #include "util/parse-events.h"
 
-int cmd_list(int argc, const char **argv, const char *prefix)
+int cmd_list(int argc __used, const char **argv __used, const char *prefix __used)
 {
        print_events();
        return 0;
index d7ebbd7575432f12c53109dc8c51054dd4a25f76..4ef78a5e6f326bf7aa08cc10715403b86574a5fe 100644 (file)
@@ -14,6 +14,8 @@
 #include "util/parse-events.h"
 #include "util/string.h"
 
+#include "util/header.h"
+
 #include <unistd.h>
 #include <sched.h>
 
@@ -39,6 +41,8 @@ static int                    force                           = 0;
 static int                     append_file                     = 0;
 static int                     call_graph                      = 0;
 static int                     verbose                         = 0;
+static int                     inherit_stat                    = 0;
+static int                     no_samples                      = 0;
 
 static long                    samples;
 static struct timeval          last_read;
@@ -52,7 +56,8 @@ static int                    nr_poll;
 static int                     nr_cpu;
 
 static int                     file_new = 1;
-static struct perf_file_header file_header;
+
+struct perf_header             *header;
 
 struct mmap_event {
        struct perf_event_header        header;
@@ -289,7 +294,7 @@ static void pid_synthesize_mmap_samples(pid_t pid)
        while (1) {
                char bf[BUFSIZ], *pbf = bf;
                struct mmap_event mmap_ev = {
-                       .header.type = PERF_EVENT_MMAP,
+                       .header = { .type = PERF_EVENT_MMAP },
                };
                int n;
                size_t size;
@@ -306,12 +311,11 @@ static void pid_synthesize_mmap_samples(pid_t pid)
                        continue;
                pbf += n + 3;
                if (*pbf == 'x') { /* vm_exec */
-                       char *execname = strrchr(bf, ' ');
+                       char *execname = strchr(bf, '/');
 
-                       if (execname == NULL || execname[1] != '/')
+                       if (execname == NULL)
                                continue;
 
-                       execname += 1;
                        size = strlen(execname);
                        execname[size - 1] = '\0'; /* Remove \n */
                        memcpy(mmap_ev.filename, execname, size);
@@ -329,7 +333,7 @@ static void pid_synthesize_mmap_samples(pid_t pid)
        fclose(fp);
 }
 
-static void synthesize_samples(void)
+static void synthesize_all(void)
 {
        DIR *proc;
        struct dirent dirent, *next;
@@ -353,10 +357,35 @@ static void synthesize_samples(void)
 
 static int group_fd;
 
+static struct perf_header_attr *get_header_attr(struct perf_counter_attr *a, int nr)
+{
+       struct perf_header_attr *h_attr;
+
+       if (nr < header->attrs) {
+               h_attr = header->attr[nr];
+       } else {
+               h_attr = perf_header_attr__new(a);
+               perf_header__add_attr(header, h_attr);
+       }
+
+       return h_attr;
+}
+
 static void create_counter(int counter, int cpu, pid_t pid)
 {
        struct perf_counter_attr *attr = attrs + counter;
-       int track = 1;
+       struct perf_header_attr *h_attr;
+       int track = !counter; /* only the first counter needs these */
+       struct {
+               u64 count;
+               u64 time_enabled;
+               u64 time_running;
+               u64 id;
+       } read_data;
+
+       attr->read_format       = PERF_FORMAT_TOTAL_TIME_ENABLED |
+                                 PERF_FORMAT_TOTAL_TIME_RUNNING |
+                                 PERF_FORMAT_ID;
 
        attr->sample_type       = PERF_SAMPLE_IP | PERF_SAMPLE_TID;
 
@@ -366,25 +395,20 @@ static void create_counter(int counter, int cpu, pid_t pid)
                attr->sample_freq       = freq;
        }
 
+       if (no_samples)
+               attr->sample_freq = 0;
+
+       if (inherit_stat)
+               attr->inherit_stat = 1;
+
        if (call_graph)
                attr->sample_type       |= PERF_SAMPLE_CALLCHAIN;
 
-       if (file_new) {
-               file_header.sample_type = attr->sample_type;
-       } else {
-               if (file_header.sample_type != attr->sample_type) {
-                       fprintf(stderr, "incompatible append\n");
-                       exit(-1);
-               }
-       }
-
        attr->mmap              = track;
        attr->comm              = track;
        attr->inherit           = (cpu < 0) && inherit;
        attr->disabled          = 1;
 
-       track = 0; /* only the first counter needs these */
-
 try_again:
        fd[nr_cpu][counter] = sys_perf_counter_open(attr, pid, cpu, group_fd, 0);
 
@@ -415,6 +439,22 @@ try_again:
                exit(-1);
        }
 
+       h_attr = get_header_attr(attr, counter);
+
+       if (!file_new) {
+               if (memcmp(&h_attr->attr, attr, sizeof(*attr))) {
+                       fprintf(stderr, "incompatible append\n");
+                       exit(-1);
+               }
+       }
+
+       if (read(fd[nr_cpu][counter], &read_data, sizeof(read_data)) == -1) {
+               perror("Unable to read perf file descriptor\n");
+               exit(-1);
+       }
+
+       perf_header_attr__add_id(h_attr, read_data.id);
+
        assert(fd[nr_cpu][counter] >= 0);
        fcntl(fd[nr_cpu][counter], F_SETFL, O_NONBLOCK);
 
@@ -445,11 +485,6 @@ static void open_counters(int cpu, pid_t pid)
 {
        int counter;
 
-       if (pid > 0) {
-               pid_synthesize_comm_event(pid, 0);
-               pid_synthesize_mmap_samples(pid);
-       }
-
        group_fd = -1;
        for (counter = 0; counter < nr_counters; counter++)
                create_counter(counter, cpu, pid);
@@ -459,17 +494,16 @@ static void open_counters(int cpu, pid_t pid)
 
 static void atexit_header(void)
 {
-       file_header.data_size += bytes_written;
+       header->data_size += bytes_written;
 
-       if (pwrite(output, &file_header, sizeof(file_header), 0) == -1)
-               perror("failed to write on file headers");
+       perf_header__write(header, output);
 }
 
 static int __cmd_record(int argc, const char **argv)
 {
        int i, counter;
        struct stat st;
-       pid_t pid;
+       pid_t pid = 0;
        int flags;
        int ret;
 
@@ -500,22 +534,31 @@ static int __cmd_record(int argc, const char **argv)
                exit(-1);
        }
 
-       if (!file_new) {
-               if (read(output, &file_header, sizeof(file_header)) == -1) {
-                       perror("failed to read file headers");
-                       exit(-1);
-               }
-
-               lseek(output, file_header.data_size, SEEK_CUR);
-       }
+       if (!file_new)
+               header = perf_header__read(output);
+       else
+               header = perf_header__new();
 
        atexit(atexit_header);
 
        if (!system_wide) {
-               open_counters(-1, target_pid != -1 ? target_pid : getpid());
+               pid = target_pid;
+               if (pid == -1)
+                       pid = getpid();
+
+               open_counters(-1, pid);
        } else for (i = 0; i < nr_cpus; i++)
                open_counters(i, target_pid);
 
+       if (file_new)
+               perf_header__write(header, output);
+
+       if (!system_wide) {
+               pid_synthesize_comm_event(pid, 0);
+               pid_synthesize_mmap_samples(pid);
+       } else
+               synthesize_all();
+
        if (target_pid == -1 && argc) {
                pid = fork();
                if (pid < 0)
@@ -539,10 +582,7 @@ static int __cmd_record(int argc, const char **argv)
                }
        }
 
-       if (system_wide)
-               synthesize_samples();
-
-       while (!done) {
+       for (;;) {
                int hits = samples;
 
                for (i = 0; i < nr_cpu; i++) {
@@ -550,8 +590,11 @@ static int __cmd_record(int argc, const char **argv)
                                mmap_read(&mmap_array[i][counter]);
                }
 
-               if (hits == samples)
+               if (hits == samples) {
+                       if (done)
+                               break;
                        ret = poll(event_array, nr_poll, 100);
+               }
        }
 
        /*
@@ -600,10 +643,14 @@ static const struct option options[] = {
                    "do call-graph (stack chain/backtrace) recording"),
        OPT_BOOLEAN('v', "verbose", &verbose,
                    "be more verbose (show counter open errors, etc)"),
+       OPT_BOOLEAN('s', "stat", &inherit_stat,
+                   "per thread counts"),
+       OPT_BOOLEAN('n', "no-samples", &no_samples,
+                   "don't sample"),
        OPT_END()
 };
 
-int cmd_record(int argc, const char **argv, const char *prefix)
+int cmd_record(int argc, const char **argv, const char *prefix __used)
 {
        int counter;
 
index 5eb5566f0c95426dd3f5c4c3cf196faf55080fbd..4e5cc266311e15f683d4b26877e158c83c2c7093 100644 (file)
 #include "util/util.h"
 
 #include "util/color.h"
-#include "util/list.h"
+#include <linux/list.h>
 #include "util/cache.h"
-#include "util/rbtree.h"
+#include <linux/rbtree.h>
 #include "util/symbol.h"
 #include "util/string.h"
+#include "util/callchain.h"
+#include "util/strlist.h"
 
 #include "perf.h"
+#include "util/header.h"
 
 #include "util/parse-options.h"
 #include "util/parse-events.h"
@@ -30,6 +33,8 @@ static char           *vmlinux = NULL;
 
 static char            default_sort_order[] = "comm,dso";
 static char            *sort_order = default_sort_order;
+static char            *dso_list_str, *comm_list_str, *sym_list_str;
+static struct strlist  *dso_list, *comm_list, *sym_list;
 
 static int             input;
 static int             show_mask = SHOW_KERNEL | SHOW_USER | SHOW_HV;
@@ -41,6 +46,8 @@ static int            dump_trace = 0;
 static int             verbose;
 #define eprintf(x...)  do { if (verbose) fprintf(stderr, x); } while (0)
 
+static int             modules;
+
 static int             full_paths;
 
 static unsigned long   page_size;
@@ -52,6 +59,18 @@ static regex_t               parent_regex;
 
 static int             exclude_other = 1;
 
+static char            callchain_default_opt[] = "fractal,0.5";
+
+static int             callchain;
+
+static
+struct callchain_param callchain_param = {
+       .mode   = CHAIN_GRAPH_ABS,
+       .min_percent = 0.5
+};
+
+static u64             sample_type;
+
 struct ip_event {
        struct perf_event_header header;
        u64 ip;
@@ -59,11 +78,6 @@ struct ip_event {
        unsigned char __more_data[];
 };
 
-struct ip_callchain {
-       u64 nr;
-       u64 ips[0];
-};
-
 struct mmap_event {
        struct perf_event_header header;
        u32 pid, tid;
@@ -97,6 +111,13 @@ struct lost_event {
        u64 lost;
 };
 
+struct read_event {
+       struct perf_event_header header;
+       u32 pid,tid;
+       u64 value;
+       u64 format[3];
+};
+
 typedef union event_union {
        struct perf_event_header        header;
        struct ip_event                 ip;
@@ -105,11 +126,13 @@ typedef union event_union {
        struct fork_event               fork;
        struct period_event             period;
        struct lost_event               lost;
+       struct read_event               read;
 } event_t;
 
 static LIST_HEAD(dsos);
 static struct dso *kernel_dso;
 static struct dso *vdso;
+static struct dso *hypervisor_dso;
 
 static void dsos__add(struct dso *dso)
 {
@@ -165,7 +188,7 @@ static void dsos__fprintf(FILE *fp)
 
 static struct symbol *vdso__find_symbol(struct dso *dso, u64 ip)
 {
-       return dso__find_symbol(kernel_dso, ip);
+       return dso__find_symbol(dso, ip);
 }
 
 static int load_kernel(void)
@@ -176,8 +199,8 @@ static int load_kernel(void)
        if (!kernel_dso)
                return -1;
 
-       err = dso__load_kernel(kernel_dso, vmlinux, NULL, verbose);
-       if (err) {
+       err = dso__load_kernel(kernel_dso, vmlinux, NULL, verbose, modules);
+       if (err <= 0) {
                dso__delete(kernel_dso);
                kernel_dso = NULL;
        } else
@@ -191,6 +214,11 @@ static int load_kernel(void)
 
        dsos__add(vdso);
 
+       hypervisor_dso = dso__new("[hypervisor]", 0);
+       if (!hypervisor_dso)
+               return -1;
+       dsos__add(hypervisor_dso);
+
        return err;
 }
 
@@ -222,14 +250,14 @@ static u64 map__map_ip(struct map *map, u64 ip)
        return ip - map->start + map->pgoff;
 }
 
-static u64 vdso__map_ip(struct map *map, u64 ip)
+static u64 vdso__map_ip(struct map *map __used, u64 ip)
 {
        return ip;
 }
 
 static inline int is_anon_memory(const char *filename)
 {
-     return strcmp(filename, "//anon") == 0;
+       return strcmp(filename, "//anon") == 0;
 }
 
 static struct map *map__new(struct mmap_event *event)
@@ -400,9 +428,27 @@ static void thread__insert_map(struct thread *self, struct map *map)
 
        list_for_each_entry_safe(pos, tmp, &self->maps, node) {
                if (map__overlap(pos, map)) {
-                       list_del_init(&pos->node);
-                       /* XXX leaks dsos */
-                       free(pos);
+                       if (verbose >= 2) {
+                               printf("overlapping maps:\n");
+                               map__fprintf(map, stdout);
+                               map__fprintf(pos, stdout);
+                       }
+
+                       if (map->start <= pos->start && map->end > pos->start)
+                               pos->start = map->end;
+
+                       if (map->end >= pos->end && map->start < pos->end)
+                               pos->end = map->start;
+
+                       if (verbose >= 2) {
+                               printf("after collision:\n");
+                               map__fprintf(pos, stdout);
+                       }
+
+                       if (pos->start >= pos->end) {
+                               list_del_init(&pos->node);
+                               free(pos);
+                       }
                }
        }
 
@@ -464,17 +510,19 @@ static size_t threads__fprintf(FILE *fp)
 static struct rb_root hist;
 
 struct hist_entry {
-       struct rb_node   rb_node;
-
-       struct thread    *thread;
-       struct map       *map;
-       struct dso       *dso;
-       struct symbol    *sym;
-       struct symbol    *parent;
-       u64              ip;
-       char             level;
-
-       u64              count;
+       struct rb_node          rb_node;
+
+       struct thread           *thread;
+       struct map              *map;
+       struct dso              *dso;
+       struct symbol           *sym;
+       struct symbol           *parent;
+       u64                     ip;
+       char                    level;
+       struct callchain_node   callchain;
+       struct rb_root          sorted_chain;
+
+       u64                     count;
 };
 
 /*
@@ -609,7 +657,11 @@ sort__sym_print(FILE *fp, struct hist_entry *self)
 
        if (self->sym) {
                ret += fprintf(fp, "[%c] %s",
-                       self->dso == kernel_dso ? 'k' : '.', self->sym->name);
+                       self->dso == kernel_dso ? 'k' :
+                       self->dso == hypervisor_dso ? 'h' : '.', self->sym->name);
+
+               if (self->sym->module)
+                       ret += fprintf(fp, "\t[%s]", self->sym->module->name);
        } else {
                ret += fprintf(fp, "%#016llx", (u64)self->ip);
        }
@@ -674,7 +726,7 @@ static LIST_HEAD(hist_entry__sort_list);
 
 static int sort_dimension__add(char *tok)
 {
-       int i;
+       unsigned int i;
 
        for (i = 0; i < ARRAY_SIZE(sort_dimensions); i++) {
                struct sort_dimension *sd = &sort_dimensions[i];
@@ -744,34 +796,180 @@ hist_entry__collapse(struct hist_entry *left, struct hist_entry *right)
        return cmp;
 }
 
+static size_t ipchain__fprintf_graph_line(FILE *fp, int depth, int depth_mask)
+{
+       int i;
+       size_t ret = 0;
+
+       ret += fprintf(fp, "%s", "                ");
+
+       for (i = 0; i < depth; i++)
+               if (depth_mask & (1 << i))
+                       ret += fprintf(fp, "|          ");
+               else
+                       ret += fprintf(fp, "           ");
+
+       ret += fprintf(fp, "\n");
+
+       return ret;
+}
 static size_t
-hist_entry__fprintf(FILE *fp, struct hist_entry *self, u64 total_samples)
+ipchain__fprintf_graph(FILE *fp, struct callchain_list *chain, int depth,
+                      int depth_mask, int count, u64 total_samples,
+                      int hits)
 {
-       struct sort_entry *se;
-       size_t ret;
+       int i;
+       size_t ret = 0;
 
-       if (exclude_other && !self->parent)
-               return 0;
+       ret += fprintf(fp, "%s", "                ");
+       for (i = 0; i < depth; i++) {
+               if (depth_mask & (1 << i))
+                       ret += fprintf(fp, "|");
+               else
+                       ret += fprintf(fp, " ");
+               if (!count && i == depth - 1) {
+                       double percent;
+
+                       percent = hits * 100.0 / total_samples;
+                       ret += percent_color_fprintf(fp, "--%2.2f%%-- ", percent);
+               } else
+                       ret += fprintf(fp, "%s", "          ");
+       }
+       if (chain->sym)
+               ret += fprintf(fp, "%s\n", chain->sym->name);
+       else
+               ret += fprintf(fp, "%p\n", (void *)(long)chain->ip);
+
+       return ret;
+}
+
+static size_t
+callchain__fprintf_graph(FILE *fp, struct callchain_node *self,
+                       u64 total_samples, int depth, int depth_mask)
+{
+       struct rb_node *node, *next;
+       struct callchain_node *child;
+       struct callchain_list *chain;
+       int new_depth_mask = depth_mask;
+       u64 new_total;
+       size_t ret = 0;
+       int i;
 
-       if (total_samples) {
-               double percent = self->count * 100.0 / total_samples;
-               char *color = PERF_COLOR_NORMAL;
+       if (callchain_param.mode == CHAIN_GRAPH_REL)
+               new_total = self->cumul_hit;
+       else
+               new_total = total_samples;
+
+       node = rb_first(&self->rb_root);
+       while (node) {
+               child = rb_entry(node, struct callchain_node, rb_node);
 
                /*
-                * We color high-overhead entries in red, mid-overhead
-                * entries in green - and keep the low overhead places
-                * normal:
+                * The depth mask manages the output of pipes that show
+                * the depth. We don't want to keep the pipes of the current
+                * level for the last child of this depth
                 */
-               if (percent >= 5.0) {
-                       color = PERF_COLOR_RED;
-               } else {
-                       if (percent >= 0.5)
-                               color = PERF_COLOR_GREEN;
+               next = rb_next(node);
+               if (!next)
+                       new_depth_mask &= ~(1 << (depth - 1));
+
+               /*
+                * But we keep the older depth mask for the line seperator
+                * to keep the level link until we reach the last child
+                */
+               ret += ipchain__fprintf_graph_line(fp, depth, depth_mask);
+               i = 0;
+               list_for_each_entry(chain, &child->val, list) {
+                       if (chain->ip >= PERF_CONTEXT_MAX)
+                               continue;
+                       ret += ipchain__fprintf_graph(fp, chain, depth,
+                                                     new_depth_mask, i++,
+                                                     new_total,
+                                                     child->cumul_hit);
+               }
+               ret += callchain__fprintf_graph(fp, child, new_total,
+                                               depth + 1,
+                                               new_depth_mask | (1 << depth));
+               node = next;
+       }
+
+       return ret;
+}
+
+static size_t
+callchain__fprintf_flat(FILE *fp, struct callchain_node *self,
+                       u64 total_samples)
+{
+       struct callchain_list *chain;
+       size_t ret = 0;
+
+       if (!self)
+               return 0;
+
+       ret += callchain__fprintf_flat(fp, self->parent, total_samples);
+
+
+       list_for_each_entry(chain, &self->val, list) {
+               if (chain->ip >= PERF_CONTEXT_MAX)
+                       continue;
+               if (chain->sym)
+                       ret += fprintf(fp, "                %s\n", chain->sym->name);
+               else
+                       ret += fprintf(fp, "                %p\n",
+                                       (void *)(long)chain->ip);
+       }
+
+       return ret;
+}
+
+static size_t
+hist_entry_callchain__fprintf(FILE *fp, struct hist_entry *self,
+                             u64 total_samples)
+{
+       struct rb_node *rb_node;
+       struct callchain_node *chain;
+       size_t ret = 0;
+
+       rb_node = rb_first(&self->sorted_chain);
+       while (rb_node) {
+               double percent;
+
+               chain = rb_entry(rb_node, struct callchain_node, rb_node);
+               percent = chain->hit * 100.0 / total_samples;
+               switch (callchain_param.mode) {
+               case CHAIN_FLAT:
+                       ret += percent_color_fprintf(fp, "           %6.2f%%\n",
+                                                    percent);
+                       ret += callchain__fprintf_flat(fp, chain, total_samples);
+                       break;
+               case CHAIN_GRAPH_ABS: /* Falldown */
+               case CHAIN_GRAPH_REL:
+                       ret += callchain__fprintf_graph(fp, chain,
+                                                       total_samples, 1, 1);
+               default:
+                       break;
                }
+               ret += fprintf(fp, "\n");
+               rb_node = rb_next(rb_node);
+       }
+
+       return ret;
+}
+
 
-               ret = color_fprintf(fp, color, "   %6.2f%%",
+static size_t
+hist_entry__fprintf(FILE *fp, struct hist_entry *self, u64 total_samples)
+{
+       struct sort_entry *se;
+       size_t ret;
+
+       if (exclude_other && !self->parent)
+               return 0;
+
+       if (total_samples)
+               ret = percent_color_fprintf(fp, "   %6.2f%%",
                                (self->count * 100.0) / total_samples);
-       else
+       else
                ret = fprintf(fp, "%12Ld ", self->count);
 
        list_for_each_entry(se, &hist_entry__sort_list, list) {
@@ -784,6 +982,9 @@ hist_entry__fprintf(FILE *fp, struct hist_entry *self, u64 total_samples)
 
        ret += fprintf(fp, "\n");
 
+       if (callchain)
+               hist_entry_callchain__fprintf(fp, self, total_samples);
+
        return ret;
 }
 
@@ -797,7 +998,7 @@ resolve_symbol(struct thread *thread, struct map **mapp,
 {
        struct dso *dso = dsop ? *dsop : NULL;
        struct map *map = mapp ? *mapp : NULL;
-       uint64_t ip = *ipp;
+       u64 ip = *ipp;
 
        if (!thread)
                return NULL;
@@ -814,7 +1015,6 @@ resolve_symbol(struct thread *thread, struct map **mapp,
                        *mapp = map;
 got_map:
                ip = map->map_ip(map, ip);
-               *ipp  = ip;
 
                dso = map->dso;
        } else {
@@ -828,6 +1028,8 @@ got_map:
                dso = kernel_dso;
        }
        dprintf(" ...... dso: %s\n", dso ? dso->name : "<not found>");
+       dprintf(" ...... map: %Lx -> %Lx\n", *ipp, ip);
+       *ipp  = ip;
 
        if (dsop)
                *dsop = dso;
@@ -846,6 +1048,58 @@ static int call__match(struct symbol *sym)
        return 0;
 }
 
+static struct symbol **
+resolve_callchain(struct thread *thread, struct map *map __used,
+                   struct ip_callchain *chain, struct hist_entry *entry)
+{
+       u64 context = PERF_CONTEXT_MAX;
+       struct symbol **syms = NULL;
+       unsigned int i;
+
+       if (callchain) {
+               syms = calloc(chain->nr, sizeof(*syms));
+               if (!syms) {
+                       fprintf(stderr, "Can't allocate memory for symbols\n");
+                       exit(-1);
+               }
+       }
+
+       for (i = 0; i < chain->nr; i++) {
+               u64 ip = chain->ips[i];
+               struct dso *dso = NULL;
+               struct symbol *sym;
+
+               if (ip >= PERF_CONTEXT_MAX) {
+                       context = ip;
+                       continue;
+               }
+
+               switch (context) {
+               case PERF_CONTEXT_HV:
+                       dso = hypervisor_dso;
+                       break;
+               case PERF_CONTEXT_KERNEL:
+                       dso = kernel_dso;
+                       break;
+               default:
+                       break;
+               }
+
+               sym = resolve_symbol(thread, NULL, &dso, &ip);
+
+               if (sym) {
+                       if (sort__has_parent && call__match(sym) &&
+                           !entry->parent)
+                               entry->parent = sym;
+                       if (!callchain)
+                               break;
+                       syms[i] = sym;
+               }
+       }
+
+       return syms;
+}
+
 /*
  * collect histogram counts
  */
@@ -858,6 +1112,7 @@ hist_entry__add(struct thread *thread, struct map *map, struct dso *dso,
        struct rb_node **p = &hist.rb_node;
        struct rb_node *parent = NULL;
        struct hist_entry *he;
+       struct symbol **syms = NULL;
        struct hist_entry entry = {
                .thread = thread,
                .map    = map,
@@ -867,39 +1122,12 @@ hist_entry__add(struct thread *thread, struct map *map, struct dso *dso,
                .level  = level,
                .count  = count,
                .parent = NULL,
+               .sorted_chain = RB_ROOT
        };
        int cmp;
 
-       if (sort__has_parent && chain) {
-               u64 context = PERF_CONTEXT_MAX;
-               int i;
-
-               for (i = 0; i < chain->nr; i++) {
-                       u64 ip = chain->ips[i];
-                       struct dso *dso = NULL;
-                       struct symbol *sym;
-
-                       if (ip >= PERF_CONTEXT_MAX) {
-                               context = ip;
-                               continue;
-                       }
-
-                       switch (context) {
-                       case PERF_CONTEXT_KERNEL:
-                               dso = kernel_dso;
-                               break;
-                       default:
-                               break;
-                       }
-
-                       sym = resolve_symbol(thread, NULL, &dso, &ip);
-
-                       if (sym && call__match(sym)) {
-                               entry.parent = sym;
-                               break;
-                       }
-               }
-       }
+       if ((sort__has_parent || callchain) && chain)
+               syms = resolve_callchain(thread, map, chain, &entry);
 
        while (*p != NULL) {
                parent = *p;
@@ -909,6 +1137,10 @@ hist_entry__add(struct thread *thread, struct map *map, struct dso *dso,
 
                if (!cmp) {
                        he->count += count;
+                       if (callchain) {
+                               append_chain(&he->callchain, chain, syms);
+                               free(syms);
+                       }
                        return 0;
                }
 
@@ -922,6 +1154,11 @@ hist_entry__add(struct thread *thread, struct map *map, struct dso *dso,
        if (!he)
                return -ENOMEM;
        *he = entry;
+       if (callchain) {
+               callchain_init(&he->callchain);
+               append_chain(&he->callchain, chain, syms);
+               free(syms);
+       }
        rb_link_node(&he->rb_node, parent, p);
        rb_insert_color(&he->rb_node, &hist);
 
@@ -992,12 +1229,16 @@ static void collapse__resort(void)
 
 static struct rb_root output_hists;
 
-static void output__insert_entry(struct hist_entry *he)
+static void output__insert_entry(struct hist_entry *he, u64 min_callchain_hits)
 {
        struct rb_node **p = &output_hists.rb_node;
        struct rb_node *parent = NULL;
        struct hist_entry *iter;
 
+       if (callchain)
+               callchain_param.sort(&he->sorted_chain, &he->callchain,
+                                     min_callchain_hits, &callchain_param);
+
        while (*p != NULL) {
                parent = *p;
                iter = rb_entry(parent, struct hist_entry, rb_node);
@@ -1012,11 +1253,14 @@ static void output__insert_entry(struct hist_entry *he)
        rb_insert_color(&he->rb_node, &output_hists);
 }
 
-static void output__resort(void)
+static void output__resort(u64 total_samples)
 {
        struct rb_node *next;
        struct hist_entry *n;
        struct rb_root *tree = &hist;
+       u64 min_callchain_hits;
+
+       min_callchain_hits = total_samples * (callchain_param.min_percent / 100);
 
        if (sort__need_collapse)
                tree = &collapse_hists;
@@ -1028,7 +1272,7 @@ static void output__resort(void)
                next = rb_next(&n->rb_node);
 
                rb_erase(&n->rb_node, tree);
-               output__insert_entry(n);
+               output__insert_entry(n, min_callchain_hits);
        }
 }
 
@@ -1054,7 +1298,7 @@ static size_t output__fprintf(FILE *fp, u64 total_samples)
 
        fprintf(fp, "# ........");
        list_for_each_entry(se, &hist_entry__sort_list, list) {
-               int i;
+               unsigned int i;
 
                if (exclude_other && (se == &sort_parent))
                        continue;
@@ -1115,7 +1359,7 @@ static int validate_chain(struct ip_callchain *chain, event_t *event)
 }
 
 static int
-process_overflow_event(event_t *event, unsigned long offset, unsigned long head)
+process_sample_event(event_t *event, unsigned long offset, unsigned long head)
 {
        char level;
        int show = 0;
@@ -1126,13 +1370,14 @@ process_overflow_event(event_t *event, unsigned long offset, unsigned long head)
        struct map *map = NULL;
        void *more_data = event->ip.__more_data;
        struct ip_callchain *chain = NULL;
+       int cpumode;
 
-       if (event->header.type & PERF_SAMPLE_PERIOD) {
+       if (sample_type & PERF_SAMPLE_PERIOD) {
                period = *(u64 *)more_data;
                more_data += sizeof(u64);
        }
 
-       dprintf("%p [%p]: PERF_EVENT (IP, %d): %d: %p period: %Ld\n",
+       dprintf("%p [%p]: PERF_EVENT_SAMPLE (IP, %d): %d: %p period: %Ld\n",
                (void *)(offset + head),
                (void *)(long)(event->header.size),
                event->header.misc,
@@ -1140,8 +1385,8 @@ process_overflow_event(event_t *event, unsigned long offset, unsigned long head)
                (void *)(long)ip,
                (long long)period);
 
-       if (event->header.type & PERF_SAMPLE_CALLCHAIN) {
-               int i;
+       if (sample_type & PERF_SAMPLE_CALLCHAIN) {
+               unsigned int i;
 
                chain = (void *)more_data;
 
@@ -1166,7 +1411,12 @@ process_overflow_event(event_t *event, unsigned long offset, unsigned long head)
                return -1;
        }
 
-       if (event->header.misc & PERF_EVENT_MISC_KERNEL) {
+       if (comm_list && !strlist__has_entry(comm_list, thread->comm))
+               return 0;
+
+       cpumode = event->header.misc & PERF_EVENT_MISC_CPUMODE_MASK;
+
+       if (cpumode == PERF_EVENT_MISC_KERNEL) {
                show = SHOW_KERNEL;
                level = 'k';
 
@@ -1174,7 +1424,7 @@ process_overflow_event(event_t *event, unsigned long offset, unsigned long head)
 
                dprintf(" ...... dso: %s\n", dso->name);
 
-       } else if (event->header.misc & PERF_EVENT_MISC_USER) {
+       } else if (cpumode == PERF_EVENT_MISC_USER) {
 
                show = SHOW_USER;
                level = '.';
@@ -1182,12 +1432,21 @@ process_overflow_event(event_t *event, unsigned long offset, unsigned long head)
        } else {
                show = SHOW_HV;
                level = 'H';
+
+               dso = hypervisor_dso;
+
                dprintf(" ...... dso: [hypervisor]\n");
        }
 
        if (show & show_mask) {
                struct symbol *sym = resolve_symbol(thread, &map, &dso, &ip);
 
+               if (dso_list && dso && dso->name && !strlist__has_entry(dso_list, dso->name))
+                       return 0;
+
+               if (sym_list && sym && !strlist__has_entry(sym_list, sym->name))
+                       return 0;
+
                if (hist_entry__add(thread, map, dso, sym, ip, chain, level, period)) {
                        eprintf("problem incrementing symbol count, skipping event\n");
                        return -1;
@@ -1327,15 +1586,28 @@ static void trace_event(event_t *event)
        dprintf(".\n");
 }
 
+static int
+process_read_event(event_t *event, unsigned long offset, unsigned long head)
+{
+       dprintf("%p [%p]: PERF_EVENT_READ: %d %d %Lu\n",
+                       (void *)(offset + head),
+                       (void *)(long)(event->header.size),
+                       event->read.pid,
+                       event->read.tid,
+                       event->read.value);
+
+       return 0;
+}
+
 static int
 process_event(event_t *event, unsigned long offset, unsigned long head)
 {
        trace_event(event);
 
-       if (event->header.misc & PERF_EVENT_MISC_OVERFLOW)
-               return process_overflow_event(event, offset, head);
-
        switch (event->header.type) {
+       case PERF_EVENT_SAMPLE:
+               return process_sample_event(event, offset, head);
+
        case PERF_EVENT_MMAP:
                return process_mmap_event(event, offset, head);
 
@@ -1351,6 +1623,9 @@ process_event(event_t *event, unsigned long offset, unsigned long head)
        case PERF_EVENT_LOST:
                return process_lost_event(event, offset, head);
 
+       case PERF_EVENT_READ:
+               return process_read_event(event, offset, head);
+
        /*
         * We dont process them right now but they are fine:
         */
@@ -1366,13 +1641,30 @@ process_event(event_t *event, unsigned long offset, unsigned long head)
        return 0;
 }
 
-static struct perf_file_header         file_header;
+static struct perf_header      *header;
+
+static u64 perf_header__sample_type(void)
+{
+       u64 sample_type = 0;
+       int i;
+
+       for (i = 0; i < header->attrs; i++) {
+               struct perf_header_attr *attr = header->attr[i];
+
+               if (!sample_type)
+                       sample_type = attr->attr.sample_type;
+               else if (sample_type != attr->attr.sample_type)
+                       die("non matching sample_type");
+       }
+
+       return sample_type;
+}
 
 static int __cmd_report(void)
 {
        int ret, rc = EXIT_FAILURE;
        unsigned long offset = 0;
-       unsigned long head = sizeof(file_header);
+       unsigned long head, shift;
        struct stat stat;
        event_t *event;
        uint32_t size;
@@ -1400,15 +1692,24 @@ static int __cmd_report(void)
                exit(0);
        }
 
-       if (read(input, &file_header, sizeof(file_header)) == -1) {
-               perror("failed to read file headers");
-               exit(-1);
-       }
+       header = perf_header__read(input);
+       head = header->data_offset;
 
-       if (sort__has_parent &&
-           !(file_header.sample_type & PERF_SAMPLE_CALLCHAIN)) {
-               fprintf(stderr, "selected --sort parent, but no callchain data\n");
-               exit(-1);
+       sample_type = perf_header__sample_type();
+
+       if (!(sample_type & PERF_SAMPLE_CALLCHAIN)) {
+               if (sort__has_parent) {
+                       fprintf(stderr, "selected --sort parent, but no"
+                                       " callchain data. Did you call"
+                                       " perf record without -g?\n");
+                       exit(-1);
+               }
+               if (callchain) {
+                       fprintf(stderr, "selected -c but no callchain data."
+                                       " Did you call perf record without"
+                                       " -g?\n");
+                       exit(-1);
+               }
        }
 
        if (load_kernel() < 0) {
@@ -1426,6 +1727,11 @@ static int __cmd_report(void)
                cwd = NULL;
                cwdlen = 0;
        }
+
+       shift = page_size * (head / page_size);
+       offset += shift;
+       head -= shift;
+
 remap:
        buf = (char *)mmap(NULL, page_size * mmap_window, PROT_READ,
                           MAP_SHARED, input, offset);
@@ -1442,9 +1748,10 @@ more:
                size = 8;
 
        if (head + event->header.size >= page_size * mmap_window) {
-               unsigned long shift = page_size * (head / page_size);
                int ret;
 
+               shift = page_size * (head / page_size);
+
                ret = munmap(buf, page_size * mmap_window);
                assert(ret == 0);
 
@@ -1482,10 +1789,10 @@ more:
 
        head += size;
 
-       if (offset + head >= sizeof(file_header) + file_header.data_size)
+       if (offset + head >= header->data_offset + header->data_size)
                goto done;
 
-       if (offset + head < stat.st_size)
+       if (offset + head < (unsigned long)stat.st_size)
                goto more;
 
 done:
@@ -1509,12 +1816,58 @@ done:
                dsos__fprintf(stdout);
 
        collapse__resort();
-       output__resort();
+       output__resort(total);
        output__fprintf(stdout, total);
 
        return rc;
 }
 
+static int
+parse_callchain_opt(const struct option *opt __used, const char *arg,
+                   int unset __used)
+{
+       char *tok;
+       char *endptr;
+
+       callchain = 1;
+
+       if (!arg)
+               return 0;
+
+       tok = strtok((char *)arg, ",");
+       if (!tok)
+               return -1;
+
+       /* get the output mode */
+       if (!strncmp(tok, "graph", strlen(arg)))
+               callchain_param.mode = CHAIN_GRAPH_ABS;
+
+       else if (!strncmp(tok, "flat", strlen(arg)))
+               callchain_param.mode = CHAIN_FLAT;
+
+       else if (!strncmp(tok, "fractal", strlen(arg)))
+               callchain_param.mode = CHAIN_GRAPH_REL;
+
+       else
+               return -1;
+
+       /* get the min percentage */
+       tok = strtok(NULL, ",");
+       if (!tok)
+               goto setup;
+
+       callchain_param.min_percent = strtod(tok, &endptr);
+       if (tok == endptr)
+               return -1;
+
+setup:
+       if (register_callchain_param(&callchain_param) < 0) {
+               fprintf(stderr, "Can't register callchain params\n");
+               return -1;
+       }
+       return 0;
+}
+
 static const char * const report_usage[] = {
        "perf report [<options>] <command>",
        NULL
@@ -1528,6 +1881,8 @@ static const struct option options[] = {
        OPT_BOOLEAN('D', "dump-raw-trace", &dump_trace,
                    "dump raw trace in ASCII"),
        OPT_STRING('k', "vmlinux", &vmlinux, "file", "vmlinux pathname"),
+       OPT_BOOLEAN('m', "modules", &modules,
+                   "load module symbols - WARNING: use only with -k and LIVE kernel"),
        OPT_STRING('s', "sort", &sort_order, "key[,key2...]",
                   "sort by key(s): pid, comm, dso, symbol, parent"),
        OPT_BOOLEAN('P', "full-paths", &full_paths,
@@ -1536,6 +1891,15 @@ static const struct option options[] = {
                   "regex filter to identify parent, see: '--sort parent'"),
        OPT_BOOLEAN('x', "exclude-other", &exclude_other,
                    "Only display entries with parent-match"),
+       OPT_CALLBACK_DEFAULT('c', "callchain", NULL, "output_type,min_percent",
+                    "Display callchains using output_type and min percent threshold. "
+                    "Default: flat,0", &parse_callchain_opt, callchain_default_opt),
+       OPT_STRING('d', "dsos", &dso_list_str, "dso[,dso...]",
+                  "only consider symbols in these dsos"),
+       OPT_STRING('C', "comms", &comm_list_str, "comm[,comm...]",
+                  "only consider symbols in these comms"),
+       OPT_STRING('S', "symbols", &sym_list_str, "symbol[,symbol...]",
+                  "only consider these symbols"),
        OPT_END()
 };
 
@@ -1554,7 +1918,20 @@ static void setup_sorting(void)
        free(str);
 }
 
-int cmd_report(int argc, const char **argv, const char *prefix)
+static void setup_list(struct strlist **list, const char *list_str,
+                      const char *list_name)
+{
+       if (list_str) {
+               *list = strlist__new(true, list_str);
+               if (!*list) {
+                       fprintf(stderr, "problems parsing %s list\n",
+                               list_name);
+                       exit(129);
+               }
+       }
+}
+
+int cmd_report(int argc, const char **argv, const char *prefix __used)
 {
        symbol__init();
 
@@ -1575,6 +1952,10 @@ int cmd_report(int argc, const char **argv, const char *prefix)
        if (argc)
                usage_with_options(report_usage, options);
 
+       setup_list(&dso_list, dso_list_str, "dso");
+       setup_list(&comm_list, comm_list_str, "comm");
+       setup_list(&sym_list, sym_list_str, "symbol");
+
        setup_pager();
 
        return __cmd_report();
index 6d3eeac1ea257b47c898dae49c6336c35c4c43f4..27921a8ce1a9ae34a4074d7694a184802351b648 100644 (file)
@@ -32,6 +32,7 @@
  *   Wu Fengguang <fengguang.wu@intel.com>
  *   Mike Galbraith <efault@gmx.de>
  *   Paul Mackerras <paulus@samba.org>
+ *   Jaswinder Singh Rajput <jaswinder@kernel.org>
  *
  * Released under the GPL v2. (and only v2, not any later version)
  */
@@ -45,7 +46,7 @@
 #include <sys/prctl.h>
 #include <math.h>
 
-static struct perf_counter_attr default_attrs[MAX_COUNTERS] = {
+static struct perf_counter_attr default_attrs[] = {
 
   { .type = PERF_TYPE_SOFTWARE, .config = PERF_COUNT_SW_TASK_CLOCK     },
   { .type = PERF_TYPE_SOFTWARE, .config = PERF_COUNT_SW_CONTEXT_SWITCHES},
@@ -59,42 +60,28 @@ static struct perf_counter_attr default_attrs[MAX_COUNTERS] = {
 
 };
 
+#define MAX_RUN                        100
+
 static int                     system_wide                     =  0;
-static int                     inherit                         =  1;
 static int                     verbose                         =  0;
+static unsigned int            nr_cpus                         =  0;
+static int                     run_idx                         =  0;
 
-static int                     fd[MAX_NR_CPUS][MAX_COUNTERS];
-
-static int                     target_pid                      = -1;
-static int                     nr_cpus                         =  0;
-static unsigned int            page_size;
-
+static int                     run_count                       =  1;
+static int                     inherit                         =  1;
 static int                     scale                           =  1;
+static int                     target_pid                      = -1;
+static int                     null_run                        =  0;
 
-static const unsigned int default_count[] = {
-       1000000,
-       1000000,
-         10000,
-         10000,
-       1000000,
-         10000,
-};
-
-#define MAX_RUN 100
-
-static int                     run_count               =  1;
-static int                     run_idx                 =  0;
-
-static u64                     event_res[MAX_RUN][MAX_COUNTERS][3];
-static u64                     event_scaled[MAX_RUN][MAX_COUNTERS];
-
-//static u64                   event_hist[MAX_RUN][MAX_COUNTERS][3];
-
+static int                     fd[MAX_NR_CPUS][MAX_COUNTERS];
 
 static u64                     runtime_nsecs[MAX_RUN];
 static u64                     walltime_nsecs[MAX_RUN];
 static u64                     runtime_cycles[MAX_RUN];
 
+static u64                     event_res[MAX_RUN][MAX_COUNTERS][3];
+static u64                     event_scaled[MAX_RUN][MAX_COUNTERS];
+
 static u64                     event_res_avg[MAX_COUNTERS][3];
 static u64                     event_res_noise[MAX_COUNTERS][3];
 
@@ -109,7 +96,14 @@ static u64                  walltime_nsecs_noise;
 static u64                     runtime_cycles_avg;
 static u64                     runtime_cycles_noise;
 
-static void create_perf_stat_counter(int counter)
+#define MATCH_EVENT(t, c, counter)                     \
+       (attrs[counter].type == PERF_TYPE_##t &&        \
+        attrs[counter].config == PERF_COUNT_##c)
+
+#define ERR_PERF_OPEN \
+"Error: counter %d, sys_perf_counter_open() syscall returned with %d (%s)\n"
+
+static void create_perf_stat_counter(int counter, int pid)
 {
        struct perf_counter_attr *attr = attrs + counter;
 
@@ -118,21 +112,23 @@ static void create_perf_stat_counter(int counter)
                                    PERF_FORMAT_TOTAL_TIME_RUNNING;
 
        if (system_wide) {
-               int cpu;
-               for (cpu = 0; cpu < nr_cpus; cpu ++) {
+               unsigned int cpu;
+
+               for (cpu = 0; cpu < nr_cpus; cpu++) {
                        fd[cpu][counter] = sys_perf_counter_open(attr, -1, cpu, -1, 0);
-                       if (fd[cpu][counter] < 0 && verbose) {
-                               printf("Error: counter %d, sys_perf_counter_open() syscall returned with %d (%s)\n", counter, fd[cpu][counter], strerror(errno));
-                       }
+                       if (fd[cpu][counter] < 0 && verbose)
+                               fprintf(stderr, ERR_PERF_OPEN, counter,
+                                       fd[cpu][counter], strerror(errno));
                }
        } else {
-               attr->inherit   = inherit;
-               attr->disabled  = 1;
-
-               fd[0][counter] = sys_perf_counter_open(attr, 0, -1, -1, 0);
-               if (fd[0][counter] < 0 && verbose) {
-                       printf("Error: counter %d, sys_perf_counter_open() syscall returned with %d (%s)\n", counter, fd[0][counter], strerror(errno));
-               }
+               attr->inherit        = inherit;
+               attr->disabled       = 1;
+               attr->enable_on_exec = 1;
+
+               fd[0][counter] = sys_perf_counter_open(attr, pid, -1, -1, 0);
+               if (fd[0][counter] < 0 && verbose)
+                       fprintf(stderr, ERR_PERF_OPEN, counter,
+                               fd[0][counter], strerror(errno));
        }
 }
 
@@ -141,13 +137,8 @@ static void create_perf_stat_counter(int counter)
  */
 static inline int nsec_counter(int counter)
 {
-       if (attrs[counter].type != PERF_TYPE_SOFTWARE)
-               return 0;
-
-       if (attrs[counter].config == PERF_COUNT_SW_CPU_CLOCK)
-               return 1;
-
-       if (attrs[counter].config == PERF_COUNT_SW_TASK_CLOCK)
+       if (MATCH_EVENT(SOFTWARE, SW_CPU_CLOCK, counter) ||
+           MATCH_EVENT(SOFTWARE, SW_TASK_CLOCK, counter))
                return 1;
 
        return 0;
@@ -159,8 +150,8 @@ static inline int nsec_counter(int counter)
 static void read_counter(int counter)
 {
        u64 *count, single_count[3];
-       ssize_t res;
-       int cpu, nv;
+       unsigned int cpu;
+       size_t res, nv;
        int scaled;
 
        count = event_res[run_idx][counter];
@@ -168,12 +159,13 @@ static void read_counter(int counter)
        count[0] = count[1] = count[2] = 0;
 
        nv = scale ? 3 : 1;
-       for (cpu = 0; cpu < nr_cpus; cpu ++) {
+       for (cpu = 0; cpu < nr_cpus; cpu++) {
                if (fd[cpu][counter] < 0)
                        continue;
 
                res = read(fd[cpu][counter], single_count, nv * sizeof(u64));
                assert(res == nv * sizeof(u64));
+
                close(fd[cpu][counter]);
                fd[cpu][counter] = -1;
 
@@ -201,46 +193,81 @@ static void read_counter(int counter)
        /*
         * Save the full runtime - to allow normalization during printout:
         */
-       if (attrs[counter].type == PERF_TYPE_SOFTWARE &&
-               attrs[counter].config == PERF_COUNT_SW_TASK_CLOCK)
+       if (MATCH_EVENT(SOFTWARE, SW_TASK_CLOCK, counter))
                runtime_nsecs[run_idx] = count[0];
-       if (attrs[counter].type == PERF_TYPE_HARDWARE &&
-               attrs[counter].config == PERF_COUNT_HW_CPU_CYCLES)
+       if (MATCH_EVENT(HARDWARE, HW_CPU_CYCLES, counter))
                runtime_cycles[run_idx] = count[0];
 }
 
-static int run_perf_stat(int argc, const char **argv)
+static int run_perf_stat(int argc __used, const char **argv)
 {
        unsigned long long t0, t1;
        int status = 0;
        int counter;
        int pid;
+       int child_ready_pipe[2], go_pipe[2];
+       char buf;
 
        if (!system_wide)
                nr_cpus = 1;
 
-       for (counter = 0; counter < nr_counters; counter++)
-               create_perf_stat_counter(counter);
-
-       /*
-        * Enable counters and exec the command:
-        */
-       t0 = rdclock();
-       prctl(PR_TASK_PERF_COUNTERS_ENABLE);
+       if (pipe(child_ready_pipe) < 0 || pipe(go_pipe) < 0) {
+               perror("failed to create pipes");
+               exit(1);
+       }
 
        if ((pid = fork()) < 0)
                perror("failed to fork");
 
        if (!pid) {
-               if (execvp(argv[0], (char **)argv)) {
-                       perror(argv[0]);
-                       exit(-1);
-               }
+               close(child_ready_pipe[0]);
+               close(go_pipe[1]);
+               fcntl(go_pipe[0], F_SETFD, FD_CLOEXEC);
+
+               /*
+                * Do a dummy execvp to get the PLT entry resolved,
+                * so we avoid the resolver overhead on the real
+                * execvp call.
+                */
+               execvp("", (char **)argv);
+
+               /*
+                * Tell the parent we're ready to go
+                */
+               close(child_ready_pipe[1]);
+
+               /*
+                * Wait until the parent tells us to go.
+                */
+               if (read(go_pipe[0], &buf, 1) == -1)
+                       perror("unable to read pipe");
+
+               execvp(argv[0], (char **)argv);
+
+               perror(argv[0]);
+               exit(-1);
        }
 
+       /*
+        * Wait for the child to be ready to exec.
+        */
+       close(child_ready_pipe[1]);
+       close(go_pipe[0]);
+       if (read(child_ready_pipe[0], &buf, 1) == -1)
+               perror("unable to read pipe");
+       close(child_ready_pipe[0]);
+
+       for (counter = 0; counter < nr_counters; counter++)
+               create_perf_stat_counter(counter, pid);
+
+       /*
+        * Enable counters and exec the command:
+        */
+       t0 = rdclock();
+
+       close(go_pipe[1]);
        wait(&status);
 
-       prctl(PR_TASK_PERF_COUNTERS_DISABLE);
        t1 = rdclock();
 
        walltime_nsecs[run_idx] = t1 - t0;
@@ -262,11 +289,9 @@ static void nsec_printout(int counter, u64 *count, u64 *noise)
 {
        double msecs = (double)count[0] / 1000000;
 
-       fprintf(stderr, " %14.6f  %-20s", msecs, event_name(counter));
-
-       if (attrs[counter].type == PERF_TYPE_SOFTWARE &&
-               attrs[counter].config == PERF_COUNT_SW_TASK_CLOCK) {
+       fprintf(stderr, " %14.6f  %-24s", msecs, event_name(counter));
 
+       if (MATCH_EVENT(SOFTWARE, SW_TASK_CLOCK, counter)) {
                if (walltime_nsecs_avg)
                        fprintf(stderr, " # %10.3f CPUs ",
                                (double)count[0] / (double)walltime_nsecs_avg);
@@ -276,12 +301,10 @@ static void nsec_printout(int counter, u64 *count, u64 *noise)
 
 static void abs_printout(int counter, u64 *count, u64 *noise)
 {
-       fprintf(stderr, " %14Ld  %-20s", count[0], event_name(counter));
+       fprintf(stderr, " %14Ld  %-24s", count[0], event_name(counter));
 
        if (runtime_cycles_avg &&
-               attrs[counter].type == PERF_TYPE_HARDWARE &&
-                       attrs[counter].config == PERF_COUNT_HW_INSTRUCTIONS) {
-
+           MATCH_EVENT(HARDWARE, HW_INSTRUCTIONS, counter)) {
                fprintf(stderr, " # %10.3f IPC  ",
                        (double)count[0] / (double)runtime_cycles_avg);
        } else {
@@ -306,7 +329,7 @@ static void print_counter(int counter)
        scaled = event_scaled_avg[counter];
 
        if (scaled == -1) {
-               fprintf(stderr, " %14s  %-20s\n",
+               fprintf(stderr, " %14s  %-24s\n",
                        "<not counted>", event_name(counter));
                return;
        }
@@ -364,8 +387,11 @@ static void calc_avg(void)
                                event_res_avg[j]+1, event_res[i][j]+1);
                        update_avg("counter/2", j,
                                event_res_avg[j]+2, event_res[i][j]+2);
-                       update_avg("scaled", j,
-                               event_scaled_avg + j, event_scaled[i]+j);
+                       if (event_scaled[i][j] != (u64)-1)
+                               update_avg("scaled", j,
+                                       event_scaled_avg + j, event_scaled[i]+j);
+                       else
+                               event_scaled_avg[j] = -1;
                }
        }
        runtime_nsecs_avg /= run_count;
@@ -429,11 +455,14 @@ static void print_stat(int argc, const char **argv)
        for (counter = 0; counter < nr_counters; counter++)
                print_counter(counter);
 
-
        fprintf(stderr, "\n");
-       fprintf(stderr, " %14.9f  seconds time elapsed.\n",
+       fprintf(stderr, " %14.9f  seconds time elapsed",
                        (double)walltime_nsecs_avg/1e9);
-       fprintf(stderr, "\n");
+       if (run_count > 1) {
+               fprintf(stderr, "   ( +- %7.3f%% )",
+                       100.0*(double)walltime_nsecs_noise/(double)walltime_nsecs_avg);
+       }
+       fprintf(stderr, "\n\n");
 }
 
 static volatile int signr = -1;
@@ -466,36 +495,37 @@ static const struct option options[] = {
        OPT_INTEGER('p', "pid", &target_pid,
                    "stat events on existing pid"),
        OPT_BOOLEAN('a', "all-cpus", &system_wide,
-                           "system-wide collection from all CPUs"),
+                   "system-wide collection from all CPUs"),
        OPT_BOOLEAN('S', "scale", &scale,
-                           "scale/normalize counters"),
+                   "scale/normalize counters"),
        OPT_BOOLEAN('v', "verbose", &verbose,
                    "be more verbose (show counter open errors, etc)"),
        OPT_INTEGER('r', "repeat", &run_count,
                    "repeat command and print average + stddev (max: 100)"),
+       OPT_BOOLEAN('n', "null", &null_run,
+                   "null run - dont start any counters"),
        OPT_END()
 };
 
-int cmd_stat(int argc, const char **argv, const char *prefix)
+int cmd_stat(int argc, const char **argv, const char *prefix __used)
 {
        int status;
 
-       page_size = sysconf(_SC_PAGE_SIZE);
-
-       memcpy(attrs, default_attrs, sizeof(attrs));
-
        argc = parse_options(argc, argv, options, stat_usage, 0);
        if (!argc)
                usage_with_options(stat_usage, options);
        if (run_count <= 0 || run_count > MAX_RUN)
                usage_with_options(stat_usage, options);
 
-       if (!nr_counters)
-               nr_counters = 8;
+       /* Set attrs and nr_counters if no event is selected and !null_run */
+       if (!null_run && !nr_counters) {
+               memcpy(attrs, default_attrs, sizeof(default_attrs));
+               nr_counters = ARRAY_SIZE(default_attrs);
+       }
 
        nr_cpus = sysconf(_SC_NPROCESSORS_ONLN);
        assert(nr_cpus <= MAX_NR_CPUS);
-       assert(nr_cpus >= 0);
+       assert((int)nr_cpus >= 0);
 
        /*
         * We dont want to block the signals - that would cause
@@ -511,7 +541,7 @@ int cmd_stat(int argc, const char **argv, const char *prefix)
        status = 0;
        for (run_idx = 0; run_idx < run_count; run_idx++) {
                if (run_count != 1 && verbose)
-                       fprintf(stderr, "[ perf stat: executing run #%d ... ]\n", run_idx+1);
+                       fprintf(stderr, "[ perf stat: executing run #%d ... ]\n", run_idx + 1);
                status = run_perf_stat(argc, argv);
        }
 
index 5352b5e352ed3a87552c917bd63a50ff301a620e..95d5c0ae375ad62fb6ae7f317af9dd097590ea87 100644 (file)
@@ -23,7 +23,7 @@
 #include "util/symbol.h"
 #include "util/color.h"
 #include "util/util.h"
-#include "util/rbtree.h"
+#include <linux/rbtree.h>
 #include "util/parse-options.h"
 #include "util/parse-events.h"
 
@@ -66,6 +66,7 @@ static unsigned int           page_size;
 static unsigned int            mmap_pages                      = 16;
 static int                     freq                            =  0;
 static int                     verbose                         =  0;
+static char                    *vmlinux                        =  NULL;
 
 static char                    *sym_filter;
 static unsigned long           filter_start;
@@ -238,7 +239,6 @@ static void print_sym_table(void)
        for (nd = rb_first(&tmp); nd; nd = rb_next(nd)) {
                struct sym_entry *syme = rb_entry(nd, struct sym_entry, rb_node);
                struct symbol *sym = (struct symbol *)(syme + 1);
-               char *color = PERF_COLOR_NORMAL;
                double pcnt;
 
                if (++printed > print_entries || syme->snap_count < count_filter)
@@ -247,29 +247,20 @@ static void print_sym_table(void)
                pcnt = 100.0 - (100.0 * ((sum_ksamples - syme->snap_count) /
                                         sum_ksamples));
 
-               /*
-                * We color high-overhead entries in red, mid-overhead
-                * entries in green - and keep the low overhead places
-                * normal:
-                */
-               if (pcnt >= 5.0) {
-                       color = PERF_COLOR_RED;
-               } else {
-                       if (pcnt >= 0.5)
-                               color = PERF_COLOR_GREEN;
-               }
-
                if (nr_counters == 1)
                        printf("%20.2f - ", syme->weight);
                else
                        printf("%9.1f %10ld - ", syme->weight, syme->snap_count);
 
-               color_fprintf(stdout, color, "%4.1f%%", pcnt);
-               printf(" - %016llx : %s\n", sym->start, sym->name);
+               percent_color_fprintf(stdout, "%4.1f%%", pcnt);
+               printf(" - %016llx : %s", sym->start, sym->name);
+               if (sym->module)
+                       printf("\t[%s]", sym->module->name);
+               printf("\n");
        }
 }
 
-static void *display_thread(void *arg)
+static void *display_thread(void *arg __used)
 {
        struct pollfd stdin_poll = { .fd = 0, .events = POLLIN };
        int delay_msecs = delay_secs * 1000;
@@ -286,11 +277,31 @@ static void *display_thread(void *arg)
        return NULL;
 }
 
+/* Tag samples to be skipped. */
+static const char *skip_symbols[] = {
+       "default_idle",
+       "cpu_idle",
+       "enter_idle",
+       "exit_idle",
+       "mwait_idle",
+       "ppc64_runlatch_off",
+       "pseries_dedicated_idle_sleep",
+       NULL
+};
+
 static int symbol_filter(struct dso *self, struct symbol *sym)
 {
        static int filter_match;
        struct sym_entry *syme;
        const char *name = sym->name;
+       int i;
+
+       /*
+        * ppc64 uses function descriptors and appends a '.' to the
+        * start of every instruction address. Remove it.
+        */
+       if (name[0] == '.')
+               name++;
 
        if (!strcmp(name, "_text") ||
            !strcmp(name, "_etext") ||
@@ -302,13 +313,12 @@ static int symbol_filter(struct dso *self, struct symbol *sym)
                return 1;
 
        syme = dso__sym_priv(self, sym);
-       /* Tag samples to be skipped. */
-       if (!strcmp("default_idle", name) ||
-           !strcmp("cpu_idle", name) ||
-           !strcmp("enter_idle", name) ||
-           !strcmp("exit_idle", name) ||
-           !strcmp("mwait_idle", name))
-               syme->skip = 1;
+       for (i = 0; skip_symbols[i]; i++) {
+               if (!strcmp(skip_symbols[i], name)) {
+                       syme->skip = 1;
+                       break;
+               }
+       }
 
        if (filter_match == 1) {
                filter_end = sym->start;
@@ -340,12 +350,13 @@ static int parse_symbols(void)
 {
        struct rb_node *node;
        struct symbol  *sym;
+       int modules = vmlinux ? 1 : 0;
 
        kernel_dso = dso__new("[kernel]", sizeof(struct sym_entry));
        if (kernel_dso == NULL)
                return -1;
 
-       if (dso__load_kernel(kernel_dso, NULL, symbol_filter, 1) != 0)
+       if (dso__load_kernel(kernel_dso, vmlinux, symbol_filter, verbose, modules) <= 0)
                goto out_delete_dso;
 
        node = rb_first(&kernel_dso->syms);
@@ -392,11 +403,11 @@ static void record_ip(u64 ip, int counter)
        samples--;
 }
 
-static void process_event(u64 ip, int counter)
+static void process_event(u64 ip, int counter, int user)
 {
        samples++;
 
-       if (ip < min_ip || ip > max_ip) {
+       if (user) {
                userspace_samples++;
                return;
        }
@@ -407,7 +418,7 @@ static void process_event(u64 ip, int counter)
 struct mmap_data {
        int                     counter;
        void                    *base;
-       unsigned int            mask;
+       int                     mask;
        unsigned int            prev;
 };
 
@@ -509,9 +520,10 @@ static void mmap_read_counter(struct mmap_data *md)
 
                old += size;
 
-               if (event->header.misc & PERF_EVENT_MISC_OVERFLOW) {
-                       if (event->header.type & PERF_SAMPLE_IP)
-                               process_event(event->ip.ip, md->counter);
+               if (event->header.type == PERF_EVENT_SAMPLE) {
+                       int user =
+       (event->header.misc & PERF_EVENT_MISC_CPUMODE_MASK) == PERF_EVENT_MISC_USER;
+                       process_event(event->ip.ip, md->counter, user);
                }
        }
 
@@ -660,6 +672,7 @@ static const struct option options[] = {
                            "system-wide collection from all CPUs"),
        OPT_INTEGER('C', "CPU", &profile_cpu,
                    "CPU to profile on"),
+       OPT_STRING('k', "vmlinux", &vmlinux, "file", "vmlinux pathname"),
        OPT_INTEGER('m', "mmap-pages", &mmap_pages,
                    "number of mmap data pages"),
        OPT_INTEGER('r', "realtime", &realtime_prio,
@@ -674,7 +687,7 @@ static const struct option options[] = {
                            "put the counters into a counter group"),
        OPT_STRING('s', "sym-filter", &sym_filter, "pattern",
                    "only display symbols matchig this pattern"),
-       OPT_BOOLEAN('z', "zero", &group,
+       OPT_BOOLEAN('z', "zero", &zero,
                    "zero history across updates"),
        OPT_INTEGER('F', "freq", &freq,
                    "profile at this frequency"),
@@ -685,10 +698,12 @@ static const struct option options[] = {
        OPT_END()
 };
 
-int cmd_top(int argc, const char **argv, const char *prefix)
+int cmd_top(int argc, const char **argv, const char *prefix __used)
 {
        int counter;
 
+       symbol__init();
+
        page_size = sysconf(_SC_PAGE_SIZE);
 
        argc = parse_options(argc, argv, options, top_usage, 0);
index 4eb725933703b6e8c41c558e46f11d705cc9d41f..c5656784c61d555ac1e67d0843c54ed00faa58c9 100644 (file)
@@ -229,9 +229,6 @@ static int run_builtin(struct cmd_struct *p, int argc, const char **argv)
                use_pager = 1;
        commit_pager_choice();
 
-       if (p->option & NEED_WORK_TREE)
-               /* setup_work_tree() */;
-
        status = p->fn(argc, argv, prefix);
        if (status)
                return status & 0xff;
@@ -266,7 +263,7 @@ static void handle_internal_command(int argc, const char **argv)
                { "annotate", cmd_annotate, 0 },
                { "version", cmd_version, 0 },
        };
-       int i;
+       unsigned int i;
        static const char ext[] = STRIP_EXTENSION;
 
        if (sizeof(ext) > 1) {
index ceb68aa51f7f5eaeaa109a250ac0ceb9ddc68665..63e67cc5487b5f5791a4dc0709454482afa8c839 100644 (file)
 #define cpu_relax()    asm volatile("" ::: "memory");
 #endif
 
+#ifdef __sh__
+#include "../../arch/sh/include/asm/unistd.h"
+#if defined(__SH4A__) || defined(__SH5__)
+# define rmb()         asm volatile("synco" ::: "memory")
+#else
+# define rmb()         asm volatile("" ::: "memory")
+#endif
+#define cpu_relax()    asm volatile("" ::: "memory")
+#endif
+
+#ifdef __hppa__
+#include "../../arch/parisc/include/asm/unistd.h"
+#define rmb()          asm volatile("" ::: "memory")
+#define cpu_relax()    asm volatile("" ::: "memory");
+#endif
+
 #include <time.h>
 #include <unistd.h>
 #include <sys/types.h>
 #include <sys/syscall.h>
 
 #include "../../include/linux/perf_counter.h"
-#include "types.h"
+#include "util/types.h"
 
 /*
  * prctl(PR_TASK_PERF_COUNTERS_DISABLE) will (cheaply) disable all
@@ -52,6 +68,8 @@ static inline unsigned long long rdclock(void)
 #define __user
 #define asmlinkage
 
+#define __used         __attribute__((__unused__))
+
 #define unlikely(x)    __builtin_expect(!!(x), 0)
 #define min(x, y) ({                           \
        typeof(x) _min1 = (x);                  \
@@ -72,10 +90,9 @@ sys_perf_counter_open(struct perf_counter_attr *attr,
 #define MAX_COUNTERS                   256
 #define MAX_NR_CPUS                    256
 
-struct perf_file_header {
-       u64     version;
-       u64     sample_type;
-       u64     data_size;
+struct ip_callchain {
+       u64 nr;
+       u64 ips[0];
 };
 
 #endif
index 9b3dd2b428df8c4e95ed0dce7e281419744cf14e..b8144e80bb1e5b436d95f1c96757fe34b9451946 100644 (file)
@@ -3,7 +3,7 @@
 static const char *alias_key;
 static char *alias_val;
 
-static int alias_lookup_cb(const char *k, const char *v, void *cb)
+static int alias_lookup_cb(const char *k, const char *v, void *cb __used)
 {
        if (!prefixcmp(k, "alias.") && !strcmp(k+6, alias_key)) {
                if (!v)
index 393d6146d13b38743641adb819c2552a56716043..161d5f413e28701f07acdd7ff2ea72ba9f082bf6 100644 (file)
@@ -3,6 +3,7 @@
 
 #include "util.h"
 #include "strbuf.h"
+#include "../perf.h"
 
 #define PERF_DIR_ENVIRONMENT "PERF_DIR"
 #define PERF_WORK_TREE_ENVIRONMENT "PERF_WORK_TREE"
diff --git a/tools/perf/util/callchain.c b/tools/perf/util/callchain.c
new file mode 100644 (file)
index 0000000..9d3c814
--- /dev/null
@@ -0,0 +1,335 @@
+/*
+ * Copyright (C) 2009, Frederic Weisbecker <fweisbec@gmail.com>
+ *
+ * Handle the callchains from the stream in an ad-hoc radix tree and then
+ * sort them in an rbtree.
+ *
+ * Using a radix for code path provides a fast retrieval and factorizes
+ * memory use. Also that lets us use the paths in a hierarchical graph view.
+ *
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <stdbool.h>
+#include <errno.h>
+
+#include "callchain.h"
+
+#define chain_for_each_child(child, parent)    \
+       list_for_each_entry(child, &parent->children, brothers)
+
+static void
+rb_insert_callchain(struct rb_root *root, struct callchain_node *chain,
+                   enum chain_mode mode)
+{
+       struct rb_node **p = &root->rb_node;
+       struct rb_node *parent = NULL;
+       struct callchain_node *rnode;
+
+       while (*p) {
+               parent = *p;
+               rnode = rb_entry(parent, struct callchain_node, rb_node);
+
+               switch (mode) {
+               case CHAIN_FLAT:
+                       if (rnode->hit < chain->hit)
+                               p = &(*p)->rb_left;
+                       else
+                               p = &(*p)->rb_right;
+                       break;
+               case CHAIN_GRAPH_ABS: /* Falldown */
+               case CHAIN_GRAPH_REL:
+                       if (rnode->cumul_hit < chain->cumul_hit)
+                               p = &(*p)->rb_left;
+                       else
+                               p = &(*p)->rb_right;
+                       break;
+               default:
+                       break;
+               }
+       }
+
+       rb_link_node(&chain->rb_node, parent, p);
+       rb_insert_color(&chain->rb_node, root);
+}
+
+static void
+__sort_chain_flat(struct rb_root *rb_root, struct callchain_node *node,
+                 u64 min_hit)
+{
+       struct callchain_node *child;
+
+       chain_for_each_child(child, node)
+               __sort_chain_flat(rb_root, child, min_hit);
+
+       if (node->hit && node->hit >= min_hit)
+               rb_insert_callchain(rb_root, node, CHAIN_FLAT);
+}
+
+/*
+ * Once we get every callchains from the stream, we can now
+ * sort them by hit
+ */
+static void
+sort_chain_flat(struct rb_root *rb_root, struct callchain_node *node,
+               u64 min_hit, struct callchain_param *param __used)
+{
+       __sort_chain_flat(rb_root, node, min_hit);
+}
+
+static void __sort_chain_graph_abs(struct callchain_node *node,
+                                  u64 min_hit)
+{
+       struct callchain_node *child;
+
+       node->rb_root = RB_ROOT;
+
+       chain_for_each_child(child, node) {
+               __sort_chain_graph_abs(child, min_hit);
+               if (child->cumul_hit >= min_hit)
+                       rb_insert_callchain(&node->rb_root, child,
+                                           CHAIN_GRAPH_ABS);
+       }
+}
+
+static void
+sort_chain_graph_abs(struct rb_root *rb_root, struct callchain_node *chain_root,
+                    u64 min_hit, struct callchain_param *param __used)
+{
+       __sort_chain_graph_abs(chain_root, min_hit);
+       rb_root->rb_node = chain_root->rb_root.rb_node;
+}
+
+static void __sort_chain_graph_rel(struct callchain_node *node,
+                                  double min_percent)
+{
+       struct callchain_node *child;
+       u64 min_hit;
+
+       node->rb_root = RB_ROOT;
+       min_hit = node->cumul_hit * min_percent / 100.0;
+
+       chain_for_each_child(child, node) {
+               __sort_chain_graph_rel(child, min_percent);
+               if (child->cumul_hit >= min_hit)
+                       rb_insert_callchain(&node->rb_root, child,
+                                           CHAIN_GRAPH_REL);
+       }
+}
+
+static void
+sort_chain_graph_rel(struct rb_root *rb_root, struct callchain_node *chain_root,
+                    u64 min_hit __used, struct callchain_param *param)
+{
+       __sort_chain_graph_rel(chain_root, param->min_percent);
+       rb_root->rb_node = chain_root->rb_root.rb_node;
+}
+
+int register_callchain_param(struct callchain_param *param)
+{
+       switch (param->mode) {
+       case CHAIN_GRAPH_ABS:
+               param->sort = sort_chain_graph_abs;
+               break;
+       case CHAIN_GRAPH_REL:
+               param->sort = sort_chain_graph_rel;
+               break;
+       case CHAIN_FLAT:
+               param->sort = sort_chain_flat;
+               break;
+       default:
+               return -1;
+       }
+       return 0;
+}
+
+/*
+ * Create a child for a parent. If inherit_children, then the new child
+ * will become the new parent of it's parent children
+ */
+static struct callchain_node *
+create_child(struct callchain_node *parent, bool inherit_children)
+{
+       struct callchain_node *new;
+
+       new = malloc(sizeof(*new));
+       if (!new) {
+               perror("not enough memory to create child for code path tree");
+               return NULL;
+       }
+       new->parent = parent;
+       INIT_LIST_HEAD(&new->children);
+       INIT_LIST_HEAD(&new->val);
+
+       if (inherit_children) {
+               struct callchain_node *next;
+
+               list_splice(&parent->children, &new->children);
+               INIT_LIST_HEAD(&parent->children);
+
+               chain_for_each_child(next, new)
+                       next->parent = new;
+       }
+       list_add_tail(&new->brothers, &parent->children);
+
+       return new;
+}
+
+/*
+ * Fill the node with callchain values
+ */
+static void
+fill_node(struct callchain_node *node, struct ip_callchain *chain,
+         int start, struct symbol **syms)
+{
+       unsigned int i;
+
+       for (i = start; i < chain->nr; i++) {
+               struct callchain_list *call;
+
+               call = malloc(sizeof(*call));
+               if (!call) {
+                       perror("not enough memory for the code path tree");
+                       return;
+               }
+               call->ip = chain->ips[i];
+               call->sym = syms[i];
+               list_add_tail(&call->list, &node->val);
+       }
+       node->val_nr = chain->nr - start;
+       if (!node->val_nr)
+               printf("Warning: empty node in callchain tree\n");
+}
+
+static void
+add_child(struct callchain_node *parent, struct ip_callchain *chain,
+         int start, struct symbol **syms)
+{
+       struct callchain_node *new;
+
+       new = create_child(parent, false);
+       fill_node(new, chain, start, syms);
+
+       new->cumul_hit = new->hit = 1;
+}
+
+/*
+ * Split the parent in two parts (a new child is created) and
+ * give a part of its callchain to the created child.
+ * Then create another child to host the given callchain of new branch
+ */
+static void
+split_add_child(struct callchain_node *parent, struct ip_callchain *chain,
+               struct callchain_list *to_split, int idx_parents, int idx_local,
+               struct symbol **syms)
+{
+       struct callchain_node *new;
+       struct list_head *old_tail;
+       unsigned int idx_total = idx_parents + idx_local;
+
+       /* split */
+       new = create_child(parent, true);
+
+       /* split the callchain and move a part to the new child */
+       old_tail = parent->val.prev;
+       list_del_range(&to_split->list, old_tail);
+       new->val.next = &to_split->list;
+       new->val.prev = old_tail;
+       to_split->list.prev = &new->val;
+       old_tail->next = &new->val;
+
+       /* split the hits */
+       new->hit = parent->hit;
+       new->cumul_hit = parent->cumul_hit;
+       new->val_nr = parent->val_nr - idx_local;
+       parent->val_nr = idx_local;
+
+       /* create a new child for the new branch if any */
+       if (idx_total < chain->nr) {
+               parent->hit = 0;
+               add_child(parent, chain, idx_total, syms);
+       } else {
+               parent->hit = 1;
+       }
+}
+
+static int
+__append_chain(struct callchain_node *root, struct ip_callchain *chain,
+              unsigned int start, struct symbol **syms);
+
+static void
+__append_chain_children(struct callchain_node *root, struct ip_callchain *chain,
+                       struct symbol **syms, unsigned int start)
+{
+       struct callchain_node *rnode;
+
+       /* lookup in childrens */
+       chain_for_each_child(rnode, root) {
+               unsigned int ret = __append_chain(rnode, chain, start, syms);
+
+               if (!ret)
+                       goto cumul;
+       }
+       /* nothing in children, add to the current node */
+       add_child(root, chain, start, syms);
+
+cumul:
+       root->cumul_hit++;
+}
+
+static int
+__append_chain(struct callchain_node *root, struct ip_callchain *chain,
+              unsigned int start, struct symbol **syms)
+{
+       struct callchain_list *cnode;
+       unsigned int i = start;
+       bool found = false;
+
+       /*
+        * Lookup in the current node
+        * If we have a symbol, then compare the start to match
+        * anywhere inside a function.
+        */
+       list_for_each_entry(cnode, &root->val, list) {
+               if (i == chain->nr)
+                       break;
+               if (cnode->sym && syms[i]) {
+                       if (cnode->sym->start != syms[i]->start)
+                               break;
+               } else if (cnode->ip != chain->ips[i])
+                       break;
+               if (!found)
+                       found = true;
+               i++;
+       }
+
+       /* matches not, relay on the parent */
+       if (!found)
+               return -1;
+
+       /* we match only a part of the node. Split it and add the new chain */
+       if (i - start < root->val_nr) {
+               split_add_child(root, chain, cnode, start, i - start, syms);
+               return 0;
+       }
+
+       /* we match 100% of the path, increment the hit */
+       if (i - start == root->val_nr && i == chain->nr) {
+               root->hit++;
+               root->cumul_hit++;
+
+               return 0;
+       }
+
+       /* We match the node and still have a part remaining */
+       __append_chain_children(root, chain, syms, i);
+
+       return 0;
+}
+
+void append_chain(struct callchain_node *root, struct ip_callchain *chain,
+                 struct symbol **syms)
+{
+       __append_chain_children(root, chain, syms, 0);
+}
diff --git a/tools/perf/util/callchain.h b/tools/perf/util/callchain.h
new file mode 100644 (file)
index 0000000..7812122
--- /dev/null
@@ -0,0 +1,54 @@
+#ifndef __PERF_CALLCHAIN_H
+#define __PERF_CALLCHAIN_H
+
+#include "../perf.h"
+#include <linux/list.h>
+#include <linux/rbtree.h>
+#include "symbol.h"
+
+enum chain_mode {
+       CHAIN_FLAT,
+       CHAIN_GRAPH_ABS,
+       CHAIN_GRAPH_REL
+};
+
+struct callchain_node {
+       struct callchain_node   *parent;
+       struct list_head        brothers;
+       struct list_head        children;
+       struct list_head        val;
+       struct rb_node          rb_node; /* to sort nodes in an rbtree */
+       struct rb_root          rb_root; /* sorted tree of children */
+       unsigned int            val_nr;
+       u64                     hit;
+       u64                     cumul_hit; /* hit + hits of children */
+};
+
+struct callchain_param;
+
+typedef void (*sort_chain_func_t)(struct rb_root *, struct callchain_node *,
+                                u64, struct callchain_param *);
+
+struct callchain_param {
+       enum chain_mode         mode;
+       double                  min_percent;
+       sort_chain_func_t       sort;
+};
+
+struct callchain_list {
+       u64                     ip;
+       struct symbol           *sym;
+       struct list_head        list;
+};
+
+static inline void callchain_init(struct callchain_node *node)
+{
+       INIT_LIST_HEAD(&node->brothers);
+       INIT_LIST_HEAD(&node->children);
+       INIT_LIST_HEAD(&node->val);
+}
+
+int register_callchain_param(struct callchain_param *param);
+void append_chain(struct callchain_node *root, struct ip_callchain *chain,
+                 struct symbol **syms);
+#endif
index 9a8c20ccc53e28dd99ab6bd2f27f548fe85532fe..90a044d1fe7dffe526a50d8afdb5ac888ff31209 100644 (file)
@@ -11,7 +11,8 @@ static int parse_color(const char *name, int len)
        };
        char *end;
        int i;
-       for (i = 0; i < ARRAY_SIZE(color_names); i++) {
+
+       for (i = 0; i < (int)ARRAY_SIZE(color_names); i++) {
                const char *str = color_names[i];
                if (!strncasecmp(name, str, len) && !str[len])
                        return i - 1;
@@ -28,7 +29,8 @@ static int parse_attr(const char *name, int len)
        static const char * const attr_names[] = {
                "bold", "dim", "ul", "blink", "reverse"
        };
-       int i;
+       unsigned int i;
+
        for (i = 0; i < ARRAY_SIZE(attr_names); i++) {
                const char *str = attr_names[i];
                if (!strncasecmp(name, str, len) && !str[len])
@@ -222,10 +224,12 @@ int color_fwrite_lines(FILE *fp, const char *color,
 {
        if (!*color)
                return fwrite(buf, count, 1, fp) != 1;
+
        while (count) {
                char *p = memchr(buf, '\n', count);
+
                if (p != buf && (fputs(color, fp) < 0 ||
-                               fwrite(buf, p ? p - buf : count, 1, fp) != 1 ||
+                               fwrite(buf, p ? (size_t)(p - buf) : count, 1, fp) != 1 ||
                                fputs(PERF_COLOR_RESET, fp) < 0))
                        return -1;
                if (!p)
@@ -238,4 +242,31 @@ int color_fwrite_lines(FILE *fp, const char *color,
        return 0;
 }
 
+char *get_percent_color(double percent)
+{
+       char *color = PERF_COLOR_NORMAL;
 
+       /*
+        * We color high-overhead entries in red, mid-overhead
+        * entries in green - and keep the low overhead places
+        * normal:
+        */
+       if (percent >= MIN_RED)
+               color = PERF_COLOR_RED;
+       else {
+               if (percent > MIN_GREEN)
+                       color = PERF_COLOR_GREEN;
+       }
+       return color;
+}
+
+int percent_color_fprintf(FILE *fp, const char *fmt, double percent)
+{
+       int r;
+       char *color;
+
+       color = get_percent_color(percent);
+       r = color_fprintf(fp, color, fmt, percent);
+
+       return r;
+}
index 5abfd379582b40428f62807b5aefa81a239a49d2..706cec50bd25188d3f123c338e4c22436f859d80 100644 (file)
@@ -15,6 +15,9 @@
 #define PERF_COLOR_CYAN                "\033[36m"
 #define PERF_COLOR_BG_RED      "\033[41m"
 
+#define MIN_GREEN      0.5
+#define MIN_RED                5.0
+
 /*
  * This variable stores the value of color.ui
  */
@@ -32,5 +35,7 @@ void color_parse_mem(const char *value, int len, const char *var, char *dst);
 int color_fprintf(FILE *fp, const char *color, const char *fmt, ...);
 int color_fprintf_ln(FILE *fp, const char *color, const char *fmt, ...);
 int color_fwrite_lines(FILE *fp, const char *color, size_t count, const char *buf);
+int percent_color_fprintf(FILE *fp, const char *fmt, double percent);
+char *get_percent_color(double percent);
 
 #endif /* COLOR_H */
index 3dd13faa6a27f9e1378184bd3349c2a3cf51f073..780df541006dd2dae77608ade75ad23069203d5f 100644 (file)
@@ -47,10 +47,12 @@ static int get_next_char(void)
 static char *parse_value(void)
 {
        static char value[1024];
-       int quote = 0, comment = 0, len = 0, space = 0;
+       int quote = 0, comment = 0, space = 0;
+       size_t len = 0;
 
        for (;;) {
                int c = get_next_char();
+
                if (len >= sizeof(value) - 1)
                        return NULL;
                if (c == '\n') {
@@ -353,13 +355,13 @@ int perf_config_string(const char **dest, const char *var, const char *value)
        return 0;
 }
 
-static int perf_default_core_config(const char *var, const char *value)
+static int perf_default_core_config(const char *var __used, const char *value __used)
 {
        /* Add other config variables here and to Documentation/config.txt. */
        return 0;
 }
 
-int perf_default_config(const char *var, const char *value, void *dummy)
+int perf_default_config(const char *var, const char *value, void *dummy __used)
 {
        if (!prefixcmp(var, "core."))
                return perf_default_core_config(var, value);
@@ -471,10 +473,10 @@ static int matches(const char* key, const char* value)
                  !regexec(store.value_regex, value, 0, NULL, 0)));
 }
 
-static int store_aux(const char* key, const char* value, void *cb)
+static int store_aux(const char* key, const char* value, void *cb __used)
 {
+       int section_len;
        const char *ep;
-       size_t section_len;
 
        switch (store.state) {
        case KEY_SEEN:
@@ -551,7 +553,7 @@ static int store_write_section(int fd, const char* key)
                strbuf_addf(&sb, "[%.*s]\n", store.baselen, key);
        }
 
-       success = write_in_full(fd, sb.buf, sb.len) == sb.len;
+       success = (write_in_full(fd, sb.buf, sb.len) == (ssize_t)sb.len);
        strbuf_release(&sb);
 
        return success;
@@ -599,7 +601,7 @@ static int store_write_pair(int fd, const char* key, const char* value)
                }
        strbuf_addf(&sb, "%s\n", quote);
 
-       success = write_in_full(fd, sb.buf, sb.len) == sb.len;
+       success = (write_in_full(fd, sb.buf, sb.len) == (ssize_t)sb.len);
        strbuf_release(&sb);
 
        return success;
@@ -741,7 +743,7 @@ int perf_config_set_multivar(const char* key, const char* value,
        } else {
                struct stat st;
                char* contents;
-               size_t contents_sz, copy_begin, copy_end;
+               ssize_t contents_sz, copy_begin, copy_end;
                int i, new_line = 0;
 
                if (value_regex == NULL)
index d39292263153021ac44a6f9b4e2779ce63478094..34a3528673822622019687929f0499c4ebc0de1a 100644 (file)
@@ -1,6 +1,9 @@
 #include "cache.h"
 #include "exec_cmd.h"
 #include "quote.h"
+
+#include <string.h>
+
 #define MAX_ARGS       32
 
 extern char **environ;
@@ -51,7 +54,7 @@ const char *perf_extract_argv0_path(const char *argv0)
                slash--;
 
        if (slash >= argv0) {
-               argv0_path = strndup(argv0, slash - argv0);
+               argv0_path = xstrndup(argv0, slash - argv0);
                return slash + 1;
        }
 
diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c
new file mode 100644 (file)
index 0000000..450384b
--- /dev/null
@@ -0,0 +1,242 @@
+#include <sys/types.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "util.h"
+#include "header.h"
+
+/*
+ *
+ */
+
+struct perf_header_attr *perf_header_attr__new(struct perf_counter_attr *attr)
+{
+       struct perf_header_attr *self = malloc(sizeof(*self));
+
+       if (!self)
+               die("nomem");
+
+       self->attr = *attr;
+       self->ids = 0;
+       self->size = 1;
+       self->id = malloc(sizeof(u64));
+
+       if (!self->id)
+               die("nomem");
+
+       return self;
+}
+
+void perf_header_attr__add_id(struct perf_header_attr *self, u64 id)
+{
+       int pos = self->ids;
+
+       self->ids++;
+       if (self->ids > self->size) {
+               self->size *= 2;
+               self->id = realloc(self->id, self->size * sizeof(u64));
+               if (!self->id)
+                       die("nomem");
+       }
+       self->id[pos] = id;
+}
+
+/*
+ *
+ */
+
+struct perf_header *perf_header__new(void)
+{
+       struct perf_header *self = malloc(sizeof(*self));
+
+       if (!self)
+               die("nomem");
+
+       self->frozen = 0;
+
+       self->attrs = 0;
+       self->size = 1;
+       self->attr = malloc(sizeof(void *));
+
+       if (!self->attr)
+               die("nomem");
+
+       self->data_offset = 0;
+       self->data_size = 0;
+
+       return self;
+}
+
+void perf_header__add_attr(struct perf_header *self,
+                          struct perf_header_attr *attr)
+{
+       int pos = self->attrs;
+
+       if (self->frozen)
+               die("frozen");
+
+       self->attrs++;
+       if (self->attrs > self->size) {
+               self->size *= 2;
+               self->attr = realloc(self->attr, self->size * sizeof(void *));
+               if (!self->attr)
+                       die("nomem");
+       }
+       self->attr[pos] = attr;
+}
+
+static const char *__perf_magic = "PERFFILE";
+
+#define PERF_MAGIC     (*(u64 *)__perf_magic)
+
+struct perf_file_section {
+       u64 offset;
+       u64 size;
+};
+
+struct perf_file_attr {
+       struct perf_counter_attr        attr;
+       struct perf_file_section        ids;
+};
+
+struct perf_file_header {
+       u64                             magic;
+       u64                             size;
+       u64                             attr_size;
+       struct perf_file_section        attrs;
+       struct perf_file_section        data;
+};
+
+static void do_write(int fd, void *buf, size_t size)
+{
+       while (size) {
+               int ret = write(fd, buf, size);
+
+               if (ret < 0)
+                       die("failed to write");
+
+               size -= ret;
+               buf += ret;
+       }
+}
+
+void perf_header__write(struct perf_header *self, int fd)
+{
+       struct perf_file_header f_header;
+       struct perf_file_attr   f_attr;
+       struct perf_header_attr *attr;
+       int i;
+
+       lseek(fd, sizeof(f_header), SEEK_SET);
+
+
+       for (i = 0; i < self->attrs; i++) {
+               attr = self->attr[i];
+
+               attr->id_offset = lseek(fd, 0, SEEK_CUR);
+               do_write(fd, attr->id, attr->ids * sizeof(u64));
+       }
+
+
+       self->attr_offset = lseek(fd, 0, SEEK_CUR);
+
+       for (i = 0; i < self->attrs; i++) {
+               attr = self->attr[i];
+
+               f_attr = (struct perf_file_attr){
+                       .attr = attr->attr,
+                       .ids  = {
+                               .offset = attr->id_offset,
+                               .size   = attr->ids * sizeof(u64),
+                       }
+               };
+               do_write(fd, &f_attr, sizeof(f_attr));
+       }
+
+
+       self->data_offset = lseek(fd, 0, SEEK_CUR);
+
+       f_header = (struct perf_file_header){
+               .magic     = PERF_MAGIC,
+               .size      = sizeof(f_header),
+               .attr_size = sizeof(f_attr),
+               .attrs = {
+                       .offset = self->attr_offset,
+                       .size   = self->attrs * sizeof(f_attr),
+               },
+               .data = {
+                       .offset = self->data_offset,
+                       .size   = self->data_size,
+               },
+       };
+
+       lseek(fd, 0, SEEK_SET);
+       do_write(fd, &f_header, sizeof(f_header));
+       lseek(fd, self->data_offset + self->data_size, SEEK_SET);
+
+       self->frozen = 1;
+}
+
+static void do_read(int fd, void *buf, size_t size)
+{
+       while (size) {
+               int ret = read(fd, buf, size);
+
+               if (ret < 0)
+                       die("failed to read");
+
+               size -= ret;
+               buf += ret;
+       }
+}
+
+struct perf_header *perf_header__read(int fd)
+{
+       struct perf_header      *self = perf_header__new();
+       struct perf_file_header f_header;
+       struct perf_file_attr   f_attr;
+       u64                     f_id;
+
+       int nr_attrs, nr_ids, i, j;
+
+       lseek(fd, 0, SEEK_SET);
+       do_read(fd, &f_header, sizeof(f_header));
+
+       if (f_header.magic      != PERF_MAGIC           ||
+           f_header.size       != sizeof(f_header)     ||
+           f_header.attr_size  != sizeof(f_attr))
+               die("incompatible file format");
+
+       nr_attrs = f_header.attrs.size / sizeof(f_attr);
+       lseek(fd, f_header.attrs.offset, SEEK_SET);
+
+       for (i = 0; i < nr_attrs; i++) {
+               struct perf_header_attr *attr;
+               off_t tmp = lseek(fd, 0, SEEK_CUR);
+
+               do_read(fd, &f_attr, sizeof(f_attr));
+
+               attr = perf_header_attr__new(&f_attr.attr);
+
+               nr_ids = f_attr.ids.size / sizeof(u64);
+               lseek(fd, f_attr.ids.offset, SEEK_SET);
+
+               for (j = 0; j < nr_ids; j++) {
+                       do_read(fd, &f_id, sizeof(f_id));
+
+                       perf_header_attr__add_id(attr, f_id);
+               }
+               perf_header__add_attr(self, attr);
+               lseek(fd, tmp, SEEK_SET);
+       }
+
+       self->data_offset = f_header.data.offset;
+       self->data_size   = f_header.data.size;
+
+       lseek(fd, self->data_offset + self->data_size, SEEK_SET);
+
+       self->frozen = 1;
+
+       return self;
+}
diff --git a/tools/perf/util/header.h b/tools/perf/util/header.h
new file mode 100644 (file)
index 0000000..b5ef53a
--- /dev/null
@@ -0,0 +1,37 @@
+#ifndef _PERF_HEADER_H
+#define _PERF_HEADER_H
+
+#include "../../../include/linux/perf_counter.h"
+#include <sys/types.h>
+#include "types.h"
+
+struct perf_header_attr {
+       struct perf_counter_attr attr;
+       int ids, size;
+       u64 *id;
+       off_t id_offset;
+};
+
+struct perf_header {
+       int frozen;
+       int attrs, size;
+       struct perf_header_attr **attr;
+       off_t attr_offset;
+       u64 data_offset;
+       u64 data_size;
+};
+
+struct perf_header *perf_header__read(int fd);
+void perf_header__write(struct perf_header *self, int fd);
+
+void perf_header__add_attr(struct perf_header *self,
+                          struct perf_header_attr *attr);
+
+struct perf_header_attr *
+perf_header_attr__new(struct perf_counter_attr *attr);
+void perf_header_attr__add_id(struct perf_header_attr *self, u64 id);
+
+
+struct perf_header *perf_header__new(void);
+
+#endif /* _PERF_HEADER_H */
index 6653f7dd1d784f96fcd8161cafc7fb78895dc6e4..fbb00978b2e2988045f4f970964b7c5826c1cba4 100644 (file)
@@ -26,7 +26,7 @@ static int term_columns(void)
        return 80;
 }
 
-void add_cmdname(struct cmdnames *cmds, const char *name, int len)
+void add_cmdname(struct cmdnames *cmds, const char *name, size_t len)
 {
        struct cmdname *ent = malloc(sizeof(*ent) + len + 1);
 
@@ -40,7 +40,8 @@ void add_cmdname(struct cmdnames *cmds, const char *name, int len)
 
 static void clean_cmdnames(struct cmdnames *cmds)
 {
-       int i;
+       unsigned int i;
+
        for (i = 0; i < cmds->cnt; ++i)
                free(cmds->names[i]);
        free(cmds->names);
@@ -57,7 +58,7 @@ static int cmdname_compare(const void *a_, const void *b_)
 
 static void uniq(struct cmdnames *cmds)
 {
-       int i, j;
+       unsigned int i, j;
 
        if (!cmds->cnt)
                return;
@@ -71,7 +72,7 @@ static void uniq(struct cmdnames *cmds)
 
 void exclude_cmds(struct cmdnames *cmds, struct cmdnames *excludes)
 {
-       int ci, cj, ei;
+       size_t ci, cj, ei;
        int cmp;
 
        ci = cj = ei = 0;
@@ -106,8 +107,9 @@ static void pretty_print_string_list(struct cmdnames *cmds, int longest)
                printf("  ");
 
                for (j = 0; j < cols; j++) {
-                       int n = j * rows + i;
-                       int size = space;
+                       unsigned int n = j * rows + i;
+                       unsigned int size = space;
+
                        if (n >= cmds->cnt)
                                break;
                        if (j == cols-1 || n + rows >= cmds->cnt)
@@ -126,21 +128,6 @@ static int is_executable(const char *name)
            !S_ISREG(st.st_mode))
                return 0;
 
-#ifdef __MINGW32__
-       /* cannot trust the executable bit, peek into the file instead */
-       char buf[3] = { 0 };
-       int n;
-       int fd = open(name, O_RDONLY);
-       st.st_mode &= ~S_IXUSR;
-       if (fd >= 0) {
-               n = read(fd, buf, 2);
-               if (n == 2)
-                       /* DOS executables start with "MZ" */
-                       if (!strcmp(buf, "#!") || !strcmp(buf, "MZ"))
-                               st.st_mode |= S_IXUSR;
-               close(fd);
-       }
-#endif
        return st.st_mode & S_IXUSR;
 }
 
@@ -223,7 +210,7 @@ void load_command_list(const char *prefix,
 void list_commands(const char *title, struct cmdnames *main_cmds,
                   struct cmdnames *other_cmds)
 {
-       int i, longest = 0;
+       unsigned int i, longest = 0;
 
        for (i = 0; i < main_cmds->cnt; i++)
                if (longest < main_cmds->names[i]->len)
@@ -254,7 +241,8 @@ void list_commands(const char *title, struct cmdnames *main_cmds,
 
 int is_in_cmdlist(struct cmdnames *c, const char *s)
 {
-       int i;
+       unsigned int i;
+
        for (i = 0; i < c->cnt; i++)
                if (!strcmp(s, c->names[i]->name))
                        return 1;
@@ -286,7 +274,8 @@ static int levenshtein_compare(const void *p1, const void *p2)
 
 static void add_cmd_list(struct cmdnames *cmds, struct cmdnames *old)
 {
-       int i;
+       unsigned int i;
+
        ALLOC_GROW(cmds->names, cmds->cnt + old->cnt, cmds->alloc);
 
        for (i = 0; i < old->cnt; i++)
@@ -298,7 +287,7 @@ static void add_cmd_list(struct cmdnames *cmds, struct cmdnames *old)
 
 const char *help_unknown_cmd(const char *cmd)
 {
-       int i, n = 0, best_similarity = 0;
+       unsigned int i, n = 0, best_similarity = 0;
        struct cmdnames main_cmds, other_cmds;
 
        memset(&main_cmds, 0, sizeof(main_cmds));
@@ -360,7 +349,7 @@ const char *help_unknown_cmd(const char *cmd)
        exit(1);
 }
 
-int cmd_version(int argc, const char **argv, const char *prefix)
+int cmd_version(int argc __used, const char **argv __used, const char *prefix __used)
 {
        printf("perf version %s\n", perf_version_string);
        return 0;
index 56bc15406ffc55115fa1c827e0d1d5a7e74c516d..7128783637b4a7be720c49a9e74ccb43cba2cac9 100644 (file)
@@ -2,8 +2,8 @@
 #define HELP_H
 
 struct cmdnames {
-       int alloc;
-       int cnt;
+       size_t alloc;
+       size_t cnt;
        struct cmdname {
                size_t len; /* also used for similarity index in help.c */
                char name[FLEX_ARRAY];
@@ -19,7 +19,7 @@ static inline void mput_char(char c, unsigned int num)
 void load_command_list(const char *prefix,
                struct cmdnames *main_cmds,
                struct cmdnames *other_cmds);
-void add_cmdname(struct cmdnames *cmds, const char *name, int len);
+void add_cmdname(struct cmdnames *cmds, const char *name, size_t len);
 /* Here we require that excludes is a sorted list. */
 void exclude_cmds(struct cmdnames *cmds, struct cmdnames *excludes);
 int is_in_cmdlist(struct cmdnames *c, const char *s);
diff --git a/tools/perf/util/include/asm/system.h b/tools/perf/util/include/asm/system.h
new file mode 100644 (file)
index 0000000..710cecc
--- /dev/null
@@ -0,0 +1 @@
+/* Empty */
diff --git a/tools/perf/util/include/linux/kernel.h b/tools/perf/util/include/linux/kernel.h
new file mode 100644 (file)
index 0000000..99c1b3d
--- /dev/null
@@ -0,0 +1,21 @@
+#ifndef PERF_LINUX_KERNEL_H_
+#define PERF_LINUX_KERNEL_H_
+
+#ifndef offsetof
+#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
+#endif
+
+#ifndef container_of
+/**
+ * container_of - cast a member of a structure out to the containing structure
+ * @ptr:       the pointer to the member.
+ * @type:      the type of the container struct this is embedded in.
+ * @member:    the name of the member within the struct.
+ *
+ */
+#define container_of(ptr, type, member) ({                     \
+       const typeof(((type *)0)->member) * __mptr = (ptr);     \
+       (type *)((char *)__mptr - offsetof(type, member)); })
+#endif
+
+#endif
diff --git a/tools/perf/util/include/linux/list.h b/tools/perf/util/include/linux/list.h
new file mode 100644 (file)
index 0000000..dbe4b81
--- /dev/null
@@ -0,0 +1,18 @@
+#include "../../../../include/linux/list.h"
+
+#ifndef PERF_LIST_H
+#define PERF_LIST_H
+/**
+ * list_del_range - deletes range of entries from list.
+ * @begin: first element in the range to delete from the list.
+ * @end: last element in the range to delete from the list.
+ * Note: list_empty on the range of entries does not return true after this,
+ * the entries is in an undefined state.
+ */
+static inline void list_del_range(struct list_head *begin,
+                                 struct list_head *end)
+{
+       begin->prev->next = end->next;
+       end->next->prev = begin->prev;
+}
+#endif
diff --git a/tools/perf/util/include/linux/module.h b/tools/perf/util/include/linux/module.h
new file mode 100644 (file)
index 0000000..b43e2dc
--- /dev/null
@@ -0,0 +1,6 @@
+#ifndef PERF_LINUX_MODULE_H
+#define PERF_LINUX_MODULE_H
+
+#define EXPORT_SYMBOL(name)
+
+#endif
diff --git a/tools/perf/util/include/linux/poison.h b/tools/perf/util/include/linux/poison.h
new file mode 100644 (file)
index 0000000..fef6dbc
--- /dev/null
@@ -0,0 +1 @@
+#include "../../../../include/linux/poison.h"
diff --git a/tools/perf/util/include/linux/prefetch.h b/tools/perf/util/include/linux/prefetch.h
new file mode 100644 (file)
index 0000000..7841e48
--- /dev/null
@@ -0,0 +1,6 @@
+#ifndef PERF_LINUX_PREFETCH_H
+#define PERF_LINUX_PREFETCH_H
+
+static inline void prefetch(void *a __attribute__((unused))) { }
+
+#endif
diff --git a/tools/perf/util/include/linux/rbtree.h b/tools/perf/util/include/linux/rbtree.h
new file mode 100644 (file)
index 0000000..7a243a1
--- /dev/null
@@ -0,0 +1 @@
+#include "../../../../include/linux/rbtree.h"
diff --git a/tools/perf/util/list.h b/tools/perf/util/list.h
deleted file mode 100644 (file)
index e2548e8..0000000
+++ /dev/null
@@ -1,603 +0,0 @@
-#ifndef _LINUX_LIST_H
-#define _LINUX_LIST_H
-/*
-  Copyright (C) Cast of dozens, comes from the Linux kernel
-
-  This program is free software; you can redistribute it and/or modify it
-  under the terms of version 2 of the GNU General Public License as
-  published by the Free Software Foundation.
-*/
-
-#include <stddef.h>
-
-/*
- * These are non-NULL pointers that will result in page faults
- * under normal circumstances, used to verify that nobody uses
- * non-initialized list entries.
- */
-#define LIST_POISON1 ((void *)0x00100100)
-#define LIST_POISON2 ((void *)0x00200200)
-
-/**
- * container_of - cast a member of a structure out to the containing structure
- * @ptr:       the pointer to the member.
- * @type:      the type of the container struct this is embedded in.
- * @member:    the name of the member within the struct.
- *
- */
-#define container_of(ptr, type, member) ({                     \
-        const typeof( ((type *)0)->member ) *__mptr = (ptr);   \
-        (type *)( (char *)__mptr - offsetof(type,member) );})
-
-/*
- * Simple doubly linked list implementation.
- *
- * Some of the internal functions ("__xxx") are useful when
- * manipulating whole lists rather than single entries, as
- * sometimes we already know the next/prev entries and we can
- * generate better code by using them directly rather than
- * using the generic single-entry routines.
- */
-
-struct list_head {
-       struct list_head *next, *prev;
-};
-
-#define LIST_HEAD_INIT(name) { &(name), &(name) }
-
-#define LIST_HEAD(name) \
-       struct list_head name = LIST_HEAD_INIT(name)
-
-static inline void INIT_LIST_HEAD(struct list_head *list)
-{
-       list->next = list;
-       list->prev = list;
-}
-
-/*
- * Insert a new entry between two known consecutive entries.
- *
- * This is only for internal list manipulation where we know
- * the prev/next entries already!
- */
-static inline void __list_add(struct list_head *new,
-                             struct list_head *prev,
-                             struct list_head *next)
-{
-       next->prev = new;
-       new->next = next;
-       new->prev = prev;
-       prev->next = new;
-}
-
-/**
- * list_add - add a new entry
- * @new: new entry to be added
- * @head: list head to add it after
- *
- * Insert a new entry after the specified head.
- * This is good for implementing stacks.
- */
-static inline void list_add(struct list_head *new, struct list_head *head)
-{
-       __list_add(new, head, head->next);
-}
-
-/**
- * list_add_tail - add a new entry
- * @new: new entry to be added
- * @head: list head to add it before
- *
- * Insert a new entry before the specified head.
- * This is useful for implementing queues.
- */
-static inline void list_add_tail(struct list_head *new, struct list_head *head)
-{
-       __list_add(new, head->prev, head);
-}
-
-/*
- * Delete a list entry by making the prev/next entries
- * point to each other.
- *
- * This is only for internal list manipulation where we know
- * the prev/next entries already!
- */
-static inline void __list_del(struct list_head * prev, struct list_head * next)
-{
-       next->prev = prev;
-       prev->next = next;
-}
-
-/**
- * list_del - deletes entry from list.
- * @entry: the element to delete from the list.
- * Note: list_empty on entry does not return true after this, the entry is
- * in an undefined state.
- */
-static inline void list_del(struct list_head *entry)
-{
-       __list_del(entry->prev, entry->next);
-       entry->next = LIST_POISON1;
-       entry->prev = LIST_POISON2;
-}
-
-/**
- * list_del_range - deletes range of entries from list.
- * @beging: first element in the range to delete from the list.
- * @beging: first element in the range to delete from the list.
- * Note: list_empty on the range of entries does not return true after this,
- * the entries is in an undefined state.
- */
-static inline void list_del_range(struct list_head *begin,
-                                 struct list_head *end)
-{
-       begin->prev->next = end->next;
-       end->next->prev = begin->prev;
-}
-
-/**
- * list_replace - replace old entry by new one
- * @old : the element to be replaced
- * @new : the new element to insert
- * Note: if 'old' was empty, it will be overwritten.
- */
-static inline void list_replace(struct list_head *old,
-                               struct list_head *new)
-{
-       new->next = old->next;
-       new->next->prev = new;
-       new->prev = old->prev;
-       new->prev->next = new;
-}
-
-static inline void list_replace_init(struct list_head *old,
-                                       struct list_head *new)
-{
-       list_replace(old, new);
-       INIT_LIST_HEAD(old);
-}
-
-/**
- * list_del_init - deletes entry from list and reinitialize it.
- * @entry: the element to delete from the list.
- */
-static inline void list_del_init(struct list_head *entry)
-{
-       __list_del(entry->prev, entry->next);
-       INIT_LIST_HEAD(entry);
-}
-
-/**
- * list_move - delete from one list and add as another's head
- * @list: the entry to move
- * @head: the head that will precede our entry
- */
-static inline void list_move(struct list_head *list, struct list_head *head)
-{
-        __list_del(list->prev, list->next);
-        list_add(list, head);
-}
-
-/**
- * list_move_tail - delete from one list and add as another's tail
- * @list: the entry to move
- * @head: the head that will follow our entry
- */
-static inline void list_move_tail(struct list_head *list,
-                                 struct list_head *head)
-{
-        __list_del(list->prev, list->next);
-        list_add_tail(list, head);
-}
-
-/**
- * list_is_last - tests whether @list is the last entry in list @head
- * @list: the entry to test
- * @head: the head of the list
- */
-static inline int list_is_last(const struct list_head *list,
-                               const struct list_head *head)
-{
-       return list->next == head;
-}
-
-/**
- * list_empty - tests whether a list is empty
- * @head: the list to test.
- */
-static inline int list_empty(const struct list_head *head)
-{
-       return head->next == head;
-}
-
-/**
- * list_empty_careful - tests whether a list is empty and not being modified
- * @head: the list to test
- *
- * Description:
- * tests whether a list is empty _and_ checks that no other CPU might be
- * in the process of modifying either member (next or prev)
- *
- * NOTE: using list_empty_careful() without synchronization
- * can only be safe if the only activity that can happen
- * to the list entry is list_del_init(). Eg. it cannot be used
- * if another CPU could re-list_add() it.
- */
-static inline int list_empty_careful(const struct list_head *head)
-{
-       struct list_head *next = head->next;
-       return (next == head) && (next == head->prev);
-}
-
-static inline void __list_splice(struct list_head *list,
-                                struct list_head *head)
-{
-       struct list_head *first = list->next;
-       struct list_head *last = list->prev;
-       struct list_head *at = head->next;
-
-       first->prev = head;
-       head->next = first;
-
-       last->next = at;
-       at->prev = last;
-}
-
-/**
- * list_splice - join two lists
- * @list: the new list to add.
- * @head: the place to add it in the first list.
- */
-static inline void list_splice(struct list_head *list, struct list_head *head)
-{
-       if (!list_empty(list))
-               __list_splice(list, head);
-}
-
-/**
- * list_splice_init - join two lists and reinitialise the emptied list.
- * @list: the new list to add.
- * @head: the place to add it in the first list.
- *
- * The list at @list is reinitialised
- */
-static inline void list_splice_init(struct list_head *list,
-                                   struct list_head *head)
-{
-       if (!list_empty(list)) {
-               __list_splice(list, head);
-               INIT_LIST_HEAD(list);
-       }
-}
-
-/**
- * list_entry - get the struct for this entry
- * @ptr:       the &struct list_head pointer.
- * @type:      the type of the struct this is embedded in.
- * @member:    the name of the list_struct within the struct.
- */
-#define list_entry(ptr, type, member) \
-       container_of(ptr, type, member)
-
-/**
- * list_first_entry - get the first element from a list
- * @ptr:       the list head to take the element from.
- * @type:      the type of the struct this is embedded in.
- * @member:    the name of the list_struct within the struct.
- *
- * Note, that list is expected to be not empty.
- */
-#define list_first_entry(ptr, type, member) \
-       list_entry((ptr)->next, type, member)
-
-/**
- * list_for_each       -       iterate over a list
- * @pos:       the &struct list_head to use as a loop cursor.
- * @head:      the head for your list.
- */
-#define list_for_each(pos, head) \
-       for (pos = (head)->next; pos != (head); \
-               pos = pos->next)
-
-/**
- * __list_for_each     -       iterate over a list
- * @pos:       the &struct list_head to use as a loop cursor.
- * @head:      the head for your list.
- *
- * This variant differs from list_for_each() in that it's the
- * simplest possible list iteration code, no prefetching is done.
- * Use this for code that knows the list to be very short (empty
- * or 1 entry) most of the time.
- */
-#define __list_for_each(pos, head) \
-       for (pos = (head)->next; pos != (head); pos = pos->next)
-
-/**
- * list_for_each_prev  -       iterate over a list backwards
- * @pos:       the &struct list_head to use as a loop cursor.
- * @head:      the head for your list.
- */
-#define list_for_each_prev(pos, head) \
-       for (pos = (head)->prev; pos != (head); \
-               pos = pos->prev)
-
-/**
- * list_for_each_safe - iterate over a list safe against removal of list entry
- * @pos:       the &struct list_head to use as a loop cursor.
- * @n:         another &struct list_head to use as temporary storage
- * @head:      the head for your list.
- */
-#define list_for_each_safe(pos, n, head) \
-       for (pos = (head)->next, n = pos->next; pos != (head); \
-               pos = n, n = pos->next)
-
-/**
- * list_for_each_entry -       iterate over list of given type
- * @pos:       the type * to use as a loop cursor.
- * @head:      the head for your list.
- * @member:    the name of the list_struct within the struct.
- */
-#define list_for_each_entry(pos, head, member)                         \
-       for (pos = list_entry((head)->next, typeof(*pos), member);      \
-            &pos->member != (head);    \
-            pos = list_entry(pos->member.next, typeof(*pos), member))
-
-/**
- * list_for_each_entry_reverse - iterate backwards over list of given type.
- * @pos:       the type * to use as a loop cursor.
- * @head:      the head for your list.
- * @member:    the name of the list_struct within the struct.
- */
-#define list_for_each_entry_reverse(pos, head, member)                 \
-       for (pos = list_entry((head)->prev, typeof(*pos), member);      \
-            &pos->member != (head);    \
-            pos = list_entry(pos->member.prev, typeof(*pos), member))
-
-/**
- * list_prepare_entry - prepare a pos entry for use in list_for_each_entry_continue
- * @pos:       the type * to use as a start point
- * @head:      the head of the list
- * @member:    the name of the list_struct within the struct.
- *
- * Prepares a pos entry for use as a start point in list_for_each_entry_continue.
- */
-#define list_prepare_entry(pos, head, member) \
-       ((pos) ? : list_entry(head, typeof(*pos), member))
-
-/**
- * list_for_each_entry_continue - continue iteration over list of given type
- * @pos:       the type * to use as a loop cursor.
- * @head:      the head for your list.
- * @member:    the name of the list_struct within the struct.
- *
- * Continue to iterate over list of given type, continuing after
- * the current position.
- */
-#define list_for_each_entry_continue(pos, head, member)                \
-       for (pos = list_entry(pos->member.next, typeof(*pos), member);  \
-            &pos->member != (head);    \
-            pos = list_entry(pos->member.next, typeof(*pos), member))
-
-/**
- * list_for_each_entry_from - iterate over list of given type from the current point
- * @pos:       the type * to use as a loop cursor.
- * @head:      the head for your list.
- * @member:    the name of the list_struct within the struct.
- *
- * Iterate over list of given type, continuing from current position.
- */
-#define list_for_each_entry_from(pos, head, member)                    \
-       for (; &pos->member != (head);  \
-            pos = list_entry(pos->member.next, typeof(*pos), member))
-
-/**
- * list_for_each_entry_safe - iterate over list of given type safe against removal of list entry
- * @pos:       the type * to use as a loop cursor.
- * @n:         another type * to use as temporary storage
- * @head:      the head for your list.
- * @member:    the name of the list_struct within the struct.
- */
-#define list_for_each_entry_safe(pos, n, head, member)                 \
-       for (pos = list_entry((head)->next, typeof(*pos), member),      \
-               n = list_entry(pos->member.next, typeof(*pos), member); \
-            &pos->member != (head);                                    \
-            pos = n, n = list_entry(n->member.next, typeof(*n), member))
-
-/**
- * list_for_each_entry_safe_continue
- * @pos:       the type * to use as a loop cursor.
- * @n:         another type * to use as temporary storage
- * @head:      the head for your list.
- * @member:    the name of the list_struct within the struct.
- *
- * Iterate over list of given type, continuing after current point,
- * safe against removal of list entry.
- */
-#define list_for_each_entry_safe_continue(pos, n, head, member)                \
-       for (pos = list_entry(pos->member.next, typeof(*pos), member),          \
-               n = list_entry(pos->member.next, typeof(*pos), member);         \
-            &pos->member != (head);                                            \
-            pos = n, n = list_entry(n->member.next, typeof(*n), member))
-
-/**
- * list_for_each_entry_safe_from
- * @pos:       the type * to use as a loop cursor.
- * @n:         another type * to use as temporary storage
- * @head:      the head for your list.
- * @member:    the name of the list_struct within the struct.
- *
- * Iterate over list of given type from current point, safe against
- * removal of list entry.
- */
-#define list_for_each_entry_safe_from(pos, n, head, member)                    \
-       for (n = list_entry(pos->member.next, typeof(*pos), member);            \
-            &pos->member != (head);                                            \
-            pos = n, n = list_entry(n->member.next, typeof(*n), member))
-
-/**
- * list_for_each_entry_safe_reverse
- * @pos:       the type * to use as a loop cursor.
- * @n:         another type * to use as temporary storage
- * @head:      the head for your list.
- * @member:    the name of the list_struct within the struct.
- *
- * Iterate backwards over list of given type, safe against removal
- * of list entry.
- */
-#define list_for_each_entry_safe_reverse(pos, n, head, member)         \
-       for (pos = list_entry((head)->prev, typeof(*pos), member),      \
-               n = list_entry(pos->member.prev, typeof(*pos), member); \
-            &pos->member != (head);                                    \
-            pos = n, n = list_entry(n->member.prev, typeof(*n), member))
-
-/*
- * Double linked lists with a single pointer list head.
- * Mostly useful for hash tables where the two pointer list head is
- * too wasteful.
- * You lose the ability to access the tail in O(1).
- */
-
-struct hlist_head {
-       struct hlist_node *first;
-};
-
-struct hlist_node {
-       struct hlist_node *next, **pprev;
-};
-
-#define HLIST_HEAD_INIT { .first = NULL }
-#define HLIST_HEAD(name) struct hlist_head name = {  .first = NULL }
-#define INIT_HLIST_HEAD(ptr) ((ptr)->first = NULL)
-static inline void INIT_HLIST_NODE(struct hlist_node *h)
-{
-       h->next = NULL;
-       h->pprev = NULL;
-}
-
-static inline int hlist_unhashed(const struct hlist_node *h)
-{
-       return !h->pprev;
-}
-
-static inline int hlist_empty(const struct hlist_head *h)
-{
-       return !h->first;
-}
-
-static inline void __hlist_del(struct hlist_node *n)
-{
-       struct hlist_node *next = n->next;
-       struct hlist_node **pprev = n->pprev;
-       *pprev = next;
-       if (next)
-               next->pprev = pprev;
-}
-
-static inline void hlist_del(struct hlist_node *n)
-{
-       __hlist_del(n);
-       n->next = LIST_POISON1;
-       n->pprev = LIST_POISON2;
-}
-
-static inline void hlist_del_init(struct hlist_node *n)
-{
-       if (!hlist_unhashed(n)) {
-               __hlist_del(n);
-               INIT_HLIST_NODE(n);
-       }
-}
-
-static inline void hlist_add_head(struct hlist_node *n, struct hlist_head *h)
-{
-       struct hlist_node *first = h->first;
-       n->next = first;
-       if (first)
-               first->pprev = &n->next;
-       h->first = n;
-       n->pprev = &h->first;
-}
-
-/* next must be != NULL */
-static inline void hlist_add_before(struct hlist_node *n,
-                                       struct hlist_node *next)
-{
-       n->pprev = next->pprev;
-       n->next = next;
-       next->pprev = &n->next;
-       *(n->pprev) = n;
-}
-
-static inline void hlist_add_after(struct hlist_node *n,
-                                       struct hlist_node *next)
-{
-       next->next = n->next;
-       n->next = next;
-       next->pprev = &n->next;
-
-       if(next->next)
-               next->next->pprev  = &next->next;
-}
-
-#define hlist_entry(ptr, type, member) container_of(ptr,type,member)
-
-#define hlist_for_each(pos, head) \
-       for (pos = (head)->first; pos; \
-            pos = pos->next)
-
-#define hlist_for_each_safe(pos, n, head) \
-       for (pos = (head)->first; pos && ({ n = pos->next; 1; }); \
-            pos = n)
-
-/**
- * hlist_for_each_entry        - iterate over list of given type
- * @tpos:      the type * to use as a loop cursor.
- * @pos:       the &struct hlist_node to use as a loop cursor.
- * @head:      the head for your list.
- * @member:    the name of the hlist_node within the struct.
- */
-#define hlist_for_each_entry(tpos, pos, head, member)                   \
-       for (pos = (head)->first;                                        \
-            pos &&                      \
-               ({ tpos = hlist_entry(pos, typeof(*tpos), member); 1;}); \
-            pos = pos->next)
-
-/**
- * hlist_for_each_entry_continue - iterate over a hlist continuing after current point
- * @tpos:      the type * to use as a loop cursor.
- * @pos:       the &struct hlist_node to use as a loop cursor.
- * @member:    the name of the hlist_node within the struct.
- */
-#define hlist_for_each_entry_continue(tpos, pos, member)                \
-       for (pos = (pos)->next;                                          \
-            pos &&                      \
-               ({ tpos = hlist_entry(pos, typeof(*tpos), member); 1;}); \
-            pos = pos->next)
-
-/**
- * hlist_for_each_entry_from - iterate over a hlist continuing from current point
- * @tpos:      the type * to use as a loop cursor.
- * @pos:       the &struct hlist_node to use as a loop cursor.
- * @member:    the name of the hlist_node within the struct.
- */
-#define hlist_for_each_entry_from(tpos, pos, member)                    \
-       for (; pos &&                    \
-               ({ tpos = hlist_entry(pos, typeof(*tpos), member); 1;}); \
-            pos = pos->next)
-
-/**
- * hlist_for_each_entry_safe - iterate over list of given type safe against removal of list entry
- * @tpos:      the type * to use as a loop cursor.
- * @pos:       the &struct hlist_node to use as a loop cursor.
- * @n:         another &struct hlist_node to use as temporary storage
- * @head:      the head for your list.
- * @member:    the name of the hlist_node within the struct.
- */
-#define hlist_for_each_entry_safe(tpos, pos, n, head, member)           \
-       for (pos = (head)->first;                                        \
-            pos && ({ n = pos->next; 1; }) &&                           \
-               ({ tpos = hlist_entry(pos, typeof(*tpos), member); 1;}); \
-            pos = n)
-
-#endif
diff --git a/tools/perf/util/module.c b/tools/perf/util/module.c
new file mode 100644 (file)
index 0000000..ddabe92
--- /dev/null
@@ -0,0 +1,509 @@
+#include "util.h"
+#include "../perf.h"
+#include "string.h"
+#include "module.h"
+
+#include <libelf.h>
+#include <gelf.h>
+#include <elf.h>
+#include <dirent.h>
+#include <sys/utsname.h>
+
+static unsigned int crc32(const char *p, unsigned int len)
+{
+       int i;
+       unsigned int crc = 0;
+
+       while (len--) {
+               crc ^= *p++;
+               for (i = 0; i < 8; i++)
+                       crc = (crc >> 1) ^ ((crc & 1) ? 0xedb88320 : 0);
+       }
+       return crc;
+}
+
+/* module section methods */
+
+struct sec_dso *sec_dso__new_dso(const char *name)
+{
+       struct sec_dso *self = malloc(sizeof(*self) + strlen(name) + 1);
+
+       if (self != NULL) {
+               strcpy(self->name, name);
+               self->secs = RB_ROOT;
+               self->find_section = sec_dso__find_section;
+       }
+
+       return self;
+}
+
+static void sec_dso__delete_section(struct section *self)
+{
+       free(((void *)self));
+}
+
+void sec_dso__delete_sections(struct sec_dso *self)
+{
+       struct section *pos;
+       struct rb_node *next = rb_first(&self->secs);
+
+       while (next) {
+               pos = rb_entry(next, struct section, rb_node);
+               next = rb_next(&pos->rb_node);
+               rb_erase(&pos->rb_node, &self->secs);
+               sec_dso__delete_section(pos);
+       }
+}
+
+void sec_dso__delete_self(struct sec_dso *self)
+{
+       sec_dso__delete_sections(self);
+       free(self);
+}
+
+static void sec_dso__insert_section(struct sec_dso *self, struct section *sec)
+{
+       struct rb_node **p = &self->secs.rb_node;
+       struct rb_node *parent = NULL;
+       const u64 hash = sec->hash;
+       struct section *s;
+
+       while (*p != NULL) {
+               parent = *p;
+               s = rb_entry(parent, struct section, rb_node);
+               if (hash < s->hash)
+                       p = &(*p)->rb_left;
+               else
+                       p = &(*p)->rb_right;
+       }
+       rb_link_node(&sec->rb_node, parent, p);
+       rb_insert_color(&sec->rb_node, &self->secs);
+}
+
+struct section *sec_dso__find_section(struct sec_dso *self, const char *name)
+{
+       struct rb_node *n;
+       u64 hash;
+       int len;
+
+       if (self == NULL)
+               return NULL;
+
+       len = strlen(name);
+       hash = crc32(name, len);
+
+       n = self->secs.rb_node;
+
+       while (n) {
+               struct section *s = rb_entry(n, struct section, rb_node);
+
+               if (hash < s->hash)
+                       n = n->rb_left;
+               else if (hash > s->hash)
+                       n = n->rb_right;
+               else {
+                       if (!strcmp(name, s->name))
+                               return s;
+                       else
+                               n = rb_next(&s->rb_node);
+               }
+       }
+
+       return NULL;
+}
+
+static size_t sec_dso__fprintf_section(struct section *self, FILE *fp)
+{
+       return fprintf(fp, "name:%s vma:%llx path:%s\n",
+                      self->name, self->vma, self->path);
+}
+
+size_t sec_dso__fprintf(struct sec_dso *self, FILE *fp)
+{
+       size_t ret = fprintf(fp, "dso: %s\n", self->name);
+
+       struct rb_node *nd;
+       for (nd = rb_first(&self->secs); nd; nd = rb_next(nd)) {
+               struct section *pos = rb_entry(nd, struct section, rb_node);
+               ret += sec_dso__fprintf_section(pos, fp);
+       }
+
+       return ret;
+}
+
+static struct section *section__new(const char *name, const char *path)
+{
+       struct section *self = calloc(1, sizeof(*self));
+
+       if (!self)
+               goto out_failure;
+
+       self->name = calloc(1, strlen(name) + 1);
+       if (!self->name)
+               goto out_failure;
+
+       self->path = calloc(1, strlen(path) + 1);
+       if (!self->path)
+               goto out_failure;
+
+       strcpy(self->name, name);
+       strcpy(self->path, path);
+       self->hash = crc32(self->name, strlen(name));
+
+       return self;
+
+out_failure:
+       if (self) {
+               if (self->name)
+                       free(self->name);
+               if (self->path)
+                       free(self->path);
+               free(self);
+       }
+
+       return NULL;
+}
+
+/* module methods */
+
+struct mod_dso *mod_dso__new_dso(const char *name)
+{
+       struct mod_dso *self = malloc(sizeof(*self) + strlen(name) + 1);
+
+       if (self != NULL) {
+               strcpy(self->name, name);
+               self->mods = RB_ROOT;
+               self->find_module = mod_dso__find_module;
+       }
+
+       return self;
+}
+
+static void mod_dso__delete_module(struct module *self)
+{
+       free(((void *)self));
+}
+
+void mod_dso__delete_modules(struct mod_dso *self)
+{
+       struct module *pos;
+       struct rb_node *next = rb_first(&self->mods);
+
+       while (next) {
+               pos = rb_entry(next, struct module, rb_node);
+               next = rb_next(&pos->rb_node);
+               rb_erase(&pos->rb_node, &self->mods);
+               mod_dso__delete_module(pos);
+       }
+}
+
+void mod_dso__delete_self(struct mod_dso *self)
+{
+       mod_dso__delete_modules(self);
+       free(self);
+}
+
+static void mod_dso__insert_module(struct mod_dso *self, struct module *mod)
+{
+       struct rb_node **p = &self->mods.rb_node;
+       struct rb_node *parent = NULL;
+       const u64 hash = mod->hash;
+       struct module *m;
+
+       while (*p != NULL) {
+               parent = *p;
+               m = rb_entry(parent, struct module, rb_node);
+               if (hash < m->hash)
+                       p = &(*p)->rb_left;
+               else
+                       p = &(*p)->rb_right;
+       }
+       rb_link_node(&mod->rb_node, parent, p);
+       rb_insert_color(&mod->rb_node, &self->mods);
+}
+
+struct module *mod_dso__find_module(struct mod_dso *self, const char *name)
+{
+       struct rb_node *n;
+       u64 hash;
+       int len;
+
+       if (self == NULL)
+               return NULL;
+
+       len = strlen(name);
+       hash = crc32(name, len);
+
+       n = self->mods.rb_node;
+
+       while (n) {
+               struct module *m = rb_entry(n, struct module, rb_node);
+
+               if (hash < m->hash)
+                       n = n->rb_left;
+               else if (hash > m->hash)
+                       n = n->rb_right;
+               else {
+                       if (!strcmp(name, m->name))
+                               return m;
+                       else
+                               n = rb_next(&m->rb_node);
+               }
+       }
+
+       return NULL;
+}
+
+static size_t mod_dso__fprintf_module(struct module *self, FILE *fp)
+{
+       return fprintf(fp, "name:%s path:%s\n", self->name, self->path);
+}
+
+size_t mod_dso__fprintf(struct mod_dso *self, FILE *fp)
+{
+       struct rb_node *nd;
+       size_t ret;
+
+       ret = fprintf(fp, "dso: %s\n", self->name);
+
+       for (nd = rb_first(&self->mods); nd; nd = rb_next(nd)) {
+               struct module *pos = rb_entry(nd, struct module, rb_node);
+
+               ret += mod_dso__fprintf_module(pos, fp);
+       }
+
+       return ret;
+}
+
+static struct module *module__new(const char *name, const char *path)
+{
+       struct module *self = calloc(1, sizeof(*self));
+
+       if (!self)
+               goto out_failure;
+
+       self->name = calloc(1, strlen(name) + 1);
+       if (!self->name)
+               goto out_failure;
+
+       self->path = calloc(1, strlen(path) + 1);
+       if (!self->path)
+               goto out_failure;
+
+       strcpy(self->name, name);
+       strcpy(self->path, path);
+       self->hash = crc32(self->name, strlen(name));
+
+       return self;
+
+out_failure:
+       if (self) {
+               if (self->name)
+                       free(self->name);
+               if (self->path)
+                       free(self->path);
+               free(self);
+       }
+
+       return NULL;
+}
+
+static int mod_dso__load_sections(struct module *mod)
+{
+       int count = 0, path_len;
+       struct dirent *entry;
+       char *line = NULL;
+       char *dir_path;
+       DIR *dir;
+       size_t n;
+
+       path_len = strlen("/sys/module/");
+       path_len += strlen(mod->name);
+       path_len += strlen("/sections/");
+
+       dir_path = calloc(1, path_len + 1);
+       if (dir_path == NULL)
+               goto out_failure;
+
+       strcat(dir_path, "/sys/module/");
+       strcat(dir_path, mod->name);
+       strcat(dir_path, "/sections/");
+
+       dir = opendir(dir_path);
+       if (dir == NULL)
+               goto out_free;
+
+       while ((entry = readdir(dir))) {
+               struct section *section;
+               char *path, *vma;
+               int line_len;
+               FILE *file;
+
+               if (!strcmp(".", entry->d_name) || !strcmp("..", entry->d_name))
+                       continue;
+
+               path = calloc(1, path_len + strlen(entry->d_name) + 1);
+               if (path == NULL)
+                       break;
+               strcat(path, dir_path);
+               strcat(path, entry->d_name);
+
+               file = fopen(path, "r");
+               if (file == NULL) {
+                       free(path);
+                       break;
+               }
+
+               line_len = getline(&line, &n, file);
+               if (line_len < 0) {
+                       free(path);
+                       fclose(file);
+                       break;
+               }
+
+               if (!line) {
+                       free(path);
+                       fclose(file);
+                       break;
+               }
+
+               line[--line_len] = '\0'; /* \n */
+
+               vma = strstr(line, "0x");
+               if (!vma) {
+                       free(path);
+                       fclose(file);
+                       break;
+               }
+               vma += 2;
+
+               section = section__new(entry->d_name, path);
+               if (!section) {
+                       fprintf(stderr, "load_sections: allocation error\n");
+                       free(path);
+                       fclose(file);
+                       break;
+               }
+
+               hex2u64(vma, &section->vma);
+               sec_dso__insert_section(mod->sections, section);
+
+               free(path);
+               fclose(file);
+               count++;
+       }
+
+       closedir(dir);
+       free(line);
+       free(dir_path);
+
+       return count;
+
+out_free:
+       free(dir_path);
+
+out_failure:
+       return count;
+}
+
+static int mod_dso__load_module_paths(struct mod_dso *self)
+{
+       struct utsname uts;
+       int count = 0, len;
+       char *line = NULL;
+       FILE *file;
+       char *path;
+       size_t n;
+
+       if (uname(&uts) < 0)
+               goto out_failure;
+
+       len = strlen("/lib/modules/");
+       len += strlen(uts.release);
+       len += strlen("/modules.dep");
+
+       path = calloc(1, len);
+       if (path == NULL)
+               goto out_failure;
+
+       strcat(path, "/lib/modules/");
+       strcat(path, uts.release);
+       strcat(path, "/modules.dep");
+
+       file = fopen(path, "r");
+       free(path);
+       if (file == NULL)
+               goto out_failure;
+
+       while (!feof(file)) {
+               char *path, *name, *tmp;
+               struct module *module;
+               int line_len, len;
+
+               line_len = getline(&line, &n, file);
+               if (line_len < 0)
+                       break;
+
+               if (!line)
+                       goto out_failure;
+
+               line[--line_len] = '\0'; /* \n */
+
+               path = strtok(line, ":");
+               if (!path)
+                       goto out_failure;
+
+               name = strdup(path);
+               name = strtok(name, "/");
+
+               tmp = name;
+
+               while (tmp) {
+                       tmp = strtok(NULL, "/");
+                       if (tmp)
+                               name = tmp;
+               }
+               name = strsep(&name, ".");
+
+               /* Quirk: replace '-' with '_' in sound modules */
+               for (len = strlen(name); len; len--) {
+                       if (*(name+len) == '-')
+                               *(name+len) = '_';
+               }
+
+               module = module__new(name, path);
+               if (!module) {
+                       fprintf(stderr, "load_module_paths: allocation error\n");
+                       goto out_failure;
+               }
+               mod_dso__insert_module(self, module);
+
+               module->sections = sec_dso__new_dso("sections");
+               if (!module->sections) {
+                       fprintf(stderr, "load_module_paths: allocation error\n");
+                       goto out_failure;
+               }
+
+               module->active = mod_dso__load_sections(module);
+
+               if (module->active > 0)
+                       count++;
+       }
+
+       free(line);
+       fclose(file);
+
+       return count;
+
+out_failure:
+       return -1;
+}
+
+int mod_dso__load_modules(struct mod_dso *dso)
+{
+       int err;
+
+       err = mod_dso__load_module_paths(dso);
+
+       return err;
+}
diff --git a/tools/perf/util/module.h b/tools/perf/util/module.h
new file mode 100644 (file)
index 0000000..8a592ef
--- /dev/null
@@ -0,0 +1,53 @@
+#ifndef _PERF_MODULE_
+#define _PERF_MODULE_ 1
+
+#include <linux/types.h>
+#include "../types.h"
+#include <linux/list.h>
+#include <linux/rbtree.h>
+
+struct section {
+       struct rb_node  rb_node;
+       u64             hash;
+       u64             vma;
+       char            *name;
+       char            *path;
+};
+
+struct sec_dso {
+       struct list_head node;
+       struct rb_root   secs;
+       struct section    *(*find_section)(struct sec_dso *, const char *name);
+       char             name[0];
+};
+
+struct module {
+       struct rb_node  rb_node;
+       u64             hash;
+       char            *name;
+       char            *path;
+       struct sec_dso  *sections;
+       int             active;
+};
+
+struct mod_dso {
+       struct list_head node;
+       struct rb_root   mods;
+       struct module    *(*find_module)(struct mod_dso *, const char *name);
+       char             name[0];
+};
+
+struct sec_dso *sec_dso__new_dso(const char *name);
+void sec_dso__delete_sections(struct sec_dso *self);
+void sec_dso__delete_self(struct sec_dso *self);
+size_t sec_dso__fprintf(struct sec_dso *self, FILE *fp);
+struct section *sec_dso__find_section(struct sec_dso *self, const char *name);
+
+struct mod_dso *mod_dso__new_dso(const char *name);
+void mod_dso__delete_modules(struct mod_dso *self);
+void mod_dso__delete_self(struct mod_dso *self);
+size_t mod_dso__fprintf(struct mod_dso *self, FILE *fp);
+struct module *mod_dso__find_module(struct mod_dso *self, const char *name);
+int mod_dso__load_modules(struct mod_dso *dso);
+
+#endif /* _PERF_MODULE_ */
index a28bccae5458b3015fdbcfe0e458746d5b2db23b..1915de20dcacf28e3dd037ca5b5f462577b561b5 100644 (file)
@@ -9,7 +9,6 @@
 
 static int spawned_pager;
 
-#ifndef __MINGW32__
 static void pager_preexec(void)
 {
        /*
@@ -24,7 +23,6 @@ static void pager_preexec(void)
 
        setenv("LESS", "FRSX", 0);
 }
-#endif
 
 static const char *pager_argv[] = { "sh", "-c", NULL, NULL };
 static struct child_process pager_process;
@@ -70,9 +68,8 @@ void setup_pager(void)
        pager_argv[2] = pager;
        pager_process.argv = pager_argv;
        pager_process.in = -1;
-#ifndef __MINGW32__
        pager_process.preexec_cb = pager_preexec;
-#endif
+
        if (start_command(&pager_process))
                return;
 
index 35d04da38d6a156de599a5ca157c73fb5fe203ca..5184959e0615b7e79e38058cac0594a55a3b6fc4 100644 (file)
@@ -16,32 +16,28 @@ struct event_symbol {
        u8      type;
        u64     config;
        char    *symbol;
+       char    *alias;
 };
 
-#define C(x, y) .type = PERF_TYPE_##x, .config = PERF_COUNT_##y
-#define CR(x, y) .type = PERF_TYPE_##x, .config = y
+#define CHW(x) .type = PERF_TYPE_HARDWARE, .config = PERF_COUNT_HW_##x
+#define CSW(x) .type = PERF_TYPE_SOFTWARE, .config = PERF_COUNT_SW_##x
 
 static struct event_symbol event_symbols[] = {
-  { C(HARDWARE, HW_CPU_CYCLES),                "cpu-cycles",           },
-  { C(HARDWARE, HW_CPU_CYCLES),                "cycles",               },
-  { C(HARDWARE, HW_INSTRUCTIONS),      "instructions",         },
-  { C(HARDWARE, HW_CACHE_REFERENCES),  "cache-references",     },
-  { C(HARDWARE, HW_CACHE_MISSES),      "cache-misses",         },
-  { C(HARDWARE, HW_BRANCH_INSTRUCTIONS),"branch-instructions", },
-  { C(HARDWARE, HW_BRANCH_INSTRUCTIONS),"branches",            },
-  { C(HARDWARE, HW_BRANCH_MISSES),     "branch-misses",        },
-  { C(HARDWARE, HW_BUS_CYCLES),                "bus-cycles",           },
-
-  { C(SOFTWARE, SW_CPU_CLOCK),         "cpu-clock",            },
-  { C(SOFTWARE, SW_TASK_CLOCK),                "task-clock",           },
-  { C(SOFTWARE, SW_PAGE_FAULTS),       "page-faults",          },
-  { C(SOFTWARE, SW_PAGE_FAULTS),       "faults",               },
-  { C(SOFTWARE, SW_PAGE_FAULTS_MIN),   "minor-faults",         },
-  { C(SOFTWARE, SW_PAGE_FAULTS_MAJ),   "major-faults",         },
-  { C(SOFTWARE, SW_CONTEXT_SWITCHES),  "context-switches",     },
-  { C(SOFTWARE, SW_CONTEXT_SWITCHES),  "cs",                   },
-  { C(SOFTWARE, SW_CPU_MIGRATIONS),    "cpu-migrations",       },
-  { C(SOFTWARE, SW_CPU_MIGRATIONS),    "migrations",           },
+  { CHW(CPU_CYCLES),           "cpu-cycles",           "cycles"        },
+  { CHW(INSTRUCTIONS),         "instructions",         ""              },
+  { CHW(CACHE_REFERENCES),     "cache-references",     ""              },
+  { CHW(CACHE_MISSES),         "cache-misses",         ""              },
+  { CHW(BRANCH_INSTRUCTIONS),  "branch-instructions",  "branches"      },
+  { CHW(BRANCH_MISSES),                "branch-misses",        ""              },
+  { CHW(BUS_CYCLES),           "bus-cycles",           ""              },
+
+  { CSW(CPU_CLOCK),            "cpu-clock",            ""              },
+  { CSW(TASK_CLOCK),           "task-clock",           ""              },
+  { CSW(PAGE_FAULTS),          "page-faults",          "faults"        },
+  { CSW(PAGE_FAULTS_MIN),      "minor-faults",         ""              },
+  { CSW(PAGE_FAULTS_MAJ),      "major-faults",         ""              },
+  { CSW(CONTEXT_SWITCHES),     "context-switches",     "cs"            },
+  { CSW(CPU_MIGRATIONS),       "cpu-migrations",       "migrations"    },
 };
 
 #define __PERF_COUNTER_FIELD(config, name) \
@@ -74,26 +70,70 @@ static char *sw_event_names[] = {
 
 #define MAX_ALIASES 8
 
-static char *hw_cache [][MAX_ALIASES] = {
      { "L1-data"             , "l1-d", "l1d"                                 },
      { "L1-instruction"      , "l1-i", "l1i"                                 },
      { "L2"                  , "l2"                                          },
      { "Data-TLB"            , "dtlb", "d-tlb"                               },
      { "Instruction-TLB"     , "itlb", "i-tlb"                               },
      { "Branch"              , "bpu" , "btb", "bpc"                          },
+static char *hw_cache[][MAX_ALIASES] = {
{ "L1-d$",    "l1-d",         "l1d",          "L1-data",              },
{ "L1-i$",    "l1-i",         "l1i",          "L1-instruction",       },
{ "LLC",      "L2"                                                    },
{ "dTLB",     "d-tlb",        "Data-TLB",                             },
{ "iTLB",     "i-tlb",        "Instruction-TLB",                      },
{ "branch",   "branches",     "bpu",          "btb",          "bpc",  },
 };
 
-static char *hw_cache_op [][MAX_ALIASES] = {
      { "Load"                , "read"                                        },
      { "Store"               , "write"                                       },
      { "Prefetch"            , "speculative-read", "speculative-load"        },
+static char *hw_cache_op[][MAX_ALIASES] = {
{ "load",     "loads",        "read",                                 },
{ "store",    "stores",       "write",                                },
{ "prefetch", "prefetches",   "speculative-read", "speculative-load", },
 };
 
-static char *hw_cache_result [][MAX_ALIASES] = {
      { "Reference"           , "ops", "access"                               },
      { "Miss"                                                                },
+static char *hw_cache_result[][MAX_ALIASES] = {
{ "refs",     "Reference",    "ops",          "access",               },
{ "misses",   "miss",                                                 },
 };
 
+#define C(x)           PERF_COUNT_HW_CACHE_##x
+#define CACHE_READ     (1 << C(OP_READ))
+#define CACHE_WRITE    (1 << C(OP_WRITE))
+#define CACHE_PREFETCH (1 << C(OP_PREFETCH))
+#define COP(x)         (1 << x)
+
+/*
+ * cache operartion stat
+ * L1I : Read and prefetch only
+ * ITLB and BPU : Read-only
+ */
+static unsigned long hw_cache_stat[C(MAX)] = {
+ [C(L1D)]      = (CACHE_READ | CACHE_WRITE | CACHE_PREFETCH),
+ [C(L1I)]      = (CACHE_READ | CACHE_PREFETCH),
+ [C(LL)]       = (CACHE_READ | CACHE_WRITE | CACHE_PREFETCH),
+ [C(DTLB)]     = (CACHE_READ | CACHE_WRITE | CACHE_PREFETCH),
+ [C(ITLB)]     = (CACHE_READ),
+ [C(BPU)]      = (CACHE_READ),
+};
+
+static int is_cache_op_valid(u8 cache_type, u8 cache_op)
+{
+       if (hw_cache_stat[cache_type] & COP(cache_op))
+               return 1;       /* valid */
+       else
+               return 0;       /* invalid */
+}
+
+static char *event_cache_name(u8 cache_type, u8 cache_op, u8 cache_result)
+{
+       static char name[50];
+
+       if (cache_result) {
+               sprintf(name, "%s-%s-%s", hw_cache[cache_type][0],
+                       hw_cache_op[cache_op][0],
+                       hw_cache_result[cache_result][0]);
+       } else {
+               sprintf(name, "%s-%s", hw_cache[cache_type][0],
+                       hw_cache_op[cache_op][1]);
+       }
+
+       return name;
+}
+
 char *event_name(int counter)
 {
        u64 config = attrs[counter].config;
@@ -113,7 +153,6 @@ char *event_name(int counter)
 
        case PERF_TYPE_HW_CACHE: {
                u8 cache_type, cache_op, cache_result;
-               static char name[100];
 
                cache_type   = (config >>  0) & 0xff;
                if (cache_type > PERF_COUNT_HW_CACHE_MAX)
@@ -127,12 +166,10 @@ char *event_name(int counter)
                if (cache_result > PERF_COUNT_HW_CACHE_RESULT_MAX)
                        return "unknown-ext-hardware-cache-result";
 
-               sprintf(name, "%s-Cache-%s-%ses",
-                       hw_cache[cache_type][0],
-                       hw_cache_op[cache_op][0],
-                       hw_cache_result[cache_result][0]);
+               if (!is_cache_op_valid(cache_type, cache_op))
+                       return "invalid-cache";
 
-               return name;
+               return event_cache_name(cache_type, cache_op, cache_result);
        }
 
        case PERF_TYPE_SOFTWARE:
@@ -147,43 +184,74 @@ char *event_name(int counter)
        return "unknown";
 }
 
-static int parse_aliases(const char *str, char *names[][MAX_ALIASES], int size)
+static int parse_aliases(const char **str, char *names[][MAX_ALIASES], int size)
 {
        int i, j;
+       int n, longest = -1;
 
        for (i = 0; i < size; i++) {
-               for (j = 0; j < MAX_ALIASES; j++) {
-                       if (!names[i][j])
-                               break;
-                       if (strcasestr(str, names[i][j]))
-                               return i;
+               for (j = 0; j < MAX_ALIASES && names[i][j]; j++) {
+                       n = strlen(names[i][j]);
+                       if (n > longest && !strncasecmp(*str, names[i][j], n))
+                               longest = n;
+               }
+               if (longest > 0) {
+                       *str += longest;
+                       return i;
                }
        }
 
        return -1;
 }
 
-static int parse_generic_hw_symbols(const char *str, struct perf_counter_attr *attr)
+static int
+parse_generic_hw_event(const char **str, struct perf_counter_attr *attr)
 {
-       int cache_type = -1, cache_op = 0, cache_result = 0;
+       const char *s = *str;
+       int cache_type = -1, cache_op = -1, cache_result = -1;
 
-       cache_type = parse_aliases(str, hw_cache, PERF_COUNT_HW_CACHE_MAX);
+       cache_type = parse_aliases(&s, hw_cache, PERF_COUNT_HW_CACHE_MAX);
        /*
         * No fallback - if we cannot get a clear cache type
         * then bail out:
         */
        if (cache_type == -1)
-               return -EINVAL;
+               return 0;
+
+       while ((cache_op == -1 || cache_result == -1) && *s == '-') {
+               ++s;
+
+               if (cache_op == -1) {
+                       cache_op = parse_aliases(&s, hw_cache_op,
+                                               PERF_COUNT_HW_CACHE_OP_MAX);
+                       if (cache_op >= 0) {
+                               if (!is_cache_op_valid(cache_type, cache_op))
+                                       return 0;
+                               continue;
+                       }
+               }
+
+               if (cache_result == -1) {
+                       cache_result = parse_aliases(&s, hw_cache_result,
+                                               PERF_COUNT_HW_CACHE_RESULT_MAX);
+                       if (cache_result >= 0)
+                               continue;
+               }
+
+               /*
+                * Can't parse this as a cache op or result, so back up
+                * to the '-'.
+                */
+               --s;
+               break;
+       }
 
-       cache_op = parse_aliases(str, hw_cache_op, PERF_COUNT_HW_CACHE_OP_MAX);
        /*
         * Fall back to reads:
         */
        if (cache_op == -1)
                cache_op = PERF_COUNT_HW_CACHE_OP_READ;
 
-       cache_result = parse_aliases(str, hw_cache_result,
-                                       PERF_COUNT_HW_CACHE_RESULT_MAX);
        /*
         * Fall back to accesses:
         */
@@ -193,82 +261,154 @@ static int parse_generic_hw_symbols(const char *str, struct perf_counter_attr *a
        attr->config = cache_type | (cache_op << 8) | (cache_result << 16);
        attr->type = PERF_TYPE_HW_CACHE;
 
+       *str = s;
+       return 1;
+}
+
+static int check_events(const char *str, unsigned int i)
+{
+       int n;
+
+       n = strlen(event_symbols[i].symbol);
+       if (!strncmp(str, event_symbols[i].symbol, n))
+               return n;
+
+       n = strlen(event_symbols[i].alias);
+       if (n)
+               if (!strncmp(str, event_symbols[i].alias, n))
+                       return n;
        return 0;
 }
 
-/*
- * Each event can have multiple symbolic names.
- * Symbolic names are (almost) exactly matched.
- */
-static int parse_event_symbols(const char *str, struct perf_counter_attr *attr)
+static int
+parse_symbolic_event(const char **strp, struct perf_counter_attr *attr)
 {
-       u64 config, id;
-       int type;
+       const char *str = *strp;
        unsigned int i;
-       const char *sep, *pstr;
+       int n;
 
-       if (str[0] == 'r' && hex2u64(str + 1, &config) > 0) {
-               attr->type = PERF_TYPE_RAW;
-               attr->config = config;
+       for (i = 0; i < ARRAY_SIZE(event_symbols); i++) {
+               n = check_events(str, i);
+               if (n > 0) {
+                       attr->type = event_symbols[i].type;
+                       attr->config = event_symbols[i].config;
+                       *strp = str + n;
+                       return 1;
+               }
+       }
+       return 0;
+}
+
+static int parse_raw_event(const char **strp, struct perf_counter_attr *attr)
+{
+       const char *str = *strp;
+       u64 config;
+       int n;
 
+       if (*str != 'r')
                return 0;
+       n = hex2u64(str + 1, &config);
+       if (n > 0) {
+               *strp = str + n + 1;
+               attr->type = PERF_TYPE_RAW;
+               attr->config = config;
+               return 1;
        }
+       return 0;
+}
 
-       pstr = str;
-       sep = strchr(pstr, ':');
-       if (sep) {
-               type = atoi(pstr);
-               pstr = sep + 1;
-               id = atoi(pstr);
-               sep = strchr(pstr, ':');
-               if (sep) {
-                       pstr = sep + 1;
-                       if (strchr(pstr, 'k'))
-                               attr->exclude_user = 1;
-                       if (strchr(pstr, 'u'))
-                               attr->exclude_kernel = 1;
+static int
+parse_numeric_event(const char **strp, struct perf_counter_attr *attr)
+{
+       const char *str = *strp;
+       char *endp;
+       unsigned long type;
+       u64 config;
+
+       type = strtoul(str, &endp, 0);
+       if (endp > str && type < PERF_TYPE_MAX && *endp == ':') {
+               str = endp + 1;
+               config = strtoul(str, &endp, 0);
+               if (endp > str) {
+                       attr->type = type;
+                       attr->config = config;
+                       *strp = endp;
+                       return 1;
                }
-               attr->type = type;
-               attr->config = id;
+       }
+       return 0;
+}
+
+static int
+parse_event_modifier(const char **strp, struct perf_counter_attr *attr)
+{
+       const char *str = *strp;
+       int eu = 1, ek = 1, eh = 1;
 
+       if (*str++ != ':')
                return 0;
+       while (*str) {
+               if (*str == 'u')
+                       eu = 0;
+               else if (*str == 'k')
+                       ek = 0;
+               else if (*str == 'h')
+                       eh = 0;
+               else
+                       break;
+               ++str;
        }
+       if (str >= *strp + 2) {
+               *strp = str;
+               attr->exclude_user   = eu;
+               attr->exclude_kernel = ek;
+               attr->exclude_hv     = eh;
+               return 1;
+       }
+       return 0;
+}
 
-       for (i = 0; i < ARRAY_SIZE(event_symbols); i++) {
-               if (!strncmp(str, event_symbols[i].symbol,
-                            strlen(event_symbols[i].symbol))) {
-
-                       attr->type = event_symbols[i].type;
-                       attr->config = event_symbols[i].config;
+/*
+ * Each event can have multiple symbolic names.
+ * Symbolic names are (almost) exactly matched.
+ */
+static int parse_event_symbols(const char **str, struct perf_counter_attr *attr)
+{
+       if (!(parse_raw_event(str, attr) ||
+             parse_numeric_event(str, attr) ||
+             parse_symbolic_event(str, attr) ||
+             parse_generic_hw_event(str, attr)))
+               return 0;
 
-                       return 0;
-               }
-       }
+       parse_event_modifier(str, attr);
 
-       return parse_generic_hw_symbols(str, attr);
+       return 1;
 }
 
-int parse_events(const struct option *opt, const char *str, int unset)
+int parse_events(const struct option *opt __used, const char *str, int unset __used)
 {
        struct perf_counter_attr attr;
-       int ret;
 
-       memset(&attr, 0, sizeof(attr));
-again:
-       if (nr_counters == MAX_COUNTERS)
-               return -1;
+       for (;;) {
+               if (nr_counters == MAX_COUNTERS)
+                       return -1;
+
+               memset(&attr, 0, sizeof(attr));
+               if (!parse_event_symbols(&str, &attr))
+                       return -1;
 
-       ret = parse_event_symbols(str, &attr);
-       if (ret < 0)
-               return ret;
+               if (!(*str == 0 || *str == ',' || isspace(*str)))
+                       return -1;
 
-       attrs[nr_counters] = attr;
-       nr_counters++;
+               attrs[nr_counters] = attr;
+               nr_counters++;
 
-       str = strstr(str, ",");
-       if (str) {
-               str++;
-               goto again;
+               if (*str == 0)
+                       break;
+               if (*str == ',')
+                       ++str;
+               while (isspace(*str))
+                       ++str;
        }
 
        return 0;
@@ -288,7 +428,8 @@ static const char * const event_type_descriptors[] = {
 void print_events(void)
 {
        struct event_symbol *syms = event_symbols;
-       unsigned int i, type, prev_type = -1;
+       unsigned int i, type, op, prev_type = -1;
+       char name[40];
 
        fprintf(stderr, "\n");
        fprintf(stderr, "List of pre-defined events (to be used in -e):\n");
@@ -301,14 +442,33 @@ void print_events(void)
                if (type != prev_type)
                        fprintf(stderr, "\n");
 
-               fprintf(stderr, "  %-30s [%s]\n", syms->symbol,
+               if (strlen(syms->alias))
+                       sprintf(name, "%s OR %s", syms->symbol, syms->alias);
+               else
+                       strcpy(name, syms->symbol);
+               fprintf(stderr, "  %-40s [%s]\n", name,
                        event_type_descriptors[type]);
 
                prev_type = type;
        }
 
        fprintf(stderr, "\n");
-       fprintf(stderr, "  %-30s [raw hardware event descriptor]\n",
+       for (type = 0; type < PERF_COUNT_HW_CACHE_MAX; type++) {
+               for (op = 0; op < PERF_COUNT_HW_CACHE_OP_MAX; op++) {
+                       /* skip invalid cache type */
+                       if (!is_cache_op_valid(type, op))
+                               continue;
+
+                       for (i = 0; i < PERF_COUNT_HW_CACHE_RESULT_MAX; i++) {
+                               fprintf(stderr, "  %-40s [%s]\n",
+                                       event_cache_name(type, op, i),
+                                       event_type_descriptors[4]);
+                       }
+               }
+       }
+
+       fprintf(stderr, "\n");
+       fprintf(stderr, "  %-40s [raw hardware event descriptor]\n",
                "rNNN");
        fprintf(stderr, "\n");
 
index b3affb1658d2a1646aea5680a941c9701df27e1b..1bf67190c820041edb9e751c3aa56713394fcdce 100644 (file)
@@ -20,7 +20,8 @@ static int get_arg(struct parse_opt_ctx_t *p, const struct option *opt,
        if (p->opt) {
                *arg = p->opt;
                p->opt = NULL;
-       } else if (p->argc == 1 && (opt->flags & PARSE_OPT_LASTARG_DEFAULT)) {
+       } else if ((opt->flags & PARSE_OPT_LASTARG_DEFAULT) && (p->argc == 1 ||
+                   **(p->argv + 1) == '-')) {
                *arg = (const char *)opt->defval;
        } else if (p->argc > 1) {
                p->argc--;
@@ -485,7 +486,7 @@ int parse_options_usage(const char * const *usagestr,
 }
 
 
-int parse_opt_verbosity_cb(const struct option *opt, const char *arg,
+int parse_opt_verbosity_cb(const struct option *opt, const char *arg __used,
                           int unset)
 {
        int *target = opt->value;
index a1039a6ce0ebabdc561fc1b061e3e2ead566cc83..8aa3464c709054ba8b6275f39d3bead3873f5936 100644 (file)
@@ -90,21 +90,22 @@ struct option {
        intptr_t defval;
 };
 
-#define OPT_END()                   { OPTION_END }
-#define OPT_ARGUMENT(l, h)          { OPTION_ARGUMENT, 0, (l), NULL, NULL, (h) }
-#define OPT_GROUP(h)                { OPTION_GROUP, 0, NULL, NULL, NULL, (h) }
-#define OPT_BIT(s, l, v, h, b)      { OPTION_BIT, (s), (l), (v), NULL, (h), 0, NULL, (b) }
-#define OPT_BOOLEAN(s, l, v, h)     { OPTION_BOOLEAN, (s), (l), (v), NULL, (h) }
-#define OPT_SET_INT(s, l, v, h, i)  { OPTION_SET_INT, (s), (l), (v), NULL, (h), 0, NULL, (i) }
-#define OPT_SET_PTR(s, l, v, h, p)  { OPTION_SET_PTR, (s), (l), (v), NULL, (h), 0, NULL, (p) }
-#define OPT_INTEGER(s, l, v, h)     { OPTION_INTEGER, (s), (l), (v), NULL, (h) }
-#define OPT_LONG(s, l, v, h)        { OPTION_LONG, (s), (l), (v), NULL, (h) }
-#define OPT_STRING(s, l, v, a, h)   { OPTION_STRING,  (s), (l), (v), (a), (h) }
+#define OPT_END()                   { .type = OPTION_END }
+#define OPT_ARGUMENT(l, h)          { .type = OPTION_ARGUMENT, .long_name = (l), .help = (h) }
+#define OPT_GROUP(h)                { .type = OPTION_GROUP, .help = (h) }
+#define OPT_BIT(s, l, v, h, b)      { .type = OPTION_BIT, .short_name = (s), .long_name = (l), .value = (v), .help = (h), .defval = (b) }
+#define OPT_BOOLEAN(s, l, v, h)     { .type = OPTION_BOOLEAN, .short_name = (s), .long_name = (l), .value = (v), .help = (h) }
+#define OPT_SET_INT(s, l, v, h, i)  { .type = OPTION_SET_INT, .short_name = (s), .long_name = (l), .value = (v), .help = (h), .defval = (i) }
+#define OPT_SET_PTR(s, l, v, h, p)  { .type = OPTION_SET_PTR, .short_name = (s), .long_name = (l), .value = (v), .help = (h), .defval = (p) }
+#define OPT_INTEGER(s, l, v, h)     { .type = OPTION_INTEGER, .short_name = (s), .long_name = (l), .value = (v), .help = (h) }
+#define OPT_LONG(s, l, v, h)        { .type = OPTION_LONG, .short_name = (s), .long_name = (l), .value = (v), .help = (h) }
+#define OPT_STRING(s, l, v, a, h)   { .type = OPTION_STRING,  .short_name = (s), .long_name = (l), .value = (v), (a), .help = (h) }
 #define OPT_DATE(s, l, v, h) \
-       { OPTION_CALLBACK, (s), (l), (v), "time",(h), 0, \
-         parse_opt_approxidate_cb }
+       { .type = OPTION_CALLBACK, .short_name = (s), .long_name = (l), .value = (v), .argh = "time", .help = (h), .callback = parse_opt_approxidate_cb }
 #define OPT_CALLBACK(s, l, v, a, h, f) \
-       { OPTION_CALLBACK, (s), (l), (v), (a), (h), 0, (f) }
+       { .type = OPTION_CALLBACK, .short_name = (s), .long_name = (l), .value = (v), (a), .help = (h), .callback = (f) }
+#define OPT_CALLBACK_DEFAULT(s, l, v, a, h, f, d) \
+       { .type = OPTION_CALLBACK, .short_name = (s), .long_name = (l), .value = (v), (a), .help = (h), .callback = (f), .defval = (intptr_t)d, .flags = PARSE_OPT_LASTARG_DEFAULT }
 
 /* parse_options() will filter out the processed options and leave the
  * non-option argments in argv[].
index f18c5212bc92b8a89437a65fbdd83c0928266110..c6e5dc0dc82f632dc2b1ae44b5f8e51f707b1755 100644 (file)
@@ -162,12 +162,16 @@ static inline int sq_must_quote(char c)
        return sq_lookup[(unsigned char)c] + quote_path_fully > 0;
 }
 
-/* returns the longest prefix not needing a quote up to maxlen if positive.
-   This stops at the first \0 because it's marked as a character needing an
-   escape */
-static size_t next_quote_pos(const char *s, ssize_t maxlen)
+/*
+ * Returns the longest prefix not needing a quote up to maxlen if
+ * positive.
+ * This stops at the first \0 because it's marked as a character
+ * needing an escape.
+ */
+static ssize_t next_quote_pos(const char *s, ssize_t maxlen)
 {
-       size_t len;
+       ssize_t len;
+
        if (maxlen < 0) {
                for (len = 0; !sq_must_quote(s[len]); len++);
        } else {
@@ -192,22 +196,22 @@ static size_t next_quote_pos(const char *s, ssize_t maxlen)
 static size_t quote_c_style_counted(const char *name, ssize_t maxlen,
                                     struct strbuf *sb, FILE *fp, int no_dq)
 {
-#undef EMIT
-#define EMIT(c)                                 \
-       do {                                        \
-               if (sb) strbuf_addch(sb, (c));          \
-               if (fp) fputc((c), fp);                 \
-               count++;                                \
+#define EMIT(c)                                                        \
+       do {                                                    \
+               if (sb) strbuf_addch(sb, (c));                  \
+               if (fp) fputc((c), fp);                         \
+               count++;                                        \
        } while (0)
-#define EMITBUF(s, l)                           \
-       do {                                        \
-               int __ret;                              \
-               if (sb) strbuf_add(sb, (s), (l));       \
-               if (fp) __ret = fwrite((s), (l), 1, fp);        \
-               count += (l);                           \
+
+#define EMITBUF(s, l)                                          \
+       do {                                                    \
+               int __ret;                                      \
+               if (sb) strbuf_add(sb, (s), (l));               \
+               if (fp) __ret = fwrite((s), (l), 1, fp);        \
+               count += (l);                                   \
        } while (0)
 
-       size_t len, count = 0;
+       ssize_t len, count = 0;
        const char *p = name;
 
        for (;;) {
@@ -273,8 +277,8 @@ void write_name_quoted(const char *name, FILE *fp, int terminator)
        fputc(terminator, fp);
 }
 
-extern void write_name_quotedpfx(const char *pfx, size_t pfxlen,
-                                 const char *name, FILE *fp, int terminator)
+void write_name_quotedpfx(const char *pfx, ssize_t pfxlen,
+                         const char *name, FILE *fp, int terminator)
 {
        int needquote = 0;
 
@@ -306,7 +310,7 @@ char *quote_path_relative(const char *in, int len,
                len = strlen(in);
 
        /* "../" prefix itself does not need quoting, but "in" might. */
-       needquote = next_quote_pos(in, len) < len;
+       needquote = (next_quote_pos(in, len) < len);
        strbuf_setlen(out, 0);
        strbuf_grow(out, len);
 
index 5dfad89816db124e9b18abc7d2964997a55a329b..a5454a1d1c137ba3640add2945f1be186727d36c 100644 (file)
@@ -53,7 +53,7 @@ extern size_t quote_c_style(const char *name, struct strbuf *, FILE *, int no_dq
 extern void quote_two_c_style(struct strbuf *, const char *, const char *, int);
 
 extern void write_name_quoted(const char *name, FILE *, int terminator);
-extern void write_name_quotedpfx(const char *pfx, size_t pfxlen,
+extern void write_name_quotedpfx(const char *pfx, ssize_t pfxlen,
                                  const char *name, FILE *, int terminator);
 
 /* quote path as relative to the given prefix */
diff --git a/tools/perf/util/rbtree.c b/tools/perf/util/rbtree.c
deleted file mode 100644 (file)
index b15ba9c..0000000
+++ /dev/null
@@ -1,383 +0,0 @@
-/*
-  Red Black Trees
-  (C) 1999  Andrea Arcangeli <andrea@suse.de>
-  (C) 2002  David Woodhouse <dwmw2@infradead.org>
-  
-  This program is free software; you can redistribute it and/or modify
-  it under the terms of the GNU General Public License as published by
-  the Free Software Foundation; either version 2 of the License, or
-  (at your option) any later version.
-
-  This program is distributed in the hope that it will be useful,
-  but WITHOUT ANY WARRANTY; without even the implied warranty of
-  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-  GNU General Public License for more details.
-
-  You should have received a copy of the GNU General Public License
-  along with this program; if not, write to the Free Software
-  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
-
-  linux/lib/rbtree.c
-*/
-
-#include "rbtree.h"
-
-static void __rb_rotate_left(struct rb_node *node, struct rb_root *root)
-{
-       struct rb_node *right = node->rb_right;
-       struct rb_node *parent = rb_parent(node);
-
-       if ((node->rb_right = right->rb_left))
-               rb_set_parent(right->rb_left, node);
-       right->rb_left = node;
-
-       rb_set_parent(right, parent);
-
-       if (parent)
-       {
-               if (node == parent->rb_left)
-                       parent->rb_left = right;
-               else
-                       parent->rb_right = right;
-       }
-       else
-               root->rb_node = right;
-       rb_set_parent(node, right);
-}
-
-static void __rb_rotate_right(struct rb_node *node, struct rb_root *root)
-{
-       struct rb_node *left = node->rb_left;
-       struct rb_node *parent = rb_parent(node);
-
-       if ((node->rb_left = left->rb_right))
-               rb_set_parent(left->rb_right, node);
-       left->rb_right = node;
-
-       rb_set_parent(left, parent);
-
-       if (parent)
-       {
-               if (node == parent->rb_right)
-                       parent->rb_right = left;
-               else
-                       parent->rb_left = left;
-       }
-       else
-               root->rb_node = left;
-       rb_set_parent(node, left);
-}
-
-void rb_insert_color(struct rb_node *node, struct rb_root *root)
-{
-       struct rb_node *parent, *gparent;
-
-       while ((parent = rb_parent(node)) && rb_is_red(parent))
-       {
-               gparent = rb_parent(parent);
-
-               if (parent == gparent->rb_left)
-               {
-                       {
-                               register struct rb_node *uncle = gparent->rb_right;
-                               if (uncle && rb_is_red(uncle))
-                               {
-                                       rb_set_black(uncle);
-                                       rb_set_black(parent);
-                                       rb_set_red(gparent);
-                                       node = gparent;
-                                       continue;
-                               }
-                       }
-
-                       if (parent->rb_right == node)
-                       {
-                               register struct rb_node *tmp;
-                               __rb_rotate_left(parent, root);
-                               tmp = parent;
-                               parent = node;
-                               node = tmp;
-                       }
-
-                       rb_set_black(parent);
-                       rb_set_red(gparent);
-                       __rb_rotate_right(gparent, root);
-               } else {
-                       {
-                               register struct rb_node *uncle = gparent->rb_left;
-                               if (uncle && rb_is_red(uncle))
-                               {
-                                       rb_set_black(uncle);
-                                       rb_set_black(parent);
-                                       rb_set_red(gparent);
-                                       node = gparent;
-                                       continue;
-                               }
-                       }
-
-                       if (parent->rb_left == node)
-                       {
-                               register struct rb_node *tmp;
-                               __rb_rotate_right(parent, root);
-                               tmp = parent;
-                               parent = node;
-                               node = tmp;
-                       }
-
-                       rb_set_black(parent);
-                       rb_set_red(gparent);
-                       __rb_rotate_left(gparent, root);
-               }
-       }
-
-       rb_set_black(root->rb_node);
-}
-
-static void __rb_erase_color(struct rb_node *node, struct rb_node *parent,
-                            struct rb_root *root)
-{
-       struct rb_node *other;
-
-       while ((!node || rb_is_black(node)) && node != root->rb_node)
-       {
-               if (parent->rb_left == node)
-               {
-                       other = parent->rb_right;
-                       if (rb_is_red(other))
-                       {
-                               rb_set_black(other);
-                               rb_set_red(parent);
-                               __rb_rotate_left(parent, root);
-                               other = parent->rb_right;
-                       }
-                       if ((!other->rb_left || rb_is_black(other->rb_left)) &&
-                           (!other->rb_right || rb_is_black(other->rb_right)))
-                       {
-                               rb_set_red(other);
-                               node = parent;
-                               parent = rb_parent(node);
-                       }
-                       else
-                       {
-                               if (!other->rb_right || rb_is_black(other->rb_right))
-                               {
-                                       rb_set_black(other->rb_left);
-                                       rb_set_red(other);
-                                       __rb_rotate_right(other, root);
-                                       other = parent->rb_right;
-                               }
-                               rb_set_color(other, rb_color(parent));
-                               rb_set_black(parent);
-                               rb_set_black(other->rb_right);
-                               __rb_rotate_left(parent, root);
-                               node = root->rb_node;
-                               break;
-                       }
-               }
-               else
-               {
-                       other = parent->rb_left;
-                       if (rb_is_red(other))
-                       {
-                               rb_set_black(other);
-                               rb_set_red(parent);
-                               __rb_rotate_right(parent, root);
-                               other = parent->rb_left;
-                       }
-                       if ((!other->rb_left || rb_is_black(other->rb_left)) &&
-                           (!other->rb_right || rb_is_black(other->rb_right)))
-                       {
-                               rb_set_red(other);
-                               node = parent;
-                               parent = rb_parent(node);
-                       }
-                       else
-                       {
-                               if (!other->rb_left || rb_is_black(other->rb_left))
-                               {
-                                       rb_set_black(other->rb_right);
-                                       rb_set_red(other);
-                                       __rb_rotate_left(other, root);
-                                       other = parent->rb_left;
-                               }
-                               rb_set_color(other, rb_color(parent));
-                               rb_set_black(parent);
-                               rb_set_black(other->rb_left);
-                               __rb_rotate_right(parent, root);
-                               node = root->rb_node;
-                               break;
-                       }
-               }
-       }
-       if (node)
-               rb_set_black(node);
-}
-
-void rb_erase(struct rb_node *node, struct rb_root *root)
-{
-       struct rb_node *child, *parent;
-       int color;
-
-       if (!node->rb_left)
-               child = node->rb_right;
-       else if (!node->rb_right)
-               child = node->rb_left;
-       else
-       {
-               struct rb_node *old = node, *left;
-
-               node = node->rb_right;
-               while ((left = node->rb_left) != NULL)
-                       node = left;
-               child = node->rb_right;
-               parent = rb_parent(node);
-               color = rb_color(node);
-
-               if (child)
-                       rb_set_parent(child, parent);
-               if (parent == old) {
-                       parent->rb_right = child;
-                       parent = node;
-               } else
-                       parent->rb_left = child;
-
-               node->rb_parent_color = old->rb_parent_color;
-               node->rb_right = old->rb_right;
-               node->rb_left = old->rb_left;
-
-               if (rb_parent(old))
-               {
-                       if (rb_parent(old)->rb_left == old)
-                               rb_parent(old)->rb_left = node;
-                       else
-                               rb_parent(old)->rb_right = node;
-               } else
-                       root->rb_node = node;
-
-               rb_set_parent(old->rb_left, node);
-               if (old->rb_right)
-                       rb_set_parent(old->rb_right, node);
-               goto color;
-       }
-
-       parent = rb_parent(node);
-       color = rb_color(node);
-
-       if (child)
-               rb_set_parent(child, parent);
-       if (parent)
-       {
-               if (parent->rb_left == node)
-                       parent->rb_left = child;
-               else
-                       parent->rb_right = child;
-       }
-       else
-               root->rb_node = child;
-
- color:
-       if (color == RB_BLACK)
-               __rb_erase_color(child, parent, root);
-}
-
-/*
- * This function returns the first node (in sort order) of the tree.
- */
-struct rb_node *rb_first(const struct rb_root *root)
-{
-       struct rb_node  *n;
-
-       n = root->rb_node;
-       if (!n)
-               return NULL;
-       while (n->rb_left)
-               n = n->rb_left;
-       return n;
-}
-
-struct rb_node *rb_last(const struct rb_root *root)
-{
-       struct rb_node  *n;
-
-       n = root->rb_node;
-       if (!n)
-               return NULL;
-       while (n->rb_right)
-               n = n->rb_right;
-       return n;
-}
-
-struct rb_node *rb_next(const struct rb_node *node)
-{
-       struct rb_node *parent;
-
-       if (rb_parent(node) == node)
-               return NULL;
-
-       /* If we have a right-hand child, go down and then left as far
-          as we can. */
-       if (node->rb_right) {
-               node = node->rb_right; 
-               while (node->rb_left)
-                       node=node->rb_left;
-               return (struct rb_node *)node;
-       }
-
-       /* No right-hand children.  Everything down and left is
-          smaller than us, so any 'next' node must be in the general
-          direction of our parent. Go up the tree; any time the
-          ancestor is a right-hand child of its parent, keep going
-          up. First time it's a left-hand child of its parent, said
-          parent is our 'next' node. */
-       while ((parent = rb_parent(node)) && node == parent->rb_right)
-               node = parent;
-
-       return parent;
-}
-
-struct rb_node *rb_prev(const struct rb_node *node)
-{
-       struct rb_node *parent;
-
-       if (rb_parent(node) == node)
-               return NULL;
-
-       /* If we have a left-hand child, go down and then right as far
-          as we can. */
-       if (node->rb_left) {
-               node = node->rb_left; 
-               while (node->rb_right)
-                       node=node->rb_right;
-               return (struct rb_node *)node;
-       }
-
-       /* No left-hand children. Go up till we find an ancestor which
-          is a right-hand child of its parent */
-       while ((parent = rb_parent(node)) && node == parent->rb_left)
-               node = parent;
-
-       return parent;
-}
-
-void rb_replace_node(struct rb_node *victim, struct rb_node *new,
-                    struct rb_root *root)
-{
-       struct rb_node *parent = rb_parent(victim);
-
-       /* Set the surrounding nodes to point to the replacement */
-       if (parent) {
-               if (victim == parent->rb_left)
-                       parent->rb_left = new;
-               else
-                       parent->rb_right = new;
-       } else {
-               root->rb_node = new;
-       }
-       if (victim->rb_left)
-               rb_set_parent(victim->rb_left, new);
-       if (victim->rb_right)
-               rb_set_parent(victim->rb_right, new);
-
-       /* Copy the pointers/colour from the victim to the replacement */
-       *new = *victim;
-}
diff --git a/tools/perf/util/rbtree.h b/tools/perf/util/rbtree.h
deleted file mode 100644 (file)
index 6bdc488..0000000
+++ /dev/null
@@ -1,171 +0,0 @@
-/*
-  Red Black Trees
-  (C) 1999  Andrea Arcangeli <andrea@suse.de>
-  
-  This program is free software; you can redistribute it and/or modify
-  it under the terms of the GNU General Public License as published by
-  the Free Software Foundation; either version 2 of the License, or
-  (at your option) any later version.
-
-  This program is distributed in the hope that it will be useful,
-  but WITHOUT ANY WARRANTY; without even the implied warranty of
-  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-  GNU General Public License for more details.
-
-  You should have received a copy of the GNU General Public License
-  along with this program; if not, write to the Free Software
-  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
-
-  linux/include/linux/rbtree.h
-
-  To use rbtrees you'll have to implement your own insert and search cores.
-  This will avoid us to use callbacks and to drop drammatically performances.
-  I know it's not the cleaner way,  but in C (not in C++) to get
-  performances and genericity...
-
-  Some example of insert and search follows here. The search is a plain
-  normal search over an ordered tree. The insert instead must be implemented
-  int two steps: as first thing the code must insert the element in
-  order as a red leaf in the tree, then the support library function
-  rb_insert_color() must be called. Such function will do the
-  not trivial work to rebalance the rbtree if necessary.
-
------------------------------------------------------------------------
-static inline struct page * rb_search_page_cache(struct inode * inode,
-                                                unsigned long offset)
-{
-       struct rb_node * n = inode->i_rb_page_cache.rb_node;
-       struct page * page;
-
-       while (n)
-       {
-               page = rb_entry(n, struct page, rb_page_cache);
-
-               if (offset < page->offset)
-                       n = n->rb_left;
-               else if (offset > page->offset)
-                       n = n->rb_right;
-               else
-                       return page;
-       }
-       return NULL;
-}
-
-static inline struct page * __rb_insert_page_cache(struct inode * inode,
-                                                  unsigned long offset,
-                                                  struct rb_node * node)
-{
-       struct rb_node ** p = &inode->i_rb_page_cache.rb_node;
-       struct rb_node * parent = NULL;
-       struct page * page;
-
-       while (*p)
-       {
-               parent = *p;
-               page = rb_entry(parent, struct page, rb_page_cache);
-
-               if (offset < page->offset)
-                       p = &(*p)->rb_left;
-               else if (offset > page->offset)
-                       p = &(*p)->rb_right;
-               else
-                       return page;
-       }
-
-       rb_link_node(node, parent, p);
-
-       return NULL;
-}
-
-static inline struct page * rb_insert_page_cache(struct inode * inode,
-                                                unsigned long offset,
-                                                struct rb_node * node)
-{
-       struct page * ret;
-       if ((ret = __rb_insert_page_cache(inode, offset, node)))
-               goto out;
-       rb_insert_color(node, &inode->i_rb_page_cache);
- out:
-       return ret;
-}
------------------------------------------------------------------------
-*/
-
-#ifndef        _LINUX_RBTREE_H
-#define        _LINUX_RBTREE_H
-
-#include <stddef.h>
-
-/**
- * container_of - cast a member of a structure out to the containing structure
- * @ptr:       the pointer to the member.
- * @type:      the type of the container struct this is embedded in.
- * @member:    the name of the member within the struct.
- *
- */
-#define container_of(ptr, type, member) ({                     \
-       const typeof( ((type *)0)->member ) *__mptr = (ptr);    \
-       (type *)( (char *)__mptr - offsetof(type,member) );})
-
-struct rb_node
-{
-       unsigned long  rb_parent_color;
-#define        RB_RED          0
-#define        RB_BLACK        1
-       struct rb_node *rb_right;
-       struct rb_node *rb_left;
-} __attribute__((aligned(sizeof(long))));
-    /* The alignment might seem pointless, but allegedly CRIS needs it */
-
-struct rb_root
-{
-       struct rb_node *rb_node;
-};
-
-
-#define rb_parent(r)   ((struct rb_node *)((r)->rb_parent_color & ~3))
-#define rb_color(r)   ((r)->rb_parent_color & 1)
-#define rb_is_red(r)   (!rb_color(r))
-#define rb_is_black(r) rb_color(r)
-#define rb_set_red(r)  do { (r)->rb_parent_color &= ~1; } while (0)
-#define rb_set_black(r)  do { (r)->rb_parent_color |= 1; } while (0)
-
-static inline void rb_set_parent(struct rb_node *rb, struct rb_node *p)
-{
-       rb->rb_parent_color = (rb->rb_parent_color & 3) | (unsigned long)p;
-}
-static inline void rb_set_color(struct rb_node *rb, int color)
-{
-       rb->rb_parent_color = (rb->rb_parent_color & ~1) | color;
-}
-
-#define RB_ROOT        (struct rb_root) { NULL, }
-#define        rb_entry(ptr, type, member) container_of(ptr, type, member)
-
-#define RB_EMPTY_ROOT(root)    ((root)->rb_node == NULL)
-#define RB_EMPTY_NODE(node)    (rb_parent(node) == node)
-#define RB_CLEAR_NODE(node)    (rb_set_parent(node, node))
-
-extern void rb_insert_color(struct rb_node *, struct rb_root *);
-extern void rb_erase(struct rb_node *, struct rb_root *);
-
-/* Find logical next and previous nodes in a tree */
-extern struct rb_node *rb_next(const struct rb_node *);
-extern struct rb_node *rb_prev(const struct rb_node *);
-extern struct rb_node *rb_first(const struct rb_root *);
-extern struct rb_node *rb_last(const struct rb_root *);
-
-/* Fast replacement of a single node without remove/rebalance/add/rebalance */
-extern void rb_replace_node(struct rb_node *victim, struct rb_node *new, 
-                           struct rb_root *root);
-
-static inline void rb_link_node(struct rb_node * node, struct rb_node * parent,
-                               struct rb_node ** rb_link)
-{
-       node->rb_parent_color = (unsigned long )parent;
-       node->rb_left = node->rb_right = NULL;
-
-       *rb_link = node;
-}
-
-#endif /* _LINUX_RBTREE_H */
index b2f5e854f40adf807eab34876a2b475bff31cf19..a3935343091ab0a8cac2759b0765a916feaeae19 100644 (file)
@@ -65,7 +65,6 @@ int start_command(struct child_process *cmd)
                cmd->err = fderr[0];
        }
 
-#ifndef __MINGW32__
        fflush(NULL);
        cmd->pid = fork();
        if (!cmd->pid) {
@@ -118,71 +117,6 @@ int start_command(struct child_process *cmd)
                }
                exit(127);
        }
-#else
-       int s0 = -1, s1 = -1, s2 = -1;  /* backups of stdin, stdout, stderr */
-       const char **sargv = cmd->argv;
-       char **env = environ;
-
-       if (cmd->no_stdin) {
-               s0 = dup(0);
-               dup_devnull(0);
-       } else if (need_in) {
-               s0 = dup(0);
-               dup2(fdin[0], 0);
-       } else if (cmd->in) {
-               s0 = dup(0);
-               dup2(cmd->in, 0);
-       }
-
-       if (cmd->no_stderr) {
-               s2 = dup(2);
-               dup_devnull(2);
-       } else if (need_err) {
-               s2 = dup(2);
-               dup2(fderr[1], 2);
-       }
-
-       if (cmd->no_stdout) {
-               s1 = dup(1);
-               dup_devnull(1);
-       } else if (cmd->stdout_to_stderr) {
-               s1 = dup(1);
-               dup2(2, 1);
-       } else if (need_out) {
-               s1 = dup(1);
-               dup2(fdout[1], 1);
-       } else if (cmd->out > 1) {
-               s1 = dup(1);
-               dup2(cmd->out, 1);
-       }
-
-       if (cmd->dir)
-               die("chdir in start_command() not implemented");
-       if (cmd->env) {
-               env = copy_environ();
-               for (; *cmd->env; cmd->env++)
-                       env = env_setenv(env, *cmd->env);
-       }
-
-       if (cmd->perf_cmd) {
-               cmd->argv = prepare_perf_cmd(cmd->argv);
-       }
-
-       cmd->pid = mingw_spawnvpe(cmd->argv[0], cmd->argv, env);
-
-       if (cmd->env)
-               free_environ(env);
-       if (cmd->perf_cmd)
-               free(cmd->argv);
-
-       cmd->argv = sargv;
-       if (s0 >= 0)
-               dup2(s0, 0), close(s0);
-       if (s1 >= 0)
-               dup2(s1, 1), close(s1);
-       if (s2 >= 0)
-               dup2(s2, 2), close(s2);
-#endif
 
        if (cmd->pid < 0) {
                int err = errno;
@@ -288,14 +222,6 @@ int run_command_v_opt_cd_env(const char **argv, int opt, const char *dir, const
        return run_command(&cmd);
 }
 
-#ifdef __MINGW32__
-static __stdcall unsigned run_thread(void *data)
-{
-       struct async *async = data;
-       return async->proc(async->fd_for_proc, async->data);
-}
-#endif
-
 int start_async(struct async *async)
 {
        int pipe_out[2];
@@ -304,7 +230,6 @@ int start_async(struct async *async)
                return error("cannot create pipe: %s", strerror(errno));
        async->out = pipe_out[0];
 
-#ifndef __MINGW32__
        /* Flush stdio before fork() to avoid cloning buffers */
        fflush(NULL);
 
@@ -319,33 +244,17 @@ int start_async(struct async *async)
                exit(!!async->proc(pipe_out[1], async->data));
        }
        close(pipe_out[1]);
-#else
-       async->fd_for_proc = pipe_out[1];
-       async->tid = (HANDLE) _beginthreadex(NULL, 0, run_thread, async, 0, NULL);
-       if (!async->tid) {
-               error("cannot create thread: %s", strerror(errno));
-               close_pair(pipe_out);
-               return -1;
-       }
-#endif
+
        return 0;
 }
 
 int finish_async(struct async *async)
 {
-#ifndef __MINGW32__
        int ret = 0;
 
        if (wait_or_whine(async->pid))
                ret = error("waitpid (async) failed");
-#else
-       DWORD ret = 0;
-       if (WaitForSingleObject(async->tid, INFINITE) != WAIT_OBJECT_0)
-               ret = error("waiting for thread failed: %lu", GetLastError());
-       else if (!GetExitCodeThread(async->tid, &ret))
-               ret = error("cannot get thread exit code: %lu", GetLastError());
-       CloseHandle(async->tid);
-#endif
+
        return ret;
 }
 
index 328289f236695fc909375378090f2783965d5582..cc1837deba88af6371785e4721f632529d19face 100644 (file)
@@ -79,12 +79,7 @@ struct async {
        int (*proc)(int fd, void *data);
        void *data;
        int out;        /* caller reads from here and closes it */
-#ifndef __MINGW32__
        pid_t pid;
-#else
-       HANDLE tid;
-       int fd_for_proc;
-#endif
 };
 
 int start_async(struct async *async);
index eaba0930680233a6f682c2d7710a2eb7fa9daac8..5249d5a1b0c203176b08fce72003ea90ce114e74 100644 (file)
@@ -16,7 +16,7 @@ int prefixcmp(const char *str, const char *prefix)
  */
 char strbuf_slopbuf[1];
 
-void strbuf_init(struct strbuf *sb, size_t hint)
+void strbuf_init(struct strbuf *sb, ssize_t hint)
 {
        sb->alloc = sb->len = 0;
        sb->buf = strbuf_slopbuf;
@@ -92,7 +92,8 @@ void strbuf_ltrim(struct strbuf *sb)
 
 void strbuf_tolower(struct strbuf *sb)
 {
-       int i;
+       unsigned int i;
+
        for (i = 0; i < sb->len; i++)
                sb->buf[i] = tolower(sb->buf[i]);
 }
@@ -259,12 +260,12 @@ size_t strbuf_fread(struct strbuf *sb, size_t size, FILE *f)
        res = fread(sb->buf + sb->len, 1, size, f);
        if (res > 0)
                strbuf_setlen(sb, sb->len + res);
-       else if (res < 0 && oldalloc == 0)
+       else if (oldalloc == 0)
                strbuf_release(sb);
        return res;
 }
 
-ssize_t strbuf_read(struct strbuf *sb, int fd, size_t hint)
+ssize_t strbuf_read(struct strbuf *sb, int fd, ssize_t hint)
 {
        size_t oldlen = sb->len;
        size_t oldalloc = sb->alloc;
@@ -293,7 +294,7 @@ ssize_t strbuf_read(struct strbuf *sb, int fd, size_t hint)
 
 #define STRBUF_MAXLINK (2*PATH_MAX)
 
-int strbuf_readlink(struct strbuf *sb, const char *path, size_t hint)
+int strbuf_readlink(struct strbuf *sb, const char *path, ssize_t hint)
 {
        size_t oldalloc = sb->alloc;
 
@@ -301,7 +302,7 @@ int strbuf_readlink(struct strbuf *sb, const char *path, size_t hint)
                hint = 32;
 
        while (hint < STRBUF_MAXLINK) {
-               int len;
+               ssize_t len;
 
                strbuf_grow(sb, hint);
                len = readlink(path, sb->buf, hint);
@@ -343,7 +344,7 @@ int strbuf_getline(struct strbuf *sb, FILE *fp, int term)
        return 0;
 }
 
-int strbuf_read_file(struct strbuf *sb, const char *path, size_t hint)
+int strbuf_read_file(struct strbuf *sb, const char *path, ssize_t hint)
 {
        int fd, len;
 
index 9ee908a3ec5d4d5329385bc10cdd676f703c0c1f..d2aa86c014c1b9a3882cfd924affaa116a122e79 100644 (file)
@@ -50,7 +50,7 @@ struct strbuf {
 #define STRBUF_INIT  { 0, 0, strbuf_slopbuf }
 
 /*----- strbuf life cycle -----*/
-extern void strbuf_init(struct strbuf *, size_t);
+extern void strbuf_init(struct strbuf *buf, ssize_t hint);
 extern void strbuf_release(struct strbuf *);
 extern char *strbuf_detach(struct strbuf *, size_t *);
 extern void strbuf_attach(struct strbuf *, void *, size_t, size_t);
@@ -61,7 +61,7 @@ static inline void strbuf_swap(struct strbuf *a, struct strbuf *b) {
 }
 
 /*----- strbuf size related -----*/
-static inline size_t strbuf_avail(const struct strbuf *sb) {
+static inline ssize_t strbuf_avail(const struct strbuf *sb) {
        return sb->alloc ? sb->alloc - sb->len - 1 : 0;
 }
 
@@ -122,9 +122,9 @@ extern void strbuf_addf(struct strbuf *sb, const char *fmt, ...);
 
 extern size_t strbuf_fread(struct strbuf *, size_t, FILE *);
 /* XXX: if read fails, any partial read is undone */
-extern ssize_t strbuf_read(struct strbuf *, int fd, size_t hint);
-extern int strbuf_read_file(struct strbuf *sb, const char *path, size_t hint);
-extern int strbuf_readlink(struct strbuf *sb, const char *path, size_t hint);
+extern ssize_t strbuf_read(struct strbuf *, int fd, ssize_t hint);
+extern int strbuf_read_file(struct strbuf *sb, const char *path, ssize_t hint);
+extern int strbuf_readlink(struct strbuf *sb, const char *path, ssize_t hint);
 
 extern int strbuf_getline(struct strbuf *, FILE *, int);
 
index 37b03255b425f4ac0e055e4ca8532050b40564e5..3dca2f654cd06a31e19728fbc0d10ddb98ea4d27 100644 (file)
@@ -1,7 +1,7 @@
 #ifndef _PERF_STRING_H_
 #define _PERF_STRING_H_
 
-#include "../types.h"
+#include "types.h"
 
 int hex2u64(const char *ptr, u64 *val);
 
diff --git a/tools/perf/util/strlist.c b/tools/perf/util/strlist.c
new file mode 100644 (file)
index 0000000..025a78e
--- /dev/null
@@ -0,0 +1,184 @@
+/*
+ * (c) 2009 Arnaldo Carvalho de Melo <acme@redhat.com>
+ *
+ * Licensed under the GPLv2.
+ */
+
+#include "strlist.h"
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+static struct str_node *str_node__new(const char *s, bool dupstr)
+{
+       struct str_node *self = malloc(sizeof(*self));
+
+       if (self != NULL) {
+               if (dupstr) {
+                       s = strdup(s);
+                       if (s == NULL)
+                               goto out_delete;
+               }
+               self->s = s;
+       }
+
+       return self;
+
+out_delete:
+       free(self);
+       return NULL;
+}
+
+static void str_node__delete(struct str_node *self, bool dupstr)
+{
+       if (dupstr)
+               free((void *)self->s);
+       free(self);
+}
+
+int strlist__add(struct strlist *self, const char *new_entry)
+{
+       struct rb_node **p = &self->entries.rb_node;
+       struct rb_node *parent = NULL;
+       struct str_node *sn;
+
+       while (*p != NULL) {
+               int rc;
+
+               parent = *p;
+               sn = rb_entry(parent, struct str_node, rb_node);
+               rc = strcmp(sn->s, new_entry);
+
+               if (rc > 0)
+                       p = &(*p)->rb_left;
+               else if (rc < 0)
+                       p = &(*p)->rb_right;
+               else
+                       return -EEXIST;
+       }
+
+       sn = str_node__new(new_entry, self->dupstr);
+       if (sn == NULL)
+               return -ENOMEM;
+
+       rb_link_node(&sn->rb_node, parent, p);
+       rb_insert_color(&sn->rb_node, &self->entries);
+
+       return 0;
+}
+
+int strlist__load(struct strlist *self, const char *filename)
+{
+       char entry[1024];
+       int err;
+       FILE *fp = fopen(filename, "r");
+
+       if (fp == NULL)
+               return errno;
+
+       while (fgets(entry, sizeof(entry), fp) != NULL) {
+               const size_t len = strlen(entry);
+
+               if (len == 0)
+                       continue;
+               entry[len - 1] = '\0';
+
+               err = strlist__add(self, entry);
+               if (err != 0)
+                       goto out;
+       }
+
+       err = 0;
+out:
+       fclose(fp);
+       return err;
+}
+
+void strlist__remove(struct strlist *self, struct str_node *sn)
+{
+       rb_erase(&sn->rb_node, &self->entries);
+       str_node__delete(sn, self->dupstr);
+}
+
+bool strlist__has_entry(struct strlist *self, const char *entry)
+{
+       struct rb_node **p = &self->entries.rb_node;
+       struct rb_node *parent = NULL;
+
+       while (*p != NULL) {
+               struct str_node *sn;
+               int rc;
+
+               parent = *p;
+               sn = rb_entry(parent, struct str_node, rb_node);
+               rc = strcmp(sn->s, entry);
+
+               if (rc > 0)
+                       p = &(*p)->rb_left;
+               else if (rc < 0)
+                       p = &(*p)->rb_right;
+               else
+                       return true;
+       }
+
+       return false;
+}
+
+static int strlist__parse_list_entry(struct strlist *self, const char *s)
+{
+       if (strncmp(s, "file://", 7) == 0)
+               return strlist__load(self, s + 7);
+
+       return strlist__add(self, s);
+}
+
+int strlist__parse_list(struct strlist *self, const char *s)
+{
+       char *sep;
+       int err;
+
+       while ((sep = strchr(s, ',')) != NULL) {
+               *sep = '\0';
+               err = strlist__parse_list_entry(self, s);
+               *sep = ',';
+               if (err != 0)
+                       return err;
+               s = sep + 1;
+       }
+
+       return *s ? strlist__parse_list_entry(self, s) : 0;
+}
+
+struct strlist *strlist__new(bool dupstr, const char *slist)
+{
+       struct strlist *self = malloc(sizeof(*self));
+
+       if (self != NULL) {
+               self->entries = RB_ROOT;
+               self->dupstr = dupstr;
+               if (slist && strlist__parse_list(self, slist) != 0)
+                       goto out_error;
+       }
+
+       return self;
+out_error:
+       free(self);
+       return NULL;
+}
+
+void strlist__delete(struct strlist *self)
+{
+       if (self != NULL) {
+               struct str_node *pos;
+               struct rb_node *next = rb_first(&self->entries);
+
+               while (next) {
+                       pos = rb_entry(next, struct str_node, rb_node);
+                       next = rb_next(&pos->rb_node);
+                       strlist__remove(self, pos);
+               }
+               self->entries = RB_ROOT;
+               free(self);
+       }
+}
diff --git a/tools/perf/util/strlist.h b/tools/perf/util/strlist.h
new file mode 100644 (file)
index 0000000..2fdcfee
--- /dev/null
@@ -0,0 +1,32 @@
+#ifndef STRLIST_H_
+#define STRLIST_H_
+
+#include <linux/rbtree.h>
+#include <stdbool.h>
+
+struct str_node {
+       struct rb_node rb_node;
+       const char     *s;
+};
+
+struct strlist {
+       struct rb_root entries;
+       bool dupstr;
+};
+
+struct strlist *strlist__new(bool dupstr, const char *slist);
+void strlist__delete(struct strlist *self);
+
+void strlist__remove(struct strlist *self, struct str_node *sn);
+int strlist__load(struct strlist *self, const char *filename);
+int strlist__add(struct strlist *self, const char *str);
+
+bool strlist__has_entry(struct strlist *self, const char *entry);
+
+static inline bool strlist__empty(const struct strlist *self)
+{
+       return rb_first(&self->entries) == NULL;
+}
+
+int strlist__parse_list(struct strlist *self, const char *s);
+#endif /* STRLIST_H_ */
index 86e14375e74e3a4990f536bc8baebb913b86e75b..4683b67b5ee4316cfb9a7266da799194bb4ad957 100644 (file)
@@ -35,7 +35,7 @@ static struct symbol *symbol__new(u64 start, u64 len,
                self = ((void *)self) + priv_size;
        }
        self->start = start;
-       self->end   = start + len - 1;
+       self->end   = len ? start + len - 1 : start;
        memcpy(self->name, name, namelen);
 
        return self;
@@ -48,8 +48,12 @@ static void symbol__delete(struct symbol *self, unsigned int priv_size)
 
 static size_t symbol__fprintf(struct symbol *self, FILE *fp)
 {
-       return fprintf(fp, " %llx-%llx %s\n",
+       if (!self->module)
+               return fprintf(fp, " %llx-%llx %s\n",
                       self->start, self->end, self->name);
+       else
+               return fprintf(fp, " %llx-%llx %s \t[%s]\n",
+                      self->start, self->end, self->name, self->module->name);
 }
 
 struct dso *dso__new(const char *name, unsigned int sym_priv_size)
@@ -146,6 +150,7 @@ static int dso__load_kallsyms(struct dso *self, symbol_filter_t filter, int verb
        char *line = NULL;
        size_t n;
        FILE *file = fopen("/proc/kallsyms", "r");
+       int count = 0;
 
        if (file == NULL)
                goto out_failure;
@@ -188,8 +193,10 @@ static int dso__load_kallsyms(struct dso *self, symbol_filter_t filter, int verb
 
                if (filter && filter(self, sym))
                        symbol__delete(sym, self->sym_priv_size);
-               else
+               else {
                        dso__insert_symbol(self, sym);
+                       count++;
+               }
        }
 
        /*
@@ -212,7 +219,7 @@ static int dso__load_kallsyms(struct dso *self, symbol_filter_t filter, int verb
        free(line);
        fclose(file);
 
-       return 0;
+       return count;
 
 out_delete_line:
        free(line);
@@ -307,6 +314,26 @@ static inline int elf_sym__is_function(const GElf_Sym *sym)
               sym->st_size != 0;
 }
 
+static inline int elf_sym__is_label(const GElf_Sym *sym)
+{
+       return elf_sym__type(sym) == STT_NOTYPE &&
+               sym->st_name != 0 &&
+               sym->st_shndx != SHN_UNDEF &&
+               sym->st_shndx != SHN_ABS;
+}
+
+static inline const char *elf_sec__name(const GElf_Shdr *shdr,
+                                       const Elf_Data *secstrs)
+{
+       return secstrs->d_buf + shdr->sh_name;
+}
+
+static inline int elf_sec__is_text(const GElf_Shdr *shdr,
+                                       const Elf_Data *secstrs)
+{
+       return strstr(elf_sec__name(shdr, secstrs), "text") != NULL;
+}
+
 static inline const char *elf_sym__name(const GElf_Sym *sym,
                                        const Elf_Data *symstrs)
 {
@@ -448,9 +475,9 @@ static int dso__synthesize_plt_symbols(struct  dso *self, Elf *elf,
 }
 
 static int dso__load_sym(struct dso *self, int fd, const char *name,
-                        symbol_filter_t filter, int verbose)
+                        symbol_filter_t filter, int verbose, struct module *mod)
 {
-       Elf_Data *symstrs;
+       Elf_Data *symstrs, *secstrs;
        uint32_t nr_syms;
        int err = -1;
        uint32_t index;
@@ -458,7 +485,7 @@ static int dso__load_sym(struct dso *self, int fd, const char *name,
        GElf_Shdr shdr;
        Elf_Data *syms;
        GElf_Sym sym;
-       Elf_Scn *sec, *sec_dynsym;
+       Elf_Scn *sec, *sec_dynsym, *sec_strndx;
        Elf *elf;
        size_t dynsym_idx;
        int nr = 0;
@@ -517,15 +544,29 @@ static int dso__load_sym(struct dso *self, int fd, const char *name,
        if (symstrs == NULL)
                goto out_elf_end;
 
+       sec_strndx = elf_getscn(elf, ehdr.e_shstrndx);
+       if (sec_strndx == NULL)
+               goto out_elf_end;
+
+       secstrs = elf_getdata(sec_strndx, NULL);
+       if (symstrs == NULL)
+               goto out_elf_end;
+
        nr_syms = shdr.sh_size / shdr.sh_entsize;
 
        memset(&sym, 0, sizeof(sym));
-
+       self->adjust_symbols = (ehdr.e_type == ET_EXEC ||
+                               elf_section_by_name(elf, &ehdr, &shdr,
+                                                    ".gnu.prelink_undo",
+                                                    NULL) != NULL);
        elf_symtab__for_each_symbol(syms, nr_syms, index, sym) {
                struct symbol *f;
                u64 obj_start;
+               struct section *section = NULL;
+               int is_label = elf_sym__is_label(&sym);
+               const char *section_name;
 
-               if (!elf_sym__is_function(&sym))
+               if (!is_label && !elf_sym__is_function(&sym))
                        continue;
 
                sec = elf_getscn(elf, sym.st_shndx);
@@ -533,9 +574,31 @@ static int dso__load_sym(struct dso *self, int fd, const char *name,
                        goto out_elf_end;
 
                gelf_getshdr(sec, &shdr);
+
+               if (is_label && !elf_sec__is_text(&shdr, secstrs))
+                       continue;
+
+               section_name = elf_sec__name(&shdr, secstrs);
                obj_start = sym.st_value;
 
-               sym.st_value -= shdr.sh_addr - shdr.sh_offset;
+               if (self->adjust_symbols) {
+                       if (verbose >= 2)
+                               printf("adjusting symbol: st_value: %Lx sh_addr: %Lx sh_offset: %Lx\n",
+                                       (u64)sym.st_value, (u64)shdr.sh_addr, (u64)shdr.sh_offset);
+
+                       sym.st_value -= shdr.sh_addr - shdr.sh_offset;
+               }
+
+               if (mod) {
+                       section = mod->sections->find_section(mod->sections, section_name);
+                       if (section)
+                               sym.st_value += section->vma;
+                       else {
+                               fprintf(stderr, "dso__load_sym() module %s lookup of %s failed\n",
+                                       mod->name, section_name);
+                               goto out_elf_end;
+                       }
+               }
 
                f = symbol__new(sym.st_value, sym.st_size,
                                elf_sym__name(&sym, symstrs),
@@ -546,6 +609,7 @@ static int dso__load_sym(struct dso *self, int fd, const char *name,
                if (filter && filter(self, f))
                        symbol__delete(f, self->sym_priv_size);
                else {
+                       f->module = mod;
                        dso__insert_symbol(self, f);
                        nr++;
                }
@@ -569,6 +633,8 @@ int dso__load(struct dso *self, symbol_filter_t filter, int verbose)
        if (!name)
                return -1;
 
+       self->adjust_symbols = 0;
+
        if (strncmp(self->name, "/tmp/perf-", 10) == 0)
                return dso__load_perf_map(self, filter, verbose);
 
@@ -593,7 +659,7 @@ more:
                fd = open(name, O_RDONLY);
        } while (fd < 0);
 
-       ret = dso__load_sym(self, fd, name, filter, verbose);
+       ret = dso__load_sym(self, fd, name, filter, verbose, NULL);
        close(fd);
 
        /*
@@ -607,6 +673,86 @@ out:
        return ret;
 }
 
+static int dso__load_module(struct dso *self, struct mod_dso *mods, const char *name,
+                            symbol_filter_t filter, int verbose)
+{
+       struct module *mod = mod_dso__find_module(mods, name);
+       int err = 0, fd;
+
+       if (mod == NULL || !mod->active)
+               return err;
+
+       fd = open(mod->path, O_RDONLY);
+
+       if (fd < 0)
+               return err;
+
+       err = dso__load_sym(self, fd, name, filter, verbose, mod);
+       close(fd);
+
+       return err;
+}
+
+int dso__load_modules(struct dso *self, symbol_filter_t filter, int verbose)
+{
+       struct mod_dso *mods = mod_dso__new_dso("modules");
+       struct module *pos;
+       struct rb_node *next;
+       int err;
+
+       err = mod_dso__load_modules(mods);
+
+       if (err <= 0)
+               return err;
+
+       /*
+        * Iterate over modules, and load active symbols.
+        */
+       next = rb_first(&mods->mods);
+       while (next) {
+               pos = rb_entry(next, struct module, rb_node);
+               err = dso__load_module(self, mods, pos->name, filter, verbose);
+
+               if (err < 0)
+                       break;
+
+               next = rb_next(&pos->rb_node);
+       }
+
+       if (err < 0) {
+               mod_dso__delete_modules(mods);
+               mod_dso__delete_self(mods);
+       }
+
+       return err;
+}
+
+static inline void dso__fill_symbol_holes(struct dso *self)
+{
+       struct symbol *prev = NULL;
+       struct rb_node *nd;
+
+       for (nd = rb_last(&self->syms); nd; nd = rb_prev(nd)) {
+               struct symbol *pos = rb_entry(nd, struct symbol, rb_node);
+
+               if (prev) {
+                       u64 hole = 0;
+                       int alias = pos->start == prev->start;
+
+                       if (!alias)
+                               hole = prev->start - pos->end - 1;
+
+                       if (hole || alias) {
+                               if (alias)
+                                       pos->end = prev->end;
+                               else if (hole)
+                                       pos->end = prev->start - 1;
+                       }
+               }
+               prev = pos;
+       }
+}
+
 static int dso__load_vmlinux(struct dso *self, const char *vmlinux,
                             symbol_filter_t filter, int verbose)
 {
@@ -615,21 +761,28 @@ static int dso__load_vmlinux(struct dso *self, const char *vmlinux,
        if (fd < 0)
                return -1;
 
-       err = dso__load_sym(self, fd, vmlinux, filter, verbose);
+       err = dso__load_sym(self, fd, vmlinux, filter, verbose, NULL);
+
+       if (err > 0)
+               dso__fill_symbol_holes(self);
+
        close(fd);
 
        return err;
 }
 
 int dso__load_kernel(struct dso *self, const char *vmlinux,
-                    symbol_filter_t filter, int verbose)
+                    symbol_filter_t filter, int verbose, int modules)
 {
        int err = -1;
 
-       if (vmlinux)
+       if (vmlinux) {
                err = dso__load_vmlinux(self, vmlinux, filter, verbose);
+               if (err > 0 && modules)
+                       err = dso__load_modules(self, filter, verbose);
+       }
 
-       if (err)
+       if (err <= 0)
                err = dso__load_kallsyms(self, filter, verbose);
 
        return err;
index ea332e56e4582d565a7975208328b9d9b60b8d22..7918cffb23cd35726cad6eca22acce0fd74cf392 100644 (file)
@@ -2,9 +2,10 @@
 #define _PERF_SYMBOL_ 1
 
 #include <linux/types.h>
-#include "../types.h"
-#include "list.h"
-#include "rbtree.h"
+#include "types.h"
+#include <linux/list.h>
+#include <linux/rbtree.h>
+#include "module.h"
 
 struct symbol {
        struct rb_node  rb_node;
@@ -13,6 +14,7 @@ struct symbol {
        u64             obj_start;
        u64             hist_sum;
        u64             *hist;
+       struct module   *module;
        void            *priv;
        char            name[0];
 };
@@ -20,8 +22,9 @@ struct symbol {
 struct dso {
        struct list_head node;
        struct rb_root   syms;
-       unsigned int     sym_priv_size;
        struct symbol    *(*find_symbol)(struct dso *, u64 ip);
+       unsigned int     sym_priv_size;
+       unsigned char    adjust_symbols;
        char             name[0];
 };
 
@@ -40,7 +43,8 @@ static inline void *dso__sym_priv(struct dso *self, struct symbol *sym)
 struct symbol *dso__find_symbol(struct dso *self, u64 ip);
 
 int dso__load_kernel(struct dso *self, const char *vmlinux,
-                    symbol_filter_t filter, int verbose);
+                    symbol_filter_t filter, int verbose, int modules);
+int dso__load_modules(struct dso *self, symbol_filter_t filter, int verbose);
 int dso__load(struct dso *self, symbol_filter_t filter, int verbose);
 
 size_t dso__fprintf(struct dso *self, FILE *fp);
similarity index 100%
rename from tools/perf/types.h
rename to tools/perf/util/types.h
index b8cfed776d81896ed882c6969d932581d07a385c..b4be6071c105754a171b5a83272b07ebe300c15b 100644 (file)
@@ -67,7 +67,6 @@
 #include <assert.h>
 #include <regex.h>
 #include <utime.h>
-#ifndef __MINGW32__
 #include <sys/wait.h>
 #include <sys/poll.h>
 #include <sys/socket.h>
 #include <netdb.h>
 #include <pwd.h>
 #include <inttypes.h>
-#if defined(__CYGWIN__)
-#undef _XOPEN_SOURCE
-#include <grp.h>
-#define _XOPEN_SOURCE 600
-#include "compat/cygwin.h"
-#else
-#undef _ALL_SOURCE /* AIX 5.3L defines a struct list with _ALL_SOURCE. */
-#include <grp.h>
-#define _ALL_SOURCE 1
-#endif
-#else  /* __MINGW32__ */
-/* pull in Windows compatibility stuff */
-#include "compat/mingw.h"
-#endif /* __MINGW32__ */
 
 #ifndef NO_ICONV
 #include <iconv.h>
index 6350d65f6d9e5f8a2faca0dd40ff790bd4cda8b9..4574ac28396f6779fcecacfafe570dc0a5e01dc6 100644 (file)
@@ -7,7 +7,7 @@
  * There's no pack memory to release - but stay close to the Git
  * version so wrap this away:
  */
-static inline void release_pack_memory(size_t size, int flag)
+static inline void release_pack_memory(size_t size __used, int flag __used)
 {
 }
 
@@ -59,7 +59,8 @@ void *xmemdupz(const void *data, size_t len)
 char *xstrndup(const char *str, size_t len)
 {
        char *p = memchr(str, '\0', len);
-       return xmemdupz(str, p ? p - str : len);
+
+       return xmemdupz(str, p ? (size_t)(p - str) : len);
 }
 
 void *xrealloc(void *ptr, size_t size)
index 764554350ed86f41b26f45eb840ad02138a55081..2884baf1d5f919a8e72183be0d390e632da4a385 100644 (file)
@@ -746,6 +746,7 @@ static bool make_all_cpus_request(struct kvm *kvm, unsigned int req)
                cpumask_clear(cpus);
 
        me = get_cpu();
+       spin_lock(&kvm->requests_lock);
        for (i = 0; i < KVM_MAX_VCPUS; ++i) {
                vcpu = kvm->vcpus[i];
                if (!vcpu)
@@ -762,6 +763,7 @@ static bool make_all_cpus_request(struct kvm *kvm, unsigned int req)
                smp_call_function_many(cpus, ack_flush, NULL, 1);
        else
                called = false;
+       spin_unlock(&kvm->requests_lock);
        put_cpu();
        free_cpumask_var(cpus);
        return called;
@@ -982,6 +984,7 @@ static struct kvm *kvm_create_vm(void)
        kvm->mm = current->mm;
        atomic_inc(&kvm->mm->mm_count);
        spin_lock_init(&kvm->mmu_lock);
+       spin_lock_init(&kvm->requests_lock);
        kvm_io_bus_init(&kvm->pio_bus);
        mutex_init(&kvm->lock);
        kvm_io_bus_init(&kvm->mmio_bus);
@@ -1194,6 +1197,8 @@ int __kvm_set_memory_region(struct kvm *kvm,
                if (!new.dirty_bitmap)
                        goto out_free;
                memset(new.dirty_bitmap, 0, dirty_bytes);
+               if (old.npages)
+                       kvm_arch_flush_shadow(kvm);
        }
 #endif /* not defined CONFIG_S390 */