OSDN Git Service

Merge branch 'perf/core' of git://git.kernel.org/pub/scm/linux/kernel/git/frederic...
authorIngo Molnar <mingo@elte.hu>
Sun, 22 May 2011 08:07:37 +0000 (10:07 +0200)
committerIngo Molnar <mingo@elte.hu>
Sun, 22 May 2011 08:10:01 +0000 (10:10 +0200)
Conflicts:
tools/perf/builtin-top.c

Semantic conflict:
util/include/linux/list.h        # fix prefetch.h removal fallout

Signed-off-by: Ingo Molnar <mingo@elte.hu>
965 files changed:
Documentation/00-INDEX
Documentation/ABI/testing/sysfs-devices-system-cpu
Documentation/ABI/testing/sysfs-firmware-dmi
Documentation/ABI/testing/sysfs-firmware-gsmi [new file with mode: 0644]
Documentation/ABI/testing/sysfs-firmware-log [new file with mode: 0644]
Documentation/ABI/testing/sysfs-kernel-fscaps [new file with mode: 0644]
Documentation/ABI/testing/sysfs-power
Documentation/DocBook/device-drivers.tmpl
Documentation/DocBook/genericirq.tmpl
Documentation/RCU/00-INDEX
Documentation/RCU/stallwarn.txt
Documentation/RCU/trace.txt
Documentation/driver-model/bus.txt
Documentation/driver-model/class.txt
Documentation/driver-model/device.txt
Documentation/driver-model/driver.txt
Documentation/feature-removal-schedule.txt
Documentation/filesystems/proc.txt
Documentation/ja_JP/HOWTO
Documentation/kernel-parameters.txt
Documentation/power/devices.txt
Documentation/power/notifiers.txt
Documentation/trace/kprobetrace.txt
Documentation/virtual/00-INDEX [new file with mode: 0644]
Documentation/virtual/kvm/api.txt [moved from Documentation/kvm/api.txt with 100% similarity]
Documentation/virtual/kvm/cpuid.txt [moved from Documentation/kvm/cpuid.txt with 100% similarity]
Documentation/virtual/kvm/locking.txt [moved from Documentation/kvm/locking.txt with 100% similarity]
Documentation/virtual/kvm/mmu.txt [moved from Documentation/kvm/mmu.txt with 100% similarity]
Documentation/virtual/kvm/msr.txt [moved from Documentation/kvm/msr.txt with 100% similarity]
Documentation/virtual/kvm/ppc-pv.txt [moved from Documentation/kvm/ppc-pv.txt with 100% similarity]
Documentation/virtual/kvm/review-checklist.txt [moved from Documentation/kvm/review-checklist.txt with 95% similarity]
Documentation/virtual/kvm/timekeeping.txt [moved from Documentation/kvm/timekeeping.txt with 100% similarity]
Documentation/virtual/lguest/.gitignore [moved from Documentation/lguest/.gitignore with 100% similarity]
Documentation/virtual/lguest/Makefile [moved from Documentation/lguest/Makefile with 100% similarity]
Documentation/virtual/lguest/extract [moved from Documentation/lguest/extract with 100% similarity]
Documentation/virtual/lguest/lguest.c [moved from Documentation/lguest/lguest.c with 100% similarity]
Documentation/virtual/lguest/lguest.txt [moved from Documentation/lguest/lguest.txt with 97% similarity]
Documentation/virtual/uml/UserModeLinux-HOWTO.txt [moved from Documentation/uml/UserModeLinux-HOWTO.txt with 100% similarity]
Documentation/x86/x86_64/boot-options.txt
Documentation/zh_CN/email-clients.txt [new file with mode: 0644]
MAINTAINERS
Makefile
arch/alpha/include/asm/unistd.h
arch/alpha/kernel/smp.c
arch/alpha/kernel/systbls.S
arch/alpha/kernel/time.c
arch/alpha/kernel/vmlinux.lds.S
arch/arm/boot/compressed/Makefile
arch/arm/boot/compressed/head.S
arch/arm/boot/compressed/vmlinux.lds.in
arch/arm/common/vic.c
arch/arm/include/asm/i8253.h [new file with mode: 0644]
arch/arm/include/asm/mach/time.h
arch/arm/include/asm/system.h
arch/arm/kernel/leds.c
arch/arm/kernel/signal.c
arch/arm/kernel/smp.c
arch/arm/kernel/time.c
arch/arm/kernel/traps.c
arch/arm/mach-davinci/cpufreq.c
arch/arm/mach-exynos4/pm.c
arch/arm/mach-footbridge/Kconfig
arch/arm/mach-footbridge/isa-timer.c
arch/arm/mach-integrator/integrator_ap.c
arch/arm/mach-omap1/pm_bus.c
arch/arm/mach-omap2/Makefile
arch/arm/mach-omap2/clkt34xx_dpll3m2.c
arch/arm/mach-omap2/pm_bus.c [deleted file]
arch/arm/mach-pxa/balloon3.c
arch/arm/mach-pxa/clock-pxa2xx.c
arch/arm/mach-pxa/clock-pxa3xx.c
arch/arm/mach-pxa/clock.h
arch/arm/mach-pxa/cm-x270.c
arch/arm/mach-pxa/cm-x2xx.c
arch/arm/mach-pxa/colibri-evalboard.c
arch/arm/mach-pxa/colibri-pxa270-income.c
arch/arm/mach-pxa/colibri-pxa270.c
arch/arm/mach-pxa/generic.h
arch/arm/mach-pxa/irq.c
arch/arm/mach-pxa/lpd270.c
arch/arm/mach-pxa/lubbock.c
arch/arm/mach-pxa/mainstone.c
arch/arm/mach-pxa/mfp-pxa2xx.c
arch/arm/mach-pxa/mfp-pxa3xx.c
arch/arm/mach-pxa/mioa701.c
arch/arm/mach-pxa/palmld.c
arch/arm/mach-pxa/palmtreo.c
arch/arm/mach-pxa/palmz72.c
arch/arm/mach-pxa/pxa25x.c
arch/arm/mach-pxa/pxa27x.c
arch/arm/mach-pxa/pxa3xx.c
arch/arm/mach-pxa/pxa95x.c
arch/arm/mach-pxa/raumfeld.c
arch/arm/mach-pxa/smemc.c
arch/arm/mach-pxa/trizeps4.c
arch/arm/mach-pxa/viper.c
arch/arm/mach-pxa/vpac270.c
arch/arm/mach-realview/include/mach/barriers.h
arch/arm/mach-s3c2410/irq.c
arch/arm/mach-s3c2410/mach-bast.c
arch/arm/mach-s3c2410/pm.c
arch/arm/mach-s3c2410/s3c2410.c
arch/arm/mach-s3c2412/irq.c
arch/arm/mach-s3c2412/mach-jive.c
arch/arm/mach-s3c2412/pm.c
arch/arm/mach-s3c2412/s3c2412.c
arch/arm/mach-s3c2416/irq.c
arch/arm/mach-s3c2416/pm.c
arch/arm/mach-s3c2416/s3c2416.c
arch/arm/mach-s3c2440/mach-osiris.c
arch/arm/mach-s3c2440/s3c2440.c
arch/arm/mach-s3c2440/s3c2442.c
arch/arm/mach-s3c2440/s3c244x-irq.c
arch/arm/mach-s3c2440/s3c244x.c
arch/arm/mach-s3c64xx/irq-pm.c
arch/arm/mach-s5pv210/pm.c
arch/arm/mach-sa1100/irq.c
arch/arm/mach-shmobile/pm_runtime.c
arch/arm/mach-tegra/include/mach/barriers.h
arch/arm/mm/init.c
arch/arm/plat-omap/gpio.c
arch/arm/plat-omap/iommu.c
arch/arm/plat-omap/omap_device.c
arch/arm/plat-pxa/gpio.c
arch/arm/plat-pxa/mfp.c
arch/arm/plat-s3c24xx/dma.c
arch/arm/plat-s3c24xx/irq-pm.c
arch/arm/plat-s5p/irq-pm.c
arch/arm/plat-samsung/include/plat/cpu.h
arch/arm/plat-samsung/include/plat/pm.h
arch/arm/vfp/vfpmodule.c
arch/avr32/mach-at32ap/intc.c
arch/blackfin/kernel/nmi.c
arch/blackfin/kernel/time-ts.c
arch/blackfin/mach-common/dpmc.c
arch/blackfin/mach-common/smp.c
arch/cris/arch-v32/kernel/smp.c
arch/ia64/kernel/cpufreq/acpi-cpufreq.c
arch/ia64/kernel/cyclone.c
arch/ia64/kernel/irq_ia64.c
arch/ia64/kernel/time.c
arch/ia64/sn/kernel/sn2/timer.c
arch/ia64/xen/irq_xen.c
arch/m32r/kernel/smp.c
arch/m32r/kernel/vmlinux.lds.S
arch/m68k/atari/atakeyb.c
arch/m68k/atari/stdma.c
arch/m68k/include/asm/atarikb.h
arch/m68k/include/asm/bitops_mm.h
arch/m68k/include/asm/unistd.h
arch/m68k/kernel/Makefile_mm
arch/m68k/kernel/entry_mm.S
arch/m68k/kernel/syscalltable.S
arch/m68k/kernel/vmlinux-std.lds
arch/m68k/kernel/vmlinux-sun3.lds
arch/microblaze/kernel/timer.c
arch/mips/Kbuild.platforms
arch/mips/Kconfig
arch/mips/Makefile
arch/mips/alchemy/common/dbdma.c
arch/mips/alchemy/common/dma.c
arch/mips/alchemy/common/irq.c
arch/mips/alchemy/common/platform.c
arch/mips/alchemy/common/setup.c
arch/mips/alchemy/common/time.c
arch/mips/alchemy/devboards/db1200/setup.c
arch/mips/alchemy/devboards/db1x00/board_setup.c
arch/mips/alchemy/devboards/pb1000/board_setup.c
arch/mips/alchemy/devboards/pb1500/board_setup.c
arch/mips/alchemy/devboards/prom.c
arch/mips/alchemy/gpr/board_setup.c
arch/mips/alchemy/gpr/init.c
arch/mips/alchemy/mtx-1/board_setup.c
arch/mips/alchemy/mtx-1/init.c
arch/mips/alchemy/mtx-1/platform.c
arch/mips/alchemy/xxs1500/board_setup.c
arch/mips/alchemy/xxs1500/init.c
arch/mips/ar7/gpio.c
arch/mips/bcm47xx/nvram.c
arch/mips/bcm47xx/setup.c
arch/mips/bcm63xx/boards/board_bcm963xx.c
arch/mips/boot/compressed/calc_vmlinuz_load_addr.c
arch/mips/boot/compressed/uart-alchemy.c
arch/mips/cavium-octeon/Kconfig
arch/mips/cavium-octeon/csrc-octeon.c
arch/mips/cavium-octeon/setup.c
arch/mips/cavium-octeon/smp.c
arch/mips/configs/lemote2f_defconfig
arch/mips/configs/malta_defconfig
arch/mips/configs/mtx1_defconfig
arch/mips/configs/nlm_xlr_defconfig [new file with mode: 0644]
arch/mips/include/asm/cache.h
arch/mips/include/asm/cevt-r4k.h
arch/mips/include/asm/cpu.h
arch/mips/include/asm/dma-mapping.h
arch/mips/include/asm/hugetlb.h
arch/mips/include/asm/i8253.h
arch/mips/include/asm/mach-au1x00/au1000.h
arch/mips/include/asm/mach-au1x00/au1000_dma.h
arch/mips/include/asm/mach-au1x00/au1xxx_dbdma.h
arch/mips/include/asm/mach-au1x00/gpio-au1000.h
arch/mips/include/asm/mach-bcm47xx/nvram.h
arch/mips/include/asm/mach-bcm63xx/bcm963xx_tag.h
arch/mips/include/asm/mach-cavium-octeon/kernel-entry-init.h
arch/mips/include/asm/mach-lantiq/lantiq.h [new file with mode: 0644]
arch/mips/include/asm/mach-lantiq/lantiq_platform.h [new file with mode: 0644]
arch/mips/include/asm/mach-lantiq/war.h [new file with mode: 0644]
arch/mips/include/asm/mach-lantiq/xway/irq.h [new file with mode: 0644]
arch/mips/include/asm/mach-lantiq/xway/lantiq_irq.h [new file with mode: 0644]
arch/mips/include/asm/mach-lantiq/xway/lantiq_soc.h [new file with mode: 0644]
arch/mips/include/asm/mach-lantiq/xway/xway_dma.h [new file with mode: 0644]
arch/mips/include/asm/mach-netlogic/cpu-feature-overrides.h [new file with mode: 0644]
arch/mips/include/asm/mach-netlogic/irq.h [new file with mode: 0644]
arch/mips/include/asm/mach-netlogic/war.h [new file with mode: 0644]
arch/mips/include/asm/module.h
arch/mips/include/asm/netlogic/interrupt.h [new file with mode: 0644]
arch/mips/include/asm/netlogic/mips-extns.h [new file with mode: 0644]
arch/mips/include/asm/netlogic/psb-bootinfo.h [new file with mode: 0644]
arch/mips/include/asm/netlogic/xlr/gpio.h [new file with mode: 0644]
arch/mips/include/asm/netlogic/xlr/iomap.h [new file with mode: 0644]
arch/mips/include/asm/netlogic/xlr/pic.h [new file with mode: 0644]
arch/mips/include/asm/netlogic/xlr/xlr.h [new file with mode: 0644]
arch/mips/include/asm/ptrace.h
arch/mips/include/asm/thread_info.h
arch/mips/include/asm/time.h
arch/mips/jazz/jazzdma.c
arch/mips/jz4740/dma.c
arch/mips/jz4740/setup.c
arch/mips/jz4740/time.c
arch/mips/jz4740/timer.c
arch/mips/kernel/Makefile
arch/mips/kernel/cevt-txx9.c
arch/mips/kernel/cpu-probe.c
arch/mips/kernel/csrc-bcm1480.c
arch/mips/kernel/csrc-ioasic.c
arch/mips/kernel/csrc-powertv.c
arch/mips/kernel/csrc-r4k.c
arch/mips/kernel/csrc-sb1250.c
arch/mips/kernel/entry.S
arch/mips/kernel/ftrace.c
arch/mips/kernel/i8253.c
arch/mips/kernel/ptrace.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/smtc.c
arch/mips/kernel/syscall.c
arch/mips/kernel/traps.c
arch/mips/kernel/vmlinux.lds.S
arch/mips/lantiq/Kconfig [new file with mode: 0644]
arch/mips/lantiq/Makefile [new file with mode: 0644]
arch/mips/lantiq/Platform [new file with mode: 0644]
arch/mips/lantiq/clk.c [new file with mode: 0644]
arch/mips/lantiq/clk.h [new file with mode: 0644]
arch/mips/lantiq/devices.c [new file with mode: 0644]
arch/mips/lantiq/devices.h [new file with mode: 0644]
arch/mips/lantiq/early_printk.c [new file with mode: 0644]
arch/mips/lantiq/irq.c [new file with mode: 0644]
arch/mips/lantiq/machtypes.h [new file with mode: 0644]
arch/mips/lantiq/prom.c [new file with mode: 0644]
arch/mips/lantiq/prom.h [new file with mode: 0644]
arch/mips/lantiq/setup.c [new file with mode: 0644]
arch/mips/lantiq/xway/Kconfig [new file with mode: 0644]
arch/mips/lantiq/xway/Makefile [new file with mode: 0644]
arch/mips/lantiq/xway/clk-ase.c [new file with mode: 0644]
arch/mips/lantiq/xway/clk-xway.c [new file with mode: 0644]
arch/mips/lantiq/xway/devices.c [new file with mode: 0644]
arch/mips/lantiq/xway/devices.h [new file with mode: 0644]
arch/mips/lantiq/xway/dma.c [new file with mode: 0644]
arch/mips/lantiq/xway/ebu.c [new file with mode: 0644]
arch/mips/lantiq/xway/gpio.c [new file with mode: 0644]
arch/mips/lantiq/xway/gpio_ebu.c [new file with mode: 0644]
arch/mips/lantiq/xway/gpio_stp.c [new file with mode: 0644]
arch/mips/lantiq/xway/mach-easy50601.c [new file with mode: 0644]
arch/mips/lantiq/xway/mach-easy50712.c [new file with mode: 0644]
arch/mips/lantiq/xway/pmu.c [new file with mode: 0644]
arch/mips/lantiq/xway/prom-ase.c [new file with mode: 0644]
arch/mips/lantiq/xway/prom-xway.c [new file with mode: 0644]
arch/mips/lantiq/xway/reset.c [new file with mode: 0644]
arch/mips/lantiq/xway/setup-ase.c [new file with mode: 0644]
arch/mips/lantiq/xway/setup-xway.c [new file with mode: 0644]
arch/mips/lib/Makefile
arch/mips/loongson/common/cs5536/cs5536_mfgpt.c
arch/mips/loongson/common/env.c
arch/mips/mm/Makefile
arch/mips/mm/c-r4k.c
arch/mips/mm/mmap.c [new file with mode: 0644]
arch/mips/mm/tlbex.c
arch/mips/mti-malta/malta-init.c
arch/mips/mti-malta/malta-int.c
arch/mips/netlogic/Kconfig [new file with mode: 0644]
arch/mips/netlogic/xlr/Makefile [new file with mode: 0644]
arch/mips/netlogic/xlr/irq.c [new file with mode: 0644]
arch/mips/netlogic/xlr/platform.c [new file with mode: 0644]
arch/mips/netlogic/xlr/setup.c [new file with mode: 0644]
arch/mips/netlogic/xlr/smp.c [new file with mode: 0644]
arch/mips/netlogic/xlr/smpboot.S [new file with mode: 0644]
arch/mips/netlogic/xlr/time.c [new file with mode: 0644]
arch/mips/netlogic/xlr/xlr_console.c [new file with mode: 0644]
arch/mips/pci/Makefile
arch/mips/pci/ops-lantiq.c [new file with mode: 0644]
arch/mips/pci/pci-lantiq.c [new file with mode: 0644]
arch/mips/pci/pci-lantiq.h [new file with mode: 0644]
arch/mips/pci/pci-xlr.c [new file with mode: 0644]
arch/mips/pmc-sierra/msp71xx/msp_irq_per.c
arch/mips/pmc-sierra/yosemite/smp.c
arch/mips/power/hibernate.S
arch/mips/rb532/gpio.c
arch/mips/sgi-ip22/ip22-platform.c
arch/mips/sgi-ip22/ip22-time.c
arch/mips/sgi-ip27/ip27-hubio.c
arch/mips/sgi-ip27/ip27-irq.c
arch/mips/sgi-ip27/ip27-klnuma.c
arch/mips/sgi-ip27/ip27-timer.c
arch/mips/sibyte/bcm1480/smp.c
arch/mips/sibyte/sb1250/smp.c
arch/mips/sni/time.c
arch/mn10300/kernel/smp.c
arch/parisc/kernel/smp.c
arch/parisc/kernel/vmlinux.lds.S
arch/powerpc/include/asm/mpic.h
arch/powerpc/kernel/smp.c
arch/powerpc/kernel/traps.c
arch/powerpc/platforms/83xx/suspend.c
arch/powerpc/platforms/cell/spu_base.c
arch/powerpc/platforms/powermac/pic.c
arch/powerpc/sysdev/fsl_msi.c
arch/powerpc/sysdev/ipic.c
arch/powerpc/sysdev/mpic.c
arch/s390/include/asm/cacheflush.h
arch/s390/include/asm/diag.h
arch/s390/include/asm/mmu_context.h
arch/s390/kernel/diag.c
arch/s390/kernel/dis.c
arch/s390/kernel/entry.S
arch/s390/kernel/entry64.S
arch/s390/kernel/smp.c
arch/s390/mm/cmm.c
arch/s390/mm/pageattr.c
arch/s390/oprofile/hwsampler.c
arch/s390/oprofile/hwsampler.h
arch/s390/oprofile/init.c
arch/sh/Kconfig
arch/sh/configs/apsh4ad0a_defconfig
arch/sh/configs/sdk7786_defconfig
arch/sh/kernel/cpu/shmobile/pm_runtime.c
arch/sh/kernel/smp.c
arch/sh/kernel/traps_32.c
arch/sparc/include/asm/topology_64.h
arch/sparc/kernel/apc.c
arch/sparc/kernel/pci_sabre.c
arch/sparc/kernel/pci_schizo.c
arch/sparc/kernel/pmc.c
arch/sparc/kernel/smp_32.c
arch/sparc/kernel/smp_64.c
arch/sparc/kernel/time_32.c
arch/sparc/lib/checksum_32.S
arch/tile/kernel/smp.c
arch/um/kernel/smp.c
arch/um/os-Linux/util.c
arch/unicore32/kernel/irq.c
arch/unicore32/kernel/traps.c
arch/x86/Kconfig
arch/x86/Kconfig.cpu
arch/x86/Makefile_32.cpu
arch/x86/include/asm/acpi.h
arch/x86/include/asm/alternative.h
arch/x86/include/asm/amd_iommu_proto.h
arch/x86/include/asm/amd_iommu_types.h
arch/x86/include/asm/amd_nb.h
arch/x86/include/asm/apic.h
arch/x86/include/asm/apicdef.h
arch/x86/include/asm/bios_ebda.h
arch/x86/include/asm/cpufeature.h
arch/x86/include/asm/dma.h
arch/x86/include/asm/efi.h
arch/x86/include/asm/i8253.h
arch/x86/include/asm/mce.h
arch/x86/include/asm/mmzone_32.h
arch/x86/include/asm/mmzone_64.h
arch/x86/include/asm/module.h
arch/x86/include/asm/nops.h
arch/x86/include/asm/numa.h
arch/x86/include/asm/numa_32.h
arch/x86/include/asm/numa_64.h
arch/x86/include/asm/numaq.h
arch/x86/include/asm/olpc_ofw.h
arch/x86/include/asm/percpu.h
arch/x86/include/asm/pgtable_types.h
arch/x86/include/asm/probe_roms.h [new file with mode: 0644]
arch/x86/include/asm/processor-flags.h
arch/x86/include/asm/setup.h
arch/x86/include/asm/srat.h [deleted file]
arch/x86/include/asm/system.h
arch/x86/include/asm/topology.h
arch/x86/include/asm/uv/uv_bau.h
arch/x86/include/asm/uv/uv_hub.h
arch/x86/include/asm/uv/uv_mmrs.h
arch/x86/include/asm/x86_init.h
arch/x86/include/asm/xen/page.h
arch/x86/include/asm/xen/pci.h
arch/x86/kernel/Makefile
arch/x86/kernel/acpi/sleep.c
arch/x86/kernel/alternative.c
arch/x86/kernel/amd_gart_64.c [moved from arch/x86/kernel/pci-gart_64.c with 100% similarity]
arch/x86/kernel/amd_iommu.c
arch/x86/kernel/amd_iommu_init.c
arch/x86/kernel/apb_timer.c
arch/x86/kernel/aperture_64.c
arch/x86/kernel/apic/apic.c
arch/x86/kernel/apic/apic_noop.c
arch/x86/kernel/apic/bigsmp_32.c
arch/x86/kernel/apic/es7000_32.c
arch/x86/kernel/apic/numaq_32.c
arch/x86/kernel/apic/probe_32.c
arch/x86/kernel/apic/summit_32.c
arch/x86/kernel/apic/x2apic_uv_x.c
arch/x86/kernel/apm_32.c
arch/x86/kernel/cpu/Makefile
arch/x86/kernel/cpu/amd.c
arch/x86/kernel/cpu/common.c
arch/x86/kernel/cpu/cpufreq/Makefile [deleted file]
arch/x86/kernel/cpu/intel.c
arch/x86/kernel/cpu/intel_cacheinfo.c
arch/x86/kernel/cpu/mcheck/mce.c
arch/x86/kernel/cpu/mcheck/mce_amd.c
arch/x86/kernel/cpu/mcheck/therm_throt.c
arch/x86/kernel/dumpstack.c
arch/x86/kernel/ftrace.c
arch/x86/kernel/head32.c
arch/x86/kernel/hpet.c
arch/x86/kernel/i8253.c
arch/x86/kernel/irq.c
arch/x86/kernel/jump_label.c
arch/x86/kernel/kprobes.c
arch/x86/kernel/kvmclock.c
arch/x86/kernel/mpparse.c
arch/x86/kernel/pci-iommu_table.c
arch/x86/kernel/probe_roms.c [moved from arch/x86/kernel/probe_roms_32.c with 65% similarity]
arch/x86/kernel/process.c
arch/x86/kernel/reboot.c
arch/x86/kernel/setup.c
arch/x86/kernel/smp.c
arch/x86/kernel/smpboot.c
arch/x86/kernel/x86_init.c
arch/x86/lguest/boot.c
arch/x86/lib/memcpy_64.S
arch/x86/mm/Makefile
arch/x86/mm/amdtopology.c [moved from arch/x86/mm/amdtopology_64.c with 90% similarity]
arch/x86/mm/init.c
arch/x86/mm/init_32.c
arch/x86/mm/init_64.c
arch/x86/mm/ioremap.c
arch/x86/mm/numa.c
arch/x86/mm/numa_32.c
arch/x86/mm/numa_64.c
arch/x86/mm/numa_emulation.c
arch/x86/mm/numa_internal.h
arch/x86/mm/srat.c [moved from arch/x86/mm/srat_64.c with 67% similarity]
arch/x86/mm/srat_32.c [deleted file]
arch/x86/pci/xen.c
arch/x86/platform/efi/efi.c
arch/x86/platform/efi/efi_64.c
arch/x86/platform/mrst/mrst.c
arch/x86/platform/olpc/Makefile
arch/x86/platform/olpc/olpc.c
arch/x86/platform/olpc/olpc_dt.c
arch/x86/platform/uv/tlb_uv.c
arch/x86/platform/uv/uv_time.c
arch/x86/xen/enlighten.c
arch/x86/xen/irq.c
arch/x86/xen/mmu.c
arch/x86/xen/p2m.c
arch/x86/xen/setup.c
arch/x86/xen/smp.c
arch/x86/xen/time.c
arch/x86/xen/xen-ops.h
block/blk-cgroup.c
block/blk-cgroup.h
block/blk-core.c
block/blk-throttle.c
block/cfq-iosched.c
drivers/Kconfig
drivers/acpi/processor_perflib.c
drivers/acpi/processor_throttling.c
drivers/ata/libahci.c
drivers/ata/libata-eh.c
drivers/atm/fore200e.c
drivers/base/Kconfig
drivers/base/base.h
drivers/base/core.c
drivers/base/dd.c
drivers/base/firmware_class.c
drivers/base/memory.c
drivers/base/platform.c
drivers/base/power/Makefile
drivers/base/power/clock_ops.c [new file with mode: 0644]
drivers/base/power/generic_ops.c
drivers/base/power/main.c
drivers/base/power/runtime.c
drivers/base/power/sysfs.c
drivers/base/power/wakeup.c
drivers/base/sys.c
drivers/block/DAC960.c
drivers/block/amiflop.c
drivers/block/ataflop.c
drivers/block/floppy.c
drivers/block/paride/pcd.c
drivers/block/paride/pd.c
drivers/block/paride/pf.c
drivers/block/rbd.c
drivers/block/swim.c
drivers/block/swim3.c
drivers/block/ub.c
drivers/block/xsysace.c
drivers/cdrom/cdrom.c
drivers/cdrom/gdrom.c
drivers/cdrom/viocd.c
drivers/char/Kconfig
drivers/char/hpet.c
drivers/char/hw_random/n2-drv.c
drivers/char/ipmi/ipmi_si_intf.c
drivers/char/mem.c
drivers/char/raw.c
drivers/char/xilinx_hwicap/xilinx_hwicap.c
drivers/clocksource/Kconfig [new file with mode: 0644]
drivers/clocksource/Makefile
drivers/clocksource/cyclone.c
drivers/clocksource/i8253.c [new file with mode: 0644]
drivers/cpufreq/Kconfig
drivers/cpufreq/Kconfig.x86 [moved from arch/x86/kernel/cpu/cpufreq/Kconfig with 97% similarity]
drivers/cpufreq/Makefile
drivers/cpufreq/acpi-cpufreq.c [moved from arch/x86/kernel/cpu/cpufreq/acpi-cpufreq.c with 94% similarity]
drivers/cpufreq/cpufreq-nforce2.c [moved from arch/x86/kernel/cpu/cpufreq/cpufreq-nforce2.c with 97% similarity]
drivers/cpufreq/cpufreq.c
drivers/cpufreq/cpufreq_performance.c
drivers/cpufreq/cpufreq_powersave.c
drivers/cpufreq/cpufreq_stats.c
drivers/cpufreq/cpufreq_userspace.c
drivers/cpufreq/e_powersaver.c [moved from arch/x86/kernel/cpu/cpufreq/e_powersaver.c with 100% similarity]
drivers/cpufreq/elanfreq.c [moved from arch/x86/kernel/cpu/cpufreq/elanfreq.c with 100% similarity]
drivers/cpufreq/freq_table.c
drivers/cpufreq/gx-suspmod.c [moved from arch/x86/kernel/cpu/cpufreq/gx-suspmod.c with 95% similarity]
drivers/cpufreq/longhaul.c [moved from arch/x86/kernel/cpu/cpufreq/longhaul.c with 98% similarity]
drivers/cpufreq/longhaul.h [moved from arch/x86/kernel/cpu/cpufreq/longhaul.h with 100% similarity]
drivers/cpufreq/longrun.c [moved from arch/x86/kernel/cpu/cpufreq/longrun.c with 94% similarity]
drivers/cpufreq/mperf.c [moved from arch/x86/kernel/cpu/cpufreq/mperf.c with 100% similarity]
drivers/cpufreq/mperf.h [moved from arch/x86/kernel/cpu/cpufreq/mperf.h with 100% similarity]
drivers/cpufreq/p4-clockmod.c [moved from arch/x86/kernel/cpu/cpufreq/p4-clockmod.c with 96% similarity]
drivers/cpufreq/pcc-cpufreq.c [moved from arch/x86/kernel/cpu/cpufreq/pcc-cpufreq.c with 91% similarity]
drivers/cpufreq/powernow-k6.c [moved from arch/x86/kernel/cpu/cpufreq/powernow-k6.c with 100% similarity]
drivers/cpufreq/powernow-k7.c [moved from arch/x86/kernel/cpu/cpufreq/powernow-k7.c with 95% similarity]
drivers/cpufreq/powernow-k7.h [moved from arch/x86/kernel/cpu/cpufreq/powernow-k7.h with 100% similarity]
drivers/cpufreq/powernow-k8.c [moved from arch/x86/kernel/cpu/cpufreq/powernow-k8.c with 93% similarity]
drivers/cpufreq/powernow-k8.h [moved from arch/x86/kernel/cpu/cpufreq/powernow-k8.h with 98% similarity]
drivers/cpufreq/sc520_freq.c [moved from arch/x86/kernel/cpu/cpufreq/sc520_freq.c with 95% similarity]
drivers/cpufreq/speedstep-centrino.c [moved from arch/x86/kernel/cpu/cpufreq/speedstep-centrino.c with 96% similarity]
drivers/cpufreq/speedstep-ich.c [moved from arch/x86/kernel/cpu/cpufreq/speedstep-ich.c with 92% similarity]
drivers/cpufreq/speedstep-lib.c [moved from arch/x86/kernel/cpu/cpufreq/speedstep-lib.c with 90% similarity]
drivers/cpufreq/speedstep-lib.h [moved from arch/x86/kernel/cpu/cpufreq/speedstep-lib.h with 100% similarity]
drivers/cpufreq/speedstep-smi.c [moved from arch/x86/kernel/cpu/cpufreq/speedstep-smi.c with 90% similarity]
drivers/edac/ppc4xx_edac.c
drivers/firmware/Kconfig
drivers/firmware/Makefile
drivers/firmware/edd.c
drivers/firmware/efivars.c
drivers/firmware/google/Kconfig [new file with mode: 0644]
drivers/firmware/google/Makefile [new file with mode: 0644]
drivers/firmware/google/gsmi.c [new file with mode: 0644]
drivers/firmware/google/memconsole.c [new file with mode: 0644]
drivers/firmware/iscsi_ibft_find.c
drivers/gpu/drm/drm_fb_helper.c
drivers/gpu/drm/i915/i915_drv.c
drivers/gpu/drm/i915/intel_display.c
drivers/gpu/drm/nouveau/nouveau_sgdma.c
drivers/gpu/drm/radeon/evergreen.c
drivers/gpu/drm/radeon/evergreend.h
drivers/gpu/drm/radeon/ni.c
drivers/gpu/drm/radeon/radeon_atombios.c
drivers/gpu/drm/radeon/radeon_gart.c
drivers/gpu/drm/radeon/reg_srcs/cayman
drivers/gpu/drm/radeon/reg_srcs/evergreen
drivers/gpu/vga/vga_switcheroo.c
drivers/i2c/busses/i2c-mpc.c
drivers/i2c/busses/i2c-pnx.c
drivers/infiniband/core/cma.c
drivers/infiniband/core/iwcm.c
drivers/infiniband/core/ucma.c
drivers/infiniband/hw/cxgb4/cm.c
drivers/infiniband/hw/cxgb4/device.c
drivers/infiniband/hw/cxgb4/iw_cxgb4.h
drivers/infiniband/hw/cxgb4/provider.c
drivers/infiniband/hw/cxgb4/qp.c
drivers/infiniband/hw/ipath/ipath_driver.c
drivers/infiniband/hw/nes/nes_cm.c
drivers/infiniband/hw/nes/nes_verbs.c
drivers/infiniband/hw/qib/qib_iba7322.c
drivers/infiniband/hw/qib/qib_pcie.c
drivers/input/keyboard/atakbd.c
drivers/input/mouse/atarimouse.c
drivers/input/touchscreen/ads7846.c
drivers/leds/leds-lm3530.c
drivers/lguest/Kconfig
drivers/lguest/Makefile
drivers/media/video/cx88/cx88-input.c
drivers/media/video/soc_camera.c
drivers/media/video/v4l2-device.c
drivers/media/video/v4l2-subdev.c
drivers/message/i2o/i2o_block.c
drivers/mfd/asic3.c
drivers/mfd/omap-usb-host.c
drivers/mfd/twl4030-power.c
drivers/misc/ti-st/Kconfig
drivers/misc/ti-st/st_core.c
drivers/misc/ti-st/st_kim.c
drivers/mmc/core/host.c
drivers/mmc/host/sdhci-of-core.c
drivers/mtd/maps/Kconfig
drivers/mtd/maps/Makefile
drivers/mtd/maps/lantiq-flash.c [new file with mode: 0644]
drivers/mtd/maps/physmap_of.c
drivers/mtd/nand/au1550nd.c
drivers/net/Kconfig
drivers/net/Makefile
drivers/net/arm/etherh.c
drivers/net/atarilance.c
drivers/net/benet/be.h
drivers/net/benet/be_cmds.c
drivers/net/benet/be_main.c
drivers/net/bonding/bond_3ad.h
drivers/net/can/mscan/mpc5xxx_can.c
drivers/net/can/sja1000/sja1000.c
drivers/net/can/slcan.c
drivers/net/ehea/ehea_ethtool.c
drivers/net/ehea/ehea_main.c
drivers/net/fs_enet/fs_enet-main.c
drivers/net/fs_enet/mii-fec.c
drivers/net/hydra.c
drivers/net/ixgbe/ixgbe_main.c
drivers/net/lantiq_etop.c [new file with mode: 0644]
drivers/net/macvlan.c
drivers/net/ne-h8300.c
drivers/net/pch_gbe/pch_gbe_main.c
drivers/net/sfc/mcdi.c
drivers/net/sfc/nic.c
drivers/net/sfc/nic.h
drivers/net/sfc/siena.c
drivers/net/slip.c
drivers/net/sunhme.c
drivers/net/usb/cdc_ether.c
drivers/net/usb/ipheth.c
drivers/net/usb/usbnet.c
drivers/net/vmxnet3/vmxnet3_drv.c
drivers/net/vmxnet3/vmxnet3_ethtool.c
drivers/net/wireless/ath/ath9k/main.c
drivers/net/wireless/iwlegacy/iwl-core.c
drivers/net/wireless/iwlegacy/iwl-dev.h
drivers/net/wireless/libertas/cmd.c
drivers/net/zorro8390.c
drivers/pci/intel-iommu.c
drivers/pci/iov.c
drivers/pci/pci.h
drivers/pci/setup-bus.c
drivers/rapidio/switches/idt_gen2.c
drivers/rapidio/switches/idtcps.c
drivers/rapidio/switches/tsi57x.c
drivers/rtc/Kconfig
drivers/rtc/class.c
drivers/rtc/rtc-davinci.c
drivers/rtc/rtc-ds1286.c
drivers/rtc/rtc-ep93xx.c
drivers/rtc/rtc-m41t80.c
drivers/rtc/rtc-max8925.c
drivers/rtc/rtc-max8998.c
drivers/rtc/rtc-mc13xxx.c
drivers/rtc/rtc-msm6242.c
drivers/rtc/rtc-mxc.c
drivers/rtc/rtc-pcap.c
drivers/rtc/rtc-rp5c01.c
drivers/rtc/rtc-s3c.c
drivers/s390/block/dasd.c
drivers/s390/char/sclp_cmd.c
drivers/s390/char/tape_block.c
drivers/scsi/qlogicpti.c
drivers/scsi/scsi_lib.c
drivers/scsi/scsi_scan.c
drivers/ssb/pci.c
drivers/ssb/sprom.c
drivers/ssb/ssb_private.h
drivers/tty/serial/Kconfig
drivers/tty/serial/Makefile
drivers/tty/serial/lantiq.c [new file with mode: 0644]
drivers/tty/serial/of_serial.c
drivers/uio/uio.c
drivers/uio/uio_netx.c
drivers/uio/uio_pdrv_genirq.c
drivers/usb/gadget/fsl_qe_udc.c
drivers/vhost/vhost.c
drivers/video/acornfb.c
drivers/video/atafb.c
drivers/video/fbmem.c
drivers/watchdog/Kconfig
drivers/watchdog/Makefile
drivers/watchdog/lantiq_wdt.c [new file with mode: 0644]
drivers/watchdog/mpc8xxx_wdt.c
drivers/watchdog/mtx-1_wdt.c
drivers/xen/Makefile
drivers/xen/balloon.c
drivers/xen/events.c
drivers/xen/gntalloc.c
drivers/xen/gntdev.c
drivers/xen/grant-table.c
drivers/xen/manage.c
drivers/xen/sys-hypervisor.c
fs/block_dev.c
fs/btrfs/acl.c
fs/btrfs/extent-tree.c
fs/btrfs/ioctl.c
fs/ceph/caps.c
fs/ceph/inode.c
fs/ceph/mds_client.c
fs/ceph/snap.c
fs/ceph/super.h
fs/cifs/cifs_unicode.c
fs/cifs/connect.c
fs/configfs/dir.c
fs/debugfs/file.c
fs/fuse/dir.c
fs/namei.c
fs/nfs/nfs4filelayout.c
fs/nfs/nfs4filelayout.h
fs/nfs/nfs4filelayoutdev.c
fs/nfs/nfs4proc.c
fs/nfs/pnfs.c
fs/nfs/pnfs.h
fs/nfs/read.c
fs/nfs/write.c
fs/nilfs2/alloc.c
fs/ocfs2/cluster/heartbeat.c
fs/ocfs2/dir.c
fs/ocfs2/dlm/dlmdomain.c
fs/ocfs2/dlm/dlmmaster.c
fs/ocfs2/file.c
fs/ocfs2/journal.c
fs/sysfs/file.c
fs/sysfs/group.c
fs/xfs/linux-2.6/xfs_sync.c
fs/xfs/xfs_trans_ail.c
include/asm-generic/vmlinux.lds.h
include/drm/drm_fb_helper.h
include/linux/alarmtimer.h [new file with mode: 0644]
include/linux/bootmem.h
include/linux/bsearch.h [new file with mode: 0644]
include/linux/capability.h
include/linux/clockchips.h
include/linux/clocksource.h
include/linux/cpufreq.h
include/linux/cred.h
include/linux/device.h
include/linux/fb.h
include/linux/fs.h
include/linux/gfp.h
include/linux/init_task.h
include/linux/interrupt.h
include/linux/irq.h
include/linux/irqdesc.h
include/linux/kmod.h
include/linux/list.h
include/linux/mmc/host.h
include/linux/module.h
include/linux/moduleparam.h
include/linux/mutex.h
include/linux/nfs_xdr.h
include/linux/of_device.h
include/linux/pci-ats.h [new file with mode: 0644]
include/linux/platform_device.h
include/linux/pm.h
include/linux/pm_runtime.h
include/linux/posix-timers.h
include/linux/proc_fs.h
include/linux/rbtree.h
include/linux/rculist.h
include/linux/rcupdate.h
include/linux/rcutiny.h
include/linux/rcutree.h
include/linux/sched.h
include/linux/seqlock.h
include/linux/signal.h
include/linux/ssb/ssb.h
include/linux/string.h
include/linux/sysdev.h
include/linux/sysfs.h
include/linux/ti_wilink_st.h
include/linux/time.h
include/linux/timerqueue.h
include/net/inet_ecn.h
include/net/ip_vs.h
include/net/llc_pdu.h
include/net/sctp/sctp.h
include/net/xfrm.h
include/rdma/iw_cm.h
include/rdma/rdma_cm.h
include/rdma/rdma_user_cm.h
include/scsi/scsi_device.h
include/trace/events/gfpflags.h
include/trace/events/irq.h
include/xen/events.h
init/Kconfig
init/main.c
kernel/capability.c
kernel/cgroup.c
kernel/cpuset.c
kernel/cred.c
kernel/events/core.c
kernel/extable.c
kernel/fork.c
kernel/freezer.c
kernel/hrtimer.c
kernel/hung_task.c
kernel/irq/Kconfig
kernel/irq/Makefile
kernel/irq/chip.c
kernel/irq/debug.h
kernel/irq/generic-chip.c [new file with mode: 0644]
kernel/irq/irqdesc.c
kernel/irq/manage.c
kernel/irq/settings.h
kernel/kexec.c
kernel/kmod.c
kernel/ksysfs.c
kernel/lockdep.c
kernel/module.c
kernel/mutex-debug.c
kernel/mutex-debug.h
kernel/mutex.c
kernel/mutex.h
kernel/params.c
kernel/power/Kconfig
kernel/power/hibernate.c
kernel/power/main.c
kernel/power/power.h
kernel/power/snapshot.c
kernel/power/suspend.c
kernel/power/user.c
kernel/rcupdate.c
kernel/rcutiny.c
kernel/rcutiny_plugin.h
kernel/rcutorture.c
kernel/rcutree.c
kernel/rcutree.h
kernel/rcutree_plugin.h
kernel/rcutree_trace.c
kernel/sched.c
kernel/sched_debug.c
kernel/sched_fair.c
kernel/sched_features.h
kernel/sched_idletask.c
kernel/sched_rt.c
kernel/sched_stoptask.c
kernel/softirq.c
kernel/sys.c
kernel/time/Makefile
kernel/time/alarmtimer.c [new file with mode: 0644]
kernel/time/clockevents.c
kernel/time/clocksource.c
kernel/time/tick-broadcast.c
kernel/time/timekeeping.c
kernel/trace/trace_kprobe.c
lib/Kconfig.debug
lib/Makefile
lib/bsearch.c [new file with mode: 0644]
lib/dma-debug.c
lib/string.c
lib/vsprintf.c
mm/kmemleak.c
mm/page_alloc.c
mm/page_cgroup.c
mm/shmem.c
mm/swap.c
mm/vmscan.c
net/8021q/vlan.c
net/8021q/vlan_dev.c
net/9p/client.c
net/9p/protocol.c
net/9p/trans_common.c
net/batman-adv/gateway_client.c
net/batman-adv/originator.c
net/batman-adv/soft-interface.c
net/bluetooth/sco.c
net/bridge/br_netfilter.c
net/bridge/netfilter/ebtables.c
net/core/dev.c
net/core/dev_addr_lists.c
net/core/drop_monitor.c
net/core/gen_estimator.c
net/core/net-sysfs.c
net/core/net_namespace.c
net/dccp/options.c
net/decnet/dn_dev.c
net/ipv4/fib_semantics.c
net/ipv4/fib_trie.c
net/ipv4/igmp.c
net/ipv4/ip_fragment.c
net/ipv4/tcp_cubic.c
net/ipv4/xfrm4_output.c
net/ipv4/xfrm4_state.c
net/ipv6/addrconf.c
net/ipv6/mcast.c
net/ipv6/netfilter/ip6t_REJECT.c
net/ipv6/sit.c
net/ipv6/xfrm6_output.c
net/ipv6/xfrm6_state.c
net/mac80211/agg-tx.c
net/mac80211/tx.c
net/mac80211/work.c
net/netfilter/ipvs/ip_vs_app.c
net/netfilter/ipvs/ip_vs_conn.c
net/netfilter/ipvs/ip_vs_core.c
net/netfilter/ipvs/ip_vs_ctl.c
net/netfilter/ipvs/ip_vs_est.c
net/netfilter/ipvs/ip_vs_proto.c
net/netfilter/ipvs/ip_vs_sync.c
net/netfilter/nf_conntrack_extend.c
net/netfilter/nf_conntrack_netlink.c
net/netfilter/x_tables.c
net/netfilter/xt_DSCP.c
net/netfilter/xt_conntrack.c
net/netfilter/xt_osf.c
net/netlabel/netlabel_unlabeled.c
net/netlink/af_netlink.c
net/phonet/pn_dev.c
net/sched/act_api.c
net/sched/act_police.c
net/sctp/bind_addr.c
net/sctp/ipv6.c
net/sctp/protocol.c
net/socket.c
net/xfrm/xfrm_policy.c
net/xfrm/xfrm_replay.c
scripts/mod/modpost.c
scripts/mod/modpost.h
scripts/module-common.lds
security/keys/user_defined.c
security/selinux/avc.c
security/selinux/include/avc.h
security/selinux/netif.c
security/selinux/selinuxfs.c
security/selinux/ss/policydb.c
sound/soc/codecs/ssm2602.c
sound/soc/codecs/uda134x.c
sound/soc/codecs/wm8903.c
sound/soc/jz4740/jz4740-i2s.c
sound/soc/mid-x86/sst_platform.c
sound/soc/soc-core.c
tools/perf/Documentation/perf-script-perl.txt
tools/perf/Documentation/perf-script-python.txt
tools/perf/builtin-record.c
tools/perf/builtin-test.c
tools/perf/builtin-top.c
tools/perf/util/evlist.c
tools/perf/util/evlist.h
tools/perf/util/include/linux/list.h
tools/perf/util/python.c
tools/perf/util/trace-event-parse.c

index c17cd4b..1b777b9 100644 (file)
@@ -328,8 +328,6 @@ sysrq.txt
        - info on the magic SysRq key.
 telephony/
        - directory with info on telephony (e.g. voice over IP) support.
-uml/
-       - directory with information about User Mode Linux.
 unicode.txt
        - info on the Unicode character/font mapping used in Linux.
 unshare.txt
index 7564e88..e7be75b 100644 (file)
@@ -183,21 +183,21 @@ Description:      Discover and change clock speed of CPUs
                to learn how to control the knobs.
 
 
-What:      /sys/devices/system/cpu/cpu*/cache/index*/cache_disable_X
-Date:      August 2008
+What:          /sys/devices/system/cpu/cpu*/cache/index3/cache_disable_{0,1}
+Date:          August 2008
 KernelVersion: 2.6.27
-Contact:       mark.langsdorf@amd.com
-Description:   These files exist in every cpu's cache index directories.
-               There are currently 2 cache_disable_# files in each
-               directory.  Reading from these files on a supported
-               processor will return that cache disable index value
-               for that processor and node.  Writing to one of these
-               files will cause the specificed cache index to be disabled.
-
-               Currently, only AMD Family 10h Processors support cache index
-               disable, and only for their L3 caches.  See the BIOS and
-               Kernel Developer's Guide at
-               http://support.amd.com/us/Embedded_TechDocs/31116-Public-GH-BKDG_3-28_5-28-09.pdf       
-               for formatting information and other details on the
-               cache index disable.
-Users:    joachim.deguara@amd.com
+Contact:       discuss@x86-64.org
+Description:   Disable L3 cache indices
+
+               These files exist in every CPU's cache/index3 directory. Each
+               cache_disable_{0,1} file corresponds to one disable slot which
+               can be used to disable a cache index. Reading from these files
+               on a processor with this functionality will return the currently
+               disabled index for that node. There is one L3 structure per
+               node, or per internal node on MCM machines. Writing a valid
+               index to one of these files will cause the specificed cache
+               index to be disabled.
+
+               All AMD processors with L3 caches provide this functionality.
+               For details, see BKDGs at
+               http://developer.amd.com/documentation/guides/Pages/default.aspx
index ba9da95..c78f9ab 100644 (file)
@@ -14,14 +14,15 @@ Description:
 
                DMI is structured as a large table of entries, where
                each entry has a common header indicating the type and
-               length of the entry, as well as 'handle' that is
-               supposed to be unique amongst all entries.
+               length of the entry, as well as a firmware-provided
+               'handle' that is supposed to be unique amongst all
+               entries.
 
                Some entries are required by the specification, but many
                others are optional.  In general though, users should
                never expect to find a specific entry type on their
                system unless they know for certain what their firmware
-               is doing.  Machine to machine will vary.
+               is doing.  Machine to machine experiences will vary.
 
                Multiple entries of the same type are allowed.  In order
                to handle these duplicate entry types, each entry is
@@ -67,25 +68,24 @@ Description:
                          and the two terminating nul characters.
                type    : The type of the entry.  This value is the same
                          as found in the directory name.  It indicates
-                         how the rest of the entry should be
-                         interpreted.
+                         how the rest of the entry should be interpreted.
                instance: The instance ordinal of the entry for the
                          given type.  This value is the same as found
                          in the parent directory name.
-               position: The position of the entry within the entirety
-                         of the entirety.
+               position: The ordinal position (zero-based) of the entry
+                         within the entirety of the DMI entry table.
 
                === Entry Specialization ===
 
                Some entry types may have other information available in
-               sysfs.
+               sysfs.  Not all types are specialized.
 
                --- Type 15 - System Event Log ---
 
                This entry allows the firmware to export a log of
                events the system has taken.  This information is
                typically backed by nvram, but the implementation
-               details are abstracted by this table.  This entries data
+               details are abstracted by this table.  This entry's data
                is exported in the directory:
 
                /sys/firmware/dmi/entries/15-0/system_event_log
diff --git a/Documentation/ABI/testing/sysfs-firmware-gsmi b/Documentation/ABI/testing/sysfs-firmware-gsmi
new file mode 100644 (file)
index 0000000..0faa0aa
--- /dev/null
@@ -0,0 +1,58 @@
+What:          /sys/firmware/gsmi
+Date:          March 2011
+Contact:       Mike Waychison <mikew@google.com>
+Description:
+               Some servers used internally at Google have firmware
+               that provides callback functionality via explicit SMI
+               triggers.  Some of the callbacks are similar to those
+               provided by the EFI runtime services page, but due to
+               historical reasons this different entry-point has been
+               used.
+
+               The gsmi driver implements the kernel's abstraction for
+               these firmware callbacks.  Currently, this functionality
+               is limited to handling the system event log and getting
+               access to EFI-style variables stored in nvram.
+
+               Layout:
+
+               /sys/firmware/gsmi/vars:
+
+                       This directory has the same layout (and
+                       underlying implementation as /sys/firmware/efi/vars.
+                       See Documentation/ABI/*/sysfs-firmware-efi-vars
+                       for more information on how to interact with
+                       this structure.
+
+               /sys/firmware/gsmi/append_to_eventlog - write-only:
+
+                       This file takes a binary blob and passes it onto
+                       the firmware to be timestamped and appended to
+                       the system eventlog.  The binary format is
+                       interpreted by the firmware and may change from
+                       platform to platform.  The only kernel-enforced
+                       requirement is that the blob be prefixed with a
+                       32bit host-endian type used as part of the
+                       firmware call.
+
+               /sys/firmware/gsmi/clear_config - write-only:
+
+                       Writing any value to this file will cause the
+                       entire firmware configuration to be reset to
+                       "factory defaults".  Callers should assume that
+                       a reboot is required for the configuration to be
+                       cleared.
+
+               /sys/firmware/gsmi/clear_eventlog - write-only:
+
+                       This file is used to clear out a portion/the
+                       whole of the system event log.  Values written
+                       should be values between 1 and 100 inclusive (in
+                       ASCII) representing the fraction of the log to
+                       clear.  Not all platforms support fractional
+                       clearing though, and this writes to this file
+                       will error out if the firmware doesn't like your
+                       submitted fraction.
+
+                       Callers should assume that a reboot is needed
+                       for this operation to complete.
diff --git a/Documentation/ABI/testing/sysfs-firmware-log b/Documentation/ABI/testing/sysfs-firmware-log
new file mode 100644 (file)
index 0000000..9b58e7c
--- /dev/null
@@ -0,0 +1,7 @@
+What:          /sys/firmware/log
+Date:          February 2011
+Contact:       Mike Waychison <mikew@google.com>
+Description:
+               The /sys/firmware/log is a binary file that represents a
+               read-only copy of the firmware's log if one is
+               available.
diff --git a/Documentation/ABI/testing/sysfs-kernel-fscaps b/Documentation/ABI/testing/sysfs-kernel-fscaps
new file mode 100644 (file)
index 0000000..50a3033
--- /dev/null
@@ -0,0 +1,8 @@
+What:          /sys/kernel/fscaps
+Date:          February 2011
+KernelVersion: 2.6.38
+Contact:       Ludwig Nussel <ludwig.nussel@suse.de>
+Description
+               Shows whether file system capabilities are honored
+               when executing a binary
+
index 194ca44..b464d12 100644 (file)
@@ -158,3 +158,17 @@ Description:
                successful, will make the kernel abort a subsequent transition
                to a sleep state if any wakeup events are reported after the
                write has returned.
+
+What:          /sys/power/reserved_size
+Date:          May 2011
+Contact:       Rafael J. Wysocki <rjw@sisk.pl>
+Description:
+               The /sys/power/reserved_size file allows user space to control
+               the amount of memory reserved for allocations made by device
+               drivers during the "device freeze" stage of hibernation.  It can
+               be written a string representing a non-negative integer that
+               will be used as the amount of memory to reserve for allocations
+               made by device drivers' "freeze" callbacks, in bytes.
+
+               Reading from this file will display the current value, which is
+               set to 1 MB by default.
index 36f63d4..b638e50 100644 (file)
@@ -96,10 +96,10 @@ X!Iinclude/linux/kobject.h
 
   <chapter id="devdrivers">
      <title>Device drivers infrastructure</title>
+     <sect1><title>The Basic Device Driver-Model Structures </title>
+!Iinclude/linux/device.h
+     </sect1>
      <sect1><title>Device Drivers Base</title>
-<!--
-X!Iinclude/linux/device.h
--->
 !Edrivers/base/driver.c
 !Edrivers/base/core.c
 !Edrivers/base/class.c
index fb10fd0..b342234 100644 (file)
        <para>
        Whenever an interrupt triggers, the lowlevel arch code calls into
        the generic interrupt code by calling desc->handle_irq().
-       This highlevel IRQ handling function only uses desc->chip primitives
-       referenced by the assigned chip descriptor structure.
+       This highlevel IRQ handling function only uses desc->irq_data.chip
+       primitives referenced by the assigned chip descriptor structure.
        </para>
     </sect1>
     <sect1 id="Highlevel_Driver_API">
          <listitem><para>enable_irq()</para></listitem>
          <listitem><para>disable_irq_nosync() (SMP only)</para></listitem>
          <listitem><para>synchronize_irq() (SMP only)</para></listitem>
-         <listitem><para>set_irq_type()</para></listitem>
-         <listitem><para>set_irq_wake()</para></listitem>
-         <listitem><para>set_irq_data()</para></listitem>
-         <listitem><para>set_irq_chip()</para></listitem>
-         <listitem><para>set_irq_chip_data()</para></listitem>
+         <listitem><para>irq_set_irq_type()</para></listitem>
+         <listitem><para>irq_set_irq_wake()</para></listitem>
+         <listitem><para>irq_set_handler_data()</para></listitem>
+         <listitem><para>irq_set_chip()</para></listitem>
+         <listitem><para>irq_set_chip_data()</para></listitem>
           </itemizedlist>
          See the autogenerated function documentation for details.
        </para>
          <listitem><para>handle_fasteoi_irq</para></listitem>
          <listitem><para>handle_simple_irq</para></listitem>
          <listitem><para>handle_percpu_irq</para></listitem>
+         <listitem><para>handle_edge_eoi_irq</para></listitem>
+         <listitem><para>handle_bad_irq</para></listitem>
          </itemizedlist>
          The interrupt flow handlers (either predefined or architecture
          specific) are assigned to specific interrupts by the architecture
                <programlisting>
 default_enable(struct irq_data *data)
 {
-       desc->chip->irq_unmask(data);
+       desc->irq_data.chip->irq_unmask(data);
 }
 
 default_disable(struct irq_data *data)
 {
        if (!delay_disable(data))
-               desc->chip->irq_mask(data);
+               desc->irq_data.chip->irq_mask(data);
 }
 
 default_ack(struct irq_data *data)
@@ -284,9 +286,9 @@ noop(struct irq_data *data))
                <para>
                The following control flow is implemented (simplified excerpt):
                <programlisting>
-desc->chip->irq_mask();
-handle_IRQ_event(desc->action);
-desc->chip->irq_unmask();
+desc->irq_data.chip->irq_mask_ack();
+handle_irq_event(desc->action);
+desc->irq_data.chip->irq_unmask();
                </programlisting>
                </para>
            </sect3>
@@ -300,8 +302,8 @@ desc->chip->irq_unmask();
                <para>
                The following control flow is implemented (simplified excerpt):
                <programlisting>
-handle_IRQ_event(desc->action);
-desc->chip->irq_eoi();
+handle_irq_event(desc->action);
+desc->irq_data.chip->irq_eoi();
                </programlisting>
                </para>
            </sect3>
@@ -315,17 +317,17 @@ desc->chip->irq_eoi();
                The following control flow is implemented (simplified excerpt):
                <programlisting>
 if (desc->status &amp; running) {
-       desc->chip->irq_mask();
+       desc->irq_data.chip->irq_mask_ack();
        desc->status |= pending | masked;
        return;
 }
-desc->chip->irq_ack();
+desc->irq_data.chip->irq_ack();
 desc->status |= running;
 do {
        if (desc->status &amp; masked)
-               desc->chip->irq_unmask();
+               desc->irq_data.chip->irq_unmask();
        desc->status &amp;= ~pending;
-       handle_IRQ_event(desc->action);
+       handle_irq_event(desc->action);
 } while (status &amp; pending);
 desc->status &amp;= ~running;
                </programlisting>
@@ -344,7 +346,7 @@ desc->status &amp;= ~running;
                <para>
                The following control flow is implemented (simplified excerpt):
                <programlisting>
-handle_IRQ_event(desc->action);
+handle_irq_event(desc->action);
                </programlisting>
                </para>
            </sect3>
@@ -362,12 +364,29 @@ handle_IRQ_event(desc->action);
                <para>
                The following control flow is implemented (simplified excerpt):
                <programlisting>
-handle_IRQ_event(desc->action);
-if (desc->chip->irq_eoi)
-        desc->chip->irq_eoi();
+if (desc->irq_data.chip->irq_ack)
+       desc->irq_data.chip->irq_ack();
+handle_irq_event(desc->action);
+if (desc->irq_data.chip->irq_eoi)
+        desc->irq_data.chip->irq_eoi();
                </programlisting>
                </para>
            </sect3>
+           <sect3 id="EOI_Edge_IRQ_flow_handler">
+               <title>EOI Edge IRQ flow handler</title>
+               <para>
+               handle_edge_eoi_irq provides an abnomination of the edge
+               handler which is solely used to tame a badly wreckaged
+               irq controller on powerpc/cell.
+               </para>
+           </sect3>
+           <sect3 id="BAD_IRQ_flow_handler">
+               <title>Bad IRQ flow handler</title>
+               <para>
+               handle_bad_irq is used for spurious interrupts which
+               have no real handler assigned..
+               </para>
+           </sect3>
        </sect2>
        <sect2 id="Quirks_and_optimizations">
        <title>Quirks and optimizations</title>
@@ -410,6 +429,7 @@ if (desc->chip->irq_eoi)
          <listitem><para>irq_mask_ack() - Optional, recommended for performance</para></listitem>
          <listitem><para>irq_mask()</para></listitem>
          <listitem><para>irq_unmask()</para></listitem>
+         <listitem><para>irq_eoi() - Optional, required for eoi flow handlers</para></listitem>
          <listitem><para>irq_retrigger() - Optional</para></listitem>
          <listitem><para>irq_set_type() - Optional</para></listitem>
          <listitem><para>irq_set_wake() - Optional</para></listitem>
@@ -424,32 +444,24 @@ if (desc->chip->irq_eoi)
   <chapter id="doirq">
      <title>__do_IRQ entry point</title>
      <para>
-       The original implementation __do_IRQ() is an alternative entry
-       point for all types of interrupts.
+       The original implementation __do_IRQ() was an alternative entry
+       point for all types of interrupts. It not longer exists.
      </para>
      <para>
        This handler turned out to be not suitable for all
        interrupt hardware and was therefore reimplemented with split
-       functionality for egde/level/simple/percpu interrupts. This is not
+       functionality for edge/level/simple/percpu interrupts. This is not
        only a functional optimization. It also shortens code paths for
        interrupts.
       </para>
-      <para>
-       To make use of the split implementation, replace the call to
-       __do_IRQ by a call to desc->handle_irq() and associate
-        the appropriate handler function to desc->handle_irq().
-       In most cases the generic handler implementations should
-       be sufficient.
-     </para>
   </chapter>
 
   <chapter id="locking">
      <title>Locking on SMP</title>
      <para>
        The locking of chip registers is up to the architecture that
-       defines the chip primitives. There is a chip->lock field that can be used
-       for serialization, but the generic layer does not touch it. The per-irq
-       structure is protected via desc->lock, by the generic layer.
+       defines the chip primitives. The per-irq structure is
+       protected via desc->lock, by the generic layer.
      </para>
   </chapter>
   <chapter id="structs">
index 71b6f50..1d7a885 100644 (file)
@@ -21,7 +21,7 @@ rcu.txt
 RTFP.txt
        - List of RCU papers (bibliography) going back to 1980.
 stallwarn.txt
-       - RCU CPU stall warnings (CONFIG_RCU_CPU_STALL_DETECTOR)
+       - RCU CPU stall warnings (module parameter rcu_cpu_stall_suppress)
 torture.txt
        - RCU Torture Test Operation (CONFIG_RCU_TORTURE_TEST)
 trace.txt
index 862c08e..4e95920 100644 (file)
@@ -1,22 +1,25 @@
 Using RCU's CPU Stall Detector
 
-The CONFIG_RCU_CPU_STALL_DETECTOR kernel config parameter enables
-RCU's CPU stall detector, which detects conditions that unduly delay
-RCU grace periods.  The stall detector's idea of what constitutes
-"unduly delayed" is controlled by a set of C preprocessor macros:
+The rcu_cpu_stall_suppress module parameter enables RCU's CPU stall
+detector, which detects conditions that unduly delay RCU grace periods.
+This module parameter enables CPU stall detection by default, but
+may be overridden via boot-time parameter or at runtime via sysfs.
+The stall detector's idea of what constitutes "unduly delayed" is
+controlled by a set of kernel configuration variables and cpp macros:
 
-RCU_SECONDS_TILL_STALL_CHECK
+CONFIG_RCU_CPU_STALL_TIMEOUT
 
-       This macro defines the period of time that RCU will wait from
-       the beginning of a grace period until it issues an RCU CPU
-       stall warning.  This time period is normally ten seconds.
+       This kernel configuration parameter defines the period of time
+       that RCU will wait from the beginning of a grace period until it
+       issues an RCU CPU stall warning.  This time period is normally
+       ten seconds.
 
 RCU_SECONDS_TILL_STALL_RECHECK
 
        This macro defines the period of time that RCU will wait after
        issuing a stall warning until it issues another stall warning
-       for the same stall.  This time period is normally set to thirty
-       seconds.
+       for the same stall.  This time period is normally set to three
+       times the check interval plus thirty seconds.
 
 RCU_STALL_RAT_DELAY
 
index 6a8c73f..c078ad4 100644 (file)
@@ -10,34 +10,46 @@ for rcutree and next for rcutiny.
 
 CONFIG_TREE_RCU and CONFIG_TREE_PREEMPT_RCU debugfs Files and Formats
 
-These implementations of RCU provides five debugfs files under the
-top-level directory RCU: rcu/rcudata (which displays fields in struct
-rcu_data), rcu/rcudata.csv (which is a .csv spreadsheet version of
-rcu/rcudata), rcu/rcugp (which displays grace-period counters),
-rcu/rcuhier (which displays the struct rcu_node hierarchy), and
-rcu/rcu_pending (which displays counts of the reasons that the
-rcu_pending() function decided that there was core RCU work to do).
+These implementations of RCU provides several debugfs files under the
+top-level directory "rcu":
+
+rcu/rcudata:
+       Displays fields in struct rcu_data.
+rcu/rcudata.csv:
+       Comma-separated values spreadsheet version of rcudata.
+rcu/rcugp:
+       Displays grace-period counters.
+rcu/rcuhier:
+       Displays the struct rcu_node hierarchy.
+rcu/rcu_pending:
+       Displays counts of the reasons rcu_pending() decided that RCU had
+       work to do.
+rcu/rcutorture:
+       Displays rcutorture test progress.
+rcu/rcuboost:
+       Displays RCU boosting statistics.  Only present if
+       CONFIG_RCU_BOOST=y.
 
 The output of "cat rcu/rcudata" looks as follows:
 
 rcu_sched:
-  0 c=17829 g=17829 pq=1 pqc=17829 qp=0 dt=10951/1 dn=0 df=1101 of=0 ri=36 ql=0 b=10
-  1 c=17829 g=17829 pq=1 pqc=17829 qp=0 dt=16117/1 dn=0 df=1015 of=0 ri=0 ql=0 b=10
-  2 c=17829 g=17829 pq=1 pqc=17829 qp=0 dt=1445/1 dn=0 df=1839 of=0 ri=0 ql=0 b=10
-  3 c=17829 g=17829 pq=1 pqc=17829 qp=0 dt=6681/1 dn=0 df=1545 of=0 ri=0 ql=0 b=10
-  4 c=17829 g=17829 pq=1 pqc=17829 qp=0 dt=1003/1 dn=0 df=1992 of=0 ri=0 ql=0 b=10
-  5 c=17829 g=17830 pq=1 pqc=17829 qp=1 dt=3887/1 dn=0 df=3331 of=0 ri=4 ql=2 b=10
-  6 c=17829 g=17829 pq=1 pqc=17829 qp=0 dt=859/1 dn=0 df=3224 of=0 ri=0 ql=0 b=10
-  7 c=17829 g=17830 pq=0 pqc=17829 qp=1 dt=3761/1 dn=0 df=1818 of=0 ri=0 ql=2 b=10
+  0 c=20972 g=20973 pq=1 pqc=20972 qp=0 dt=545/1/0 df=50 of=0 ri=0 ql=163 qs=NRW. kt=0/W/0 ktl=ebc3 b=10 ci=153737 co=0 ca=0
+  1 c=20972 g=20973 pq=1 pqc=20972 qp=0 dt=967/1/0 df=58 of=0 ri=0 ql=634 qs=NRW. kt=0/W/1 ktl=58c b=10 ci=191037 co=0 ca=0
+  2 c=20972 g=20973 pq=1 pqc=20972 qp=0 dt=1081/1/0 df=175 of=0 ri=0 ql=74 qs=N.W. kt=0/W/2 ktl=da94 b=10 ci=75991 co=0 ca=0
+  3 c=20942 g=20943 pq=1 pqc=20942 qp=1 dt=1846/0/0 df=404 of=0 ri=0 ql=0 qs=.... kt=0/W/3 ktl=d1cd b=10 ci=72261 co=0 ca=0
+  4 c=20972 g=20973 pq=1 pqc=20972 qp=0 dt=369/1/0 df=83 of=0 ri=0 ql=48 qs=N.W. kt=0/W/4 ktl=e0e7 b=10 ci=128365 co=0 ca=0
+  5 c=20972 g=20973 pq=1 pqc=20972 qp=0 dt=381/1/0 df=64 of=0 ri=0 ql=169 qs=NRW. kt=0/W/5 ktl=fb2f b=10 ci=164360 co=0 ca=0
+  6 c=20972 g=20973 pq=1 pqc=20972 qp=0 dt=1037/1/0 df=183 of=0 ri=0 ql=62 qs=N.W. kt=0/W/6 ktl=d2ad b=10 ci=65663 co=0 ca=0
+  7 c=20897 g=20897 pq=1 pqc=20896 qp=0 dt=1572/0/0 df=382 of=0 ri=0 ql=0 qs=.... kt=0/W/7 ktl=cf15 b=10 ci=75006 co=0 ca=0
 rcu_bh:
-  0 c=-275 g=-275 pq=1 pqc=-275 qp=0 dt=10951/1 dn=0 df=0 of=0 ri=0 ql=0 b=10
-  1 c=-275 g=-275 pq=1 pqc=-275 qp=0 dt=16117/1 dn=0 df=13 of=0 ri=0 ql=0 b=10
-  2 c=-275 g=-275 pq=1 pqc=-275 qp=0 dt=1445/1 dn=0 df=15 of=0 ri=0 ql=0 b=10
-  3 c=-275 g=-275 pq=1 pqc=-275 qp=0 dt=6681/1 dn=0 df=9 of=0 ri=0 ql=0 b=10
-  4 c=-275 g=-275 pq=1 pqc=-275 qp=0 dt=1003/1 dn=0 df=15 of=0 ri=0 ql=0 b=10
-  5 c=-275 g=-275 pq=1 pqc=-275 qp=0 dt=3887/1 dn=0 df=15 of=0 ri=0 ql=0 b=10
-  6 c=-275 g=-275 pq=1 pqc=-275 qp=0 dt=859/1 dn=0 df=15 of=0 ri=0 ql=0 b=10
-  7 c=-275 g=-275 pq=1 pqc=-275 qp=0 dt=3761/1 dn=0 df=15 of=0 ri=0 ql=0 b=10
+  0 c=1480 g=1480 pq=1 pqc=1479 qp=0 dt=545/1/0 df=6 of=0 ri=1 ql=0 qs=.... kt=0/W/0 ktl=ebc3 b=10 ci=0 co=0 ca=0
+  1 c=1480 g=1480 pq=1 pqc=1479 qp=0 dt=967/1/0 df=3 of=0 ri=1 ql=0 qs=.... kt=0/W/1 ktl=58c b=10 ci=151 co=0 ca=0
+  2 c=1480 g=1480 pq=1 pqc=1479 qp=0 dt=1081/1/0 df=6 of=0 ri=1 ql=0 qs=.... kt=0/W/2 ktl=da94 b=10 ci=0 co=0 ca=0
+  3 c=1480 g=1480 pq=1 pqc=1479 qp=0 dt=1846/0/0 df=8 of=0 ri=1 ql=0 qs=.... kt=0/W/3 ktl=d1cd b=10 ci=0 co=0 ca=0
+  4 c=1480 g=1480 pq=1 pqc=1479 qp=0 dt=369/1/0 df=6 of=0 ri=1 ql=0 qs=.... kt=0/W/4 ktl=e0e7 b=10 ci=0 co=0 ca=0
+  5 c=1480 g=1480 pq=1 pqc=1479 qp=0 dt=381/1/0 df=4 of=0 ri=1 ql=0 qs=.... kt=0/W/5 ktl=fb2f b=10 ci=0 co=0 ca=0
+  6 c=1480 g=1480 pq=1 pqc=1479 qp=0 dt=1037/1/0 df=6 of=0 ri=1 ql=0 qs=.... kt=0/W/6 ktl=d2ad b=10 ci=0 co=0 ca=0
+  7 c=1474 g=1474 pq=1 pqc=1473 qp=0 dt=1572/0/0 df=8 of=0 ri=1 ql=0 qs=.... kt=0/W/7 ktl=cf15 b=10 ci=0 co=0 ca=0
 
 The first section lists the rcu_data structures for rcu_sched, the second
 for rcu_bh.  Note that CONFIG_TREE_PREEMPT_RCU kernels will have an
@@ -52,17 +64,18 @@ o   The number at the beginning of each line is the CPU number.
        substantially larger than the number of actual CPUs.
 
 o      "c" is the count of grace periods that this CPU believes have
-       completed.  CPUs in dynticks idle mode may lag quite a ways
-       behind, for example, CPU 4 under "rcu_sched" above, which has
-       slept through the past 25 RCU grace periods.  It is not unusual
-       to see CPUs lagging by thousands of grace periods.
+       completed.  Offlined CPUs and CPUs in dynticks idle mode may
+       lag quite a ways behind, for example, CPU 6 under "rcu_sched"
+       above, which has been offline through not quite 40,000 RCU grace
+       periods.  It is not unusual to see CPUs lagging by thousands of
+       grace periods.
 
 o      "g" is the count of grace periods that this CPU believes have
-       started.  Again, CPUs in dynticks idle mode may lag behind.
-       If the "c" and "g" values are equal, this CPU has already
-       reported a quiescent state for the last RCU grace period that
-       it is aware of, otherwise, the CPU believes that it owes RCU a
-       quiescent state.
+       started.  Again, offlined CPUs and CPUs in dynticks idle mode
+       may lag behind.  If the "c" and "g" values are equal, this CPU
+       has already reported a quiescent state for the last RCU grace
+       period that it is aware of, otherwise, the CPU believes that it
+       owes RCU a quiescent state.
 
 o      "pq" indicates that this CPU has passed through a quiescent state
        for the current grace period.  It is possible for "pq" to be
@@ -81,7 +94,8 @@ o     "pqc" indicates which grace period the last-observed quiescent
        the next grace period!
 
 o      "qp" indicates that RCU still expects a quiescent state from
-       this CPU.
+       this CPU.  Offlined CPUs and CPUs in dyntick idle mode might
+       well have qp=1, which is OK: RCU is still ignoring them.
 
 o      "dt" is the current value of the dyntick counter that is incremented
        when entering or leaving dynticks idle state, either by the
@@ -108,7 +122,7 @@ o   "df" is the number of times that some other CPU has forced a
 
 o      "of" is the number of times that some other CPU has forced a
        quiescent state on behalf of this CPU due to this CPU being
-       offline.  In a perfect world, this might neve happen, but it
+       offline.  In a perfect world, this might never happen, but it
        turns out that offlining and onlining a CPU can take several grace
        periods, and so there is likely to be an extended period of time
        when RCU believes that the CPU is online when it really is not.
@@ -125,6 +139,62 @@ o  "ql" is the number of RCU callbacks currently residing on
        of what state they are in (new, waiting for grace period to
        start, waiting for grace period to end, ready to invoke).
 
+o      "qs" gives an indication of the state of the callback queue
+       with four characters:
+
+       "N"     Indicates that there are callbacks queued that are not
+               ready to be handled by the next grace period, and thus
+               will be handled by the grace period following the next
+               one.
+
+       "R"     Indicates that there are callbacks queued that are
+               ready to be handled by the next grace period.
+
+       "W"     Indicates that there are callbacks queued that are
+               waiting on the current grace period.
+
+       "D"     Indicates that there are callbacks queued that have
+               already been handled by a prior grace period, and are
+               thus waiting to be invoked.  Note that callbacks in
+               the process of being invoked are not counted here.
+               Callbacks in the process of being invoked are those
+               that have been removed from the rcu_data structures
+               queues by rcu_do_batch(), but which have not yet been
+               invoked.
+
+       If there are no callbacks in a given one of the above states,
+       the corresponding character is replaced by ".".
+
+o      "kt" is the per-CPU kernel-thread state.  The digit preceding
+       the first slash is zero if there is no work pending and 1
+       otherwise.  The character between the first pair of slashes is
+       as follows:
+
+       "S"     The kernel thread is stopped, in other words, all
+               CPUs corresponding to this rcu_node structure are
+               offline.
+
+       "R"     The kernel thread is running.
+
+       "W"     The kernel thread is waiting because there is no work
+               for it to do.
+
+       "O"     The kernel thread is waiting because it has been
+               forced off of its designated CPU or because its
+               ->cpus_allowed mask permits it to run on other than
+               its designated CPU.
+
+       "Y"     The kernel thread is yielding to avoid hogging CPU.
+
+       "?"     Unknown value, indicates a bug.
+
+       The number after the final slash is the CPU that the kthread
+       is actually running on.
+
+o      "ktl" is the low-order 16 bits (in hexadecimal) of the count of
+       the number of times that this CPU's per-CPU kthread has gone
+       through its loop servicing invoke_rcu_cpu_kthread() requests.
+
 o      "b" is the batch limit for this CPU.  If more than this number
        of RCU callbacks is ready to invoke, then the remainder will
        be deferred.
@@ -174,14 +244,14 @@ o "gpnum" is the number of grace periods that have started.  It is
 The output of "cat rcu/rcuhier" looks as follows, with very long lines:
 
 c=6902 g=6903 s=2 jfq=3 j=72c7 nfqs=13142/nfqsng=0(13142) fqlh=6
-1/1 .>. 0:127 ^0    
-3/3 .>. 0:35 ^0    0/0 .>. 36:71 ^1    0/0 .>. 72:107 ^2    0/0 .>. 108:127 ^3    
-3/3f .>. 0:5 ^0    2/3 .>. 6:11 ^1    0/0 .>. 12:17 ^2    0/0 .>. 18:23 ^3    0/0 .>. 24:29 ^4    0/0 .>. 30:35 ^5    0/0 .>. 36:41 ^0    0/0 .>. 42:47 ^1    0/0 .>. 48:53 ^2    0/0 .>. 54:59 ^3    0/0 .>. 60:65 ^4    0/0 .>. 66:71 ^5    0/0 .>. 72:77 ^0    0/0 .>. 78:83 ^1    0/0 .>. 84:89 ^2    0/0 .>. 90:95 ^3    0/0 .>. 96:101 ^4    0/0 .>. 102:107 ^5    0/0 .>. 108:113 ^0    0/0 .>. 114:119 ^1    0/0 .>. 120:125 ^2    0/0 .>. 126:127 ^3    
+1/1 ..>. 0:127 ^0
+3/3 ..>. 0:35 ^0    0/0 ..>. 36:71 ^1    0/0 ..>. 72:107 ^2    0/0 ..>. 108:127 ^3
+3/3f ..>. 0:5 ^0    2/3 ..>. 6:11 ^1    0/0 ..>. 12:17 ^2    0/0 ..>. 18:23 ^3    0/0 ..>. 24:29 ^4    0/0 ..>. 30:35 ^5    0/0 ..>. 36:41 ^0    0/0 ..>. 42:47 ^1    0/0 ..>. 48:53 ^2    0/0 ..>. 54:59 ^3    0/0 ..>. 60:65 ^4    0/0 ..>. 66:71 ^5    0/0 ..>. 72:77 ^0    0/0 ..>. 78:83 ^1    0/0 ..>. 84:89 ^2    0/0 ..>. 90:95 ^3    0/0 ..>. 96:101 ^4    0/0 ..>. 102:107 ^5    0/0 ..>. 108:113 ^0    0/0 ..>. 114:119 ^1    0/0 ..>. 120:125 ^2    0/0 ..>. 126:127 ^3
 rcu_bh:
 c=-226 g=-226 s=1 jfq=-5701 j=72c7 nfqs=88/nfqsng=0(88) fqlh=0
-0/1 .>. 0:127 ^0    
-0/3 .>. 0:35 ^0    0/0 .>. 36:71 ^1    0/0 .>. 72:107 ^2    0/0 .>. 108:127 ^3    
-0/3f .>. 0:5 ^0    0/3 .>. 6:11 ^1    0/0 .>. 12:17 ^2    0/0 .>. 18:23 ^3    0/0 .>. 24:29 ^4    0/0 .>. 30:35 ^5    0/0 .>. 36:41 ^0    0/0 .>. 42:47 ^1    0/0 .>. 48:53 ^2    0/0 .>. 54:59 ^3    0/0 .>. 60:65 ^4    0/0 .>. 66:71 ^5    0/0 .>. 72:77 ^0    0/0 .>. 78:83 ^1    0/0 .>. 84:89 ^2    0/0 .>. 90:95 ^3    0/0 .>. 96:101 ^4    0/0 .>. 102:107 ^5    0/0 .>. 108:113 ^0    0/0 .>. 114:119 ^1    0/0 .>. 120:125 ^2    0/0 .>. 126:127 ^3
+0/1 ..>. 0:127 ^0
+0/3 ..>. 0:35 ^0    0/0 ..>. 36:71 ^1    0/0 ..>. 72:107 ^2    0/0 ..>. 108:127 ^3
+0/3f ..>. 0:5 ^0    0/3 ..>. 6:11 ^1    0/0 ..>. 12:17 ^2    0/0 ..>. 18:23 ^3    0/0 ..>. 24:29 ^4    0/0 ..>. 30:35 ^5    0/0 ..>. 36:41 ^0    0/0 ..>. 42:47 ^1    0/0 ..>. 48:53 ^2    0/0 ..>. 54:59 ^3    0/0 ..>. 60:65 ^4    0/0 ..>. 66:71 ^5    0/0 ..>. 72:77 ^0    0/0 ..>. 78:83 ^1    0/0 ..>. 84:89 ^2    0/0 ..>. 90:95 ^3    0/0 ..>. 96:101 ^4    0/0 ..>. 102:107 ^5    0/0 ..>. 108:113 ^0    0/0 ..>. 114:119 ^1    0/0 ..>. 120:125 ^2    0/0 ..>. 126:127 ^3
 
 This is once again split into "rcu_sched" and "rcu_bh" portions,
 and CONFIG_TREE_PREEMPT_RCU kernels will again have an additional
@@ -240,13 +310,20 @@ o Each element of the form "1/1 0:127 ^0" represents one struct
                current grace period.
 
        o       The characters separated by the ">" indicate the state
-               of the blocked-tasks lists.  A "T" preceding the ">"
+               of the blocked-tasks lists.  A "G" preceding the ">"
                indicates that at least one task blocked in an RCU
                read-side critical section blocks the current grace
-               period, while a "." preceding the ">" indicates otherwise.
-               The character following the ">" indicates similarly for
-               the next grace period.  A "T" should appear in this
-               field only for rcu-preempt.
+               period, while a "E" preceding the ">" indicates that
+               at least one task blocked in an RCU read-side critical
+               section blocks the current expedited grace period.
+               A "T" character following the ">" indicates that at
+               least one task is blocked within an RCU read-side
+               critical section, regardless of whether any current
+               grace period (expedited or normal) is inconvenienced.
+               A "." character appears if the corresponding condition
+               does not hold, so that "..>." indicates that no tasks
+               are blocked.  In contrast, "GE>T" indicates maximal
+               inconvenience from blocked tasks.
 
        o       The numbers separated by the ":" are the range of CPUs
                served by this struct rcu_node.  This can be helpful
@@ -328,6 +405,113 @@ o "nn" is the number of times that this CPU needed nothing.  Alert
        is due to short-circuit evaluation in rcu_pending().
 
 
+The output of "cat rcu/rcutorture" looks as follows:
+
+rcutorture test sequence: 0 (test in progress)
+rcutorture update version number: 615
+
+The first line shows the number of rcutorture tests that have completed
+since boot.  If a test is currently running, the "(test in progress)"
+string will appear as shown above.  The second line shows the number of
+update cycles that the current test has started, or zero if there is
+no test in progress.
+
+
+The output of "cat rcu/rcuboost" looks as follows:
+
+0:5 tasks=.... kt=W ntb=0 neb=0 nnb=0 j=2f95 bt=300f
+     balk: nt=0 egt=989 bt=0 nb=0 ny=0 nos=16
+6:7 tasks=.... kt=W ntb=0 neb=0 nnb=0 j=2f95 bt=300f
+     balk: nt=0 egt=225 bt=0 nb=0 ny=0 nos=6
+
+This information is output only for rcu_preempt.  Each two-line entry
+corresponds to a leaf rcu_node strcuture.  The fields are as follows:
+
+o      "n:m" is the CPU-number range for the corresponding two-line
+       entry.  In the sample output above, the first entry covers
+       CPUs zero through five and the second entry covers CPUs 6
+       and 7.
+
+o      "tasks=TNEB" gives the state of the various segments of the
+       rnp->blocked_tasks list:
+
+       "T"     This indicates that there are some tasks that blocked
+               while running on one of the corresponding CPUs while
+               in an RCU read-side critical section.
+
+       "N"     This indicates that some of the blocked tasks are preventing
+               the current normal (non-expedited) grace period from
+               completing.
+
+       "E"     This indicates that some of the blocked tasks are preventing
+               the current expedited grace period from completing.
+
+       "B"     This indicates that some of the blocked tasks are in
+               need of RCU priority boosting.
+
+       Each character is replaced with "." if the corresponding
+       condition does not hold.
+
+o      "kt" is the state of the RCU priority-boosting kernel
+       thread associated with the corresponding rcu_node structure.
+       The state can be one of the following:
+
+       "S"     The kernel thread is stopped, in other words, all
+               CPUs corresponding to this rcu_node structure are
+               offline.
+
+       "R"     The kernel thread is running.
+
+       "W"     The kernel thread is waiting because there is no work
+               for it to do.
+
+       "Y"     The kernel thread is yielding to avoid hogging CPU.
+
+       "?"     Unknown value, indicates a bug.
+
+o      "ntb" is the number of tasks boosted.
+
+o      "neb" is the number of tasks boosted in order to complete an
+       expedited grace period.
+
+o      "nnb" is the number of tasks boosted in order to complete a
+       normal (non-expedited) grace period.  When boosting a task
+       that was blocking both an expedited and a normal grace period,
+       it is counted against the expedited total above.
+
+o      "j" is the low-order 16 bits of the jiffies counter in
+       hexadecimal.
+
+o      "bt" is the low-order 16 bits of the value that the jiffies
+       counter will have when we next start boosting, assuming that
+       the current grace period does not end beforehand.  This is
+       also in hexadecimal.
+
+o      "balk: nt" counts the number of times we didn't boost (in
+       other words, we balked) even though it was time to boost because
+       there were no blocked tasks to boost.  This situation occurs
+       when there is one blocked task on one rcu_node structure and
+       none on some other rcu_node structure.
+
+o      "egt" counts the number of times we balked because although
+       there were blocked tasks, none of them were blocking the
+       current grace period, whether expedited or otherwise.
+
+o      "bt" counts the number of times we balked because boosting
+       had already been initiated for the current grace period.
+
+o      "nb" counts the number of times we balked because there
+       was at least one task blocking the current non-expedited grace
+       period that never had blocked.  If it is already running, it
+       just won't help to boost its priority!
+
+o      "ny" counts the number of times we balked because it was
+       not yet time to start boosting.
+
+o      "nos" counts the number of times we balked for other
+       reasons, e.g., the grace period ended first.
+
+
 CONFIG_TINY_RCU and CONFIG_TINY_PREEMPT_RCU debugfs Files and Formats
 
 These implementations of RCU provides a single debugfs file under the
@@ -394,9 +578,9 @@ o   "neb" is the number of expedited grace periods that have had
 o      "nnb" is the number of normal grace periods that have had
        to resort to RCU priority boosting since boot.
 
-o      "j" is the low-order 12 bits of the jiffies counter in hexadecimal.
+o      "j" is the low-order 16 bits of the jiffies counter in hexadecimal.
 
-o      "bt" is the low-order 12 bits of the value that the jiffies counter
+o      "bt" is the low-order 16 bits of the value that the jiffies counter
        will have at the next time that boosting is scheduled to begin.
 
 o      In the line beginning with "normal balk", the fields are as follows:
index 5001b75..6754b2d 100644 (file)
@@ -3,24 +3,7 @@ Bus Types
 
 Definition
 ~~~~~~~~~~
-
-struct bus_type {
-       char                    * name;
-
-       struct subsystem        subsys;
-       struct kset             drivers;
-       struct kset             devices;
-
-       struct bus_attribute    * bus_attrs;
-       struct device_attribute * dev_attrs;
-       struct driver_attribute * drv_attrs;
-
-       int             (*match)(struct device * dev, struct device_driver * drv);
-       int             (*hotplug) (struct device *dev, char **envp, 
-                                   int num_envp, char *buffer, int buffer_size);
-       int             (*suspend)(struct device * dev, pm_message_t state);
-       int             (*resume)(struct device * dev);
-};
+See the kerneldoc for the struct bus_type.
 
 int bus_register(struct bus_type * bus);
 
index 548505f..1fefc48 100644 (file)
@@ -27,22 +27,7 @@ The device class structure looks like:
 typedef int (*devclass_add)(struct device *);
 typedef void (*devclass_remove)(struct device *);
 
-struct device_class {
-       char                    * name;
-       rwlock_t                lock;
-       u32                     devnum;
-       struct list_head        node;
-
-       struct list_head        drivers;
-       struct list_head        intf_list;
-
-       struct driver_dir_entry dir;
-       struct driver_dir_entry device_dir;
-       struct driver_dir_entry driver_dir;
-
-       devclass_add            add_device;
-       devclass_remove         remove_device;
-};
+See the kerneldoc for the struct class.
 
 A typical device class definition would look like: 
 
index a124f31..b2ff426 100644 (file)
@@ -2,96 +2,7 @@
 The Basic Device Structure
 ~~~~~~~~~~~~~~~~~~~~~~~~~~
 
-struct device {
-        struct list_head g_list;
-        struct list_head node;
-        struct list_head bus_list;
-        struct list_head driver_list;
-        struct list_head intf_list;
-        struct list_head children;
-        struct device   * parent;
-
-        char    name[DEVICE_NAME_SIZE];
-        char    bus_id[BUS_ID_SIZE];
-
-        spinlock_t      lock;
-        atomic_t        refcount;
-
-        struct bus_type * bus;
-        struct driver_dir_entry dir;
-
-       u32             class_num;
-
-        struct device_driver *driver;
-        void            *driver_data;
-        void            *platform_data;
-
-        u32             current_state;
-        unsigned char *saved_state;
-
-        void    (*release)(struct device * dev);
-};
-
-Fields 
-~~~~~~
-g_list:        Node in the global device list.
-
-node:  Node in device's parent's children list.
-
-bus_list: Node in device's bus's devices list.
-
-driver_list:   Node in device's driver's devices list.
-
-intf_list:     List of intf_data. There is one structure allocated for
-              each interface that the device supports.
-
-children:      List of child devices.
-
-parent:        *** FIXME ***
-
-name:         ASCII description of device. 
-              Example: " 3Com Corporation 3c905 100BaseTX [Boomerang]"
-
-bus_id:               ASCII representation of device's bus position. This 
-              field should be a name unique across all devices on the
-              bus type the device belongs to. 
-
-              Example: PCI bus_ids are in the form of
-              <bus number>:<slot number>.<function number> 
-              This name is unique across all PCI devices in the system.
-
-lock:         Spinlock for the device. 
-
-refcount:      Reference count on the device.
-
-bus:          Pointer to struct bus_type that device belongs to.
-
-dir:          Device's sysfs directory.
-
-class_num:     Class-enumerated value of the device.
-
-driver:               Pointer to struct device_driver that controls the device.
-
-driver_data:   Driver-specific data.
-
-platform_data: Platform data specific to the device.
-
-              Example:  for devices on custom boards, as typical of embedded
-              and SOC based hardware, Linux often uses platform_data to point
-              to board-specific structures describing devices and how they
-              are wired.  That can include what ports are available, chip
-              variants, which GPIO pins act in what additional roles, and so
-              on.  This shrinks the "Board Support Packages" (BSPs) and
-              minimizes board-specific #ifdefs in drivers.
-
-current_state: Current power state of the device.
-
-saved_state:   Pointer to saved state of the device. This is usable by
-              the device driver controlling the device.
-
-release:       Callback to free the device after all references have 
-              gone away. This should be set by the allocator of the 
-              device (i.e. the bus driver that discovered the device).
+See the kerneldoc for the struct device.
 
 
 Programming Interface
index d2cd6fb..4421135 100644 (file)
@@ -1,23 +1,7 @@
 
 Device Drivers
 
-struct device_driver {
-        char                    * name;
-        struct bus_type         * bus;
-
-        struct completion      unloaded;
-        struct kobject         kobj;
-        list_t                  devices;
-
-        struct module          *owner;
-
-        int     (*probe)        (struct device * dev);
-        int     (*remove)       (struct device * dev);
-
-        int     (*suspend)      (struct device * dev, pm_message_t state);
-        int     (*resume)       (struct device * dev);
-};
-
+See the kerneldoc for the struct device_driver.
 
 
 Allocation
index 492e81d..f6a24e8 100644 (file)
@@ -460,14 +460,6 @@ Who:       Thomas Gleixner <tglx@linutronix.de>
 
 ----------------------------
 
-What:  The acpi_sleep=s4_nonvs command line option
-When:  2.6.37
-Files: arch/x86/kernel/acpi/sleep.c
-Why:   superseded by acpi_sleep=nonvs
-Who:   Rafael J. Wysocki <rjw@sisk.pl>
-
-----------------------------
-
 What:  PCI DMA unmap state API
 When:  August 2012
 Why:   PCI DMA unmap state API (include/linux/pci-dma.h) was replaced
index b0b814d..60740e8 100644 (file)
@@ -836,7 +836,6 @@ Provides counts of softirq handlers serviced since boot time, for each cpu.
  TASKLET:          0          0          0        290
    SCHED:      27035      26983      26971      26746
  HRTIMER:          0          0          0          0
-     RCU:       1678       1769       2178       2250
 
 
 1.3 IDE devices in /proc/ide
index b63301a..050d37f 100644 (file)
@@ -11,14 +11,14 @@ for non English (read: Japanese) speakers and is not intended as a
 fork. So if you have any comments or updates for this file, please try
 to update the original English file first.
 
-Last Updated: 2008/10/24
+Last Updated: 2011/03/31
 ==================================
 これは、
-linux-2.6.28/Documentation/HOWTO
+linux-2.6.38/Documentation/HOWTO
 の和訳です。
 
 翻訳団体: JF プロジェクト < http://www.linux.or.jp/JF/ >
-翻訳日: 2008/10/24
+翻訳日: 2011/3/28
 翻訳者: Tsugikazu Shibata <tshibata at ab dot jp dot nec dot com>
 校正者: 松倉さん <nbh--mats at nifty dot com>
          小林 雅典さん (Masanori Kobayasi) <zap03216 at nifty dot ne dot jp>
@@ -256,8 +256,8 @@ Linux カーネルの開発プロセスは現在幾つかの異なるメイン
   - メインの 2.6.x カーネルツリー
   - 2.6.x.y -stable カーネルツリー
   - 2.6.x -git カーネルパッチ
-  - 2.6.x -mm カーネルパッチ
   - サブシステム毎のカーネルツリーとパッチ
+  - 統合テストのための 2.6.x -next カーネルツリー
 
 2.6.x カーネルツリー
 -----------------
@@ -268,9 +268,9 @@ Linux カーネルの開発プロセスは現在幾つかの異なるメイン
 
   - 新しいカーネルがリリースされた直後に、2週間の特別期間が設けられ、
     この期間中に、メンテナ達は Linus に大きな差分を送ることができます。
-    このような差分は通常 -mm カーネルに数週間含まれてきたパッチです。
+    このような差分は通常 -next カーネルに数週間含まれてきたパッチです。
     大きな変更は git(カーネルのソース管理ツール、詳細は
-    http://git.or.cz/  参照) を使って送るのが好ましいやり方ですが、パッ
+    http://git-scm.com/  参照) を使って送るのが好ましいやり方ですが、パッ
     チファイルの形式のまま送るのでも十分です。
 
   - 2週間後、-rc1 カーネルがリリースされ、この後にはカーネル全体の安定
@@ -333,86 +333,44 @@ git リポジトリで管理されているLinus のカーネルツリーの毎
 れは -rc カーネルと比べて、パッチが大丈夫かどうかも確認しないで自動的
 に生成されるので、より実験的です。
 
-2.6.x -mm カーネルパッチ
-------------------------
-
-Andrew Morton によってリリースされる実験的なカーネルパッチ群です。
-Andrew は個別のサブシステムカーネルツリーとパッチを全て集めてきて
-linux-kernel メーリングリストで収集された多数のパッチと同時に一つにま
-とめます。
-このツリーは新機能とパッチが検証される場となります。ある期間の間パッチ
-が -mm に入って価値を証明されたら、Andrew やサブシステムメンテナが、
-メインラインへ入れるように Linus にプッシュします。
-
-メインカーネルツリーに含めるために Linus に送る前に、すべての新しいパッ
-チが -mm ツリーでテストされることが強く推奨されています。マージウィン
-ドウが開く前に -mm ツリーに現れなかったパッチはメインラインにマージさ
-れることは困難になります。
-
-これらのカーネルは安定して動作すべきシステムとして使うのには適切ではあ
-りませんし、カーネルブランチの中でももっとも動作にリスクが高いものです。
-
-もしあなたが、カーネル開発プロセスの支援をしたいと思っているのであれば、
-どうぞこれらのカーネルリリースをテストに使ってみて、そしてもし問題があ
-れば、またもし全てが正しく動作したとしても、linux-kernel メーリングリ
-ストにフィードバックを提供してください。
-
-すべての他の実験的パッチに加えて、これらのカーネルは通常リリース時点で
-メインラインの -git カーネルに含まれる全ての変更も含んでいます。
-
--mm カーネルは決まったスケジュールではリリースされません、しかし通常幾
-つかの -mm カーネル (1 から 3 が普通)が各-rc カーネルの間にリリースさ
-れます。
-
 サブシステム毎のカーネルツリーとパッチ
 -------------------------------------------
 
-カーネルの様々な領域で何が起きているかを見られるようにするため、多くの
-カーネルサブシステム開発者は彼らの開発ツリーを公開しています。これらの
-ツリーは説明したように -mm カーネルリリースに入れ込まれます。
-
-以下はさまざまなカーネルツリーの中のいくつかのリスト-
-
-  git ツリー-
-    - Kbuild の開発ツリー、Sam Ravnborg <sam@ravnborg.org>
-       git.kernel.org:/pub/scm/linux/kernel/git/sam/kbuild.git
-
-    - ACPI の開発ツリー、 Len Brown <len.brown@intel.com>
-       git.kernel.org:/pub/scm/linux/kernel/git/lenb/linux-acpi-2.6.git
-
-    - Block の開発ツリー、Jens Axboe <axboe@suse.de>
-       git.kernel.org:/pub/scm/linux/kernel/git/axboe/linux-2.6-block.git
-
-    - DRM の開発ツリー、Dave Airlie <airlied@linux.ie>
-       git.kernel.org:/pub/scm/linux/kernel/git/airlied/drm-2.6.git
-
-    - ia64 の開発ツリー、Tony Luck <tony.luck@intel.com>
-       git.kernel.org:/pub/scm/linux/kernel/git/aegl/linux-2.6.git
-
-    - infiniband, Roland Dreier <rolandd@cisco.com>
-       git.kernel.org:/pub/scm/linux/kernel/git/roland/infiniband.git
-
-    - libata, Jeff Garzik <jgarzik@pobox.com>
-       git.kernel.org:/pub/scm/linux/kernel/git/jgarzik/libata-dev.git
-
-    - ネットワークドライバ, Jeff Garzik <jgarzik@pobox.com>
-       git.kernel.org:/pub/scm/linux/kernel/git/jgarzik/netdev-2.6.git
-
-    - pcmcia, Dominik Brodowski <linux@dominikbrodowski.net>
-       git.kernel.org:/pub/scm/linux/kernel/git/brodo/pcmcia-2.6.git
-
-    - SCSI, James Bottomley <James.Bottomley@hansenpartnership.com>
-       git.kernel.org:/pub/scm/linux/kernel/git/jejb/scsi-misc-2.6.git
-
-    - x86, Ingo Molnar <mingo@elte.hu>
-       git://git.kernel.org/pub/scm/linux/kernel/git/x86/linux-2.6-x86.git
-
-  quilt ツリー-
-    - USB, ドライバコアと I2C, Greg Kroah-Hartman <gregkh@suse.de>
-       kernel.org/pub/linux/kernel/people/gregkh/gregkh-2.6/
+それぞれのカーネルサブシステムのメンテナ達は --- そして多くのカーネル
+サブシステムの開発者達も --- 各自の最新の開発状況をソースリポジトリに
+公開しています。そのため、自分とは異なる領域のカーネルで何が起きている
+かを他の人が見られるようになっています。開発が早く進んでいる領域では、
+開発者は自身の投稿がどのサブシステムカーネルツリーを元にしているか質問
+されるので、その投稿とすでに進行中の他の作業との衝突が避けられます。
+
+大部分のこれらのリポジトリは git ツリーです。しかしその他の SCM や
+quilt シリーズとして公開されているパッチキューも使われています。これら
+のサブシステムリポジトリのアドレスは MAINTAINERS ファイルにリストされ
+ています。これらの多くは http://git.kernel.org/ で参照することができま
+す。
 
-  その他のカーネルツリーは http://git.kernel.org/ と MAINTAINERS ファ
-  イルに一覧表があります。
+提案されたパッチがこのようなサブシステムツリーにコミットされる前に、メー
+リングリストで事前にレビューにかけられます(以下の対応するセクションを
+参照)。いくつかのカーネルサブシステムでは、このレビューは patchwork
+というツールによって追跡されます。Patchwork は web インターフェイスに
+よってパッチ投稿の表示、パッチへのコメント付けや改訂などができ、そして
+メンテナはパッチに対して、レビュー中、受付済み、拒否というようなマーク
+をつけることができます。大部分のこれらの patchwork のサイトは
+http://patchwork.kernel.org/ でリストされています。
+
+統合テストのための 2.6.x -next カーネルツリー
+---------------------------------------------
+
+サブシステムツリーの更新内容がメインラインの 2.6.x ツリーにマージされ
+る前に、それらは統合テストされる必要があります。この目的のため、実質的
+に全サブシステムツリーからほぼ毎日プルされてできる特別なテスト用のリ
+ポジトリが存在します-
+       http://git.kernel.org/?p=linux/kernel/git/sfr/linux-next.git
+       http://linux.f-seidel.de/linux-next/pmwiki/
+
+このやり方によって、-next カーネルは次のマージ機会でどんなものがメイン
+ラインカーネルにマージされるか、おおまかなの展望を提供します。-next 
+カーネルの実行テストを行う冒険好きなテスターは大いに歓迎されます
 
 バグレポート
 -------------
@@ -673,10 +631,9 @@ Linux カーネルコミュニティは、一度に大量のコードの塊を
 じところからスタートしたのですから。
 
 Paolo Ciarrocchi に感謝、彼は彼の書いた "Development Process"
-(http://linux.tar.bz/articles/2.6-development_process)セクショ
-ンをこのテキストの原型にすることを許可してくれました。
-Rundy Dunlap と Gerrit Huizenga はメーリングリストでやるべきこととやっ
-てはいけないことのリストを提供してくれました。
+(http://lwn.net/Articles/94386/) セクションをこのテキストの原型にする
+ことを許可してくれました。Rundy Dunlap と Gerrit Huizenga はメーリング
+リストでやるべきこととやってはいけないことのリストを提供してくれました。
 以下の人々のレビュー、コメント、貢献に感謝。
 Pat Mochel, Hanna Linder, Randy Dunlap, Kay Sievers,
 Vojtech Pavlik, Jan Kara, Josh Boyer, Kees Cook, Andrew Morton, Andi
index cc85a92..c603ef7 100644 (file)
@@ -245,7 +245,7 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
 
        acpi_sleep=     [HW,ACPI] Sleep options
                        Format: { s3_bios, s3_mode, s3_beep, s4_nohwsig,
-                                 old_ordering, s4_nonvs, sci_force_enable }
+                                 old_ordering, nonvs, sci_force_enable }
                        See Documentation/power/video.txt for information on
                        s3_bios and s3_mode.
                        s3_beep is for debugging; it makes the PC's speaker beep
@@ -1664,6 +1664,10 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
                        noexec=on: enable non-executable mappings (default)
                        noexec=off: disable non-executable mappings
 
+       nosmep          [X86]
+                       Disable SMEP (Supervisor Mode Execution Protection)
+                       even if it is supported by processor.
+
        noexec32        [X86-64]
                        This affects only 32-bit executables.
                        noexec32=on: enable non-executable mappings (default)
index 1971bcf..8888083 100644 (file)
@@ -279,11 +279,15 @@ When the system goes into the standby or memory sleep state, the phases are:
        time.)  Unlike the other suspend-related phases, during the prepare
        phase the device tree is traversed top-down.
 
-       The prepare phase uses only a bus callback.  After the callback method
-       returns, no new children may be registered below the device.  The method
-       may also prepare the device or driver in some way for the upcoming
-       system power transition, but it should not put the device into a
-       low-power state.
+       In addition to that, if device drivers need to allocate additional
+       memory to be able to hadle device suspend correctly, that should be
+       done in the prepare phase.
+
+       After the prepare callback method returns, no new children may be
+       registered below the device.  The method may also prepare the device or
+       driver in some way for the upcoming system power transition (for
+       example, by allocating additional memory required for this purpose), but
+       it should not put the device into a low-power state.
 
     2. The suspend methods should quiesce the device to stop it from performing
        I/O.  They also may save the device registers and put it into the
index cf98070..c2a4a34 100644 (file)
@@ -1,46 +1,41 @@
 Suspend notifiers
-       (C) 2007 Rafael J. Wysocki <rjw@sisk.pl>, GPL
-
-There are some operations that device drivers may want to carry out in their
-.suspend() routines, but shouldn't, because they can cause the hibernation or
-suspend to fail. For example, a driver may want to allocate a substantial amount
-of memory (like 50 MB) in .suspend(), but that shouldn't be done after the
-swsusp's memory shrinker has run.
-
-Also, there may be some operations, that subsystems want to carry out before a
-hibernation/suspend or after a restore/resume, requiring the system to be fully
-functional, so the drivers' .suspend() and .resume() routines are not suitable
-for this purpose.  For example, device drivers may want to upload firmware to
-their devices after a restore from a hibernation image, but they cannot do it by
-calling request_firmware() from their .resume() routines (user land processes
-are frozen at this point).  The solution may be to load the firmware into
-memory before processes are frozen and upload it from there in the .resume()
-routine.  Of course, a hibernation notifier may be used for this purpose.
-
-The subsystems that have such needs can register suspend notifiers that will be
-called upon the following events by the suspend core:
+       (C) 2007-2011 Rafael J. Wysocki <rjw@sisk.pl>, GPL
+
+There are some operations that subsystems or drivers may want to carry out
+before hibernation/suspend or after restore/resume, but they require the system
+to be fully functional, so the drivers' and subsystems' .suspend() and .resume()
+or even .prepare() and .complete() callbacks are not suitable for this purpose.
+For example, device drivers may want to upload firmware to their devices after
+resume/restore, but they cannot do it by calling request_firmware() from their
+.resume() or .complete() routines (user land processes are frozen at these
+points).  The solution may be to load the firmware into memory before processes
+are frozen and upload it from there in the .resume() routine.
+A suspend/hibernation notifier may be used for this purpose.
+
+The subsystems or drivers having such needs can register suspend notifiers that
+will be called upon the following events by the PM core:
 
 PM_HIBERNATION_PREPARE The system is going to hibernate or suspend, tasks will
                        be frozen immediately.
 
 PM_POST_HIBERNATION    The system memory state has been restored from a
-                       hibernation image or an error occurred during the
-                       hibernation.  Device drivers' .resume() callbacks have
+                       hibernation image or an error occurred during
+                       hibernation.  Device drivers' restore callbacks have
                        been executed and tasks have been thawed.
 
 PM_RESTORE_PREPARE     The system is going to restore a hibernation image.
-                       If all goes well the restored kernel will issue a
+                       If all goes well, the restored kernel will issue a
                        PM_POST_HIBERNATION notification.
 
-PM_POST_RESTORE                An error occurred during the hibernation restore.
-                       Device drivers' .resume() callbacks have been executed
+PM_POST_RESTORE                An error occurred during restore from hibernation.
+                       Device drivers' restore callbacks have been executed
                        and tasks have been thawed.
 
-PM_SUSPEND_PREPARE     The system is preparing for suspend.
+PM_SUSPEND_PREPARE     The system is preparing for suspend.
 
 PM_POST_SUSPEND                The system has just resumed or an error occurred during
-                       the suspend.    Device drivers' .resume() callbacks have
-                       been executed and tasks have been thawed.
+                       suspend.  Device drivers' resume callbacks have been
+                       executed and tasks have been thawed.
 
 It is generally assumed that whatever the notifiers do for
 PM_HIBERNATION_PREPARE, should be undone for PM_POST_HIBERNATION.  Analogously,
index 6d27ab8..c83bd6b 100644 (file)
@@ -120,7 +120,6 @@ format:
         field:unsigned char common_flags;       offset:2;       size:1; signed:0;
         field:unsigned char common_preempt_count;       offset:3; size:1;signed:0;
         field:int common_pid;   offset:4;       size:4; signed:1;
-        field:int common_lock_depth;    offset:8;       size:4; signed:1;
 
         field:unsigned long __probe_ip; offset:12;      size:4; signed:0;
         field:int __probe_nargs;        offset:16;      size:4; signed:1;
diff --git a/Documentation/virtual/00-INDEX b/Documentation/virtual/00-INDEX
new file mode 100644 (file)
index 0000000..fe0251c
--- /dev/null
@@ -0,0 +1,10 @@
+Virtualization support in the Linux kernel.
+
+00-INDEX
+       - this file.
+kvm/
+       - Kernel Virtual Machine.  See also http://linux-kvm.org
+lguest/
+       - Extremely simple hypervisor for experimental/educational use.
+uml/
+       - User Mode Linux, builds/runs Linux kernel as a userspace program.
similarity index 95%
rename from Documentation/kvm/review-checklist.txt
rename to Documentation/virtual/kvm/review-checklist.txt
index 730475a..a850986 100644 (file)
@@ -7,7 +7,7 @@ Review checklist for kvm patches
 2.  Patches should be against kvm.git master branch.
 
 3.  If the patch introduces or modifies a new userspace API:
-    - the API must be documented in Documentation/kvm/api.txt
+    - the API must be documented in Documentation/virtual/kvm/api.txt
     - the API must be discoverable using KVM_CHECK_EXTENSION
 
 4.  New state must include support for save/restore.
similarity index 97%
rename from Documentation/lguest/lguest.txt
rename to Documentation/virtual/lguest/lguest.txt
index dad9997..bff0c55 100644 (file)
@@ -74,7 +74,8 @@ Running Lguest:
 
 - Run an lguest as root:
 
-      Documentation/lguest/lguest 64 vmlinux --tunnet=192.168.19.1 --block=rootfile root=/dev/vda
+      Documentation/virtual/lguest/lguest 64 vmlinux --tunnet=192.168.19.1 \
+        --block=rootfile root=/dev/vda
 
    Explanation:
     64: the amount of memory to use, in MB.
index 092e596..c54b4f5 100644 (file)
@@ -206,7 +206,7 @@ IOMMU (input/output memory management unit)
       (e.g. because you have < 3 GB memory).
       Kernel boot message: "PCI-DMA: Disabling IOMMU"
 
-   2. <arch/x86_64/kernel/pci-gart.c>: AMD GART based hardware IOMMU.
+   2. <arch/x86/kernel/amd_gart_64.c>: AMD GART based hardware IOMMU.
       Kernel boot message: "PCI-DMA: using GART IOMMU"
 
    3. <arch/x86_64/kernel/pci-swiotlb.c> : Software IOMMU implementation. Used
diff --git a/Documentation/zh_CN/email-clients.txt b/Documentation/zh_CN/email-clients.txt
new file mode 100644 (file)
index 0000000..5d65e32
--- /dev/null
@@ -0,0 +1,210 @@
+锘?Chinese translated version of Documentation/email-clients.txt
+
+If you have any comment or update to the content, please contact the
+original document maintainer directly.  However, if you have a problem
+communicating in English you can also ask the Chinese maintainer for
+help.  Contact the Chinese maintainer if this translation is outdated
+or if there is a problem with the translation.
+
+Chinese maintainer: Harry Wei <harryxiyou@gmail.com>
+---------------------------------------------------------------------
+Documentation/email-clients.txt ???涓????缈昏??
+
+濡??????宠??璁烘????存?版???????????瀹癸??璇风?存?ヨ??绯诲?????妗g??缁存?よ?????濡????浣?浣跨?ㄨ?辨??
+浜ゆ???????伴?剧??璇?锛?涔????浠ュ??涓???????缁存?よ??姹???┿??濡???????缈昏????存?颁???????舵?????缈?
+璇?瀛???ㄩ??棰?锛?璇疯??绯讳腑??????缁存?よ?????
+
+涓???????缁存?よ??锛? 璐惧??濞?  Harry Wei <harryxiyou@gmail.com>
+涓???????缈昏?????锛? 璐惧??濞?  Harry Wei <harryxiyou@gmail.com>
+涓?????????¤?????锛? Yinglin Luan <synmyth@gmail.com>
+               Xiaochen Wang <wangxiaochen0@gmail.com>
+               yaxinsn <yaxinsn@163.com>
+
+浠ヤ??涓烘?f??
+---------------------------------------------------------------------
+
+Linux???浠跺?㈡?风?????缃?淇℃??
+======================================================================
+
+?????????缃?
+----------------------------------------------------------------------
+Linux?????歌ˉ涓???????杩????浠惰?????浜ょ??锛????濂芥??琛ヤ??浣?涓洪??浠朵????????宓?????????????浜?缁存?よ??
+??ユ?堕??浠讹??浣???????浠剁?????瀹规?煎??搴?璇ユ??"text/plain"?????惰??锛????浠朵????????涓?璧???????锛?
+???涓鸿??浼?浣胯ˉ涓????寮???ㄩ?ㄥ????ㄨ??璁鸿??绋?涓???????寰???伴?俱??
+
+??ㄦ?ュ?????Linux?????歌ˉ涓???????浠跺?㈡?风????ㄥ?????琛ヤ????跺??璇ュ??浜?????????????濮???舵?????渚?濡?锛?
+浠?浠?涓???芥?瑰?????????????ゅ?惰〃绗???????绌烘?硷???????虫????ㄦ??涓?琛????寮?澶存?????缁?灏俱??
+
+涓?瑕????杩?"format=flowed"妯″????????琛ヤ?????杩???蜂??寮?璧蜂?????棰????浠ュ?????瀹崇?????琛????
+
+涓?瑕?璁╀????????浠跺?㈡?风??杩?琛??????ㄦ?㈣?????杩???蜂??浼???村??浣????琛ヤ?????
+
+???浠跺?㈡?风??涓???芥?瑰???????????瀛?绗????缂??????瑰?????瑕??????????琛ヤ???????芥??ASCII??????UTF-8缂??????瑰??锛?
+濡????浣?浣跨??UTF-8缂??????瑰???????????浠讹????d??浣?灏?浼???垮??涓?浜??????藉????????瀛?绗???????棰????
+
+???浠跺?㈡?风??搴?璇ュ舰???骞朵??淇???? References: ?????? In-Reply-To: ???棰?锛???d??
+???浠惰??棰?灏变??浼?涓???????
+
+澶???剁??甯?(?????????璐寸??甯?)???甯镐????界?ㄤ??琛ヤ??锛????涓哄?惰〃绗?浼?杞????涓虹┖??笺??浣跨??xclipboard, xclip
+??????xcutsel涔?璁稿??浠ワ??浣???????濂芥??璇?涓?涓?????????垮??浣跨?ㄥ????剁??甯????
+
+涓?瑕???ㄤ娇???PGP/GPG缃插????????浠朵腑??????琛ヤ?????杩???蜂??浣垮??寰?澶???????涓???借?诲??????????ㄤ??浣????琛ヤ?????
+锛?杩?涓????棰?搴?璇ユ?????浠ヤ慨澶????锛?
+
+??ㄧ???????搁??浠跺??琛ㄥ?????琛ヤ??涔????锛?缁????宸卞?????涓?涓?琛ヤ?????涓?涓???????涓绘??锛?淇?瀛???ユ?跺?扮??
+???浠讹??灏?琛ヤ?????'patch'??戒护???涓?锛?濡??????????浜?锛????缁??????搁??浠跺??琛ㄥ????????
+
+
+涓?浜????浠跺?㈡?风?????绀?
+----------------------------------------------------------------------
+杩????缁???轰??浜?璇?缁????MUA???缃????绀猴?????浠ョ?ㄤ??缁?Linux?????稿?????琛ヤ?????杩?浜?骞朵???????虫??
+?????????杞?浠跺?????缃???荤?????
+
+璇存??锛?
+TUI = 浠ユ?????涓哄?虹???????ㄦ?锋?ュ??
+GUI = ??惧舰?????㈢?ㄦ?锋?ュ??
+
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+Alpine (TUI)
+
+???缃????椤癸??
+???"Sending Preferences"??ㄥ??锛?
+
+- "Do Not Send Flowed Text"蹇?椤诲?????
+- "Strip Whitespace Before Sending"蹇?椤诲?抽??
+
+褰???????浠舵?讹????????搴?璇ユ?惧?ㄨˉ涓?浼???虹?扮????版?癸????跺?????涓?CTRL-R缁???????锛?浣挎??瀹????
+琛ヤ?????浠跺????ュ?伴??浠朵腑???
+
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+Evolution (GUI)
+
+涓?浜?寮????????????????浣跨?ㄥ????????琛ヤ??
+
+褰??????╅??浠堕??椤癸??Preformat
+  浠?Format->Heading->Preformatted (Ctrl-7)??????宸ュ?锋??
+
+??跺??浣跨??锛?
+  Insert->Text File... (Alt-n x)?????ヨˉ涓????浠躲??
+
+浣?杩????浠?"diff -Nru old.c new.c | xclip"锛???????Preformat锛???跺??浣跨?ㄤ腑??撮??杩?琛?绮?甯????
+
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+Kmail (GUI)
+
+涓?浜?寮????????????????浣跨?ㄥ????????琛ヤ?????
+
+榛?璁よ?剧疆涓?涓?HTML??煎??????????????锛?涓?瑕??????ㄥ?????
+
+褰?涔????涓?灏????浠剁????跺??锛???ㄩ??椤逛?????涓?瑕??????╄????ㄦ?㈣????????涓????缂虹?瑰氨???浣???ㄩ??浠朵腑杈???ョ??浠讳????????
+??戒??浼?琚??????ㄦ?㈣??锛????姝や??蹇?椤诲?ㄥ?????琛ヤ??涔?????????ㄦ?㈣????????绠?????????规??灏辨???????ㄨ????ㄦ?㈣????ヤ功??????浠讹??
+??跺?????瀹?淇?瀛?涓鸿??绋裤??涓????浣???ㄨ??绋夸腑???娆℃??寮?瀹?锛?瀹?宸茬????ㄩ?ㄨ????ㄦ?㈣??浜?锛???d??浣???????浠惰?界?舵病???
+?????╄????ㄦ?㈣??锛?浣????杩?涓?浼?澶卞?诲凡???????????ㄦ?㈣?????
+
+??ㄩ??浠剁??搴????锛??????ヨˉ涓?涔????锛???句??甯哥?ㄧ??琛ヤ??瀹????绗?锛?涓?涓?杩?瀛????(---)???
+
+??跺?????"Message"????????$??锛??????╂????ユ??浠讹????ョ????????浣????琛ヤ?????浠躲??杩????涓?涓?棰?澶???????椤癸??浣????浠?
+???杩?瀹????缃?浣???????浠跺缓绔?宸ュ?锋????????锛?杩????浠ュ甫涓?"insert file"??炬?????
+
+浣????浠ュ????ㄥ?伴??杩?GPG???璁伴??浠讹??浣???????宓?琛ヤ?????濂戒??瑕?浣跨??GPG???璁板??浠????浣?涓哄??宓??????????绛惧??琛ヤ??锛?
+褰?浠?GPG涓???????7浣?缂??????朵??浣夸??浠?????????村??澶???????
+
+濡????浣????瑕?浠ラ??浠剁??褰㈠????????琛ヤ??锛???d??灏卞?抽????瑰?婚??浠讹????跺?????涓?灞???э??绐????"Suggest automatic
+display"锛?杩???峰??宓????浠舵?村?规??璁╄?昏???????般??
+
+褰?浣?瑕?淇?瀛?灏?瑕?????????????宓???????琛ヤ??锛?浣????浠ヤ??娑???????琛ㄧ????奸????╁?????琛ヤ????????浠讹????跺????冲?婚?????
+"save as"???浣????浠ヤ娇??ㄤ??涓?娌℃????存?圭????????琛ヤ????????浠讹??濡????瀹????浠ユ?g‘???褰㈠??缁???????褰?浣?姝g????ㄥ??
+???宸辩??绐???d??涓?瀵????锛???f?舵病??????椤瑰??浠ヤ??瀛????浠?--宸茬?????涓?涓?杩???风??bug琚?姹???ュ?颁??kmail???bugzilla
+骞朵??甯????杩?灏?浼?琚?澶??????????浠舵??浠ュ?????瀵规??涓???ㄦ?峰??璇诲???????????琚?淇?瀛????锛????浠ュ?????浣???虫?????浠跺????跺?板?朵????版?癸??
+浣?涓?寰?涓????浠?浠????????????逛负缁?????????翠?????璇汇??
+
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+Lotus Notes (GUI)
+
+涓?瑕?浣跨?ㄥ?????
+
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+Mutt (TUI)
+
+寰?澶?Linux寮????浜哄??浣跨??mutt瀹㈡?风??锛????浠ヨ?????瀹????瀹?宸ヤ????????甯告??浜????
+
+Mutt涓????甯?缂?杈????锛????浠ヤ??绠′??浣跨?ㄤ??涔?缂?杈???ㄩ?戒??搴?璇ュ甫????????ㄦ??琛????澶у????扮??杈???ㄩ?藉甫???
+涓?涓?"insert file"???椤癸??瀹????浠ラ??杩?涓???瑰?????浠跺??瀹圭????瑰???????ユ??浠躲??
+
+'vim'浣?涓?mutt???缂?杈????锛?
+  set editor="vi"
+
+  濡????浣跨??xclip锛???插?ヤ互涓???戒护
+  :set paste
+  ???涓????涔??????????shift-insert??????浣跨??
+  :r filename
+
+濡??????宠?????琛ヤ??浣?涓哄??宓??????????
+(a)ttach宸ヤ?????寰?濂斤??涓?甯????"set paste"???
+
+???缃????椤癸??
+瀹?搴?璇ヤ互榛?璁よ?剧疆???褰㈠??宸ヤ?????
+??惰??锛????"send_charset"璁剧疆涓?"us-ascii::utf-8"涔????涓?涓?涓???????涓绘?????
+
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+Pine (TUI)
+
+Pine杩???绘??涓?浜?绌烘?煎????????棰?锛?浣????杩?浜???板?ㄥ??璇ラ?借??淇?澶?浜????
+
+濡???????浠ワ??璇蜂娇???alpine(pine???缁ф?胯??)
+
+???缃????椤癸??
+- ???杩?????????????瑕?娑???ゆ??绋???????
+- "no-strip-whitespace-before-send"???椤逛????????瑕???????
+
+
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+Sylpheed (GUI)
+
+- ???宓??????????浠ュ??濂界??宸ヤ??锛???????浣跨?ㄩ??浠讹?????
+- ???璁镐娇??ㄥ????ㄧ??缂?杈???ㄣ??
+- 瀵逛?????褰?杈?澶???堕??甯告?????
+- 濡???????杩?non-SSL杩???ワ?????娉?浣跨??TLS SMTP?????????
+- ??ㄧ?????绐???d腑???涓?涓?寰??????ㄧ??ruler bar???
+- 缁???板?????涓?娣诲????板??灏变??浼?姝g‘???浜?瑙f?剧ず??????
+
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+Thunderbird (GUI)
+
+榛?璁ゆ????典??锛?thunderbird寰?瀹规??????????????锛?浣????杩????涓?浜???规?????浠ュ己??跺?????寰???村ソ???
+
+- ??ㄧ?ㄦ?峰????疯?剧疆???锛?缁???????瀵诲??锛?涓?瑕???????"Compose messages in HTML format"???
+
+- 缂?杈?浣????Thunderbird???缃?璁剧疆??ヤ娇瀹?涓?瑕????琛?浣跨??锛?user_pref("mailnews.wraplength", 0);
+
+- 缂?杈?浣????Thunderbird???缃?璁剧疆锛?浣垮??涓?瑕?浣跨??"format=flowed"??煎??锛?user_pref("mailnews.
+  send_plaintext_flowed", false);
+
+- 浣????瑕?浣?Thunderbird???涓洪???????煎????瑰??锛?
+  濡????榛?璁ゆ????典??浣?涔??????????HTML??煎??锛???d?????寰???俱??浠?浠?浠????棰???????涓????妗?涓???????"Preformat"??煎?????
+  濡????榛?璁ゆ????典??浣?涔??????????????????煎??锛?浣?涓?寰????瀹???逛负HTML??煎??锛?浠?浠?浣?涓轰??娆℃?х??锛???ヤ功?????扮??娑????锛?
+  ??跺??寮哄?朵娇瀹??????版???????煎??锛???????瀹?灏变?????琛????瑕?瀹???板??锛???ㄥ??淇$????炬??涓?浣跨??shift?????ヤ娇瀹????涓?HTML
+  ??煎??锛???跺?????棰???????涓????妗?涓???????"Preformat"??煎?????
+
+- ???璁镐娇??ㄥ????ㄧ??缂?杈????锛?
+  ???瀵?Thunderbird???琛ヤ?????绠?????????规??灏辨??浣跨?ㄤ??涓?"external editor"??╁??锛???跺??浣跨?ㄤ????????娆㈢??
+  $EDITOR??ヨ?诲???????????骞惰ˉ涓???版?????涓????瑕?瀹???板??锛????浠ヤ??杞藉苟涓?瀹?瑁?杩?涓???╁??锛???跺??娣诲??涓?涓?浣跨?ㄥ?????
+  ??????View->Toolbars->Customize...??????褰?浣?涔????淇℃???????跺??浠?浠???瑰?诲??灏卞??浠ヤ?????
+
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+TkRat (GUI)
+
+???浠ヤ娇??ㄥ?????浣跨??"Insert file..."??????澶???ㄧ??缂?杈???ㄣ??
+
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+Gmail (Web GUI)
+
+涓?瑕?浣跨?ㄥ????????琛ヤ?????
+
+Gmail缃?椤靛?㈡?风???????ㄥ?版????惰〃绗?杞????涓虹┖??笺??
+
+??界?跺?惰〃绗?杞????涓虹┖??奸??棰????浠ヨ??澶???ㄧ??杈???ㄨВ??筹???????跺??杩?浼?浣跨?ㄥ??杞???㈣?????姣?琛???????涓?78涓?瀛?绗????
+
+???涓?涓????棰????Gmail杩?浼????浠讳??涓????ASCII???瀛?绗????淇℃????逛负base64缂???????瀹????涓?瑗垮????????娆ф床浜虹?????瀛????
+
+                                ###
index 16a5c5f..8df8d2d 100644 (file)
@@ -405,8 +405,8 @@ S:  Maintained
 F:     sound/oss/aedsp16.c
 
 AFFS FILE SYSTEM
-M:     Roman Zippel <zippel@linux-m68k.org>
-S:     Maintained
+L:     linux-fsdevel@vger.kernel.org
+S:     Orphan
 F:     Documentation/filesystems/affs.txt
 F:     fs/affs/
 
@@ -2813,38 +2813,19 @@ F:      Documentation/gpio.txt
 F:     drivers/gpio/
 F:     include/linux/gpio*
 
+GRE DEMULTIPLEXER DRIVER
+M:     Dmitry Kozlov <xeb@mail.ru>
+L:     netdev@vger.kernel.org
+S:     Maintained
+F:     net/ipv4/gre.c
+F:     include/net/gre.h
+
 GRETH 10/100/1G Ethernet MAC device driver
 M:     Kristoffer Glembo <kristoffer@gaisler.com>
 L:     netdev@vger.kernel.org
 S:     Maintained
 F:     drivers/net/greth*
 
-HARD DRIVE ACTIVE PROTECTION SYSTEM (HDAPS) DRIVER
-M:     Frank Seidel <frank@f-seidel.de>
-L:     platform-driver-x86@vger.kernel.org
-W:     http://www.kernel.org/pub/linux/kernel/people/fseidel/hdaps/
-S:     Maintained
-F:     drivers/platform/x86/hdaps.c
-
-HWPOISON MEMORY FAILURE HANDLING
-M:     Andi Kleen <andi@firstfloor.org>
-L:     linux-mm@kvack.org
-T:     git git://git.kernel.org/pub/scm/linux/kernel/git/ak/linux-mce-2.6.git hwpoison
-S:     Maintained
-F:     mm/memory-failure.c
-F:     mm/hwpoison-inject.c
-
-HYPERVISOR VIRTUAL CONSOLE DRIVER
-L:     linuxppc-dev@lists.ozlabs.org
-S:     Odd Fixes
-F:     drivers/tty/hvc/
-
-iSCSI BOOT FIRMWARE TABLE (iBFT) DRIVER
-M:     Peter Jones <pjones@redhat.com>
-M:     Konrad Rzeszutek Wilk <konrad@kernel.org>
-S:     Maintained
-F:     drivers/firmware/iscsi_ibft*
-
 GSPCA FINEPIX SUBDRIVER
 M:     Frank Zago <frank@zago.net>
 L:     linux-media@vger.kernel.org
@@ -2895,6 +2876,26 @@ T:       git git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-2.6.git
 S:     Maintained
 F:     drivers/media/video/gspca/
 
+HARD DRIVE ACTIVE PROTECTION SYSTEM (HDAPS) DRIVER
+M:     Frank Seidel <frank@f-seidel.de>
+L:     platform-driver-x86@vger.kernel.org
+W:     http://www.kernel.org/pub/linux/kernel/people/fseidel/hdaps/
+S:     Maintained
+F:     drivers/platform/x86/hdaps.c
+
+HWPOISON MEMORY FAILURE HANDLING
+M:     Andi Kleen <andi@firstfloor.org>
+L:     linux-mm@kvack.org
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/ak/linux-mce-2.6.git hwpoison
+S:     Maintained
+F:     mm/memory-failure.c
+F:     mm/hwpoison-inject.c
+
+HYPERVISOR VIRTUAL CONSOLE DRIVER
+L:     linuxppc-dev@lists.ozlabs.org
+S:     Odd Fixes
+F:     drivers/tty/hvc/
+
 HARDWARE MONITORING
 M:     Jean Delvare <khali@linux-fr.org>
 M:     Guenter Roeck <guenter.roeck@ericsson.com>
@@ -2945,8 +2946,8 @@ F:        drivers/block/cciss*
 F:     include/linux/cciss_ioctl.h
 
 HFS FILESYSTEM
-M:     Roman Zippel <zippel@linux-m68k.org>
-S:     Maintained
+L:     linux-fsdevel@vger.kernel.org
+S:     Orphan
 F:     Documentation/filesystems/hfs.txt
 F:     fs/hfs/
 
@@ -3478,6 +3479,12 @@ F:       Documentation/isapnp.txt
 F:     drivers/pnp/isapnp/
 F:     include/linux/isapnp.h
 
+iSCSI BOOT FIRMWARE TABLE (iBFT) DRIVER
+M:     Peter Jones <pjones@redhat.com>
+M:     Konrad Rzeszutek Wilk <konrad@kernel.org>
+S:     Maintained
+F:     drivers/firmware/iscsi_ibft*
+
 ISCSI
 M:     Mike Christie <michaelc@cs.wisc.edu>
 L:     open-iscsi@googlegroups.com
@@ -3807,7 +3814,7 @@ M:        Rusty Russell <rusty@rustcorp.com.au>
 L:     lguest@lists.ozlabs.org
 W:     http://lguest.ozlabs.org/
 S:     Odd Fixes
-F:     Documentation/lguest/
+F:     Documentation/virtual/lguest/
 F:     arch/x86/lguest/
 F:     drivers/lguest/
 F:     include/linux/lguest*.h
@@ -3994,7 +4001,6 @@ F:        arch/m32r/
 
 M68K ARCHITECTURE
 M:     Geert Uytterhoeven <geert@linux-m68k.org>
-M:     Roman Zippel <zippel@linux-m68k.org>
 L:     linux-m68k@lists.linux-m68k.org
 W:     http://www.linux-m68k.org/
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/geert/linux-m68k.git
@@ -4989,6 +4995,13 @@ F:       Documentation/pps/
 F:     drivers/pps/
 F:     include/linux/pps*.h
 
+PPTP DRIVER
+M:     Dmitry Kozlov <xeb@mail.ru>
+L:     netdev@vger.kernel.org
+S:     Maintained
+F:     drivers/net/pptp.c
+W:     http://sourceforge.net/projects/accel-pptp
+
 PREEMPTIBLE KERNEL
 M:     Robert Love <rml@tech9.net>
 L:     kpreempt-tech@lists.sourceforge.net
@@ -6618,7 +6631,7 @@ L:        user-mode-linux-devel@lists.sourceforge.net
 L:     user-mode-linux-user@lists.sourceforge.net
 W:     http://user-mode-linux.sourceforge.net
 S:     Maintained
-F:     Documentation/uml/
+F:     Documentation/virtual/uml/
 F:     arch/um/
 F:     fs/hostfs/
 F:     fs/hppfs/
@@ -7024,20 +7037,6 @@ M:       "Maciej W. Rozycki" <macro@linux-mips.org>
 S:     Maintained
 F:     drivers/tty/serial/zs.*
 
-GRE DEMULTIPLEXER DRIVER
-M:     Dmitry Kozlov <xeb@mail.ru>
-L:     netdev@vger.kernel.org
-S:     Maintained
-F:     net/ipv4/gre.c
-F:     include/net/gre.h
-
-PPTP DRIVER
-M:     Dmitry Kozlov <xeb@mail.ru>
-L:     netdev@vger.kernel.org
-S:     Maintained
-F:     drivers/net/pptp.c
-W:     http://sourceforge.net/projects/accel-pptp
-
 THE REST
 M:     Linus Torvalds <torvalds@linux-foundation.org>
 L:     linux-kernel@vger.kernel.org
index e7d01ad..a0344a8 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -1,7 +1,7 @@
 VERSION = 2
 PATCHLEVEL = 6
 SUBLEVEL = 39
-EXTRAVERSION = -rc7
+EXTRAVERSION =
 NAME = Flesh-Eating Bats with Fangs
 
 # *DOCUMENTATION*
index 058937b..b183416 100644 (file)
 #define __NR_fanotify_init             494
 #define __NR_fanotify_mark             495
 #define __NR_prlimit64                 496
+#define __NR_name_to_handle_at         497
+#define __NR_open_by_handle_at         498
+#define __NR_clock_adjtime             499
+#define __NR_syncfs                    500
 
 #ifdef __KERNEL__
 
-#define NR_SYSCALLS                    497
+#define NR_SYSCALLS                    501
 
 #define __ARCH_WANT_IPC_PARSE_VERSION
 #define __ARCH_WANT_OLD_READDIR
index 42aa078..5a621c6 100644 (file)
@@ -585,8 +585,7 @@ handle_ipi(struct pt_regs *regs)
 
                switch (which) {
                case IPI_RESCHEDULE:
-                       /* Reschedule callback.  Everything to be done
-                          is done by the interrupt return path.  */
+                       scheduler_ipi();
                        break;
 
                case IPI_CALL_FUNC:
index a6a1de9..15f999d 100644 (file)
@@ -498,23 +498,27 @@ sys_call_table:
        .quad sys_ni_syscall                    /* sys_timerfd */
        .quad sys_eventfd
        .quad sys_recvmmsg
-       .quad sys_fallocate                             /* 480 */
+       .quad sys_fallocate                     /* 480 */
        .quad sys_timerfd_create
        .quad sys_timerfd_settime
        .quad sys_timerfd_gettime
        .quad sys_signalfd4
-       .quad sys_eventfd2                              /* 485 */
+       .quad sys_eventfd2                      /* 485 */
        .quad sys_epoll_create1
        .quad sys_dup3
        .quad sys_pipe2
        .quad sys_inotify_init1
-       .quad sys_preadv                                /* 490 */
+       .quad sys_preadv                        /* 490 */
        .quad sys_pwritev
        .quad sys_rt_tgsigqueueinfo
        .quad sys_perf_event_open
        .quad sys_fanotify_init
-       .quad sys_fanotify_mark                         /* 495 */
+       .quad sys_fanotify_mark                 /* 495 */
        .quad sys_prlimit64
+       .quad sys_name_to_handle_at
+       .quad sys_open_by_handle_at
+       .quad sys_clock_adjtime
+       .quad sys_syncfs                        /* 500 */
 
        .size sys_call_table, . - sys_call_table
        .type sys_call_table, @object
index 918e8e0..818e74e 100644 (file)
@@ -375,8 +375,7 @@ static struct clocksource clocksource_rpcc = {
 
 static inline void register_rpcc_clocksource(long cycle_freq)
 {
-       clocksource_calc_mult_shift(&clocksource_rpcc, cycle_freq, 4);
-       clocksource_register(&clocksource_rpcc);
+       clocksource_register_hz(&clocksource_rpcc, cycle_freq);
 }
 #else /* !CONFIG_SMP */
 static inline void register_rpcc_clocksource(long cycle_freq)
index 433be2a..3d890a9 100644 (file)
@@ -46,6 +46,7 @@ SECTIONS
        __init_end = .;
        /* Freed after init ends here */
 
+       _sdata = .;     /* Start of rw data section */
        _data = .;
        RW_DATA_SECTION(L1_CACHE_BYTES, PAGE_SIZE, THREAD_SIZE)
 
index 8ebbb51..0c6852d 100644 (file)
@@ -74,7 +74,7 @@ ZTEXTADDR     := $(CONFIG_ZBOOT_ROM_TEXT)
 ZBSSADDR       := $(CONFIG_ZBOOT_ROM_BSS)
 else
 ZTEXTADDR      := 0
-ZBSSADDR       := ALIGN(4)
+ZBSSADDR       := ALIGN(8)
 endif
 
 SEDFLAGS       = s/TEXT_START/$(ZTEXTADDR)/;s/BSS_START/$(ZBSSADDR)/
index adf583c..49f5b2e 100644 (file)
@@ -179,15 +179,14 @@ not_angel:
                bl      cache_on
 
 restart:       adr     r0, LC0
-               ldmia   r0, {r1, r2, r3, r5, r6, r9, r11, r12}
-               ldr     sp, [r0, #32]
+               ldmia   r0, {r1, r2, r3, r6, r9, r11, r12}
+               ldr     sp, [r0, #28]
 
                /*
                 * We might be running at a different address.  We need
                 * to fix up various pointers.
                 */
                sub     r0, r0, r1              @ calculate the delta offset
-               add     r5, r5, r0              @ _start
                add     r6, r6, r0              @ _edata
 
 #ifndef CONFIG_ZBOOT_ROM
@@ -206,31 +205,40 @@ restart:  adr     r0, LC0
 /*
  * Check to see if we will overwrite ourselves.
  *   r4  = final kernel address
- *   r5  = start of this image
  *   r9  = size of decompressed image
  *   r10 = end of this image, including  bss/stack/malloc space if non XIP
  * We basically want:
- *   r4 >= r10 -> OK
- *   r4 + image length <= r5 -> OK
+ *   r4 - 16k page directory >= r10 -> OK
+ *   r4 + image length <= current position (pc) -> OK
  */
+               add     r10, r10, #16384
                cmp     r4, r10
                bhs     wont_overwrite
                add     r10, r4, r9
-               cmp     r10, r5
+   ARM(                cmp     r10, pc         )
+ THUMB(                mov     lr, pc          )
+ THUMB(                cmp     r10, lr         )
                bls     wont_overwrite
 
 /*
  * Relocate ourselves past the end of the decompressed kernel.
- *   r5  = start of this image
  *   r6  = _edata
  *   r10 = end of the decompressed kernel
  * Because we always copy ahead, we need to do it from the end and go
  * backward in case the source and destination overlap.
  */
-               /* Round up to next 256-byte boundary. */
-               add     r10, r10, #256
+               /*
+                * Bump to the next 256-byte boundary with the size of
+                * the relocation code added. This avoids overwriting
+                * ourself when the offset is small.
+                */
+               add     r10, r10, #((reloc_code_end - restart + 256) & ~255)
                bic     r10, r10, #255
 
+               /* Get start of code we want to copy and align it down. */
+               adr     r5, restart
+               bic     r5, r5, #31
+
                sub     r9, r6, r5              @ size to copy
                add     r9, r9, #31             @ rounded up to a multiple
                bic     r9, r9, #31             @ ... of 32 bytes
@@ -245,6 +253,11 @@ restart:   adr     r0, LC0
                /* Preserve offset to relocated code. */
                sub     r6, r9, r6
 
+#ifndef CONFIG_ZBOOT_ROM
+               /* cache_clean_flush may use the stack, so relocate it */
+               add     sp, sp, r6
+#endif
+
                bl      cache_clean_flush
 
                adr     r0, BSYM(restart)
@@ -333,7 +346,6 @@ not_relocated:      mov     r0, #0
 LC0:           .word   LC0                     @ r1
                .word   __bss_start             @ r2
                .word   _end                    @ r3
-               .word   _start                  @ r5
                .word   _edata                  @ r6
                .word   _image_size             @ r9
                .word   _got_start              @ r11
@@ -1062,6 +1074,7 @@ memdump:  mov     r12, r0
 #endif
 
                .ltorg
+reloc_code_end:
 
                .align
                .section ".stack", "aw", %nobits
index 5309909..ea80abe 100644 (file)
@@ -54,6 +54,7 @@ SECTIONS
   .bss                 : { *(.bss) }
   _end = .;
 
+  . = ALIGN(8);                /* the stack must be 64-bit aligned */
   .stack               : { *(.stack) }
 
   .stab 0              : { *(.stab) }
index 113085a..7aa4262 100644 (file)
 #include <linux/init.h>
 #include <linux/list.h>
 #include <linux/io.h>
-#include <linux/sysdev.h>
+#include <linux/syscore_ops.h>
 #include <linux/device.h>
 #include <linux/amba/bus.h>
 
 #include <asm/mach/irq.h>
 #include <asm/hardware/vic.h>
 
-#if defined(CONFIG_PM)
+#ifdef CONFIG_PM
 /**
  * struct vic_device - VIC PM device
- * @sysdev: The system device which is registered.
  * @irq: The IRQ number for the base of the VIC.
  * @base: The register base for the VIC.
  * @resume_sources: A bitmask of interrupts for resume.
@@ -43,8 +42,6 @@
  * @protect: Save for VIC_PROTECT.
  */
 struct vic_device {
-       struct sys_device sysdev;
-
        void __iomem    *base;
        int             irq;
        u32             resume_sources;
@@ -59,11 +56,6 @@ struct vic_device {
 static struct vic_device vic_devices[CONFIG_ARM_VIC_NR];
 
 static int vic_id;
-
-static inline struct vic_device *to_vic(struct sys_device *sys)
-{
-       return container_of(sys, struct vic_device, sysdev);
-}
 #endif /* CONFIG_PM */
 
 /**
@@ -85,10 +77,9 @@ static void vic_init2(void __iomem *base)
        writel(32, base + VIC_PL190_DEF_VECT_ADDR);
 }
 
-#if defined(CONFIG_PM)
-static int vic_class_resume(struct sys_device *dev)
+#ifdef CONFIG_PM
+static void resume_one_vic(struct vic_device *vic)
 {
-       struct vic_device *vic = to_vic(dev);
        void __iomem *base = vic->base;
 
        printk(KERN_DEBUG "%s: resuming vic at %p\n", __func__, base);
@@ -107,13 +98,18 @@ static int vic_class_resume(struct sys_device *dev)
 
        writel(vic->soft_int, base + VIC_INT_SOFT);
        writel(~vic->soft_int, base + VIC_INT_SOFT_CLEAR);
+}
 
-       return 0;
+static void vic_resume(void)
+{
+       int id;
+
+       for (id = vic_id - 1; id >= 0; id--)
+               resume_one_vic(vic_devices + id);
 }
 
-static int vic_class_suspend(struct sys_device *dev, pm_message_t state)
+static void suspend_one_vic(struct vic_device *vic)
 {
-       struct vic_device *vic = to_vic(dev);
        void __iomem *base = vic->base;
 
        printk(KERN_DEBUG "%s: suspending vic at %p\n", __func__, base);
@@ -128,14 +124,21 @@ static int vic_class_suspend(struct sys_device *dev, pm_message_t state)
 
        writel(vic->resume_irqs, base + VIC_INT_ENABLE);
        writel(~vic->resume_irqs, base + VIC_INT_ENABLE_CLEAR);
+}
+
+static int vic_suspend(void)
+{
+       int id;
+
+       for (id = 0; id < vic_id; id++)
+               suspend_one_vic(vic_devices + id);
 
        return 0;
 }
 
-struct sysdev_class vic_class = {
-       .name           = "vic",
-       .suspend        = vic_class_suspend,
-       .resume         = vic_class_resume,
+struct syscore_ops vic_syscore_ops = {
+       .suspend        = vic_suspend,
+       .resume         = vic_resume,
 };
 
 /**
@@ -147,30 +150,8 @@ struct sysdev_class vic_class = {
 */
 static int __init vic_pm_init(void)
 {
-       struct vic_device *dev = vic_devices;
-       int err;
-       int id;
-
-       if (vic_id == 0)
-               return 0;
-
-       err = sysdev_class_register(&vic_class);
-       if (err) {
-               printk(KERN_ERR "%s: cannot register class\n", __func__);
-               return err;
-       }
-
-       for (id = 0; id < vic_id; id++, dev++) {
-               dev->sysdev.id = id;
-               dev->sysdev.cls = &vic_class;
-
-               err = sysdev_register(&dev->sysdev);
-               if (err) {
-                       printk(KERN_ERR "%s: failed to register device\n",
-                              __func__);
-                       return err;
-               }
-       }
+       if (vic_id > 0)
+               register_syscore_ops(&vic_syscore_ops);
 
        return 0;
 }
diff --git a/arch/arm/include/asm/i8253.h b/arch/arm/include/asm/i8253.h
new file mode 100644 (file)
index 0000000..70656b6
--- /dev/null
@@ -0,0 +1,15 @@
+#ifndef __ASMARM_I8253_H
+#define __ASMARM_I8253_H
+
+/* i8253A PIT registers */
+#define PIT_MODE       0x43
+#define PIT_CH0                0x40
+
+#define PIT_LATCH      ((PIT_TICK_RATE + HZ / 2) / HZ)
+
+extern raw_spinlock_t i8253_lock;
+
+#define outb_pit       outb_p
+#define inb_pit                inb_p
+
+#endif
index 883f6be..d5adaae 100644 (file)
@@ -34,7 +34,6 @@
  *   timer interrupt which may be pending.
  */
 struct sys_timer {
-       struct sys_device       dev;
        void                    (*init)(void);
        void                    (*suspend)(void);
        void                    (*resume)(void);
index 885be09..832888d 100644 (file)
@@ -159,7 +159,7 @@ extern unsigned int user_debug;
 #include <mach/barriers.h>
 #elif defined(CONFIG_ARM_DMA_MEM_BUFFERABLE) || defined(CONFIG_SMP)
 #define mb()           do { dsb(); outer_sync(); } while (0)
-#define rmb()          dmb()
+#define rmb()          dsb()
 #define wmb()          mb()
 #else
 #include <asm/memory.h>
index 31a316c..0f107dc 100644 (file)
@@ -10,6 +10,7 @@
 #include <linux/module.h>
 #include <linux/init.h>
 #include <linux/sysdev.h>
+#include <linux/syscore_ops.h>
 
 #include <asm/leds.h>
 
@@ -69,36 +70,37 @@ static ssize_t leds_store(struct sys_device *dev,
 
 static SYSDEV_ATTR(event, 0200, NULL, leds_store);
 
-static int leds_suspend(struct sys_device *dev, pm_message_t state)
+static struct sysdev_class leds_sysclass = {
+       .name           = "leds",
+};
+
+static struct sys_device leds_device = {
+       .id             = 0,
+       .cls            = &leds_sysclass,
+};
+
+static int leds_suspend(void)
 {
        leds_event(led_stop);
        return 0;
 }
 
-static int leds_resume(struct sys_device *dev)
+static void leds_resume(void)
 {
        leds_event(led_start);
-       return 0;
 }
 
-static int leds_shutdown(struct sys_device *dev)
+static void leds_shutdown(void)
 {
        leds_event(led_halted);
-       return 0;
 }
 
-static struct sysdev_class leds_sysclass = {
-       .name           = "leds",
+static struct syscore_ops leds_syscore_ops = {
        .shutdown       = leds_shutdown,
        .suspend        = leds_suspend,
        .resume         = leds_resume,
 };
 
-static struct sys_device leds_device = {
-       .id             = 0,
-       .cls            = &leds_sysclass,
-};
-
 static int __init leds_init(void)
 {
        int ret;
@@ -107,6 +109,8 @@ static int __init leds_init(void)
                ret = sysdev_register(&leds_device);
        if (ret == 0)
                ret = sysdev_create_file(&leds_device, &attr_event);
+       if (ret == 0)
+               register_syscore_ops(&leds_syscore_ops);
        return ret;
 }
 
index cb83983..0340224 100644 (file)
@@ -597,19 +597,13 @@ setup_rt_frame(int usig, struct k_sigaction *ka, siginfo_t *info,
        return err;
 }
 
-static inline void setup_syscall_restart(struct pt_regs *regs)
-{
-       regs->ARM_r0 = regs->ARM_ORIG_r0;
-       regs->ARM_pc -= thumb_mode(regs) ? 2 : 4;
-}
-
 /*
  * OK, we're invoking a handler
  */    
 static int
 handle_signal(unsigned long sig, struct k_sigaction *ka,
              siginfo_t *info, sigset_t *oldset,
-             struct pt_regs * regs, int syscall)
+             struct pt_regs * regs)
 {
        struct thread_info *thread = current_thread_info();
        struct task_struct *tsk = current;
@@ -617,26 +611,6 @@ handle_signal(unsigned long sig, struct k_sigaction *ka,
        int ret;
 
        /*
-        * If we were from a system call, check for system call restarting...
-        */
-       if (syscall) {
-               switch (regs->ARM_r0) {
-               case -ERESTART_RESTARTBLOCK:
-               case -ERESTARTNOHAND:
-                       regs->ARM_r0 = -EINTR;
-                       break;
-               case -ERESTARTSYS:
-                       if (!(ka->sa.sa_flags & SA_RESTART)) {
-                               regs->ARM_r0 = -EINTR;
-                               break;
-                       }
-                       /* fallthrough */
-               case -ERESTARTNOINTR:
-                       setup_syscall_restart(regs);
-               }
-       }
-
-       /*
         * translate the signal
         */
        if (usig < 32 && thread->exec_domain && thread->exec_domain->signal_invmap)
@@ -685,6 +659,7 @@ handle_signal(unsigned long sig, struct k_sigaction *ka,
  */
 static void do_signal(struct pt_regs *regs, int syscall)
 {
+       unsigned int retval = 0, continue_addr = 0, restart_addr = 0;
        struct k_sigaction ka;
        siginfo_t info;
        int signr;
@@ -698,18 +673,61 @@ static void do_signal(struct pt_regs *regs, int syscall)
        if (!user_mode(regs))
                return;
 
+       /*
+        * If we were from a system call, check for system call restarting...
+        */
+       if (syscall) {
+               continue_addr = regs->ARM_pc;
+               restart_addr = continue_addr - (thumb_mode(regs) ? 2 : 4);
+               retval = regs->ARM_r0;
+
+               /*
+                * Prepare for system call restart.  We do this here so that a
+                * debugger will see the already changed PSW.
+                */
+               switch (retval) {
+               case -ERESTARTNOHAND:
+               case -ERESTARTSYS:
+               case -ERESTARTNOINTR:
+                       regs->ARM_r0 = regs->ARM_ORIG_r0;
+                       regs->ARM_pc = restart_addr;
+                       break;
+               case -ERESTART_RESTARTBLOCK:
+                       regs->ARM_r0 = -EINTR;
+                       break;
+               }
+       }
+
        if (try_to_freeze())
                goto no_signal;
 
+       /*
+        * Get the signal to deliver.  When running under ptrace, at this
+        * point the debugger may change all our registers ...
+        */
        signr = get_signal_to_deliver(&info, &ka, regs, NULL);
        if (signr > 0) {
                sigset_t *oldset;
 
+               /*
+                * Depending on the signal settings we may need to revert the
+                * decision to restart the system call.  But skip this if a
+                * debugger has chosen to restart at a different PC.
+                */
+               if (regs->ARM_pc == restart_addr) {
+                       if (retval == -ERESTARTNOHAND
+                           || (retval == -ERESTARTSYS
+                               && !(ka.sa.sa_flags & SA_RESTART))) {
+                               regs->ARM_r0 = -EINTR;
+                               regs->ARM_pc = continue_addr;
+                       }
+               }
+
                if (test_thread_flag(TIF_RESTORE_SIGMASK))
                        oldset = &current->saved_sigmask;
                else
                        oldset = &current->blocked;
-               if (handle_signal(signr, &ka, &info, oldset, regs, syscall) == 0) {
+               if (handle_signal(signr, &ka, &info, oldset, regs) == 0) {
                        /*
                         * A signal was successfully delivered; the saved
                         * sigmask will have been stored in the signal frame,
@@ -723,11 +741,14 @@ static void do_signal(struct pt_regs *regs, int syscall)
        }
 
  no_signal:
-       /*
-        * No signal to deliver to the process - restart the syscall.
-        */
        if (syscall) {
-               if (regs->ARM_r0 == -ERESTART_RESTARTBLOCK) {
+               /*
+                * Handle restarting a different system call.  As above,
+                * if a debugger has chosen to restart at a different PC,
+                * ignore the restart.
+                */
+               if (retval == -ERESTART_RESTARTBLOCK
+                   && regs->ARM_pc == continue_addr) {
                        if (thumb_mode(regs)) {
                                regs->ARM_r7 = __NR_restart_syscall - __NR_SYSCALL_BASE;
                                regs->ARM_pc -= 2;
@@ -750,11 +771,6 @@ static void do_signal(struct pt_regs *regs, int syscall)
 #endif
                        }
                }
-               if (regs->ARM_r0 == -ERESTARTNOHAND ||
-                   regs->ARM_r0 == -ERESTARTSYS ||
-                   regs->ARM_r0 == -ERESTARTNOINTR) {
-                       setup_syscall_restart(regs);
-               }
 
                /* If there's no signal to deliver, we just put the saved sigmask
                 * back.
index f29b8a2..007a0a9 100644 (file)
@@ -560,10 +560,7 @@ asmlinkage void __exception_irq_entry do_IPI(int ipinr, struct pt_regs *regs)
                break;
 
        case IPI_RESCHEDULE:
-               /*
-                * nothing more to do - eveything is
-                * done on the interrupt return path
-                */
+               scheduler_ipi();
                break;
 
        case IPI_CALL_FUNC:
index 1ff46ca..cb634c3 100644 (file)
@@ -21,7 +21,7 @@
 #include <linux/timex.h>
 #include <linux/errno.h>
 #include <linux/profile.h>
-#include <linux/sysdev.h>
+#include <linux/syscore_ops.h>
 #include <linux/timer.h>
 #include <linux/irq.h>
 
@@ -115,48 +115,37 @@ void timer_tick(void)
 #endif
 
 #if defined(CONFIG_PM) && !defined(CONFIG_GENERIC_CLOCKEVENTS)
-static int timer_suspend(struct sys_device *dev, pm_message_t state)
+static int timer_suspend(void)
 {
-       struct sys_timer *timer = container_of(dev, struct sys_timer, dev);
-
-       if (timer->suspend != NULL)
-               timer->suspend();
+       if (system_timer->suspend)
+               system_timer->suspend();
 
        return 0;
 }
 
-static int timer_resume(struct sys_device *dev)
+static void timer_resume(void)
 {
-       struct sys_timer *timer = container_of(dev, struct sys_timer, dev);
-
-       if (timer->resume != NULL)
-               timer->resume();
-
-       return 0;
+       if (system_timer->resume)
+               system_timer->resume();
 }
 #else
 #define timer_suspend NULL
 #define timer_resume NULL
 #endif
 
-static struct sysdev_class timer_sysclass = {
-       .name           = "timer",
+static struct syscore_ops timer_syscore_ops = {
        .suspend        = timer_suspend,
        .resume         = timer_resume,
 };
 
-static int __init timer_init_sysfs(void)
+static int __init timer_init_syscore_ops(void)
 {
-       int ret = sysdev_class_register(&timer_sysclass);
-       if (ret == 0) {
-               system_timer->dev.cls = &timer_sysclass;
-               ret = sysdev_register(&system_timer->dev);
-       }
+       register_syscore_ops(&timer_syscore_ops);
 
-       return ret;
+       return 0;
 }
 
-device_initcall(timer_init_sysfs);
+device_initcall(timer_init_syscore_ops);
 
 void __init time_init(void)
 {
index 3b54ad1..d52eec2 100644 (file)
@@ -234,7 +234,6 @@ static int __die(const char *str, int err, struct thread_info *thread, struct pt
 
        printk(KERN_EMERG "Internal error: %s: %x [#%d]" S_PREEMPT S_SMP "\n",
               str, err, ++die_counter);
-       sysfs_printk_last_file();
 
        /* trap and error numbers are mostly meaningless on ARM */
        ret = notify_die(DIE_OOPS, str, regs, err, tsk->thread.trap_no, SIGSEGV);
index 0a95be1..41669ec 100644 (file)
@@ -94,9 +94,7 @@ static int davinci_target(struct cpufreq_policy *policy,
        if (freqs.old == freqs.new)
                return ret;
 
-       cpufreq_debug_printk(CPUFREQ_DEBUG_DRIVER,
-                       dev_driver_string(cpufreq.dev),
-                       "transition: %u --> %u\n", freqs.old, freqs.new);
+       dev_dbg(&cpufreq.dev, "transition: %u --> %u\n", freqs.old, freqs.new);
 
        ret = cpufreq_frequency_table_target(policy, pdata->freq_table,
                                                freqs.new, relation, &idx);
index 10d917d..8755ca8 100644 (file)
@@ -16,6 +16,7 @@
 
 #include <linux/init.h>
 #include <linux/suspend.h>
+#include <linux/syscore_ops.h>
 #include <linux/io.h>
 
 #include <asm/cacheflush.h>
@@ -372,7 +373,27 @@ void exynos4_scu_enable(void __iomem *scu_base)
        flush_cache_all();
 }
 
-static int exynos4_pm_resume(struct sys_device *dev)
+static struct sysdev_driver exynos4_pm_driver = {
+       .add            = exynos4_pm_add,
+};
+
+static __init int exynos4_pm_drvinit(void)
+{
+       unsigned int tmp;
+
+       s3c_pm_init();
+
+       /* All wakeup disable */
+
+       tmp = __raw_readl(S5P_WAKEUP_MASK);
+       tmp |= ((0xFF << 8) | (0x1F << 1));
+       __raw_writel(tmp, S5P_WAKEUP_MASK);
+
+       return sysdev_driver_register(&exynos4_sysclass, &exynos4_pm_driver);
+}
+arch_initcall(exynos4_pm_drvinit);
+
+static void exynos4_pm_resume(void)
 {
        /* For release retention */
 
@@ -394,27 +415,15 @@ static int exynos4_pm_resume(struct sys_device *dev)
        /* enable L2X0*/
        writel_relaxed(1, S5P_VA_L2CC + L2X0_CTRL);
 #endif
-
-       return 0;
 }
 
-static struct sysdev_driver exynos4_pm_driver = {
-       .add            = exynos4_pm_add,
+static struct syscore_ops exynos4_pm_syscore_ops = {
        .resume         = exynos4_pm_resume,
 };
 
-static __init int exynos4_pm_drvinit(void)
+static __init int exynos4_pm_syscore_init(void)
 {
-       unsigned int tmp;
-
-       s3c_pm_init();
-
-       /* All wakeup disable */
-
-       tmp = __raw_readl(S5P_WAKEUP_MASK);
-       tmp |= ((0xFF << 8) | (0x1F << 1));
-       __raw_writel(tmp, S5P_WAKEUP_MASK);
-
-       return sysdev_driver_register(&exynos4_sysclass, &exynos4_pm_driver);
+       register_syscore_ops(&exynos4_pm_syscore_ops);
+       return 0;
 }
-arch_initcall(exynos4_pm_drvinit);
+arch_initcall(exynos4_pm_syscore_init);
index bdd2579..46adca0 100644 (file)
@@ -4,6 +4,7 @@ menu "Footbridge Implementations"
 
 config ARCH_CATS
        bool "CATS"
+       select CLKSRC_I8253
        select FOOTBRIDGE_HOST
        select ISA
        select ISA_DMA
@@ -59,6 +60,7 @@ config ARCH_EBSA285_HOST
 
 config ARCH_NETWINDER
        bool "NetWinder"
+       select CLKSRC_I8253
        select FOOTBRIDGE_HOST
        select ISA
        select ISA_DMA
index 441c6ce..7020f1a 100644 (file)
 #include <linux/interrupt.h>
 #include <linux/irq.h>
 #include <linux/io.h>
+#include <linux/spinlock.h>
 #include <linux/timex.h>
 
 #include <asm/irq.h>
-
+#include <asm/i8253.h>
 #include <asm/mach/time.h>
 
 #include "common.h"
 
-#define PIT_MODE       0x43
-#define PIT_CH0                0x40
-
-#define PIT_LATCH      ((PIT_TICK_RATE + HZ / 2) / HZ)
-
-static cycle_t pit_read(struct clocksource *cs)
-{
-       unsigned long flags;
-       static int old_count;
-       static u32 old_jifs;
-       int count;
-       u32 jifs;
-
-       raw_local_irq_save(flags);
-
-       jifs = jiffies;
-       outb_p(0x00, PIT_MODE);         /* latch the count */
-       count = inb_p(PIT_CH0);         /* read the latched count */
-       count |= inb_p(PIT_CH0) << 8;
-
-       if (count > old_count && jifs == old_jifs)
-               count = old_count;
-
-       old_count = count;
-       old_jifs = jifs;
-
-       raw_local_irq_restore(flags);
-
-       count = (PIT_LATCH - 1) - count;
-
-       return (cycle_t)(jifs * PIT_LATCH) + count;
-}
-
-static struct clocksource pit_cs = {
-       .name           = "pit",
-       .rating         = 110,
-       .read           = pit_read,
-       .mask           = CLOCKSOURCE_MASK(32),
-};
+DEFINE_RAW_SPINLOCK(i8253_lock);
 
 static void pit_set_mode(enum clock_event_mode mode,
        struct clock_event_device *evt)
@@ -121,7 +84,7 @@ static void __init isa_timer_init(void)
        pit_ce.max_delta_ns = clockevent_delta2ns(0x7fff, &pit_ce);
        pit_ce.min_delta_ns = clockevent_delta2ns(0x000f, &pit_ce);
 
-       clocksource_register_hz(&pit_cs, PIT_TICK_RATE);
+       clocksource_i8253_init();
 
        setup_irq(pit_ce.irq, &pit_timer_irq);
        clockevents_register_device(&pit_ce);
index 980803f..d3e9645 100644 (file)
@@ -24,7 +24,7 @@
 #include <linux/platform_device.h>
 #include <linux/slab.h>
 #include <linux/string.h>
-#include <linux/sysdev.h>
+#include <linux/syscore_ops.h>
 #include <linux/amba/bus.h>
 #include <linux/amba/kmi.h>
 #include <linux/clocksource.h>
@@ -180,13 +180,13 @@ static void __init ap_init_irq(void)
 #ifdef CONFIG_PM
 static unsigned long ic_irq_enable;
 
-static int irq_suspend(struct sys_device *dev, pm_message_t state)
+static int irq_suspend(void)
 {
        ic_irq_enable = readl(VA_IC_BASE + IRQ_ENABLE);
        return 0;
 }
 
-static int irq_resume(struct sys_device *dev)
+static void irq_resume(void)
 {
        /* disable all irq sources */
        writel(-1, VA_CMIC_BASE + IRQ_ENABLE_CLEAR);
@@ -194,33 +194,25 @@ static int irq_resume(struct sys_device *dev)
        writel(-1, VA_IC_BASE + FIQ_ENABLE_CLEAR);
 
        writel(ic_irq_enable, VA_IC_BASE + IRQ_ENABLE_SET);
-       return 0;
 }
 #else
 #define irq_suspend NULL
 #define irq_resume NULL
 #endif
 
-static struct sysdev_class irq_class = {
-       .name           = "irq",
+static struct syscore_ops irq_syscore_ops = {
        .suspend        = irq_suspend,
        .resume         = irq_resume,
 };
 
-static struct sys_device irq_device = {
-       .id     = 0,
-       .cls    = &irq_class,
-};
-
-static int __init irq_init_sysfs(void)
+static int __init irq_syscore_init(void)
 {
-       int ret = sysdev_class_register(&irq_class);
-       if (ret == 0)
-               ret = sysdev_register(&irq_device);
-       return ret;
+       register_syscore_ops(&irq_syscore_ops);
+
+       return 0;
 }
 
-device_initcall(irq_init_sysfs);
+device_initcall(irq_syscore_init);
 
 /*
  * Flash handling.
index 6588c22..fe31d93 100644 (file)
 #ifdef CONFIG_PM_RUNTIME
 static int omap1_pm_runtime_suspend(struct device *dev)
 {
-       struct clk *iclk, *fclk;
-       int ret = 0;
+       int ret;
 
        dev_dbg(dev, "%s\n", __func__);
 
        ret = pm_generic_runtime_suspend(dev);
+       if (ret)
+               return ret;
 
-       fclk = clk_get(dev, "fck");
-       if (!IS_ERR(fclk)) {
-               clk_disable(fclk);
-               clk_put(fclk);
-       }
-
-       iclk = clk_get(dev, "ick");
-       if (!IS_ERR(iclk)) {
-               clk_disable(iclk);
-               clk_put(iclk);
+       ret = pm_runtime_clk_suspend(dev);
+       if (ret) {
+               pm_generic_runtime_resume(dev);
+               return ret;
        }
 
        return 0;
-};
+}
 
 static int omap1_pm_runtime_resume(struct device *dev)
 {
-       struct clk *iclk, *fclk;
-
        dev_dbg(dev, "%s\n", __func__);
 
-       iclk = clk_get(dev, "ick");
-       if (!IS_ERR(iclk)) {
-               clk_enable(iclk);
-               clk_put(iclk);
-       }
+       pm_runtime_clk_resume(dev);
+       return pm_generic_runtime_resume(dev);
+}
 
-       fclk = clk_get(dev, "fck");
-       if (!IS_ERR(fclk)) {
-               clk_enable(fclk);
-               clk_put(fclk);
-       }
+static struct dev_power_domain default_power_domain = {
+       .ops = {
+               .runtime_suspend = omap1_pm_runtime_suspend,
+               .runtime_resume = omap1_pm_runtime_resume,
+               USE_PLATFORM_PM_SLEEP_OPS
+       },
+};
 
-       return pm_generic_runtime_resume(dev);
+static struct pm_clk_notifier_block platform_bus_notifier = {
+       .pwr_domain = &default_power_domain,
+       .con_ids = { "ick", "fck", NULL, },
 };
 
 static int __init omap1_pm_runtime_init(void)
 {
-       const struct dev_pm_ops *pm;
-       struct dev_pm_ops *omap_pm;
-
        if (!cpu_class_is_omap1())
                return -ENODEV;
 
-       pm = platform_bus_get_pm_ops();
-       if (!pm) {
-               pr_err("%s: unable to get dev_pm_ops from platform_bus\n",
-                       __func__);
-               return -ENODEV;
-       }
-
-       omap_pm = kmemdup(pm, sizeof(struct dev_pm_ops), GFP_KERNEL);
-       if (!omap_pm) {
-               pr_err("%s: unable to alloc memory for new dev_pm_ops\n",
-                       __func__);
-               return -ENOMEM;
-       }
-
-       omap_pm->runtime_suspend = omap1_pm_runtime_suspend;
-       omap_pm->runtime_resume = omap1_pm_runtime_resume;
-
-       platform_bus_set_pm_ops(omap_pm);
+       pm_runtime_clk_add_notifier(&platform_bus_type, &platform_bus_notifier);
 
        return 0;
 }
index 512b152..66dfbcc 100644 (file)
@@ -59,10 +59,10 @@ endif
 # Power Management
 ifeq ($(CONFIG_PM),y)
 obj-$(CONFIG_ARCH_OMAP2)               += pm24xx.o
-obj-$(CONFIG_ARCH_OMAP2)               += sleep24xx.o pm_bus.o
+obj-$(CONFIG_ARCH_OMAP2)               += sleep24xx.o
 obj-$(CONFIG_ARCH_OMAP3)               += pm34xx.o sleep34xx.o \
-                                          cpuidle34xx.o pm_bus.o
-obj-$(CONFIG_ARCH_OMAP4)               += pm44xx.o pm_bus.o
+                                          cpuidle34xx.o
+obj-$(CONFIG_ARCH_OMAP4)               += pm44xx.o
 obj-$(CONFIG_PM_DEBUG)                 += pm-debug.o
 obj-$(CONFIG_OMAP_SMARTREFLEX)          += sr_device.o smartreflex.o
 obj-$(CONFIG_OMAP_SMARTREFLEX_CLASS3)  += smartreflex-class3.o
index b2b1e37..d6e34dd 100644 (file)
@@ -115,6 +115,7 @@ int omap3_core_dpll_m2_set_rate(struct clk *clk, unsigned long rate)
                                  sdrc_cs0->rfr_ctrl, sdrc_cs0->actim_ctrla,
                                  sdrc_cs0->actim_ctrlb, sdrc_cs0->mr,
                                  0, 0, 0, 0);
+       clk->rate = rate;
 
        return 0;
 }
diff --git a/arch/arm/mach-omap2/pm_bus.c b/arch/arm/mach-omap2/pm_bus.c
deleted file mode 100644 (file)
index 5acd2ab..0000000
+++ /dev/null
@@ -1,85 +0,0 @@
-/*
- * Runtime PM support code for OMAP
- *
- * Author: Kevin Hilman, Deep Root Systems, LLC
- *
- * Copyright (C) 2010 Texas Instruments, Inc.
- *
- * This file is licensed under the terms of the GNU General Public
- * License version 2. This program is licensed "as is" without any
- * warranty of any kind, whether express or implied.
- */
-#include <linux/init.h>
-#include <linux/kernel.h>
-#include <linux/io.h>
-#include <linux/pm_runtime.h>
-#include <linux/platform_device.h>
-#include <linux/mutex.h>
-
-#include <plat/omap_device.h>
-#include <plat/omap-pm.h>
-
-#ifdef CONFIG_PM_RUNTIME
-static int omap_pm_runtime_suspend(struct device *dev)
-{
-       struct platform_device *pdev = to_platform_device(dev);
-       int r, ret = 0;
-
-       dev_dbg(dev, "%s\n", __func__);
-
-       ret = pm_generic_runtime_suspend(dev);
-
-       if (!ret && dev->parent == &omap_device_parent) {
-               r = omap_device_idle(pdev);
-               WARN_ON(r);
-       }
-
-       return ret;
-};
-
-static int omap_pm_runtime_resume(struct device *dev)
-{
-       struct platform_device *pdev = to_platform_device(dev);
-       int r;
-
-       dev_dbg(dev, "%s\n", __func__);
-
-       if (dev->parent == &omap_device_parent) {
-               r = omap_device_enable(pdev);
-               WARN_ON(r);
-       }
-
-       return pm_generic_runtime_resume(dev);
-};
-#else
-#define omap_pm_runtime_suspend NULL
-#define omap_pm_runtime_resume NULL
-#endif /* CONFIG_PM_RUNTIME */
-
-static int __init omap_pm_runtime_init(void)
-{
-       const struct dev_pm_ops *pm;
-       struct dev_pm_ops *omap_pm;
-
-       pm = platform_bus_get_pm_ops();
-       if (!pm) {
-               pr_err("%s: unable to get dev_pm_ops from platform_bus\n",
-                       __func__);
-               return -ENODEV;
-       }
-
-       omap_pm = kmemdup(pm, sizeof(struct dev_pm_ops), GFP_KERNEL);
-       if (!omap_pm) {
-               pr_err("%s: unable to alloc memory for new dev_pm_ops\n",
-                       __func__);
-               return -ENOMEM;
-       }
-
-       omap_pm->runtime_suspend = omap_pm_runtime_suspend;
-       omap_pm->runtime_resume = omap_pm_runtime_resume;
-
-       platform_bus_set_pm_ops(omap_pm);
-
-       return 0;
-}
-core_initcall(omap_pm_runtime_init);
index bfbecec..810a982 100644 (file)
@@ -15,7 +15,6 @@
 
 #include <linux/init.h>
 #include <linux/platform_device.h>
-#include <linux/sysdev.h>
 #include <linux/interrupt.h>
 #include <linux/sched.h>
 #include <linux/bitops.h>
index 1ce0904..1d5859d 100644 (file)
@@ -9,7 +9,7 @@
 #include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/init.h>
-#include <linux/sysdev.h>
+#include <linux/syscore_ops.h>
 
 #include <mach/pxa2xx-regs.h>
 
@@ -33,32 +33,22 @@ const struct clkops clk_pxa2xx_cken_ops = {
 #ifdef CONFIG_PM
 static uint32_t saved_cken;
 
-static int pxa2xx_clock_suspend(struct sys_device *d, pm_message_t state)
+static int pxa2xx_clock_suspend(void)
 {
        saved_cken = CKEN;
        return 0;
 }
 
-static int pxa2xx_clock_resume(struct sys_device *d)
+static void pxa2xx_clock_resume(void)
 {
        CKEN = saved_cken;
-       return 0;
 }
 #else
 #define pxa2xx_clock_suspend   NULL
 #define pxa2xx_clock_resume    NULL
 #endif
 
-struct sysdev_class pxa2xx_clock_sysclass = {
-       .name           = "pxa2xx-clock",
+struct syscore_ops pxa2xx_clock_syscore_ops = {
        .suspend        = pxa2xx_clock_suspend,
        .resume         = pxa2xx_clock_resume,
 };
-
-static int __init pxa2xx_clock_init(void)
-{
-       if (cpu_is_pxa2xx())
-               return sysdev_class_register(&pxa2xx_clock_sysclass);
-       return 0;
-}
-postcore_initcall(pxa2xx_clock_init);
index 3f864cd..2a37a9a 100644 (file)
@@ -10,6 +10,7 @@
 #include <linux/kernel.h>
 #include <linux/init.h>
 #include <linux/io.h>
+#include <linux/syscore_ops.h>
 
 #include <mach/smemc.h>
 #include <mach/pxa3xx-regs.h>
@@ -182,7 +183,7 @@ const struct clkops clk_pxa3xx_pout_ops = {
 static uint32_t cken[2];
 static uint32_t accr;
 
-static int pxa3xx_clock_suspend(struct sys_device *d, pm_message_t state)
+static int pxa3xx_clock_suspend(void)
 {
        cken[0] = CKENA;
        cken[1] = CKENB;
@@ -190,28 +191,18 @@ static int pxa3xx_clock_suspend(struct sys_device *d, pm_message_t state)
        return 0;
 }
 
-static int pxa3xx_clock_resume(struct sys_device *d)
+static void pxa3xx_clock_resume(void)
 {
        ACCR = accr;
        CKENA = cken[0];
        CKENB = cken[1];
-       return 0;
 }
 #else
 #define pxa3xx_clock_suspend   NULL
 #define pxa3xx_clock_resume    NULL
 #endif
 
-struct sysdev_class pxa3xx_clock_sysclass = {
-       .name           = "pxa3xx-clock",
+struct syscore_ops pxa3xx_clock_syscore_ops = {
        .suspend        = pxa3xx_clock_suspend,
        .resume         = pxa3xx_clock_resume,
 };
-
-static int __init pxa3xx_clock_init(void)
-{
-       if (cpu_is_pxa3xx() || cpu_is_pxa95x())
-               return sysdev_class_register(&pxa3xx_clock_sysclass);
-       return 0;
-}
-postcore_initcall(pxa3xx_clock_init);
index f9f349a..1f2fb9c 100644 (file)
@@ -1,5 +1,5 @@
 #include <linux/clkdev.h>
-#include <linux/sysdev.h>
+#include <linux/syscore_ops.h>
 
 struct clkops {
        void                    (*enable)(struct clk *);
@@ -54,7 +54,7 @@ extern const struct clkops clk_pxa2xx_cken_ops;
 void clk_pxa2xx_cken_enable(struct clk *clk);
 void clk_pxa2xx_cken_disable(struct clk *clk);
 
-extern struct sysdev_class pxa2xx_clock_sysclass;
+extern struct syscore_ops pxa2xx_clock_syscore_ops;
 
 #if defined(CONFIG_PXA3xx) || defined(CONFIG_PXA95x)
 #define DEFINE_PXA3_CKEN(_name, _cken, _rate, _delay)  \
@@ -74,5 +74,6 @@ extern const struct clkops clk_pxa3xx_smemc_ops;
 extern void clk_pxa3xx_cken_enable(struct clk *);
 extern void clk_pxa3xx_cken_disable(struct clk *);
 
-extern struct sysdev_class pxa3xx_clock_sysclass;
+extern struct syscore_ops pxa3xx_clock_syscore_ops;
+
 #endif
index b88d601..13518a7 100644 (file)
@@ -10,7 +10,6 @@
  */
 
 #include <linux/platform_device.h>
-#include <linux/sysdev.h>
 #include <linux/irq.h>
 #include <linux/gpio.h>
 #include <linux/delay.h>
index 8225e2e..a109967 100644 (file)
@@ -10,7 +10,7 @@
  */
 
 #include <linux/platform_device.h>
-#include <linux/sysdev.h>
+#include <linux/syscore_ops.h>
 #include <linux/irq.h>
 #include <linux/gpio.h>
 
@@ -388,7 +388,7 @@ static inline void cmx2xx_init_display(void) {}
 #ifdef CONFIG_PM
 static unsigned long sleep_save_msc[10];
 
-static int cmx2xx_suspend(struct sys_device *dev, pm_message_t state)
+static int cmx2xx_suspend(void)
 {
        cmx2xx_pci_suspend();
 
@@ -412,7 +412,7 @@ static int cmx2xx_suspend(struct sys_device *dev, pm_message_t state)
        return 0;
 }
 
-static int cmx2xx_resume(struct sys_device *dev)
+static void cmx2xx_resume(void)
 {
        cmx2xx_pci_resume();
 
@@ -420,27 +420,18 @@ static int cmx2xx_resume(struct sys_device *dev)
        __raw_writel(sleep_save_msc[0], MSC0);
        __raw_writel(sleep_save_msc[1], MSC1);
        __raw_writel(sleep_save_msc[2], MSC2);
-
-       return 0;
 }
 
-static struct sysdev_class cmx2xx_pm_sysclass = {
-       .name = "pm",
+static struct syscore_ops cmx2xx_pm_syscore_ops = {
        .resume = cmx2xx_resume,
        .suspend = cmx2xx_suspend,
 };
 
-static struct sys_device cmx2xx_pm_device = {
-       .cls = &cmx2xx_pm_sysclass,
-};
-
 static int __init cmx2xx_pm_init(void)
 {
-       int error;
-       error = sysdev_class_register(&cmx2xx_pm_sysclass);
-       if (error == 0)
-               error = sysdev_register(&cmx2xx_pm_device);
-       return error;
+       register_syscore_ops(&cmx2xx_pm_syscore_ops);
+
+       return 0;
 }
 #else
 static int __init cmx2xx_pm_init(void) { return 0; }
index 81c3c43..d28e802 100644 (file)
@@ -13,7 +13,6 @@
 #include <linux/init.h>
 #include <linux/kernel.h>
 #include <linux/platform_device.h>
-#include <linux/sysdev.h>
 #include <linux/interrupt.h>
 #include <linux/gpio.h>
 #include <asm/mach-types.h>
index 44c1b77..80538b8 100644 (file)
@@ -22,7 +22,6 @@
 #include <linux/platform_device.h>
 #include <linux/pwm_backlight.h>
 #include <linux/i2c/pxa-i2c.h>
-#include <linux/sysdev.h>
 
 #include <asm/irq.h>
 #include <asm/mach-types.h>
index 6fc5d32..7545a48 100644 (file)
@@ -17,7 +17,6 @@
 #include <linux/mtd/partitions.h>
 #include <linux/mtd/physmap.h>
 #include <linux/platform_device.h>
-#include <linux/sysdev.h>
 #include <linux/ucb1400.h>
 
 #include <asm/mach/arch.h>
index a079d8b..e6c9344 100644 (file)
@@ -61,10 +61,10 @@ extern unsigned pxa3xx_get_clk_frequency_khz(int);
 #define pxa3xx_get_clk_frequency_khz(x)                (0)
 #endif
 
-extern struct sysdev_class pxa_irq_sysclass;
-extern struct sysdev_class pxa_gpio_sysclass;
-extern struct sysdev_class pxa2xx_mfp_sysclass;
-extern struct sysdev_class pxa3xx_mfp_sysclass;
+extern struct syscore_ops pxa_irq_syscore_ops;
+extern struct syscore_ops pxa_gpio_syscore_ops;
+extern struct syscore_ops pxa2xx_mfp_syscore_ops;
+extern struct syscore_ops pxa3xx_mfp_syscore_ops;
 
 void __init pxa_set_ffuart_info(void *info);
 void __init pxa_set_btuart_info(void *info);
index 6251e3f..32ed551 100644 (file)
@@ -15,7 +15,7 @@
 #include <linux/init.h>
 #include <linux/module.h>
 #include <linux/interrupt.h>
-#include <linux/sysdev.h>
+#include <linux/syscore_ops.h>
 #include <linux/io.h>
 #include <linux/irq.h>
 
@@ -183,7 +183,7 @@ void __init pxa_init_irq(int irq_nr, set_wake_t fn)
 static unsigned long saved_icmr[MAX_INTERNAL_IRQS/32];
 static unsigned long saved_ipr[MAX_INTERNAL_IRQS];
 
-static int pxa_irq_suspend(struct sys_device *dev, pm_message_t state)
+static int pxa_irq_suspend(void)
 {
        int i;
 
@@ -202,7 +202,7 @@ static int pxa_irq_suspend(struct sys_device *dev, pm_message_t state)
        return 0;
 }
 
-static int pxa_irq_resume(struct sys_device *dev)
+static void pxa_irq_resume(void)
 {
        int i;
 
@@ -218,22 +218,13 @@ static int pxa_irq_resume(struct sys_device *dev)
                        __raw_writel(saved_ipr[i], IRQ_BASE + IPR(i));
 
        __raw_writel(1, IRQ_BASE + ICCR);
-       return 0;
 }
 #else
 #define pxa_irq_suspend                NULL
 #define pxa_irq_resume         NULL
 #endif
 
-struct sysdev_class pxa_irq_sysclass = {
-       .name           = "irq",
+struct syscore_ops pxa_irq_syscore_ops = {
        .suspend        = pxa_irq_suspend,
        .resume         = pxa_irq_resume,
 };
-
-static int __init pxa_irq_init(void)
-{
-       return sysdev_class_register(&pxa_irq_sysclass);
-}
-
-core_initcall(pxa_irq_init);
index f5de541..6cf8180 100644 (file)
@@ -15,7 +15,7 @@
 
 #include <linux/init.h>
 #include <linux/platform_device.h>
-#include <linux/sysdev.h>
+#include <linux/syscore_ops.h>
 #include <linux/interrupt.h>
 #include <linux/sched.h>
 #include <linux/bitops.h>
@@ -159,30 +159,22 @@ static void __init lpd270_init_irq(void)
 
 
 #ifdef CONFIG_PM
-static int lpd270_irq_resume(struct sys_device *dev)
+static void lpd270_irq_resume(void)
 {
        __raw_writew(lpd270_irq_enabled, LPD270_INT_MASK);
-       return 0;
 }
 
-static struct sysdev_class lpd270_irq_sysclass = {
-       .name = "cpld_irq",
+static struct syscore_ops lpd270_irq_syscore_ops = {
        .resume = lpd270_irq_resume,
 };
 
-static struct sys_device lpd270_irq_device = {
-       .cls = &lpd270_irq_sysclass,
-};
-
 static int __init lpd270_irq_device_init(void)
 {
-       int ret = -ENODEV;
        if (machine_is_logicpd_pxa270()) {
-               ret = sysdev_class_register(&lpd270_irq_sysclass);
-               if (ret == 0)
-                       ret = sysdev_register(&lpd270_irq_device);
+               register_syscore_ops(&lpd270_irq_syscore_ops);
+               return 0;
        }
-       return ret;
+       return -ENODEV;
 }
 
 device_initcall(lpd270_irq_device_init);
index 3ede978..e10ddb8 100644 (file)
@@ -15,7 +15,7 @@
 #include <linux/kernel.h>
 #include <linux/init.h>
 #include <linux/platform_device.h>
-#include <linux/sysdev.h>
+#include <linux/syscore_ops.h>
 #include <linux/major.h>
 #include <linux/fb.h>
 #include <linux/interrupt.h>
@@ -176,31 +176,22 @@ static void __init lubbock_init_irq(void)
 
 #ifdef CONFIG_PM
 
-static int lubbock_irq_resume(struct sys_device *dev)
+static void lubbock_irq_resume(void)
 {
        LUB_IRQ_MASK_EN = lubbock_irq_enabled;
-       return 0;
 }
 
-static struct sysdev_class lubbock_irq_sysclass = {
-       .name = "cpld_irq",
+static struct syscore_ops lubbock_irq_syscore_ops = {
        .resume = lubbock_irq_resume,
 };
 
-static struct sys_device lubbock_irq_device = {
-       .cls = &lubbock_irq_sysclass,
-};
-
 static int __init lubbock_irq_device_init(void)
 {
-       int ret = -ENODEV;
-
        if (machine_is_lubbock()) {
-               ret = sysdev_class_register(&lubbock_irq_sysclass);
-               if (ret == 0)
-                       ret = sysdev_register(&lubbock_irq_device);
+               register_syscore_ops(&lubbock_irq_syscore_ops);
+               return 0;
        }
-       return ret;
+       return -ENODEV;
 }
 
 device_initcall(lubbock_irq_device_init);
index 95163ba..3479e2b 100644 (file)
@@ -15,7 +15,7 @@
 
 #include <linux/init.h>
 #include <linux/platform_device.h>
-#include <linux/sysdev.h>
+#include <linux/syscore_ops.h>
 #include <linux/interrupt.h>
 #include <linux/sched.h>
 #include <linux/bitops.h>
@@ -185,31 +185,21 @@ static void __init mainstone_init_irq(void)
 
 #ifdef CONFIG_PM
 
-static int mainstone_irq_resume(struct sys_device *dev)
+static void mainstone_irq_resume(void)
 {
        MST_INTMSKENA = mainstone_irq_enabled;
-       return 0;
 }
 
-static struct sysdev_class mainstone_irq_sysclass = {
-       .name = "cpld_irq",
+static struct syscore_ops mainstone_irq_syscore_ops = {
        .resume = mainstone_irq_resume,
 };
 
-static struct sys_device mainstone_irq_device = {
-       .cls = &mainstone_irq_sysclass,
-};
-
 static int __init mainstone_irq_device_init(void)
 {
-       int ret = -ENODEV;
+       if (machine_is_mainstone())
+               register_syscore_ops(&mainstone_irq_syscore_ops);
 
-       if (machine_is_mainstone()) {
-               ret = sysdev_class_register(&mainstone_irq_sysclass);
-               if (ret == 0)
-                       ret = sysdev_register(&mainstone_irq_device);
-       }
-       return ret;
+       return 0;
 }
 
 device_initcall(mainstone_irq_device_init);
index 1d1419b..87ae312 100644 (file)
@@ -16,7 +16,7 @@
 #include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/init.h>
-#include <linux/sysdev.h>
+#include <linux/syscore_ops.h>
 
 #include <mach/gpio.h>
 #include <mach/pxa2xx-regs.h>
@@ -338,7 +338,7 @@ static unsigned long saved_gafr[2][4];
 static unsigned long saved_gpdr[4];
 static unsigned long saved_pgsr[4];
 
-static int pxa2xx_mfp_suspend(struct sys_device *d, pm_message_t state)
+static int pxa2xx_mfp_suspend(void)
 {
        int i;
 
@@ -365,7 +365,7 @@ static int pxa2xx_mfp_suspend(struct sys_device *d, pm_message_t state)
        return 0;
 }
 
-static int pxa2xx_mfp_resume(struct sys_device *d)
+static void pxa2xx_mfp_resume(void)
 {
        int i;
 
@@ -376,15 +376,13 @@ static int pxa2xx_mfp_resume(struct sys_device *d)
                PGSR(i) = saved_pgsr[i];
        }
        PSSR = PSSR_RDH | PSSR_PH;
-       return 0;
 }
 #else
 #define pxa2xx_mfp_suspend     NULL
 #define pxa2xx_mfp_resume      NULL
 #endif
 
-struct sysdev_class pxa2xx_mfp_sysclass = {
-       .name           = "mfp",
+struct syscore_ops pxa2xx_mfp_syscore_ops = {
        .suspend        = pxa2xx_mfp_suspend,
        .resume         = pxa2xx_mfp_resume,
 };
@@ -409,6 +407,6 @@ static int __init pxa2xx_mfp_init(void)
        for (i = 0; i <= gpio_to_bank(pxa_last_gpio); i++)
                gpdr_lpm[i] = GPDR(i * 32);
 
-       return sysdev_class_register(&pxa2xx_mfp_sysclass);
+       return 0;
 }
 postcore_initcall(pxa2xx_mfp_init);
index 7a270ee..89863a0 100644 (file)
@@ -17,7 +17,7 @@
 #include <linux/kernel.h>
 #include <linux/init.h>
 #include <linux/io.h>
-#include <linux/sysdev.h>
+#include <linux/syscore_ops.h>
 
 #include <mach/hardware.h>
 #include <mach/mfp-pxa3xx.h>
  * a pull-down mode if they're an active low chip select, and we're
  * just entering standby.
  */
-static int pxa3xx_mfp_suspend(struct sys_device *d, pm_message_t state)
+static int pxa3xx_mfp_suspend(void)
 {
        mfp_config_lpm();
        return 0;
 }
 
-static int pxa3xx_mfp_resume(struct sys_device *d)
+static void pxa3xx_mfp_resume(void)
 {
        mfp_config_run();
 
@@ -47,24 +47,13 @@ static int pxa3xx_mfp_resume(struct sys_device *d)
         * preserve them here in case they will be referenced later
         */
        ASCR &= ~(ASCR_RDH | ASCR_D1S | ASCR_D2S | ASCR_D3S);
-       return 0;
 }
 #else
 #define pxa3xx_mfp_suspend     NULL
 #define pxa3xx_mfp_resume      NULL
 #endif
 
-struct sysdev_class pxa3xx_mfp_sysclass = {
-       .name           = "mfp",
+struct syscore_ops pxa3xx_mfp_syscore_ops = {
        .suspend        = pxa3xx_mfp_suspend,
-       .resume         = pxa3xx_mfp_resume,
+       .resume         = pxa3xx_mfp_resume,
 };
-
-static int __init mfp_init_devicefs(void)
-{
-       if (cpu_is_pxa3xx())
-               return sysdev_class_register(&pxa3xx_mfp_sysclass);
-
-       return 0;
-}
-postcore_initcall(mfp_init_devicefs);
index 23925db..e347013 100644 (file)
@@ -22,7 +22,7 @@
 #include <linux/kernel.h>
 #include <linux/init.h>
 #include <linux/platform_device.h>
-#include <linux/sysdev.h>
+#include <linux/syscore_ops.h>
 #include <linux/input.h>
 #include <linux/delay.h>
 #include <linux/gpio_keys.h>
@@ -488,7 +488,7 @@ static void install_bootstrap(void)
 }
 
 
-static int mioa701_sys_suspend(struct sys_device *sysdev, pm_message_t state)
+static int mioa701_sys_suspend(void)
 {
        int i = 0, is_bt_on;
        u32 *mem_resume_vector  = phys_to_virt(RESUME_VECTOR_ADDR);
@@ -514,7 +514,7 @@ static int mioa701_sys_suspend(struct sys_device *sysdev, pm_message_t state)
        return 0;
 }
 
-static int mioa701_sys_resume(struct sys_device *sysdev)
+static void mioa701_sys_resume(void)
 {
        int i = 0;
        u32 *mem_resume_vector  = phys_to_virt(RESUME_VECTOR_ADDR);
@@ -527,43 +527,18 @@ static int mioa701_sys_resume(struct sys_device *sysdev)
        *mem_resume_enabler = save_buffer[i++];
        *mem_resume_bt      = save_buffer[i++];
        *mem_resume_unknown = save_buffer[i++];
-
-       return 0;
 }
 
-static struct sysdev_class mioa701_sysclass = {
-       .name = "mioa701",
-};
-
-static struct sys_device sysdev_bootstrap = {
-       .cls            = &mioa701_sysclass,
-};
-
-static struct sysdev_driver driver_bootstrap = {
-       .suspend        = &mioa701_sys_suspend,
-       .resume         = &mioa701_sys_resume,
+static struct syscore_ops mioa701_syscore_ops = {
+       .suspend        = mioa701_sys_suspend,
+       .resume         = mioa701_sys_resume,
 };
 
 static int __init bootstrap_init(void)
 {
-       int rc;
        int save_size = mioa701_bootstrap_lg + (sizeof(u32) * 3);
 
-       rc = sysdev_class_register(&mioa701_sysclass);
-       if (rc) {
-               printk(KERN_ERR "Failed registering mioa701 sys class\n");
-               return -ENODEV;
-       }
-       rc = sysdev_register(&sysdev_bootstrap);
-       if (rc) {
-               printk(KERN_ERR "Failed registering mioa701 sys device\n");
-               return -ENODEV;
-       }
-       rc = sysdev_driver_register(&mioa701_sysclass, &driver_bootstrap);
-       if (rc) {
-               printk(KERN_ERR "Failed registering PMU sys driver\n");
-               return -ENODEV;
-       }
+       register_syscore_ops(&mioa701_syscore_ops);
 
        save_buffer = kmalloc(save_size, GFP_KERNEL);
        if (!save_buffer)
@@ -576,9 +551,7 @@ static int __init bootstrap_init(void)
 static void bootstrap_exit(void)
 {
        kfree(save_buffer);
-       sysdev_driver_unregister(&mioa701_sysclass, &driver_bootstrap);
-       sysdev_unregister(&sysdev_bootstrap);
-       sysdev_class_unregister(&mioa701_sysclass);
+       unregister_syscore_ops(&mioa701_syscore_ops);
 
        printk(KERN_CRIT "Unregistering mioa701 suspend will hang next"
               "resume !!!\n");
index a6f898c..4061ecd 100644 (file)
@@ -24,7 +24,6 @@
 #include <linux/gpio.h>
 #include <linux/wm97xx.h>
 #include <linux/power_supply.h>
-#include <linux/sysdev.h>
 #include <linux/mtd/mtd.h>
 #include <linux/mtd/partitions.h>
 #include <linux/mtd/physmap.h>
index 8aadad5..20d1b18 100644 (file)
@@ -25,7 +25,6 @@
 #include <linux/pwm_backlight.h>
 #include <linux/gpio.h>
 #include <linux/power_supply.h>
-#include <linux/sysdev.h>
 #include <linux/w1-gpio.h>
 
 #include <asm/mach-types.h>
index 3b8a4f3..65f24f0 100644 (file)
@@ -19,7 +19,7 @@
  */
 
 #include <linux/platform_device.h>
-#include <linux/sysdev.h>
+#include <linux/syscore_ops.h>
 #include <linux/delay.h>
 #include <linux/irq.h>
 #include <linux/gpio_keys.h>
@@ -233,9 +233,9 @@ static struct palmz72_resume_info palmz72_resume_info = {
 
 static unsigned long store_ptr;
 
-/* sys_device for Palm Zire 72 PM */
+/* syscore_ops for Palm Zire 72 PM */
 
-static int palmz72_pm_suspend(struct sys_device *dev, pm_message_t msg)
+static int palmz72_pm_suspend(void)
 {
        /* setup the resume_info struct for the original bootloader */
        palmz72_resume_info.resume_addr = (u32) cpu_resume;
@@ -249,31 +249,23 @@ static int palmz72_pm_suspend(struct sys_device *dev, pm_message_t msg)
        return 0;
 }
 
-static int palmz72_pm_resume(struct sys_device *dev)
+static void palmz72_pm_resume(void)
 {
        *PALMZ72_SAVE_DWORD = store_ptr;
-       return 0;
 }
 
-static struct sysdev_class palmz72_pm_sysclass = {
-       .name = "palmz72_pm",
+static struct syscore_ops palmz72_pm_syscore_ops = {
        .suspend = palmz72_pm_suspend,
        .resume = palmz72_pm_resume,
 };
 
-static struct sys_device palmz72_pm_device = {
-       .cls = &palmz72_pm_sysclass,
-};
-
 static int __init palmz72_pm_init(void)
 {
-       int ret = -ENODEV;
        if (machine_is_palmz72()) {
-               ret = sysdev_class_register(&palmz72_pm_sysclass);
-               if (ret == 0)
-                       ret = sysdev_register(&palmz72_pm_device);
+               register_syscore_ops(&palmz72_pm_syscore_ops);
+               return 0;
        }
-       return ret;
+       return -ENODEV;
 }
 
 device_initcall(palmz72_pm_init);
index a4af8c5..fed363c 100644 (file)
@@ -21,7 +21,7 @@
 #include <linux/init.h>
 #include <linux/platform_device.h>
 #include <linux/suspend.h>
-#include <linux/sysdev.h>
+#include <linux/syscore_ops.h>
 #include <linux/irq.h>
 
 #include <asm/mach/map.h>
@@ -350,21 +350,9 @@ static struct platform_device *pxa25x_devices[] __initdata = {
        &pxa_device_asoc_platform,
 };
 
-static struct sys_device pxa25x_sysdev[] = {
-       {
-               .cls    = &pxa_irq_sysclass,
-       }, {
-               .cls    = &pxa2xx_mfp_sysclass,
-       }, {
-               .cls    = &pxa_gpio_sysclass,
-       }, {
-               .cls    = &pxa2xx_clock_sysclass,
-       }
-};
-
 static int __init pxa25x_init(void)
 {
-       int i, ret = 0;
+       int ret = 0;
 
        if (cpu_is_pxa25x()) {
 
@@ -377,11 +365,10 @@ static int __init pxa25x_init(void)
 
                pxa25x_init_pm();
 
-               for (i = 0; i < ARRAY_SIZE(pxa25x_sysdev); i++) {
-                       ret = sysdev_register(&pxa25x_sysdev[i]);
-                       if (ret)
-                               pr_err("failed to register sysdev[%d]\n", i);
-               }
+               register_syscore_ops(&pxa_irq_syscore_ops);
+               register_syscore_ops(&pxa2xx_mfp_syscore_ops);
+               register_syscore_ops(&pxa_gpio_syscore_ops);
+               register_syscore_ops(&pxa2xx_clock_syscore_ops);
 
                ret = platform_add_devices(pxa25x_devices,
                                           ARRAY_SIZE(pxa25x_devices));
index 909756e..2fecbec 100644 (file)
@@ -16,7 +16,7 @@
 #include <linux/init.h>
 #include <linux/suspend.h>
 #include <linux/platform_device.h>
-#include <linux/sysdev.h>
+#include <linux/syscore_ops.h>
 #include <linux/io.h>
 #include <linux/irq.h>
 #include <linux/i2c/pxa-i2c.h>
@@ -428,21 +428,9 @@ static struct platform_device *devices[] __initdata = {
        &pxa27x_device_pwm1,
 };
 
-static struct sys_device pxa27x_sysdev[] = {
-       {
-               .cls    = &pxa_irq_sysclass,
-       }, {
-               .cls    = &pxa2xx_mfp_sysclass,
-       }, {
-               .cls    = &pxa_gpio_sysclass,
-       }, {
-               .cls    = &pxa2xx_clock_sysclass,
-       }
-};
-
 static int __init pxa27x_init(void)
 {
-       int i, ret = 0;
+       int ret = 0;
 
        if (cpu_is_pxa27x()) {
 
@@ -455,11 +443,10 @@ static int __init pxa27x_init(void)
 
                pxa27x_init_pm();
 
-               for (i = 0; i < ARRAY_SIZE(pxa27x_sysdev); i++) {
-                       ret = sysdev_register(&pxa27x_sysdev[i]);
-                       if (ret)
-                               pr_err("failed to register sysdev[%d]\n", i);
-               }
+               register_syscore_ops(&pxa_irq_syscore_ops);
+               register_syscore_ops(&pxa2xx_mfp_syscore_ops);
+               register_syscore_ops(&pxa_gpio_syscore_ops);
+               register_syscore_ops(&pxa2xx_clock_syscore_ops);
 
                ret = platform_add_devices(devices, ARRAY_SIZE(devices));
        }
index 8dd1073..8521d7d 100644 (file)
@@ -20,7 +20,7 @@
 #include <linux/platform_device.h>
 #include <linux/irq.h>
 #include <linux/io.h>
-#include <linux/sysdev.h>
+#include <linux/syscore_ops.h>
 #include <linux/i2c/pxa-i2c.h>
 
 #include <asm/mach/map.h>
@@ -427,21 +427,9 @@ static struct platform_device *devices[] __initdata = {
        &pxa27x_device_pwm1,
 };
 
-static struct sys_device pxa3xx_sysdev[] = {
-       {
-               .cls    = &pxa_irq_sysclass,
-       }, {
-               .cls    = &pxa3xx_mfp_sysclass,
-       }, {
-               .cls    = &pxa_gpio_sysclass,
-       }, {
-               .cls    = &pxa3xx_clock_sysclass,
-       }
-};
-
 static int __init pxa3xx_init(void)
 {
-       int i, ret = 0;
+       int ret = 0;
 
        if (cpu_is_pxa3xx()) {
 
@@ -462,11 +450,10 @@ static int __init pxa3xx_init(void)
 
                pxa3xx_init_pm();
 
-               for (i = 0; i < ARRAY_SIZE(pxa3xx_sysdev); i++) {
-                       ret = sysdev_register(&pxa3xx_sysdev[i]);
-                       if (ret)
-                               pr_err("failed to register sysdev[%d]\n", i);
-               }
+               register_syscore_ops(&pxa_irq_syscore_ops);
+               register_syscore_ops(&pxa3xx_mfp_syscore_ops);
+               register_syscore_ops(&pxa_gpio_syscore_ops);
+               register_syscore_ops(&pxa3xx_clock_syscore_ops);
 
                ret = platform_add_devices(devices, ARRAY_SIZE(devices));
        }
index 23b229b..ecc82a3 100644 (file)
@@ -18,7 +18,7 @@
 #include <linux/i2c/pxa-i2c.h>
 #include <linux/irq.h>
 #include <linux/io.h>
-#include <linux/sysdev.h>
+#include <linux/syscore_ops.h>
 
 #include <mach/hardware.h>
 #include <mach/gpio.h>
@@ -260,16 +260,6 @@ static struct platform_device *devices[] __initdata = {
        &pxa27x_device_pwm1,
 };
 
-static struct sys_device pxa95x_sysdev[] = {
-       {
-               .cls    = &pxa_irq_sysclass,
-       }, {
-               .cls    = &pxa_gpio_sysclass,
-       }, {
-               .cls    = &pxa3xx_clock_sysclass,
-       }
-};
-
 static int __init pxa95x_init(void)
 {
        int ret = 0, i;
@@ -293,11 +283,9 @@ static int __init pxa95x_init(void)
                if ((ret = pxa_init_dma(IRQ_DMA, 32)))
                        return ret;
 
-               for (i = 0; i < ARRAY_SIZE(pxa95x_sysdev); i++) {
-                       ret = sysdev_register(&pxa95x_sysdev[i]);
-                       if (ret)
-                               pr_err("failed to register sysdev[%d]\n", i);
-               }
+               register_syscore_ops(&pxa_irq_syscore_ops);
+               register_syscore_ops(&pxa_gpio_syscore_ops);
+               register_syscore_ops(&pxa3xx_clock_syscore_ops);
 
                ret = platform_add_devices(devices, ARRAY_SIZE(devices));
        }
index cd18613..d130f77 100644 (file)
@@ -18,7 +18,6 @@
 
 #include <linux/init.h>
 #include <linux/kernel.h>
-#include <linux/sysdev.h>
 #include <linux/platform_device.h>
 #include <linux/interrupt.h>
 #include <linux/gpio.h>
index 232b731..7992305 100644 (file)
@@ -6,7 +6,7 @@
 #include <linux/kernel.h>
 #include <linux/init.h>
 #include <linux/io.h>
-#include <linux/sysdev.h>
+#include <linux/syscore_ops.h>
 
 #include <mach/hardware.h>
 #include <mach/smemc.h>
@@ -16,7 +16,7 @@ static unsigned long msc[2];
 static unsigned long sxcnfg, memclkcfg;
 static unsigned long csadrcfg[4];
 
-static int pxa3xx_smemc_suspend(struct sys_device *dev, pm_message_t state)
+static int pxa3xx_smemc_suspend(void)
 {
        msc[0] = __raw_readl(MSC0);
        msc[1] = __raw_readl(MSC1);
@@ -30,7 +30,7 @@ static int pxa3xx_smemc_suspend(struct sys_device *dev, pm_message_t state)
        return 0;
 }
 
-static int pxa3xx_smemc_resume(struct sys_device *dev)
+static void pxa3xx_smemc_resume(void)
 {
        __raw_writel(msc[0], MSC0);
        __raw_writel(msc[1], MSC1);
@@ -40,34 +40,19 @@ static int pxa3xx_smemc_resume(struct sys_device *dev)
        __raw_writel(csadrcfg[1], CSADRCFG1);
        __raw_writel(csadrcfg[2], CSADRCFG2);
        __raw_writel(csadrcfg[3], CSADRCFG3);
-
-       return 0;
 }
 
-static struct sysdev_class smemc_sysclass = {
-       .name           = "smemc",
+static struct syscore_ops smemc_syscore_ops = {
        .suspend        = pxa3xx_smemc_suspend,
        .resume         = pxa3xx_smemc_resume,
 };
 
-static struct sys_device smemc_sysdev = {
-       .id             = 0,
-       .cls            = &smemc_sysclass,
-};
-
 static int __init smemc_init(void)
 {
-       int ret = 0;
+       if (cpu_is_pxa3xx())
+               register_syscore_ops(&smemc_syscore_ops);
 
-       if (cpu_is_pxa3xx()) {
-               ret = sysdev_class_register(&smemc_sysclass);
-               if (ret)
-                       return ret;
-
-               ret = sysdev_register(&smemc_sysdev);
-       }
-
-       return ret;
+       return 0;
 }
 subsys_initcall(smemc_init);
 #endif
index b9cfbeb..687417a 100644 (file)
@@ -15,7 +15,6 @@
 #include <linux/init.h>
 #include <linux/kernel.h>
 #include <linux/platform_device.h>
-#include <linux/sysdev.h>
 #include <linux/interrupt.h>
 #include <linux/sched.h>
 #include <linux/bitops.h>
index b523f11..903218e 100644 (file)
@@ -44,6 +44,7 @@
 #include <linux/mtd/mtd.h>
 #include <linux/mtd/partitions.h>
 #include <linux/mtd/physmap.h>
+#include <linux/syscore_ops.h>
 
 #include <mach/pxa25x.h>
 #include <mach/audio.h>
@@ -130,20 +131,19 @@ static u8 viper_hw_version(void)
        return v1;
 }
 
-/* CPU sysdev */
-static int viper_cpu_suspend(struct sys_device *sysdev, pm_message_t state)
+/* CPU system core operations. */
+static int viper_cpu_suspend(void)
 {
        viper_icr_set_bit(VIPER_ICR_R_DIS);
        return 0;
 }
 
-static int viper_cpu_resume(struct sys_device *sysdev)
+static void viper_cpu_resume(void)
 {
        viper_icr_clear_bit(VIPER_ICR_R_DIS);
-       return 0;
 }
 
-static struct sysdev_driver viper_cpu_sysdev_driver = {
+static struct syscore_ops viper_cpu_syscore_ops = {
        .suspend        = viper_cpu_suspend,
        .resume         = viper_cpu_resume,
 };
@@ -945,7 +945,7 @@ static void __init viper_init(void)
        viper_init_vcore_gpios();
        viper_init_cpufreq();
 
-       sysdev_driver_register(&cpu_sysdev_class, &viper_cpu_sysdev_driver);
+       register_syscore_ops(&viper_cpu_syscore_ops);
 
        if (version) {
                pr_info("viper: hardware v%di%d detected. "
index f71d377..67bd414 100644 (file)
@@ -16,7 +16,6 @@
 #include <linux/gpio_keys.h>
 #include <linux/input.h>
 #include <linux/gpio.h>
-#include <linux/sysdev.h>
 #include <linux/usb/gpio_vbus.h>
 #include <linux/mtd/mtd.h>
 #include <linux/mtd/partitions.h>
index 0c5d749..9a73219 100644 (file)
@@ -4,5 +4,5 @@
  * operation to deadlock the system.
  */
 #define mb()           dsb()
-#define rmb()          dmb()
+#define rmb()          dsb()
 #define wmb()          mb()
index 5e2f353..2854129 100644 (file)
 #include <linux/module.h>
 #include <linux/interrupt.h>
 #include <linux/ioport.h>
-#include <linux/sysdev.h>
+#include <linux/syscore_ops.h>
 
 #include <plat/cpu.h>
 #include <plat/pm.h>
 
-static int s3c2410_irq_add(struct sys_device *sysdev)
-{
-       return 0;
-}
-
-static struct sysdev_driver s3c2410_irq_driver = {
-       .add            = s3c2410_irq_add,
+struct syscore_ops s3c24xx_irq_syscore_ops = {
        .suspend        = s3c24xx_irq_suspend,
        .resume         = s3c24xx_irq_resume,
 };
-
-static int __init s3c2410_irq_init(void)
-{
-       return sysdev_driver_register(&s3c2410_sysclass, &s3c2410_irq_driver);
-}
-
-arch_initcall(s3c2410_irq_init);
-
-static struct sysdev_driver s3c2410a_irq_driver = {
-       .add            = s3c2410_irq_add,
-       .suspend        = s3c24xx_irq_suspend,
-       .resume         = s3c24xx_irq_resume,
-};
-
-static int __init s3c2410a_irq_init(void)
-{
-       return sysdev_driver_register(&s3c2410a_sysclass, &s3c2410a_irq_driver);
-}
-
-arch_initcall(s3c2410a_irq_init);
index 2970ea9..1e2d536 100644 (file)
@@ -17,7 +17,7 @@
 #include <linux/timer.h>
 #include <linux/init.h>
 #include <linux/gpio.h>
-#include <linux/sysdev.h>
+#include <linux/syscore_ops.h>
 #include <linux/serial_core.h>
 #include <linux/platform_device.h>
 #include <linux/dm9000.h>
@@ -214,17 +214,16 @@ static struct s3c2410_uartcfg bast_uartcfgs[] __initdata = {
 /* NAND Flash on BAST board */
 
 #ifdef CONFIG_PM
-static int bast_pm_suspend(struct sys_device *sd, pm_message_t state)
+static int bast_pm_suspend(void)
 {
        /* ensure that an nRESET is not generated on resume. */
        gpio_direction_output(S3C2410_GPA(21), 1);
        return 0;
 }
 
-static int bast_pm_resume(struct sys_device *sd)
+static void bast_pm_resume(void)
 {
        s3c_gpio_cfgpin(S3C2410_GPA(21), S3C2410_GPA21_nRSTOUT);
-       return 0;
 }
 
 #else
@@ -232,16 +231,11 @@ static int bast_pm_resume(struct sys_device *sd)
 #define bast_pm_resume NULL
 #endif
 
-static struct sysdev_class bast_pm_sysclass = {
-       .name           = "mach-bast",
+static struct syscore_ops bast_pm_syscore_ops = {
        .suspend        = bast_pm_suspend,
        .resume         = bast_pm_resume,
 };
 
-static struct sys_device bast_pm_sysdev = {
-       .cls            = &bast_pm_sysclass,
-};
-
 static int smartmedia_map[] = { 0 };
 static int chip0_map[] = { 1 };
 static int chip1_map[] = { 2 };
@@ -642,8 +636,7 @@ static void __init bast_map_io(void)
 
 static void __init bast_init(void)
 {
-       sysdev_class_register(&bast_pm_sysclass);
-       sysdev_register(&bast_pm_sysdev);
+       register_syscore_ops(&bast_pm_syscore_ops);
 
        s3c_i2c0_set_platdata(&bast_i2c_info);
        s3c_nand_set_platdata(&bast_nand_info);
index 725636f..4728f9a 100644 (file)
@@ -25,6 +25,7 @@
 #include <linux/errno.h>
 #include <linux/time.h>
 #include <linux/sysdev.h>
+#include <linux/syscore_ops.h>
 #include <linux/gpio.h>
 #include <linux/io.h>
 
@@ -92,7 +93,7 @@ static void s3c2410_pm_prepare(void)
        }
 }
 
-static int s3c2410_pm_resume(struct sys_device *dev)
+static void s3c2410_pm_resume(void)
 {
        unsigned long tmp;
 
@@ -104,10 +105,12 @@ static int s3c2410_pm_resume(struct sys_device *dev)
 
        if ( machine_is_aml_m5900() )
                s3c2410_gpio_setpin(S3C2410_GPF(2), 0);
-
-       return 0;
 }
 
+struct syscore_ops s3c2410_pm_syscore_ops = {
+       .resume         = s3c2410_pm_resume,
+};
+
 static int s3c2410_pm_add(struct sys_device *dev)
 {
        pm_cpu_prep = s3c2410_pm_prepare;
@@ -119,7 +122,6 @@ static int s3c2410_pm_add(struct sys_device *dev)
 #if defined(CONFIG_CPU_S3C2410)
 static struct sysdev_driver s3c2410_pm_driver = {
        .add            = s3c2410_pm_add,
-       .resume         = s3c2410_pm_resume,
 };
 
 /* register ourselves */
@@ -133,7 +135,6 @@ arch_initcall(s3c2410_pm_drvinit);
 
 static struct sysdev_driver s3c2410a_pm_driver = {
        .add            = s3c2410_pm_add,
-       .resume         = s3c2410_pm_resume,
 };
 
 static int __init s3c2410a_pm_drvinit(void)
@@ -147,7 +148,6 @@ arch_initcall(s3c2410a_pm_drvinit);
 #if defined(CONFIG_CPU_S3C2440)
 static struct sysdev_driver s3c2440_pm_driver = {
        .add            = s3c2410_pm_add,
-       .resume         = s3c2410_pm_resume,
 };
 
 static int __init s3c2440_pm_drvinit(void)
@@ -161,7 +161,6 @@ arch_initcall(s3c2440_pm_drvinit);
 #if defined(CONFIG_CPU_S3C2442)
 static struct sysdev_driver s3c2442_pm_driver = {
        .add            = s3c2410_pm_add,
-       .resume         = s3c2410_pm_resume,
 };
 
 static int __init s3c2442_pm_drvinit(void)
index adc90a3..f1d3bd8 100644 (file)
@@ -19,6 +19,7 @@
 #include <linux/gpio.h>
 #include <linux/clk.h>
 #include <linux/sysdev.h>
+#include <linux/syscore_ops.h>
 #include <linux/serial_core.h>
 #include <linux/platform_device.h>
 #include <linux/io.h>
@@ -40,6 +41,7 @@
 #include <plat/devs.h>
 #include <plat/clock.h>
 #include <plat/pll.h>
+#include <plat/pm.h>
 
 #include <plat/gpio-core.h>
 #include <plat/gpio-cfg.h>
@@ -168,6 +170,9 @@ int __init s3c2410_init(void)
 {
        printk("S3C2410: Initialising architecture\n");
 
+       register_syscore_ops(&s3c2410_pm_syscore_ops);
+       register_syscore_ops(&s3c24xx_irq_syscore_ops);
+
        return sysdev_register(&s3c2410_sysdev);
 }
 
index f3355d2..1a1aa22 100644 (file)
@@ -202,8 +202,6 @@ static int s3c2412_irq_add(struct sys_device *sysdev)
 
 static struct sysdev_driver s3c2412_irq_driver = {
        .add            = s3c2412_irq_add,
-       .suspend        = s3c24xx_irq_suspend,
-       .resume         = s3c24xx_irq_resume,
 };
 
 static int s3c2412_irq_init(void)
index 923e01b..85dcaeb 100644 (file)
@@ -17,7 +17,7 @@
 #include <linux/timer.h>
 #include <linux/init.h>
 #include <linux/gpio.h>
-#include <linux/sysdev.h>
+#include <linux/syscore_ops.h>
 #include <linux/serial_core.h>
 #include <linux/platform_device.h>
 #include <linux/i2c.h>
@@ -486,7 +486,7 @@ static struct s3c2410_udc_mach_info jive_udc_cfg __initdata = {
 /* Jive power management device */
 
 #ifdef CONFIG_PM
-static int jive_pm_suspend(struct sys_device *sd, pm_message_t state)
+static int jive_pm_suspend(void)
 {
        /* Write the magic value u-boot uses to check for resume into
         * the INFORM0 register, and ensure INFORM1 is set to the
@@ -498,10 +498,9 @@ static int jive_pm_suspend(struct sys_device *sd, pm_message_t state)
        return 0;
 }
 
-static int jive_pm_resume(struct sys_device *sd)
+static void jive_pm_resume(void)
 {
        __raw_writel(0x0, S3C2412_INFORM0);
-       return 0;
 }
 
 #else
@@ -509,16 +508,11 @@ static int jive_pm_resume(struct sys_device *sd)
 #define jive_pm_resume NULL
 #endif
 
-static struct sysdev_class jive_pm_sysclass = {
-       .name           = "jive-pm",
+static struct syscore_ops jive_pm_syscore_ops = {
        .suspend        = jive_pm_suspend,
        .resume         = jive_pm_resume,
 };
 
-static struct sys_device jive_pm_sysdev = {
-       .cls            = &jive_pm_sysclass,
-};
-
 static void __init jive_map_io(void)
 {
        s3c24xx_init_io(jive_iodesc, ARRAY_SIZE(jive_iodesc));
@@ -536,10 +530,9 @@ static void jive_power_off(void)
 
 static void __init jive_machine_init(void)
 {
-       /* register system devices for managing low level suspend */
+       /* register system core operations for managing low level suspend */
 
-       sysdev_class_register(&jive_pm_sysclass);
-       sysdev_register(&jive_pm_sysdev);
+       register_syscore_ops(&jive_pm_syscore_ops);
 
        /* write our sleep configurations for the IO. Pull down all unused
         * IO, ensure that we have turned off all peripherals we do not
index a7417c4..752b13a 100644 (file)
@@ -17,6 +17,7 @@
 #include <linux/timer.h>
 #include <linux/init.h>
 #include <linux/sysdev.h>
+#include <linux/syscore_ops.h>
 #include <linux/platform_device.h>
 #include <linux/io.h>
 
@@ -86,13 +87,24 @@ static struct sleep_save s3c2412_sleep[] = {
        SAVE_ITEM(S3C2413_GPJSLPCON),
 };
 
-static int s3c2412_pm_suspend(struct sys_device *dev, pm_message_t state)
+static struct sysdev_driver s3c2412_pm_driver = {
+       .add            = s3c2412_pm_add,
+};
+
+static __init int s3c2412_pm_init(void)
+{
+       return sysdev_driver_register(&s3c2412_sysclass, &s3c2412_pm_driver);
+}
+
+arch_initcall(s3c2412_pm_init);
+
+static int s3c2412_pm_suspend(void)
 {
        s3c_pm_do_save(s3c2412_sleep, ARRAY_SIZE(s3c2412_sleep));
        return 0;
 }
 
-static int s3c2412_pm_resume(struct sys_device *dev)
+static void s3c2412_pm_resume(void)
 {
        unsigned long tmp;
 
@@ -102,18 +114,9 @@ static int s3c2412_pm_resume(struct sys_device *dev)
        __raw_writel(tmp, S3C2412_PWRCFG);
 
        s3c_pm_do_restore(s3c2412_sleep, ARRAY_SIZE(s3c2412_sleep));
-       return 0;
 }
 
-static struct sysdev_driver s3c2412_pm_driver = {
-       .add            = s3c2412_pm_add,
+struct syscore_ops s3c2412_pm_syscore_ops = {
        .suspend        = s3c2412_pm_suspend,
        .resume         = s3c2412_pm_resume,
 };
-
-static __init int s3c2412_pm_init(void)
-{
-       return sysdev_driver_register(&s3c2412_sysclass, &s3c2412_pm_driver);
-}
-
-arch_initcall(s3c2412_pm_init);
index 4c6df51..ef0958d 100644 (file)
@@ -19,6 +19,7 @@
 #include <linux/clk.h>
 #include <linux/delay.h>
 #include <linux/sysdev.h>
+#include <linux/syscore_ops.h>
 #include <linux/serial_core.h>
 #include <linux/platform_device.h>
 #include <linux/io.h>
@@ -244,5 +245,8 @@ int __init s3c2412_init(void)
 {
        printk("S3C2412: Initialising architecture\n");
 
+       register_syscore_ops(&s3c2412_pm_syscore_ops);
+       register_syscore_ops(&s3c24xx_irq_syscore_ops);
+
        return sysdev_register(&s3c2412_sysdev);
 }
index 77b38f2..28ad20d 100644 (file)
@@ -236,8 +236,6 @@ static int __init s3c2416_irq_add(struct sys_device *sysdev)
 
 static struct sysdev_driver s3c2416_irq_driver = {
        .add            = s3c2416_irq_add,
-       .suspend        = s3c24xx_irq_suspend,
-       .resume         = s3c24xx_irq_resume,
 };
 
 static int __init s3c2416_irq_init(void)
index 4a04205..41db2b2 100644 (file)
@@ -11,6 +11,7 @@
 */
 
 #include <linux/sysdev.h>
+#include <linux/syscore_ops.h>
 #include <linux/io.h>
 
 #include <asm/cacheflush.h>
@@ -55,30 +56,26 @@ static int s3c2416_pm_add(struct sys_device *sysdev)
        return 0;
 }
 
-static int s3c2416_pm_suspend(struct sys_device *dev, pm_message_t state)
+static struct sysdev_driver s3c2416_pm_driver = {
+       .add            = s3c2416_pm_add,
+};
+
+static __init int s3c2416_pm_init(void)
 {
-       return 0;
+       return sysdev_driver_register(&s3c2416_sysclass, &s3c2416_pm_driver);
 }
 
-static int s3c2416_pm_resume(struct sys_device *dev)
+arch_initcall(s3c2416_pm_init);
+
+
+static void s3c2416_pm_resume(void)
 {
        /* unset the return-from-sleep amd inform flags */
        __raw_writel(0x0, S3C2443_PWRMODE);
        __raw_writel(0x0, S3C2412_INFORM0);
        __raw_writel(0x0, S3C2412_INFORM1);
-
-       return 0;
 }
 
-static struct sysdev_driver s3c2416_pm_driver = {
-       .add            = s3c2416_pm_add,
-       .suspend        = s3c2416_pm_suspend,
+struct syscore_ops s3c2416_pm_syscore_ops = {
        .resume         = s3c2416_pm_resume,
 };
-
-static __init int s3c2416_pm_init(void)
-{
-       return sysdev_driver_register(&s3c2416_sysclass, &s3c2416_pm_driver);
-}
-
-arch_initcall(s3c2416_pm_init);
index ba7fd87..494ce91 100644 (file)
@@ -32,6 +32,7 @@
 #include <linux/platform_device.h>
 #include <linux/serial_core.h>
 #include <linux/sysdev.h>
+#include <linux/syscore_ops.h>
 #include <linux/clk.h>
 #include <linux/io.h>
 
@@ -54,6 +55,7 @@
 #include <plat/devs.h>
 #include <plat/cpu.h>
 #include <plat/sdhci.h>
+#include <plat/pm.h>
 
 #include <plat/iic-core.h>
 #include <plat/fb-core.h>
@@ -95,6 +97,9 @@ int __init s3c2416_init(void)
 
        s3c_fb_setname("s3c2443-fb");
 
+       register_syscore_ops(&s3c2416_pm_syscore_ops);
+       register_syscore_ops(&s3c24xx_irq_syscore_ops);
+
        return sysdev_register(&s3c2416_sysdev);
 }
 
index 14dc678..d885363 100644 (file)
@@ -17,7 +17,7 @@
 #include <linux/init.h>
 #include <linux/gpio.h>
 #include <linux/device.h>
-#include <linux/sysdev.h>
+#include <linux/syscore_ops.h>
 #include <linux/serial_core.h>
 #include <linux/clk.h>
 #include <linux/i2c.h>
@@ -284,7 +284,7 @@ static struct platform_device osiris_pcmcia = {
 #ifdef CONFIG_PM
 static unsigned char pm_osiris_ctrl0;
 
-static int osiris_pm_suspend(struct sys_device *sd, pm_message_t state)
+static int osiris_pm_suspend(void)
 {
        unsigned int tmp;
 
@@ -304,7 +304,7 @@ static int osiris_pm_suspend(struct sys_device *sd, pm_message_t state)
        return 0;
 }
 
-static int osiris_pm_resume(struct sys_device *sd)
+static void osiris_pm_resume(void)
 {
        if (pm_osiris_ctrl0 & OSIRIS_CTRL0_FIX8)
                __raw_writeb(OSIRIS_CTRL1_FIX8, OSIRIS_VA_CTRL1);
@@ -312,8 +312,6 @@ static int osiris_pm_resume(struct sys_device *sd)
        __raw_writeb(pm_osiris_ctrl0, OSIRIS_VA_CTRL0);
 
        s3c_gpio_cfgpin(S3C2410_GPA(21), S3C2410_GPA21_nRSTOUT);
-
-       return 0;
 }
 
 #else
@@ -321,16 +319,11 @@ static int osiris_pm_resume(struct sys_device *sd)
 #define osiris_pm_resume NULL
 #endif
 
-static struct sysdev_class osiris_pm_sysclass = {
-       .name           = "mach-osiris",
+static struct syscore_ops osiris_pm_syscore_ops = {
        .suspend        = osiris_pm_suspend,
        .resume         = osiris_pm_resume,
 };
 
-static struct sys_device osiris_pm_sysdev = {
-       .cls            = &osiris_pm_sysclass,
-};
-
 /* Link for DVS driver to TPS65011 */
 
 static void osiris_tps_release(struct device *dev)
@@ -439,8 +432,7 @@ static void __init osiris_map_io(void)
 
 static void __init osiris_init(void)
 {
-       sysdev_class_register(&osiris_pm_sysclass);
-       sysdev_register(&osiris_pm_sysdev);
+       register_syscore_ops(&osiris_pm_syscore_ops);
 
        s3c_i2c0_set_platdata(NULL);
        s3c_nand_set_platdata(&osiris_nand_info);
index f7663f7..ce99ff7 100644 (file)
@@ -19,6 +19,7 @@
 #include <linux/platform_device.h>
 #include <linux/serial_core.h>
 #include <linux/sysdev.h>
+#include <linux/syscore_ops.h>
 #include <linux/gpio.h>
 #include <linux/clk.h>
 #include <linux/io.h>
@@ -33,6 +34,7 @@
 #include <plat/devs.h>
 #include <plat/cpu.h>
 #include <plat/s3c244x.h>
+#include <plat/pm.h>
 
 #include <plat/gpio-core.h>
 #include <plat/gpio-cfg.h>
@@ -51,6 +53,12 @@ int __init s3c2440_init(void)
        s3c_device_wdt.resource[1].start = IRQ_S3C2440_WDT;
        s3c_device_wdt.resource[1].end   = IRQ_S3C2440_WDT;
 
+       /* register suspend/resume handlers */
+
+       register_syscore_ops(&s3c2410_pm_syscore_ops);
+       register_syscore_ops(&s3c244x_pm_syscore_ops);
+       register_syscore_ops(&s3c24xx_irq_syscore_ops);
+
        /* register our system device for everything else */
 
        return sysdev_register(&s3c2440_sysdev);
index ecf8135..6224bad 100644 (file)
@@ -29,6 +29,7 @@
 #include <linux/err.h>
 #include <linux/device.h>
 #include <linux/sysdev.h>
+#include <linux/syscore_ops.h>
 #include <linux/interrupt.h>
 #include <linux/ioport.h>
 #include <linux/mutex.h>
@@ -45,6 +46,7 @@
 #include <plat/clock.h>
 #include <plat/cpu.h>
 #include <plat/s3c244x.h>
+#include <plat/pm.h>
 
 #include <plat/gpio-core.h>
 #include <plat/gpio-cfg.h>
@@ -167,6 +169,10 @@ int __init s3c2442_init(void)
 {
        printk("S3C2442: Initialising architecture\n");
 
+       register_syscore_ops(&s3c2410_pm_syscore_ops);
+       register_syscore_ops(&s3c244x_pm_syscore_ops);
+       register_syscore_ops(&s3c24xx_irq_syscore_ops);
+
        return sysdev_register(&s3c2442_sysdev);
 }
 
index de07c2f..c63e8f2 100644 (file)
@@ -116,8 +116,6 @@ static int s3c244x_irq_add(struct sys_device *sysdev)
 
 static struct sysdev_driver s3c2440_irq_driver = {
        .add            = s3c244x_irq_add,
-       .suspend        = s3c24xx_irq_suspend,
-       .resume         = s3c24xx_irq_resume,
 };
 
 static int s3c2440_irq_init(void)
@@ -129,8 +127,6 @@ arch_initcall(s3c2440_irq_init);
 
 static struct sysdev_driver s3c2442_irq_driver = {
        .add            = s3c244x_irq_add,
-       .suspend        = s3c24xx_irq_suspend,
-       .resume         = s3c24xx_irq_resume,
 };
 
 
index 90c1707..7e8a23d 100644 (file)
@@ -19,6 +19,7 @@
 #include <linux/serial_core.h>
 #include <linux/platform_device.h>
 #include <linux/sysdev.h>
+#include <linux/syscore_ops.h>
 #include <linux/clk.h>
 #include <linux/io.h>
 
@@ -134,45 +135,14 @@ void __init s3c244x_init_clocks(int xtal)
        s3c2410_baseclk_add();
 }
 
-#ifdef CONFIG_PM
-
-static struct sleep_save s3c244x_sleep[] = {
-       SAVE_ITEM(S3C2440_DSC0),
-       SAVE_ITEM(S3C2440_DSC1),
-       SAVE_ITEM(S3C2440_GPJDAT),
-       SAVE_ITEM(S3C2440_GPJCON),
-       SAVE_ITEM(S3C2440_GPJUP)
-};
-
-static int s3c244x_suspend(struct sys_device *dev, pm_message_t state)
-{
-       s3c_pm_do_save(s3c244x_sleep, ARRAY_SIZE(s3c244x_sleep));
-       return 0;
-}
-
-static int s3c244x_resume(struct sys_device *dev)
-{
-       s3c_pm_do_restore(s3c244x_sleep, ARRAY_SIZE(s3c244x_sleep));
-       return 0;
-}
-
-#else
-#define s3c244x_suspend NULL
-#define s3c244x_resume  NULL
-#endif
-
 /* Since the S3C2442 and S3C2440 share  items, put both sysclasses here */
 
 struct sysdev_class s3c2440_sysclass = {
        .name           = "s3c2440-core",
-       .suspend        = s3c244x_suspend,
-       .resume         = s3c244x_resume
 };
 
 struct sysdev_class s3c2442_sysclass = {
        .name           = "s3c2442-core",
-       .suspend        = s3c244x_suspend,
-       .resume         = s3c244x_resume
 };
 
 /* need to register class before we actually register the device, and
@@ -194,3 +164,33 @@ static int __init s3c2442_core_init(void)
 }
 
 core_initcall(s3c2442_core_init);
+
+
+#ifdef CONFIG_PM
+static struct sleep_save s3c244x_sleep[] = {
+       SAVE_ITEM(S3C2440_DSC0),
+       SAVE_ITEM(S3C2440_DSC1),
+       SAVE_ITEM(S3C2440_GPJDAT),
+       SAVE_ITEM(S3C2440_GPJCON),
+       SAVE_ITEM(S3C2440_GPJUP)
+};
+
+static int s3c244x_suspend(void)
+{
+       s3c_pm_do_save(s3c244x_sleep, ARRAY_SIZE(s3c244x_sleep));
+       return 0;
+}
+
+static void s3c244x_resume(void)
+{
+       s3c_pm_do_restore(s3c244x_sleep, ARRAY_SIZE(s3c244x_sleep));
+}
+#else
+#define s3c244x_suspend NULL
+#define s3c244x_resume  NULL
+#endif
+
+struct syscore_ops s3c244x_pm_syscore_ops = {
+       .suspend        = s3c244x_suspend,
+       .resume         = s3c244x_resume,
+};
index da1bec6..8bec61e 100644 (file)
@@ -13,7 +13,7 @@
  */
 
 #include <linux/kernel.h>
-#include <linux/sysdev.h>
+#include <linux/syscore_ops.h>
 #include <linux/interrupt.h>
 #include <linux/serial_core.h>
 #include <linux/irq.h>
@@ -54,7 +54,7 @@ static struct irq_grp_save {
 
 static u32 irq_uart_mask[CONFIG_SERIAL_SAMSUNG_UARTS];
 
-static int s3c64xx_irq_pm_suspend(struct sys_device *dev, pm_message_t state)
+static int s3c64xx_irq_pm_suspend(void)
 {
        struct irq_grp_save *grp = eint_grp_save;
        int i;
@@ -75,7 +75,7 @@ static int s3c64xx_irq_pm_suspend(struct sys_device *dev, pm_message_t state)
        return 0;
 }
 
-static int s3c64xx_irq_pm_resume(struct sys_device *dev)
+static void s3c64xx_irq_pm_resume(void)
 {
        struct irq_grp_save *grp = eint_grp_save;
        int i;
@@ -94,18 +94,18 @@ static int s3c64xx_irq_pm_resume(struct sys_device *dev)
        }
 
        S3C_PMDBG("%s: IRQ configuration restored\n", __func__);
-       return 0;
 }
 
-static struct sysdev_driver s3c64xx_irq_driver = {
+struct syscore_ops s3c64xx_irq_syscore_ops = {
        .suspend = s3c64xx_irq_pm_suspend,
        .resume  = s3c64xx_irq_pm_resume,
 };
 
-static int __init s3c64xx_irq_pm_init(void)
+static __init int s3c64xx_syscore_init(void)
 {
-       return sysdev_driver_register(&s3c64xx_sysclass, &s3c64xx_irq_driver);
-}
+       register_syscore_ops(&s3c64xx_irq_syscore_ops);
 
-arch_initcall(s3c64xx_irq_pm_init);
+       return 0;
+}
 
+core_initcall(s3c64xx_syscore_init);
index 549d792..24febae 100644 (file)
@@ -16,6 +16,7 @@
 
 #include <linux/init.h>
 #include <linux/suspend.h>
+#include <linux/syscore_ops.h>
 #include <linux/io.h>
 
 #include <plat/cpu.h>
@@ -140,7 +141,17 @@ static int s5pv210_pm_add(struct sys_device *sysdev)
        return 0;
 }
 
-static int s5pv210_pm_resume(struct sys_device *dev)
+static struct sysdev_driver s5pv210_pm_driver = {
+       .add            = s5pv210_pm_add,
+};
+
+static __init int s5pv210_pm_drvinit(void)
+{
+       return sysdev_driver_register(&s5pv210_sysclass, &s5pv210_pm_driver);
+}
+arch_initcall(s5pv210_pm_drvinit);
+
+static void s5pv210_pm_resume(void)
 {
        u32 tmp;
 
@@ -150,17 +161,15 @@ static int s5pv210_pm_resume(struct sys_device *dev)
        __raw_writel(tmp , S5P_OTHERS);
 
        s3c_pm_do_restore_core(s5pv210_core_save, ARRAY_SIZE(s5pv210_core_save));
-
-       return 0;
 }
 
-static struct sysdev_driver s5pv210_pm_driver = {
-       .add            = s5pv210_pm_add,
+static struct syscore_ops s5pv210_pm_syscore_ops = {
        .resume         = s5pv210_pm_resume,
 };
 
-static __init int s5pv210_pm_drvinit(void)
+static __init int s5pv210_pm_syscore_init(void)
 {
-       return sysdev_driver_register(&s5pv210_sysclass, &s5pv210_pm_driver);
+       register_syscore_ops(&s5pv210_pm_syscore_ops);
+       return 0;
 }
-arch_initcall(s5pv210_pm_drvinit);
+arch_initcall(s5pv210_pm_syscore_init);
index 423ddb3..dfbf824 100644 (file)
@@ -14,7 +14,7 @@
 #include <linux/interrupt.h>
 #include <linux/irq.h>
 #include <linux/ioport.h>
-#include <linux/sysdev.h>
+#include <linux/syscore_ops.h>
 
 #include <mach/hardware.h>
 #include <asm/mach/irq.h>
@@ -234,7 +234,7 @@ static struct sa1100irq_state {
        unsigned int    iccr;
 } sa1100irq_state;
 
-static int sa1100irq_suspend(struct sys_device *dev, pm_message_t state)
+static int sa1100irq_suspend(void)
 {
        struct sa1100irq_state *st = &sa1100irq_state;
 
@@ -264,7 +264,7 @@ static int sa1100irq_suspend(struct sys_device *dev, pm_message_t state)
        return 0;
 }
 
-static int sa1100irq_resume(struct sys_device *dev)
+static void sa1100irq_resume(void)
 {
        struct sa1100irq_state *st = &sa1100irq_state;
 
@@ -277,24 +277,17 @@ static int sa1100irq_resume(struct sys_device *dev)
 
                ICMR = st->icmr;
        }
-       return 0;
 }
 
-static struct sysdev_class sa1100irq_sysclass = {
-       .name           = "sa11x0-irq",
+static struct syscore_ops sa1100irq_syscore_ops = {
        .suspend        = sa1100irq_suspend,
        .resume         = sa1100irq_resume,
 };
 
-static struct sys_device sa1100irq_device = {
-       .id             = 0,
-       .cls            = &sa1100irq_sysclass,
-};
-
 static int __init sa1100irq_init_devicefs(void)
 {
-       sysdev_class_register(&sa1100irq_sysclass);
-       return sysdev_register(&sa1100irq_device);
+       register_syscore_ops(&sa1100irq_syscore_ops);
+       return 0;
 }
 
 device_initcall(sa1100irq_init_devicefs);
index 94912d3..2d1b67a 100644 (file)
 #include <linux/clk.h>
 #include <linux/sh_clk.h>
 #include <linux/bitmap.h>
+#include <linux/slab.h>
 
 #ifdef CONFIG_PM_RUNTIME
-#define BIT_ONCE 0
-#define BIT_ACTIVE 1
-#define BIT_CLK_ENABLED 2
 
-struct pm_runtime_data {
-       unsigned long flags;
-       struct clk *clk;
-};
-
-static void __devres_release(struct device *dev, void *res)
-{
-       struct pm_runtime_data *prd = res;
-
-       dev_dbg(dev, "__devres_release()\n");
-
-       if (test_bit(BIT_CLK_ENABLED, &prd->flags))
-               clk_disable(prd->clk);
-
-       if (test_bit(BIT_ACTIVE, &prd->flags))
-               clk_put(prd->clk);
-}
-
-static struct pm_runtime_data *__to_prd(struct device *dev)
-{
-       return devres_find(dev, __devres_release, NULL, NULL);
-}
-
-static void platform_pm_runtime_init(struct device *dev,
-                                    struct pm_runtime_data *prd)
-{
-       if (prd && !test_and_set_bit(BIT_ONCE, &prd->flags)) {
-               prd->clk = clk_get(dev, NULL);
-               if (!IS_ERR(prd->clk)) {
-                       set_bit(BIT_ACTIVE, &prd->flags);
-                       dev_info(dev, "clocks managed by runtime pm\n");
-               }
-       }
-}
-
-static void platform_pm_runtime_bug(struct device *dev,
-                                   struct pm_runtime_data *prd)
-{
-       if (prd && !test_and_set_bit(BIT_ONCE, &prd->flags))
-               dev_err(dev, "runtime pm suspend before resume\n");
-}
-
-int platform_pm_runtime_suspend(struct device *dev)
-{
-       struct pm_runtime_data *prd = __to_prd(dev);
-
-       dev_dbg(dev, "platform_pm_runtime_suspend()\n");
-
-       platform_pm_runtime_bug(dev, prd);
-
-       if (prd && test_bit(BIT_ACTIVE, &prd->flags)) {
-               clk_disable(prd->clk);
-               clear_bit(BIT_CLK_ENABLED, &prd->flags);
-       }
-
-       return 0;
-}
-
-int platform_pm_runtime_resume(struct device *dev)
-{
-       struct pm_runtime_data *prd = __to_prd(dev);
-
-       dev_dbg(dev, "platform_pm_runtime_resume()\n");
-
-       platform_pm_runtime_init(dev, prd);
-
-       if (prd && test_bit(BIT_ACTIVE, &prd->flags)) {
-               clk_enable(prd->clk);
-               set_bit(BIT_CLK_ENABLED, &prd->flags);
-       }
-
-       return 0;
-}
-
-int platform_pm_runtime_idle(struct device *dev)
+static int default_platform_runtime_idle(struct device *dev)
 {
        /* suspend synchronously to disable clocks immediately */
        return pm_runtime_suspend(dev);
 }
 
-static int platform_bus_notify(struct notifier_block *nb,
-                              unsigned long action, void *data)
-{
-       struct device *dev = data;
-       struct pm_runtime_data *prd;
-
-       dev_dbg(dev, "platform_bus_notify() %ld !\n", action);
-
-       if (action == BUS_NOTIFY_BIND_DRIVER) {
-               prd = devres_alloc(__devres_release, sizeof(*prd), GFP_KERNEL);
-               if (prd)
-                       devres_add(dev, prd);
-               else
-                       dev_err(dev, "unable to alloc memory for runtime pm\n");
-       }
-
-       return 0;
-}
-
-#else /* CONFIG_PM_RUNTIME */
-
-static int platform_bus_notify(struct notifier_block *nb,
-                              unsigned long action, void *data)
-{
-       struct device *dev = data;
-       struct clk *clk;
+static struct dev_power_domain default_power_domain = {
+       .ops = {
+               .runtime_suspend = pm_runtime_clk_suspend,
+               .runtime_resume = pm_runtime_clk_resume,
+               .runtime_idle = default_platform_runtime_idle,
+               USE_PLATFORM_PM_SLEEP_OPS
+       },
+};
 
-       dev_dbg(dev, "platform_bus_notify() %ld !\n", action);
+#define DEFAULT_PWR_DOMAIN_PTR (&default_power_domain)
 
-       switch (action) {
-       case BUS_NOTIFY_BIND_DRIVER:
-               clk = clk_get(dev, NULL);
-               if (!IS_ERR(clk)) {
-                       clk_enable(clk);
-                       clk_put(clk);
-                       dev_info(dev, "runtime pm disabled, clock forced on\n");
-               }
-               break;
-       case BUS_NOTIFY_UNBOUND_DRIVER:
-               clk = clk_get(dev, NULL);
-               if (!IS_ERR(clk)) {
-                       clk_disable(clk);
-                       clk_put(clk);
-                       dev_info(dev, "runtime pm disabled, clock forced off\n");
-               }
-               break;
-       }
+#else
 
-       return 0;
-}
+#define DEFAULT_PWR_DOMAIN_PTR NULL
 
 #endif /* CONFIG_PM_RUNTIME */
 
-static struct notifier_block platform_bus_notifier = {
-       .notifier_call = platform_bus_notify
+static struct pm_clk_notifier_block platform_bus_notifier = {
+       .pwr_domain = DEFAULT_PWR_DOMAIN_PTR,
+       .con_ids = { NULL, },
 };
 
 static int __init sh_pm_runtime_init(void)
 {
-       bus_register_notifier(&platform_bus_type, &platform_bus_notifier);
+       pm_runtime_clk_add_notifier(&platform_bus_type, &platform_bus_notifier);
        return 0;
 }
 core_initcall(sh_pm_runtime_init);
index cc11517..425b42e 100644 (file)
@@ -23,7 +23,7 @@
 
 #include <asm/outercache.h>
 
-#define rmb()          dmb()
+#define rmb()          dsb()
 #define wmb()          do { dsb(); outer_sync(); } while (0)
 #define mb()           wmb()
 
index e5f6fc4..e591513 100644 (file)
@@ -392,7 +392,7 @@ free_memmap(unsigned long start_pfn, unsigned long end_pfn)
         * Convert start_pfn/end_pfn to a struct page pointer.
         */
        start_pg = pfn_to_page(start_pfn - 1) + 1;
-       end_pg = pfn_to_page(end_pfn);
+       end_pg = pfn_to_page(end_pfn - 1) + 1;
 
        /*
         * Convert to physical addresses, and
@@ -426,6 +426,14 @@ static void __init free_unused_memmap(struct meminfo *mi)
 
                bank_start = bank_pfn_start(bank);
 
+#ifdef CONFIG_SPARSEMEM
+               /*
+                * Take care not to free memmap entries that don't exist
+                * due to SPARSEMEM sections which aren't present.
+                */
+               bank_start = min(bank_start,
+                                ALIGN(prev_bank_end, PAGES_PER_SECTION));
+#endif
                /*
                 * If we had a previous bank, and there is a space
                 * between the current bank and the previous, free it.
@@ -440,6 +448,12 @@ static void __init free_unused_memmap(struct meminfo *mi)
                 */
                prev_bank_end = ALIGN(bank_pfn_end(bank), MAX_ORDER_NR_PAGES);
        }
+
+#ifdef CONFIG_SPARSEMEM
+       if (!IS_ALIGNED(prev_bank_end, PAGES_PER_SECTION))
+               free_memmap(prev_bank_end,
+                           ALIGN(prev_bank_end, PAGES_PER_SECTION));
+#endif
 }
 
 static void __init free_highpages(void)
index d2adcdd..bd9e321 100644 (file)
@@ -17,7 +17,7 @@
 #include <linux/init.h>
 #include <linux/module.h>
 #include <linux/interrupt.h>
-#include <linux/sysdev.h>
+#include <linux/syscore_ops.h>
 #include <linux/err.h>
 #include <linux/clk.h>
 #include <linux/io.h>
@@ -1372,9 +1372,7 @@ static const struct dev_pm_ops omap_mpuio_dev_pm_ops = {
        .resume_noirq = omap_mpuio_resume_noirq,
 };
 
-/* use platform_driver for this, now that there's no longer any
- * point to sys_device (other than not disturbing old code).
- */
+/* use platform_driver for this. */
 static struct platform_driver omap_mpuio_driver = {
        .driver         = {
                .name   = "mpuio",
@@ -1745,7 +1743,7 @@ static int __devinit omap_gpio_probe(struct platform_device *pdev)
 }
 
 #if defined(CONFIG_ARCH_OMAP16XX) || defined(CONFIG_ARCH_OMAP2PLUS)
-static int omap_gpio_suspend(struct sys_device *dev, pm_message_t mesg)
+static int omap_gpio_suspend(void)
 {
        int i;
 
@@ -1795,12 +1793,12 @@ static int omap_gpio_suspend(struct sys_device *dev, pm_message_t mesg)
        return 0;
 }
 
-static int omap_gpio_resume(struct sys_device *dev)
+static void omap_gpio_resume(void)
 {
        int i;
 
        if (!cpu_class_is_omap2() && !cpu_is_omap16xx())
-               return 0;
+               return;
 
        for (i = 0; i < gpio_bank_count; i++) {
                struct gpio_bank *bank = &gpio_bank[i];
@@ -1836,21 +1834,13 @@ static int omap_gpio_resume(struct sys_device *dev)
                __raw_writel(bank->saved_wakeup, wake_set);
                spin_unlock_irqrestore(&bank->lock, flags);
        }
-
-       return 0;
 }
 
-static struct sysdev_class omap_gpio_sysclass = {
-       .name           = "gpio",
+static struct syscore_ops omap_gpio_syscore_ops = {
        .suspend        = omap_gpio_suspend,
        .resume         = omap_gpio_resume,
 };
 
-static struct sys_device omap_gpio_device = {
-       .id             = 0,
-       .cls            = &omap_gpio_sysclass,
-};
-
 #endif
 
 #ifdef CONFIG_ARCH_OMAP2PLUS
@@ -2108,21 +2098,14 @@ postcore_initcall(omap_gpio_drv_reg);
 
 static int __init omap_gpio_sysinit(void)
 {
-       int ret = 0;
-
        mpuio_init();
 
 #if defined(CONFIG_ARCH_OMAP16XX) || defined(CONFIG_ARCH_OMAP2PLUS)
-       if (cpu_is_omap16xx() || cpu_class_is_omap2()) {
-               if (ret == 0) {
-                       ret = sysdev_class_register(&omap_gpio_sysclass);
-                       if (ret == 0)
-                               ret = sysdev_register(&omap_gpio_device);
-               }
-       }
+       if (cpu_is_omap16xx() || cpu_class_is_omap2())
+               register_syscore_ops(&omap_gpio_syscore_ops);
 #endif
 
-       return ret;
+       return 0;
 }
 
 arch_initcall(omap_gpio_sysinit);
index 8a51fd5..34fc31e 100644 (file)
@@ -793,6 +793,8 @@ static irqreturn_t iommu_fault_handler(int irq, void *data)
        clk_enable(obj->clk);
        errs = iommu_report_fault(obj, &da);
        clk_disable(obj->clk);
+       if (errs == 0)
+               return IRQ_HANDLED;
 
        /* Fault callback or TLB/PTE Dynamic loading */
        if (obj->isr && !obj->isr(obj, da, errs, obj->isr_priv))
index 9bbda9a..a37b8eb 100644 (file)
@@ -536,6 +536,28 @@ int omap_early_device_register(struct omap_device *od)
        return 0;
 }
 
+static int _od_runtime_suspend(struct device *dev)
+{
+       struct platform_device *pdev = to_platform_device(dev);
+
+       return omap_device_idle(pdev);
+}
+
+static int _od_runtime_resume(struct device *dev)
+{
+       struct platform_device *pdev = to_platform_device(dev);
+
+       return omap_device_enable(pdev);
+}
+
+static struct dev_power_domain omap_device_power_domain = {
+       .ops = {
+               .runtime_suspend = _od_runtime_suspend,
+               .runtime_resume = _od_runtime_resume,
+               USE_PLATFORM_PM_SLEEP_OPS
+       }
+};
+
 /**
  * omap_device_register - register an omap_device with one omap_hwmod
  * @od: struct omap_device * to register
@@ -549,6 +571,7 @@ int omap_device_register(struct omap_device *od)
        pr_debug("omap_device: %s: registering\n", od->pdev.name);
 
        od->pdev.dev.parent = &omap_device_parent;
+       od->pdev.dev.pwr_domain = &omap_device_power_domain;
        return platform_device_register(&od->pdev);
 }
 
index dce088f..48ebb94 100644 (file)
@@ -15,7 +15,7 @@
 #include <linux/init.h>
 #include <linux/irq.h>
 #include <linux/io.h>
-#include <linux/sysdev.h>
+#include <linux/syscore_ops.h>
 #include <linux/slab.h>
 
 #include <mach/gpio.h>
@@ -295,7 +295,7 @@ void __init pxa_init_gpio(int mux_irq, int start, int end, set_wake_t fn)
 }
 
 #ifdef CONFIG_PM
-static int pxa_gpio_suspend(struct sys_device *dev, pm_message_t state)
+static int pxa_gpio_suspend(void)
 {
        struct pxa_gpio_chip *c;
        int gpio;
@@ -312,7 +312,7 @@ static int pxa_gpio_suspend(struct sys_device *dev, pm_message_t state)
        return 0;
 }
 
-static int pxa_gpio_resume(struct sys_device *dev)
+static void pxa_gpio_resume(void)
 {
        struct pxa_gpio_chip *c;
        int gpio;
@@ -326,22 +326,13 @@ static int pxa_gpio_resume(struct sys_device *dev)
                __raw_writel(c->saved_gfer, c->regbase + GFER_OFFSET);
                __raw_writel(c->saved_gpdr, c->regbase + GPDR_OFFSET);
        }
-       return 0;
 }
 #else
 #define pxa_gpio_suspend       NULL
 #define pxa_gpio_resume                NULL
 #endif
 
-struct sysdev_class pxa_gpio_sysclass = {
-       .name           = "gpio",
+struct syscore_ops pxa_gpio_syscore_ops = {
        .suspend        = pxa_gpio_suspend,
        .resume         = pxa_gpio_resume,
 };
-
-static int __init pxa_gpio_init(void)
-{
-       return sysdev_class_register(&pxa_gpio_sysclass);
-}
-
-core_initcall(pxa_gpio_init);
index a9aa5ad..be12ead 100644 (file)
@@ -17,7 +17,6 @@
 #include <linux/kernel.h>
 #include <linux/init.h>
 #include <linux/io.h>
-#include <linux/sysdev.h>
 
 #include <plat/mfp.h>
 
index 27ea852..c10d10c 100644 (file)
@@ -22,7 +22,7 @@
 #include <linux/sched.h>
 #include <linux/spinlock.h>
 #include <linux/interrupt.h>
-#include <linux/sysdev.h>
+#include <linux/syscore_ops.h>
 #include <linux/slab.h>
 #include <linux/errno.h>
 #include <linux/io.h>
@@ -1195,19 +1195,12 @@ int s3c2410_dma_getposition(unsigned int channel, dma_addr_t *src, dma_addr_t *d
 
 EXPORT_SYMBOL(s3c2410_dma_getposition);
 
-static inline struct s3c2410_dma_chan *to_dma_chan(struct sys_device *dev)
-{
-       return container_of(dev, struct s3c2410_dma_chan, dev);
-}
-
-/* system device class */
+/* system core operations */
 
 #ifdef CONFIG_PM
 
-static int s3c2410_dma_suspend(struct sys_device *dev, pm_message_t state)
+static void s3c2410_dma_suspend_chan(s3c2410_dma_chan *cp)
 {
-       struct s3c2410_dma_chan *cp = to_dma_chan(dev);
-
        printk(KERN_DEBUG "suspending dma channel %d\n", cp->number);
 
        if (dma_rdreg(cp, S3C2410_DMA_DMASKTRIG) & S3C2410_DMASKTRIG_ON) {
@@ -1222,13 +1215,21 @@ static int s3c2410_dma_suspend(struct sys_device *dev, pm_message_t state)
 
                s3c2410_dma_dostop(cp);
        }
+}
+
+static int s3c2410_dma_suspend(void)
+{
+       struct s3c2410_dma_chan *cp = s3c2410_chans;
+       int channel;
+
+       for (channel = 0; channel < dma_channels; cp++, channel++)
+               s3c2410_dma_suspend_chan(cp);
 
        return 0;
 }
 
-static int s3c2410_dma_resume(struct sys_device *dev)
+static void s3c2410_dma_resume_chan(struct s3c2410_dma_chan *cp)
 {
-       struct s3c2410_dma_chan *cp = to_dma_chan(dev);
        unsigned int no = cp->number | DMACH_LOW_LEVEL;
 
        /* restore channel's hardware configuration */
@@ -1249,13 +1250,21 @@ static int s3c2410_dma_resume(struct sys_device *dev)
        return 0;
 }
 
+static void s3c2410_dma_resume(void)
+{
+       struct s3c2410_dma_chan *cp = s3c2410_chans + dma_channels - 1;
+       int channel;
+
+       for (channel = dma_channels - 1; channel >= 0; cp++, channel--)
+               s3c2410_dma_resume_chan(cp);
+}
+
 #else
 #define s3c2410_dma_suspend NULL
 #define s3c2410_dma_resume  NULL
 #endif /* CONFIG_PM */
 
-struct sysdev_class dma_sysclass = {
-       .name           = "s3c24xx-dma",
+struct syscore_ops dma_syscore_ops = {
        .suspend        = s3c2410_dma_suspend,
        .resume         = s3c2410_dma_resume,
 };
@@ -1269,39 +1278,14 @@ static void s3c2410_dma_cache_ctor(void *p)
 
 /* initialisation code */
 
-static int __init s3c24xx_dma_sysclass_init(void)
+static int __init s3c24xx_dma_syscore_init(void)
 {
-       int ret = sysdev_class_register(&dma_sysclass);
-
-       if (ret != 0)
-               printk(KERN_ERR "dma sysclass registration failed\n");
-
-       return ret;
-}
-
-core_initcall(s3c24xx_dma_sysclass_init);
-
-static int __init s3c24xx_dma_sysdev_register(void)
-{
-       struct s3c2410_dma_chan *cp = s3c2410_chans;
-       int channel, ret;
-
-       for (channel = 0; channel < dma_channels; cp++, channel++) {
-               cp->dev.cls = &dma_sysclass;
-               cp->dev.id  = channel;
-               ret = sysdev_register(&cp->dev);
-
-               if (ret) {
-                       printk(KERN_ERR "error registering dev for dma %d\n",
-                              channel);
-                       return ret;
-               }
-       }
+       register_syscore_ops(&dma_syscore_ops);
 
        return 0;
 }
 
-late_initcall(s3c24xx_dma_sysdev_register);
+late_initcall(s3c24xx_dma_syscore_init);
 
 int __init s3c24xx_dma_init(unsigned int channels, unsigned int irq,
                            unsigned int stride)
index c3624d8..0efb2e2 100644 (file)
@@ -14,7 +14,6 @@
 #include <linux/init.h>
 #include <linux/module.h>
 #include <linux/interrupt.h>
-#include <linux/sysdev.h>
 #include <linux/irq.h>
 
 #include <plat/cpu.h>
@@ -65,7 +64,7 @@ static unsigned long save_extint[3];
 static unsigned long save_eintflt[4];
 static unsigned long save_eintmask;
 
-int s3c24xx_irq_suspend(struct sys_device *dev, pm_message_t state)
+int s3c24xx_irq_suspend(void)
 {
        unsigned int i;
 
@@ -81,7 +80,7 @@ int s3c24xx_irq_suspend(struct sys_device *dev, pm_message_t state)
        return 0;
 }
 
-int s3c24xx_irq_resume(struct sys_device *dev)
+void s3c24xx_irq_resume(void)
 {
        unsigned int i;
 
@@ -93,6 +92,4 @@ int s3c24xx_irq_resume(struct sys_device *dev)
 
        s3c_pm_do_restore(irq_save, ARRAY_SIZE(irq_save));
        __raw_writel(save_eintmask, S3C24XX_EINTMASK);
-
-       return 0;
 }
index 5259ad4..327acb3 100644 (file)
@@ -16,7 +16,6 @@
 #include <linux/init.h>
 #include <linux/module.h>
 #include <linux/interrupt.h>
-#include <linux/sysdev.h>
 
 #include <plat/cpu.h>
 #include <plat/irqs.h>
@@ -77,17 +76,15 @@ static struct sleep_save eint_save[] = {
        SAVE_ITEM(S5P_EINT_MASK(3)),
 };
 
-int s3c24xx_irq_suspend(struct sys_device *dev, pm_message_t state)
+int s3c24xx_irq_suspend(void)
 {
        s3c_pm_do_save(eint_save, ARRAY_SIZE(eint_save));
 
        return 0;
 }
 
-int s3c24xx_irq_resume(struct sys_device *dev)
+void s3c24xx_irq_resume(void)
 {
        s3c_pm_do_restore(eint_save, ARRAY_SIZE(eint_save));
-
-       return 0;
 }
 
index cedfff5..3aedac0 100644 (file)
@@ -68,6 +68,12 @@ extern void s3c24xx_init_uartdevs(char *name,
 struct sys_timer;
 extern struct sys_timer s3c24xx_timer;
 
+extern struct syscore_ops s3c2410_pm_syscore_ops;
+extern struct syscore_ops s3c2412_pm_syscore_ops;
+extern struct syscore_ops s3c2416_pm_syscore_ops;
+extern struct syscore_ops s3c244x_pm_syscore_ops;
+extern struct syscore_ops s3c64xx_irq_syscore_ops;
+
 /* system device classes */
 
 extern struct sysdev_class s3c2410_sysclass;
index 937cc2a..7fb6f6b 100644 (file)
@@ -103,14 +103,16 @@ extern void s3c_pm_do_restore_core(struct sleep_save *ptr, int count);
 
 #ifdef CONFIG_PM
 extern int s3c_irqext_wake(struct irq_data *data, unsigned int state);
-extern int s3c24xx_irq_suspend(struct sys_device *dev, pm_message_t state);
-extern int s3c24xx_irq_resume(struct sys_device *dev);
+extern int s3c24xx_irq_suspend(void);
+extern void s3c24xx_irq_resume(void);
 #else
 #define s3c_irqext_wake NULL
 #define s3c24xx_irq_suspend NULL
 #define s3c24xx_irq_resume  NULL
 #endif
 
+extern struct syscore_ops s3c24xx_irq_syscore_ops;
+
 /* PM debug functions */
 
 #ifdef CONFIG_SAMSUNG_PM_DEBUG
index f746950..f25e7ec 100644 (file)
@@ -398,9 +398,9 @@ static void vfp_enable(void *unused)
 }
 
 #ifdef CONFIG_PM
-#include <linux/sysdev.h>
+#include <linux/syscore_ops.h>
 
-static int vfp_pm_suspend(struct sys_device *dev, pm_message_t state)
+static int vfp_pm_suspend(void)
 {
        struct thread_info *ti = current_thread_info();
        u32 fpexc = fmrx(FPEXC);
@@ -420,34 +420,25 @@ static int vfp_pm_suspend(struct sys_device *dev, pm_message_t state)
        return 0;
 }
 
-static int vfp_pm_resume(struct sys_device *dev)
+static void vfp_pm_resume(void)
 {
        /* ensure we have access to the vfp */
        vfp_enable(NULL);
 
        /* and disable it to ensure the next usage restores the state */
        fmxr(FPEXC, fmrx(FPEXC) & ~FPEXC_EN);
-
-       return 0;
 }
 
-static struct sysdev_class vfp_pm_sysclass = {
-       .name           = "vfp",
+static struct syscore_ops vfp_pm_syscore_ops = {
        .suspend        = vfp_pm_suspend,
        .resume         = vfp_pm_resume,
 };
 
-static struct sys_device vfp_pm_sysdev = {
-       .cls    = &vfp_pm_sysclass,
-};
-
 static void vfp_pm_init(void)
 {
-       sysdev_class_register(&vfp_pm_sysclass);
-       sysdev_register(&vfp_pm_sysdev);
+       register_syscore_ops(&vfp_pm_syscore_ops);
 }
 
-
 #else
 static inline void vfp_pm_init(void) { }
 #endif /* CONFIG_PM */
index 21ce35f..3e36461 100644 (file)
@@ -12,7 +12,7 @@
 #include <linux/interrupt.h>
 #include <linux/irq.h>
 #include <linux/platform_device.h>
-#include <linux/sysdev.h>
+#include <linux/syscore_ops.h>
 
 #include <asm/io.h>
 
@@ -21,7 +21,6 @@
 struct intc {
        void __iomem            *regs;
        struct irq_chip         chip;
-       struct sys_device       sysdev;
 #ifdef CONFIG_PM
        unsigned long           suspend_ipr;
        unsigned long           saved_ipr[64];
@@ -146,9 +145,8 @@ void intc_set_suspend_handler(unsigned long offset)
        intc0.suspend_ipr = offset;
 }
 
-static int intc_suspend(struct sys_device *sdev, pm_message_t state)
+static int intc_suspend(void)
 {
-       struct intc *intc = container_of(sdev, struct intc, sysdev);
        int i;
 
        if (unlikely(!irqs_disabled())) {
@@ -156,28 +154,25 @@ static int intc_suspend(struct sys_device *sdev, pm_message_t state)
                return -EINVAL;
        }
 
-       if (unlikely(!intc->suspend_ipr)) {
+       if (unlikely(!intc0.suspend_ipr)) {
                pr_err("intc_suspend: suspend_ipr not initialized\n");
                return -EINVAL;
        }
 
        for (i = 0; i < 64; i++) {
-               intc->saved_ipr[i] = intc_readl(intc, INTPR0 + 4 * i);
-               intc_writel(intc, INTPR0 + 4 * i, intc->suspend_ipr);
+               intc0.saved_ipr[i] = intc_readl(&intc0, INTPR0 + 4 * i);
+               intc_writel(&intc0, INTPR0 + 4 * i, intc0.suspend_ipr);
        }
 
        return 0;
 }
 
-static int intc_resume(struct sys_device *sdev)
+static int intc_resume(void)
 {
-       struct intc *intc = container_of(sdev, struct intc, sysdev);
        int i;
 
-       WARN_ON(!irqs_disabled());
-
        for (i = 0; i < 64; i++)
-               intc_writel(intc, INTPR0 + 4 * i, intc->saved_ipr[i]);
+               intc_writel(&intc0, INTPR0 + 4 * i, intc0.saved_ipr[i]);
 
        return 0;
 }
@@ -186,27 +181,18 @@ static int intc_resume(struct sys_device *sdev)
 #define intc_resume    NULL
 #endif
 
-static struct sysdev_class intc_class = {
-       .name           = "intc",
+static struct syscore_ops intc_syscore_ops = {
        .suspend        = intc_suspend,
        .resume         = intc_resume,
 };
 
-static int __init intc_init_sysdev(void)
+static int __init intc_init_syscore(void)
 {
-       int ret;
-
-       ret = sysdev_class_register(&intc_class);
-       if (ret)
-               return ret;
+       register_syscore_ops(&intc_syscore_ops);
 
-       intc0.sysdev.id = 0;
-       intc0.sysdev.cls = &intc_class;
-       ret = sysdev_register(&intc0.sysdev);
-
-       return ret;
+       return 0;
 }
-device_initcall(intc_init_sysdev);
+device_initcall(intc_init_syscore);
 
 unsigned long intc_get_pending(unsigned int group)
 {
index 0b5f72f..401eb1d 100644 (file)
@@ -12,7 +12,7 @@
 
 #include <linux/bitops.h>
 #include <linux/hardirq.h>
-#include <linux/sysdev.h>
+#include <linux/syscore_ops.h>
 #include <linux/pm.h>
 #include <linux/nmi.h>
 #include <linux/smp.h>
@@ -196,43 +196,31 @@ void touch_nmi_watchdog(void)
 
 /* Suspend/resume support */
 #ifdef CONFIG_PM
-static int nmi_wdt_suspend(struct sys_device *dev, pm_message_t state)
+static int nmi_wdt_suspend(void)
 {
        nmi_wdt_stop();
        return 0;
 }
 
-static int nmi_wdt_resume(struct sys_device *dev)
+static void nmi_wdt_resume(void)
 {
        if (nmi_active)
                nmi_wdt_start();
-       return 0;
 }
 
-static struct sysdev_class nmi_sysclass = {
-       .name           = DRV_NAME,
+static struct syscore_ops nmi_syscore_ops = {
        .resume         = nmi_wdt_resume,
        .suspend        = nmi_wdt_suspend,
 };
 
-static struct sys_device device_nmi_wdt = {
-       .id     = 0,
-       .cls    = &nmi_sysclass,
-};
-
-static int __init init_nmi_wdt_sysfs(void)
+static int __init init_nmi_wdt_syscore(void)
 {
-       int error;
-
-       if (!nmi_active)
-               return 0;
+       if (nmi_active)
+               register_syscore_ops(&nmi_syscore_ops);
 
-       error = sysdev_class_register(&nmi_sysclass);
-       if (!error)
-               error = sysdev_register(&device_nmi_wdt);
-       return error;
+       return 0;
 }
-late_initcall(init_nmi_wdt_sysfs);
+late_initcall(init_nmi_wdt_syscore);
 
 #endif /* CONFIG_PM */
 
index cdb4beb..9e9b60d 100644 (file)
 #include <asm/gptimers.h>
 #include <asm/nmi.h>
 
-/* Accelerators for sched_clock()
- * convert from cycles(64bits) => nanoseconds (64bits)
- *  basic equation:
- *             ns = cycles / (freq / ns_per_sec)
- *             ns = cycles * (ns_per_sec / freq)
- *             ns = cycles * (10^9 / (cpu_khz * 10^3))
- *             ns = cycles * (10^6 / cpu_khz)
- *
- *     Then we use scaling math (suggested by george@mvista.com) to get:
- *             ns = cycles * (10^6 * SC / cpu_khz) / SC
- *             ns = cycles * cyc2ns_scale / SC
- *
- *     And since SC is a constant power of two, we can convert the div
- *  into a shift.
- *
- *  We can use khz divisor instead of mhz to keep a better precision, since
- *  cyc2ns_scale is limited to 10^6 * 2^10, which fits in 32 bits.
- *  (mathieu.desnoyers@polymtl.ca)
- *
- *                     -johnstul@us.ibm.com "math is hard, lets go shopping!"
- */
-
-#define CYC2NS_SCALE_FACTOR 10 /* 2^10, carefully chosen */
 
 #if defined(CONFIG_CYCLES_CLOCKSOURCE)
 
@@ -63,7 +40,6 @@ static struct clocksource bfin_cs_cycles = {
        .rating         = 400,
        .read           = bfin_read_cycles,
        .mask           = CLOCKSOURCE_MASK(64),
-       .shift          = CYC2NS_SCALE_FACTOR,
        .flags          = CLOCK_SOURCE_IS_CONTINUOUS,
 };
 
@@ -75,10 +51,7 @@ static inline unsigned long long bfin_cs_cycles_sched_clock(void)
 
 static int __init bfin_cs_cycles_init(void)
 {
-       bfin_cs_cycles.mult = \
-               clocksource_hz2mult(get_cclk(), bfin_cs_cycles.shift);
-
-       if (clocksource_register(&bfin_cs_cycles))
+       if (clocksource_register_hz(&bfin_cs_cycles, get_cclk()))
                panic("failed to register clocksource");
 
        return 0;
@@ -111,7 +84,6 @@ static struct clocksource bfin_cs_gptimer0 = {
        .rating         = 350,
        .read           = bfin_read_gptimer0,
        .mask           = CLOCKSOURCE_MASK(32),
-       .shift          = CYC2NS_SCALE_FACTOR,
        .flags          = CLOCK_SOURCE_IS_CONTINUOUS,
 };
 
@@ -125,10 +97,7 @@ static int __init bfin_cs_gptimer0_init(void)
 {
        setup_gptimer0();
 
-       bfin_cs_gptimer0.mult = \
-               clocksource_hz2mult(get_sclk(), bfin_cs_gptimer0.shift);
-
-       if (clocksource_register(&bfin_cs_gptimer0))
+       if (clocksource_register_hz(&bfin_cs_gptimer0, get_sclk()))
                panic("failed to register clocksource");
 
        return 0;
index 382099f..5e4112e 100644 (file)
@@ -19,9 +19,6 @@
 
 #define DRIVER_NAME "bfin dpmc"
 
-#define dprintk(msg...) \
-       cpufreq_debug_printk(CPUFREQ_DEBUG_DRIVER, DRIVER_NAME, msg)
-
 struct bfin_dpmc_platform_data *pdata;
 
 /**
index 8bce5ed..1fbd94c 100644 (file)
@@ -177,6 +177,9 @@ static irqreturn_t ipi_handler_int1(int irq, void *dev_instance)
        while (msg_queue->count) {
                msg = &msg_queue->ipi_message[msg_queue->head];
                switch (msg->type) {
+               case BFIN_IPI_RESCHEDULE:
+                       scheduler_ipi();
+                       break;
                case BFIN_IPI_CALL_FUNC:
                        spin_unlock_irqrestore(&msg_queue->lock, flags);
                        ipi_call_function(cpu, msg);
index 4c9e3e1..66cc756 100644 (file)
@@ -342,15 +342,18 @@ irqreturn_t crisv32_ipi_interrupt(int irq, void *dev_id)
 
        ipi = REG_RD(intr_vect, irq_regs[smp_processor_id()], rw_ipi);
 
+       if (ipi.vector & IPI_SCHEDULE) {
+               scheduler_ipi();
+       }
        if (ipi.vector & IPI_CALL) {
-                func(info);
+               func(info);
        }
        if (ipi.vector & IPI_FLUSH_TLB) {
-                    if (flush_mm == FLUSH_ALL)
-                        __flush_tlb_all();
-                    else if (flush_vma == FLUSH_ALL)
+               if (flush_mm == FLUSH_ALL)
+                       __flush_tlb_all();
+               else if (flush_vma == FLUSH_ALL)
                        __flush_tlb_mm(flush_mm);
-                    else
+               else
                        __flush_tlb_page(flush_vma, flush_addr);
        }
 
index 22f6152..f09b174 100644 (file)
@@ -23,8 +23,6 @@
 #include <linux/acpi.h>
 #include <acpi/processor.h>
 
-#define dprintk(msg...) cpufreq_debug_printk(CPUFREQ_DEBUG_DRIVER, "acpi-cpufreq", msg)
-
 MODULE_AUTHOR("Venkatesh Pallipadi");
 MODULE_DESCRIPTION("ACPI Processor P-States Driver");
 MODULE_LICENSE("GPL");
@@ -47,12 +45,12 @@ processor_set_pstate (
 {
        s64 retval;
 
-       dprintk("processor_set_pstate\n");
+       pr_debug("processor_set_pstate\n");
 
        retval = ia64_pal_set_pstate((u64)value);
 
        if (retval) {
-               dprintk("Failed to set freq to 0x%x, with error 0x%lx\n",
+               pr_debug("Failed to set freq to 0x%x, with error 0x%lx\n",
                        value, retval);
                return -ENODEV;
        }
@@ -67,14 +65,14 @@ processor_get_pstate (
        u64     pstate_index = 0;
        s64     retval;
 
-       dprintk("processor_get_pstate\n");
+       pr_debug("processor_get_pstate\n");
 
        retval = ia64_pal_get_pstate(&pstate_index,
                                     PAL_GET_PSTATE_TYPE_INSTANT);
        *value = (u32) pstate_index;
 
        if (retval)
-               dprintk("Failed to get current freq with "
+               pr_debug("Failed to get current freq with "
                        "error 0x%lx, idx 0x%x\n", retval, *value);
 
        return (int)retval;
@@ -90,7 +88,7 @@ extract_clock (
 {
        unsigned long i;
 
-       dprintk("extract_clock\n");
+       pr_debug("extract_clock\n");
 
        for (i = 0; i < data->acpi_data.state_count; i++) {
                if (value == data->acpi_data.states[i].status)
@@ -110,7 +108,7 @@ processor_get_freq (
        cpumask_t               saved_mask;
        unsigned long           clock_freq;
 
-       dprintk("processor_get_freq\n");
+       pr_debug("processor_get_freq\n");
 
        saved_mask = current->cpus_allowed;
        set_cpus_allowed_ptr(current, cpumask_of(cpu));
@@ -148,7 +146,7 @@ processor_set_freq (
        cpumask_t               saved_mask;
        int                     retval;
 
-       dprintk("processor_set_freq\n");
+       pr_debug("processor_set_freq\n");
 
        saved_mask = current->cpus_allowed;
        set_cpus_allowed_ptr(current, cpumask_of(cpu));
@@ -159,16 +157,16 @@ processor_set_freq (
 
        if (state == data->acpi_data.state) {
                if (unlikely(data->resume)) {
-                       dprintk("Called after resume, resetting to P%d\n", state);
+                       pr_debug("Called after resume, resetting to P%d\n", state);
                        data->resume = 0;
                } else {
-                       dprintk("Already at target state (P%d)\n", state);
+                       pr_debug("Already at target state (P%d)\n", state);
                        retval = 0;
                        goto migrate_end;
                }
        }
 
-       dprintk("Transitioning from P%d to P%d\n",
+       pr_debug("Transitioning from P%d to P%d\n",
                data->acpi_data.state, state);
 
        /* cpufreq frequency struct */
@@ -186,7 +184,7 @@ processor_set_freq (
 
        value = (u32) data->acpi_data.states[state].control;
 
-       dprintk("Transitioning to state: 0x%08x\n", value);
+       pr_debug("Transitioning to state: 0x%08x\n", value);
 
        ret = processor_set_pstate(value);
        if (ret) {
@@ -219,7 +217,7 @@ acpi_cpufreq_get (
 {
        struct cpufreq_acpi_io *data = acpi_io_data[cpu];
 
-       dprintk("acpi_cpufreq_get\n");
+       pr_debug("acpi_cpufreq_get\n");
 
        return processor_get_freq(data, cpu);
 }
@@ -235,7 +233,7 @@ acpi_cpufreq_target (
        unsigned int next_state = 0;
        unsigned int result = 0;
 
-       dprintk("acpi_cpufreq_setpolicy\n");
+       pr_debug("acpi_cpufreq_setpolicy\n");
 
        result = cpufreq_frequency_table_target(policy,
                        data->freq_table, target_freq, relation, &next_state);
@@ -255,7 +253,7 @@ acpi_cpufreq_verify (
        unsigned int result = 0;
        struct cpufreq_acpi_io *data = acpi_io_data[policy->cpu];
 
-       dprintk("acpi_cpufreq_verify\n");
+       pr_debug("acpi_cpufreq_verify\n");
 
        result = cpufreq_frequency_table_verify(policy,
                        data->freq_table);
@@ -273,7 +271,7 @@ acpi_cpufreq_cpu_init (
        struct cpufreq_acpi_io  *data;
        unsigned int            result = 0;
 
-       dprintk("acpi_cpufreq_cpu_init\n");
+       pr_debug("acpi_cpufreq_cpu_init\n");
 
        data = kzalloc(sizeof(struct cpufreq_acpi_io), GFP_KERNEL);
        if (!data)
@@ -288,7 +286,7 @@ acpi_cpufreq_cpu_init (
 
        /* capability check */
        if (data->acpi_data.state_count <= 1) {
-               dprintk("No P-States\n");
+               pr_debug("No P-States\n");
                result = -ENODEV;
                goto err_unreg;
        }
@@ -297,7 +295,7 @@ acpi_cpufreq_cpu_init (
                                        ACPI_ADR_SPACE_FIXED_HARDWARE) ||
            (data->acpi_data.status_register.space_id !=
                                        ACPI_ADR_SPACE_FIXED_HARDWARE)) {
-               dprintk("Unsupported address space [%d, %d]\n",
+               pr_debug("Unsupported address space [%d, %d]\n",
                        (u32) (data->acpi_data.control_register.space_id),
                        (u32) (data->acpi_data.status_register.space_id));
                result = -ENODEV;
@@ -348,7 +346,7 @@ acpi_cpufreq_cpu_init (
               "activated.\n", cpu);
 
        for (i = 0; i < data->acpi_data.state_count; i++)
-               dprintk("     %cP%d: %d MHz, %d mW, %d uS, %d uS, 0x%x 0x%x\n",
+               pr_debug("     %cP%d: %d MHz, %d mW, %d uS, %d uS, 0x%x 0x%x\n",
                        (i == data->acpi_data.state?'*':' '), i,
                        (u32) data->acpi_data.states[i].core_frequency,
                        (u32) data->acpi_data.states[i].power,
@@ -383,7 +381,7 @@ acpi_cpufreq_cpu_exit (
 {
        struct cpufreq_acpi_io *data = acpi_io_data[policy->cpu];
 
-       dprintk("acpi_cpufreq_cpu_exit\n");
+       pr_debug("acpi_cpufreq_cpu_exit\n");
 
        if (data) {
                cpufreq_frequency_table_put_attr(policy->cpu);
@@ -418,7 +416,7 @@ static struct cpufreq_driver acpi_cpufreq_driver = {
 static int __init
 acpi_cpufreq_init (void)
 {
-       dprintk("acpi_cpufreq_init\n");
+       pr_debug("acpi_cpufreq_init\n");
 
        return cpufreq_register_driver(&acpi_cpufreq_driver);
 }
@@ -427,7 +425,7 @@ acpi_cpufreq_init (void)
 static void __exit
 acpi_cpufreq_exit (void)
 {
-       dprintk("acpi_cpufreq_exit\n");
+       pr_debug("acpi_cpufreq_exit\n");
 
        cpufreq_unregister_driver(&acpi_cpufreq_driver);
        return;
index 1b811c6..f64097b 100644 (file)
@@ -31,8 +31,6 @@ static struct clocksource clocksource_cyclone = {
         .rating         = 300,
         .read           = read_cyclone,
         .mask           = (1LL << 40) - 1,
-        .mult           = 0, /*to be calculated*/
-        .shift          = 16,
         .flags          = CLOCK_SOURCE_IS_CONTINUOUS,
 };
 
@@ -118,9 +116,7 @@ int __init init_cyclone_clock(void)
        /* initialize last tick */
        cyclone_mc = cyclone_timer;
        clocksource_cyclone.fsys_mmio = cyclone_timer;
-       clocksource_cyclone.mult = clocksource_hz2mult(CYCLONE_TIMER_FREQ,
-                                               clocksource_cyclone.shift);
-       clocksource_register(&clocksource_cyclone);
+       clocksource_register_hz(&clocksource_cyclone, CYCLONE_TIMER_FREQ);
 
        return 0;
 }
index 5b70474..782c3a3 100644 (file)
@@ -31,6 +31,7 @@
 #include <linux/irq.h>
 #include <linux/ratelimit.h>
 #include <linux/acpi.h>
+#include <linux/sched.h>
 
 #include <asm/delay.h>
 #include <asm/intrinsics.h>
@@ -496,6 +497,7 @@ ia64_handle_irq (ia64_vector vector, struct pt_regs *regs)
                        smp_local_flush_tlb();
                        kstat_incr_irqs_this_cpu(irq, desc);
                } else if (unlikely(IS_RESCHEDULE(vector))) {
+                       scheduler_ipi();
                        kstat_incr_irqs_this_cpu(irq, desc);
                } else {
                        ia64_setreg(_IA64_REG_CR_TPR, vector);
index 156ad80..04440cc 100644 (file)
@@ -73,8 +73,6 @@ static struct clocksource clocksource_itc = {
        .rating         = 350,
        .read           = itc_get_cycles,
        .mask           = CLOCKSOURCE_MASK(64),
-       .mult           = 0, /*to be calculated*/
-       .shift          = 16,
        .flags          = CLOCK_SOURCE_IS_CONTINUOUS,
 #ifdef CONFIG_PARAVIRT
        .resume         = paravirt_clocksource_resume,
@@ -365,11 +363,8 @@ ia64_init_itm (void)
        ia64_cpu_local_tick();
 
        if (!itc_clocksource) {
-               /* Sort out mult/shift values: */
-               clocksource_itc.mult =
-                       clocksource_hz2mult(local_cpu_data->itc_freq,
-                                               clocksource_itc.shift);
-               clocksource_register(&clocksource_itc);
+               clocksource_register_hz(&clocksource_itc,
+                                               local_cpu_data->itc_freq);
                itc_clocksource = &clocksource_itc;
        }
 }
index 21d6f09..c34efda 100644 (file)
@@ -33,8 +33,6 @@ static struct clocksource clocksource_sn2 = {
         .rating         = 450,
         .read           = read_sn2,
         .mask           = (1LL << 55) - 1,
-        .mult           = 0,
-        .shift          = 10,
         .flags          = CLOCK_SOURCE_IS_CONTINUOUS,
 };
 
@@ -57,9 +55,7 @@ ia64_sn_udelay (unsigned long usecs)
 void __init sn_timer_init(void)
 {
        clocksource_sn2.fsys_mmio = RTC_COUNTER_ADDR;
-       clocksource_sn2.mult = clocksource_hz2mult(sn_rtc_cycles_per_second,
-                                                       clocksource_sn2.shift);
-       clocksource_register(&clocksource_sn2);
+       clocksource_register_hz(&clocksource_sn2, sn_rtc_cycles_per_second);
 
        ia64_udelay = &ia64_sn_udelay;
 }
index 108bb85..b279e14 100644 (file)
@@ -92,6 +92,8 @@ static unsigned short saved_irq_cnt;
 static int xen_slab_ready;
 
 #ifdef CONFIG_SMP
+#include <linux/sched.h>
+
 /* Dummy stub. Though we may check XEN_RESCHEDULE_VECTOR before __do_IRQ,
  * it ends up to issue several memory accesses upon percpu data and
  * thus adds unnecessary traffic to other paths.
@@ -99,7 +101,13 @@ static int xen_slab_ready;
 static irqreturn_t
 xen_dummy_handler(int irq, void *dev_id)
 {
+       return IRQ_HANDLED;
+}
 
+static irqreturn_t
+xen_resched_handler(int irq, void *dev_id)
+{
+       scheduler_ipi();
        return IRQ_HANDLED;
 }
 
@@ -110,7 +118,7 @@ static struct irqaction xen_ipi_irqaction = {
 };
 
 static struct irqaction xen_resched_irqaction = {
-       .handler =      xen_dummy_handler,
+       .handler =      xen_resched_handler,
        .flags =        IRQF_DISABLED,
        .name =         "resched"
 };
index 31cef20..fc10b39 100644 (file)
@@ -122,8 +122,6 @@ void smp_send_reschedule(int cpu_id)
  *
  * Description:  This routine executes on CPU which received
  *               'RESCHEDULE_IPI'.
- *               Rescheduling is processed at the exit of interrupt
- *               operation.
  *
  * Born on Date: 2002.02.05
  *
@@ -138,7 +136,7 @@ void smp_send_reschedule(int cpu_id)
  *==========================================================================*/
 void smp_reschedule_interrupt(void)
 {
-       /* nothing to do */
+       scheduler_ipi();
 }
 
 /*==========================================================================*
index c194d64..cf95aec 100644 (file)
@@ -44,6 +44,7 @@ SECTIONS
   EXCEPTION_TABLE(16)
   NOTES
 
+  _sdata = .;                  /* Start of data section */
   RODATA
   RW_DATA_SECTION(32, PAGE_SIZE, THREAD_SIZE)
   _edata = .;                  /* End of data section */
index b995513..95022b0 100644 (file)
 
 /* Hook for MIDI serial driver */
 void (*atari_MIDI_interrupt_hook) (void);
-/* Hook for mouse driver */
-void (*atari_mouse_interrupt_hook) (char *);
 /* Hook for keyboard inputdev  driver */
 void (*atari_input_keyboard_interrupt_hook) (unsigned char, char);
 /* Hook for mouse inputdev  driver */
 void (*atari_input_mouse_interrupt_hook) (char *);
-EXPORT_SYMBOL(atari_mouse_interrupt_hook);
 EXPORT_SYMBOL(atari_input_keyboard_interrupt_hook);
 EXPORT_SYMBOL(atari_input_mouse_interrupt_hook);
 
@@ -263,8 +260,8 @@ repeat:
                        kb_state.buf[kb_state.len++] = scancode;
                        if (kb_state.len == 3) {
                                kb_state.state = KEYBOARD;
-                               if (atari_mouse_interrupt_hook)
-                                       atari_mouse_interrupt_hook(kb_state.buf);
+                               if (atari_input_mouse_interrupt_hook)
+                                       atari_input_mouse_interrupt_hook(kb_state.buf);
                        }
                        break;
 
@@ -575,7 +572,7 @@ int atari_keyb_init(void)
        kb_state.len = 0;
 
        error = request_irq(IRQ_MFP_ACIA, atari_keyboard_interrupt,
-                           IRQ_TYPE_SLOW, "keyboard/mouse/MIDI",
+                           IRQ_TYPE_SLOW, "keyboard,mouse,MIDI",
                            atari_keyboard_interrupt);
        if (error)
                return error;
index 604329f..ddbf43c 100644 (file)
@@ -180,7 +180,7 @@ void __init stdma_init(void)
 {
        stdma_isr = NULL;
        if (request_irq(IRQ_MFP_FDC, stdma_int, IRQ_TYPE_SLOW | IRQF_SHARED,
-                       "ST-DMA: floppy/ACSI/IDE/Falcon-SCSI", stdma_int))
+                       "ST-DMA floppy,ACSI,IDE,Falcon-SCSI", stdma_int))
                pr_err("Couldn't register ST-DMA interrupt\n");
 }
 
index 546e7da..68f3622 100644 (file)
@@ -34,8 +34,6 @@ void ikbd_joystick_disable(void);
 
 /* Hook for MIDI serial driver */
 extern void (*atari_MIDI_interrupt_hook) (void);
-/* Hook for mouse driver */
-extern void (*atari_mouse_interrupt_hook) (char *);
 /* Hook for keyboard inputdev  driver */
 extern void (*atari_input_keyboard_interrupt_hook) (unsigned char, char);
 /* Hook for mouse inputdev  driver */
index 9d69f6e..e9020f8 100644 (file)
@@ -181,14 +181,15 @@ static inline int find_first_zero_bit(const unsigned long *vaddr,
 {
        const unsigned long *p = vaddr;
        int res = 32;
+       unsigned int words;
        unsigned long num;
 
        if (!size)
                return 0;
 
-       size = (size + 31) >> 5;
+       words = (size + 31) >> 5;
        while (!(num = ~*p++)) {
-               if (!--size)
+               if (!--words)
                        goto out;
        }
 
@@ -196,7 +197,8 @@ static inline int find_first_zero_bit(const unsigned long *vaddr,
                              : "=d" (res) : "d" (num & -num));
        res ^= 31;
 out:
-       return ((long)p - (long)vaddr - 4) * 8 + res;
+       res += ((long)p - (long)vaddr - 4) * 8;
+       return res < size ? res : size;
 }
 
 static inline int find_next_zero_bit(const unsigned long *vaddr, int size,
@@ -215,27 +217,32 @@ static inline int find_next_zero_bit(const unsigned long *vaddr, int size,
                /* Look for zero in first longword */
                __asm__ __volatile__ ("bfffo %1{#0,#0},%0"
                                      : "=d" (res) : "d" (num & -num));
-               if (res < 32)
-                       return offset + (res ^ 31);
+               if (res < 32) {
+                       offset += res ^ 31;
+                       return offset < size ? offset : size;
+               }
                offset += 32;
+
+               if (offset >= size)
+                       return size;
        }
        /* No zero yet, search remaining full bytes for a zero */
-       res = find_first_zero_bit(p, size - ((long)p - (long)vaddr) * 8);
-       return offset + res;
+       return offset + find_first_zero_bit(p, size - offset);
 }
 
 static inline int find_first_bit(const unsigned long *vaddr, unsigned size)
 {
        const unsigned long *p = vaddr;
        int res = 32;
+       unsigned int words;
        unsigned long num;
 
        if (!size)
                return 0;
 
-       size = (size + 31) >> 5;
+       words = (size + 31) >> 5;
        while (!(num = *p++)) {
-               if (!--size)
+               if (!--words)
                        goto out;
        }
 
@@ -243,7 +250,8 @@ static inline int find_first_bit(const unsigned long *vaddr, unsigned size)
                              : "=d" (res) : "d" (num & -num));
        res ^= 31;
 out:
-       return ((long)p - (long)vaddr - 4) * 8 + res;
+       res += ((long)p - (long)vaddr - 4) * 8;
+       return res < size ? res : size;
 }
 
 static inline int find_next_bit(const unsigned long *vaddr, int size,
@@ -262,13 +270,17 @@ static inline int find_next_bit(const unsigned long *vaddr, int size,
                /* Look for one in first longword */
                __asm__ __volatile__ ("bfffo %1{#0,#0},%0"
                                      : "=d" (res) : "d" (num & -num));
-               if (res < 32)
-                       return offset + (res ^ 31);
+               if (res < 32) {
+                       offset += res ^ 31;
+                       return offset < size ? offset : size;
+               }
                offset += 32;
+
+               if (offset >= size)
+                       return size;
        }
        /* No one yet, search remaining full bytes for a one */
-       res = find_first_bit(p, size - ((long)p - (long)vaddr) * 8);
-       return offset + res;
+       return offset + find_first_bit(p, size - offset);
 }
 
 /*
@@ -366,23 +378,25 @@ static inline int test_bit_le(int nr, const void *vaddr)
 static inline int find_first_zero_bit_le(const void *vaddr, unsigned size)
 {
        const unsigned long *p = vaddr, *addr = vaddr;
-       int res;
+       int res = 0;
+       unsigned int words;
 
        if (!size)
                return 0;
 
-       size = (size >> 5) + ((size & 31) > 0);
-       while (*p++ == ~0UL)
-       {
-               if (--size == 0)
-                       return (p - addr) << 5;
+       words = (size >> 5) + ((size & 31) > 0);
+       while (*p++ == ~0UL) {
+               if (--words == 0)
+                       goto out;
        }
 
        --p;
        for (res = 0; res < 32; res++)
                if (!test_bit_le(res, p))
                        break;
-       return (p - addr) * 32 + res;
+out:
+       res += (p - addr) * 32;
+       return res < size ? res : size;
 }
 
 static inline unsigned long find_next_zero_bit_le(const void *addr,
@@ -400,10 +414,15 @@ static inline unsigned long find_next_zero_bit_le(const void *addr,
                offset -= bit;
                /* Look for zero in first longword */
                for (res = bit; res < 32; res++)
-                       if (!test_bit_le(res, p))
-                               return offset + res;
+                       if (!test_bit_le(res, p)) {
+                               offset += res;
+                               return offset < size ? offset : size;
+                       }
                p++;
                offset += 32;
+
+               if (offset >= size)
+                       return size;
        }
        /* No zero yet, search remaining full bytes for a zero */
        return offset + find_first_zero_bit_le(p, size - offset);
@@ -412,22 +431,25 @@ static inline unsigned long find_next_zero_bit_le(const void *addr,
 static inline int find_first_bit_le(const void *vaddr, unsigned size)
 {
        const unsigned long *p = vaddr, *addr = vaddr;
-       int res;
+       int res = 0;
+       unsigned int words;
 
        if (!size)
                return 0;
 
-       size = (size >> 5) + ((size & 31) > 0);
+       words = (size >> 5) + ((size & 31) > 0);
        while (*p++ == 0UL) {
-               if (--size == 0)
-                       return (p - addr) << 5;
+               if (--words == 0)
+                       goto out;
        }
 
        --p;
        for (res = 0; res < 32; res++)
                if (test_bit_le(res, p))
                        break;
-       return (p - addr) * 32 + res;
+out:
+       res += (p - addr) * 32;
+       return res < size ? res : size;
 }
 
 static inline unsigned long find_next_bit_le(const void *addr,
@@ -445,10 +467,15 @@ static inline unsigned long find_next_bit_le(const void *addr,
                offset -= bit;
                /* Look for one in first longword */
                for (res = bit; res < 32; res++)
-                       if (test_bit_le(res, p))
-                               return offset + res;
+                       if (test_bit_le(res, p)) {
+                               offset += res;
+                               return offset < size ? offset : size;
+                       }
                p++;
                offset += 32;
+
+               if (offset >= size)
+                       return size;
        }
        /* No set bit yet, search remaining full bytes for a set bit */
        return offset + find_first_bit_le(p, size - offset);
index 29e1790..f3b649d 100644 (file)
@@ -22,7 +22,7 @@
 #define __NR_mknod              14
 #define __NR_chmod              15
 #define __NR_chown              16
-#define __NR_break              17
+/*#define __NR_break            17*/
 #define __NR_oldstat            18
 #define __NR_lseek              19
 #define __NR_getpid             20
 #define __NR_oldfstat           28
 #define __NR_pause              29
 #define __NR_utime              30
-#define __NR_stty               31
-#define __NR_gtty               32
+/*#define __NR_stty             31*/
+/*#define __NR_gtty             32*/
 #define __NR_access             33
 #define __NR_nice               34
-#define __NR_ftime              35
+/*#define __NR_ftime            35*/
 #define __NR_sync               36
 #define __NR_kill               37
 #define __NR_rename             38
@@ -49,7 +49,7 @@
 #define __NR_dup                41
 #define __NR_pipe               42
 #define __NR_times              43
-#define __NR_prof               44
+/*#define __NR_prof             44*/
 #define __NR_brk                45
 #define __NR_setgid             46
 #define __NR_getgid             47
 #define __NR_getegid            50
 #define __NR_acct               51
 #define __NR_umount2            52
-#define __NR_lock               53
+/*#define __NR_lock             53*/
 #define __NR_ioctl              54
 #define __NR_fcntl              55
-#define __NR_mpx                56
+/*#define __NR_mpx              56*/
 #define __NR_setpgid            57
-#define __NR_ulimit             58
-#define __NR_oldolduname        59
+/*#define __NR_ulimit           58*/
+/*#define __NR_oldolduname      59*/
 #define __NR_umask              60
 #define __NR_chroot             61
 #define __NR_ustat              62
 #define __NR_fchown             95
 #define __NR_getpriority        96
 #define __NR_setpriority        97
-#define __NR_profil             98
+/*#define __NR_profil           98*/
 #define __NR_statfs             99
 #define __NR_fstatfs           100
-#define __NR_ioperm            101
+/*#define __NR_ioperm          101*/
 #define __NR_socketcall                102
 #define __NR_syslog            103
 #define __NR_setitimer         104
 #define __NR_stat              106
 #define __NR_lstat             107
 #define __NR_fstat             108
-#define __NR_olduname          109
-#define __NR_iopl              /* 110 */ not supported
+/*#define __NR_olduname                109*/
+/*#define __NR_iopl            110*/ /* not supported */
 #define __NR_vhangup           111
-#define __NR_idle              /* 112 */ Obsolete
-#define __NR_vm86              /* 113 */ not supported
+/*#define __NR_idle            112*/ /* Obsolete */
+/*#define __NR_vm86            113*/ /* not supported */
 #define __NR_wait4             114
 #define __NR_swapoff           115
 #define __NR_sysinfo           116
 #define __NR_adjtimex          124
 #define __NR_mprotect          125
 #define __NR_sigprocmask       126
-#define __NR_create_module     127
+/*#define __NR_create_module   127*/
 #define __NR_init_module       128
 #define __NR_delete_module     129
-#define __NR_get_kernel_syms   130
+/*#define __NR_get_kernel_syms 130*/
 #define __NR_quotactl          131
 #define __NR_getpgid           132
 #define __NR_fchdir            133
 #define __NR_bdflush           134
 #define __NR_sysfs             135
 #define __NR_personality       136
-#define __NR_afs_syscall       137 /* Syscall for Andrew File System */
+/*#define __NR_afs_syscall     137*/ /* Syscall for Andrew File System */
 #define __NR_setfsuid          138
 #define __NR_setfsgid          139
 #define __NR__llseek           140
 #define __NR_setresuid         164
 #define __NR_getresuid         165
 #define __NR_getpagesize       166
-#define __NR_query_module      167
+/*#define __NR_query_module    167*/
 #define __NR_poll              168
 #define __NR_nfsservctl                169
 #define __NR_setresgid         170
 #define __NR_capset            185
 #define __NR_sigaltstack       186
 #define __NR_sendfile          187
-#define __NR_getpmsg           188     /* some people actually want streams */
-#define __NR_putpmsg           189     /* some people actually want streams */
+/*#define __NR_getpmsg         188*/   /* some people actually want streams */
+/*#define __NR_putpmsg         189*/   /* some people actually want streams */
 #define __NR_vfork             190
 #define __NR_ugetrlimit                191
 #define __NR_mmap2             192
 #define __NR_setfsuid32                215
 #define __NR_setfsgid32                216
 #define __NR_pivot_root                217
+/* 218*/
+/* 219*/
 #define __NR_getdents64                220
 #define __NR_gettid            221
 #define __NR_tkill             222
 #define __NR_mq_notify         275
 #define __NR_mq_getsetattr     276
 #define __NR_waitid            277
-#define __NR_vserver           278
+/*#define __NR_vserver         278*/
 #define __NR_add_key           279
 #define __NR_request_key       280
 #define __NR_keyctl            281
index 55d5d6b..aced678 100644 (file)
@@ -10,7 +10,7 @@ endif
 extra-y        += vmlinux.lds
 
 obj-y  := entry.o process.o traps.o ints.o signal.o ptrace.o module.o \
-          sys_m68k.o time.o setup.o m68k_ksyms.o devres.o
+          sys_m68k.o time.o setup.o m68k_ksyms.o devres.o syscalltable.o
 
 devres-y = ../../../kernel/irq/devres.o
 
index 1359ee6..bd0ec05 100644 (file)
@@ -407,351 +407,3 @@ resume:
 
        rts
 
-.data
-ALIGN
-sys_call_table:
-       .long sys_restart_syscall       /* 0 - old "setup()" system call, used for restarting */
-       .long sys_exit
-       .long sys_fork
-       .long sys_read
-       .long sys_write
-       .long sys_open          /* 5 */
-       .long sys_close
-       .long sys_waitpid
-       .long sys_creat
-       .long sys_link
-       .long sys_unlink        /* 10 */
-       .long sys_execve
-       .long sys_chdir
-       .long sys_time
-       .long sys_mknod
-       .long sys_chmod         /* 15 */
-       .long sys_chown16
-       .long sys_ni_syscall                            /* old break syscall holder */
-       .long sys_stat
-       .long sys_lseek
-       .long sys_getpid        /* 20 */
-       .long sys_mount
-       .long sys_oldumount
-       .long sys_setuid16
-       .long sys_getuid16
-       .long sys_stime         /* 25 */
-       .long sys_ptrace
-       .long sys_alarm
-       .long sys_fstat
-       .long sys_pause
-       .long sys_utime         /* 30 */
-       .long sys_ni_syscall                            /* old stty syscall holder */
-       .long sys_ni_syscall                            /* old gtty syscall holder */
-       .long sys_access
-       .long sys_nice
-       .long sys_ni_syscall    /* 35 */        /* old ftime syscall holder */
-       .long sys_sync
-       .long sys_kill
-       .long sys_rename
-       .long sys_mkdir
-       .long sys_rmdir         /* 40 */
-       .long sys_dup
-       .long sys_pipe
-       .long sys_times
-       .long sys_ni_syscall                            /* old prof syscall holder */
-       .long sys_brk           /* 45 */
-       .long sys_setgid16
-       .long sys_getgid16
-       .long sys_signal
-       .long sys_geteuid16
-       .long sys_getegid16     /* 50 */
-       .long sys_acct
-       .long sys_umount                                /* recycled never used phys() */
-       .long sys_ni_syscall                            /* old lock syscall holder */
-       .long sys_ioctl
-       .long sys_fcntl         /* 55 */
-       .long sys_ni_syscall                            /* old mpx syscall holder */
-       .long sys_setpgid
-       .long sys_ni_syscall                            /* old ulimit syscall holder */
-       .long sys_ni_syscall
-       .long sys_umask         /* 60 */
-       .long sys_chroot
-       .long sys_ustat
-       .long sys_dup2
-       .long sys_getppid
-       .long sys_getpgrp       /* 65 */
-       .long sys_setsid
-       .long sys_sigaction
-       .long sys_sgetmask
-       .long sys_ssetmask
-       .long sys_setreuid16    /* 70 */
-       .long sys_setregid16
-       .long sys_sigsuspend
-       .long sys_sigpending
-       .long sys_sethostname
-       .long sys_setrlimit     /* 75 */
-       .long sys_old_getrlimit
-       .long sys_getrusage
-       .long sys_gettimeofday
-       .long sys_settimeofday
-       .long sys_getgroups16   /* 80 */
-       .long sys_setgroups16
-       .long sys_old_select
-       .long sys_symlink
-       .long sys_lstat
-       .long sys_readlink      /* 85 */
-       .long sys_uselib
-       .long sys_swapon
-       .long sys_reboot
-       .long sys_old_readdir
-       .long sys_old_mmap      /* 90 */
-       .long sys_munmap
-       .long sys_truncate
-       .long sys_ftruncate
-       .long sys_fchmod
-       .long sys_fchown16      /* 95 */
-       .long sys_getpriority
-       .long sys_setpriority
-       .long sys_ni_syscall                            /* old profil syscall holder */
-       .long sys_statfs
-       .long sys_fstatfs       /* 100 */
-       .long sys_ni_syscall                            /* ioperm for i386 */
-       .long sys_socketcall
-       .long sys_syslog
-       .long sys_setitimer
-       .long sys_getitimer     /* 105 */
-       .long sys_newstat
-       .long sys_newlstat
-       .long sys_newfstat
-       .long sys_ni_syscall
-       .long sys_ni_syscall    /* 110 */       /* iopl for i386 */
-       .long sys_vhangup
-       .long sys_ni_syscall                            /* obsolete idle() syscall */
-       .long sys_ni_syscall                            /* vm86old for i386 */
-       .long sys_wait4
-       .long sys_swapoff       /* 115 */
-       .long sys_sysinfo
-       .long sys_ipc
-       .long sys_fsync
-       .long sys_sigreturn
-       .long sys_clone         /* 120 */
-       .long sys_setdomainname
-       .long sys_newuname
-       .long sys_cacheflush                            /* modify_ldt for i386 */
-       .long sys_adjtimex
-       .long sys_mprotect      /* 125 */
-       .long sys_sigprocmask
-       .long sys_ni_syscall            /* old "create_module" */
-       .long sys_init_module
-       .long sys_delete_module
-       .long sys_ni_syscall    /* 130 - old "get_kernel_syms" */
-       .long sys_quotactl
-       .long sys_getpgid
-       .long sys_fchdir
-       .long sys_bdflush
-       .long sys_sysfs         /* 135 */
-       .long sys_personality
-       .long sys_ni_syscall                            /* for afs_syscall */
-       .long sys_setfsuid16
-       .long sys_setfsgid16
-       .long sys_llseek        /* 140 */
-       .long sys_getdents
-       .long sys_select
-       .long sys_flock
-       .long sys_msync
-       .long sys_readv         /* 145 */
-       .long sys_writev
-       .long sys_getsid
-       .long sys_fdatasync
-       .long sys_sysctl
-       .long sys_mlock         /* 150 */
-       .long sys_munlock
-       .long sys_mlockall
-       .long sys_munlockall
-       .long sys_sched_setparam
-       .long sys_sched_getparam        /* 155 */
-       .long sys_sched_setscheduler
-       .long sys_sched_getscheduler
-       .long sys_sched_yield
-       .long sys_sched_get_priority_max
-       .long sys_sched_get_priority_min  /* 160 */
-       .long sys_sched_rr_get_interval
-       .long sys_nanosleep
-       .long sys_mremap
-       .long sys_setresuid16
-       .long sys_getresuid16   /* 165 */
-       .long sys_getpagesize
-       .long sys_ni_syscall            /* old sys_query_module */
-       .long sys_poll
-       .long sys_nfsservctl
-       .long sys_setresgid16   /* 170 */
-       .long sys_getresgid16
-       .long sys_prctl
-       .long sys_rt_sigreturn
-       .long sys_rt_sigaction
-       .long sys_rt_sigprocmask        /* 175 */
-       .long sys_rt_sigpending
-       .long sys_rt_sigtimedwait
-       .long sys_rt_sigqueueinfo
-       .long sys_rt_sigsuspend
-       .long sys_pread64       /* 180 */
-       .long sys_pwrite64
-       .long sys_lchown16;
-       .long sys_getcwd
-       .long sys_capget
-       .long sys_capset        /* 185 */
-       .long sys_sigaltstack
-       .long sys_sendfile
-       .long sys_ni_syscall                            /* streams1 */
-       .long sys_ni_syscall                            /* streams2 */
-       .long sys_vfork         /* 190 */
-       .long sys_getrlimit
-       .long sys_mmap2
-       .long sys_truncate64
-       .long sys_ftruncate64
-       .long sys_stat64        /* 195 */
-       .long sys_lstat64
-       .long sys_fstat64
-       .long sys_chown
-       .long sys_getuid
-       .long sys_getgid        /* 200 */
-       .long sys_geteuid
-       .long sys_getegid
-       .long sys_setreuid
-       .long sys_setregid
-       .long sys_getgroups     /* 205 */
-       .long sys_setgroups
-       .long sys_fchown
-       .long sys_setresuid
-       .long sys_getresuid
-       .long sys_setresgid     /* 210 */
-       .long sys_getresgid
-       .long sys_lchown
-       .long sys_setuid
-       .long sys_setgid
-       .long sys_setfsuid      /* 215 */
-       .long sys_setfsgid
-       .long sys_pivot_root
-       .long sys_ni_syscall
-       .long sys_ni_syscall
-       .long sys_getdents64    /* 220 */
-       .long sys_gettid
-       .long sys_tkill
-       .long sys_setxattr
-       .long sys_lsetxattr
-       .long sys_fsetxattr     /* 225 */
-       .long sys_getxattr
-       .long sys_lgetxattr
-       .long sys_fgetxattr
-       .long sys_listxattr
-       .long sys_llistxattr    /* 230 */
-       .long sys_flistxattr
-       .long sys_removexattr
-       .long sys_lremovexattr
-       .long sys_fremovexattr
-       .long sys_futex         /* 235 */
-       .long sys_sendfile64
-       .long sys_mincore
-       .long sys_madvise
-       .long sys_fcntl64
-       .long sys_readahead     /* 240 */
-       .long sys_io_setup
-       .long sys_io_destroy
-       .long sys_io_getevents
-       .long sys_io_submit
-       .long sys_io_cancel     /* 245 */
-       .long sys_fadvise64
-       .long sys_exit_group
-       .long sys_lookup_dcookie
-       .long sys_epoll_create
-       .long sys_epoll_ctl     /* 250 */
-       .long sys_epoll_wait
-       .long sys_remap_file_pages
-       .long sys_set_tid_address
-       .long sys_timer_create
-       .long sys_timer_settime /* 255 */
-       .long sys_timer_gettime
-       .long sys_timer_getoverrun
-       .long sys_timer_delete
-       .long sys_clock_settime
-       .long sys_clock_gettime /* 260 */
-       .long sys_clock_getres
-       .long sys_clock_nanosleep
-       .long sys_statfs64
-       .long sys_fstatfs64
-       .long sys_tgkill        /* 265 */
-       .long sys_utimes
-       .long sys_fadvise64_64
-       .long sys_mbind
-       .long sys_get_mempolicy
-       .long sys_set_mempolicy /* 270 */
-       .long sys_mq_open
-       .long sys_mq_unlink
-       .long sys_mq_timedsend
-       .long sys_mq_timedreceive
-       .long sys_mq_notify     /* 275 */
-       .long sys_mq_getsetattr
-       .long sys_waitid
-       .long sys_ni_syscall    /* for sys_vserver */
-       .long sys_add_key
-       .long sys_request_key   /* 280 */
-       .long sys_keyctl
-       .long sys_ioprio_set
-       .long sys_ioprio_get
-       .long sys_inotify_init
-       .long sys_inotify_add_watch     /* 285 */
-       .long sys_inotify_rm_watch
-       .long sys_migrate_pages
-       .long sys_openat
-       .long sys_mkdirat
-       .long sys_mknodat               /* 290 */
-       .long sys_fchownat
-       .long sys_futimesat
-       .long sys_fstatat64
-       .long sys_unlinkat
-       .long sys_renameat              /* 295 */
-       .long sys_linkat
-       .long sys_symlinkat
-       .long sys_readlinkat
-       .long sys_fchmodat
-       .long sys_faccessat             /* 300 */
-       .long sys_ni_syscall            /* Reserved for pselect6 */
-       .long sys_ni_syscall            /* Reserved for ppoll */
-       .long sys_unshare
-       .long sys_set_robust_list
-       .long sys_get_robust_list       /* 305 */
-       .long sys_splice
-       .long sys_sync_file_range
-       .long sys_tee
-       .long sys_vmsplice
-       .long sys_move_pages            /* 310 */
-       .long sys_sched_setaffinity
-       .long sys_sched_getaffinity
-       .long sys_kexec_load
-       .long sys_getcpu
-       .long sys_epoll_pwait           /* 315 */
-       .long sys_utimensat
-       .long sys_signalfd
-       .long sys_timerfd_create
-       .long sys_eventfd
-       .long sys_fallocate             /* 320 */
-       .long sys_timerfd_settime
-       .long sys_timerfd_gettime
-       .long sys_signalfd4
-       .long sys_eventfd2
-       .long sys_epoll_create1         /* 325 */
-       .long sys_dup3
-       .long sys_pipe2
-       .long sys_inotify_init1
-       .long sys_preadv
-       .long sys_pwritev               /* 330 */
-       .long sys_rt_tgsigqueueinfo
-       .long sys_perf_event_open
-       .long sys_get_thread_area
-       .long sys_set_thread_area
-       .long sys_atomic_cmpxchg_32     /* 335 */
-       .long sys_atomic_barrier
-       .long sys_fanotify_init
-       .long sys_fanotify_mark
-       .long sys_prlimit64
-       .long sys_name_to_handle_at     /* 340 */
-       .long sys_open_by_handle_at
-       .long sys_clock_adjtime
-       .long sys_syncfs
-
index 9b8393d..5909e39 100644 (file)
@@ -1,6 +1,4 @@
 /*
- *  linux/arch/m68knommu/kernel/syscalltable.S
- *
  *  Copyright (C) 2002, Greg Ungerer (gerg@snapgear.com)
  *
  *  Based on older entry.S files, the following copyrights apply:
  *                      Kenneth Albanowski <kjahds@kjahds.com>,
  *  Copyright (C) 2000  Lineo Inc. (www.lineo.com) 
  *  Copyright (C) 1991, 1992  Linus Torvalds
+ *
+ *  Linux/m68k support by Hamish Macdonald
  */
 
 #include <linux/sys.h>
 #include <linux/linkage.h>
-#include <asm/unistd.h>
 
-.text
+#ifndef CONFIG_MMU
+#define sys_mmap2              sys_mmap_pgoff
+#endif
+
+.section .rodata
 ALIGN
 ENTRY(sys_call_table)
-       .long sys_restart_syscall       /* 0  -  old "setup()" system call */
+       .long sys_restart_syscall       /* 0 - old "setup()" system call, used for restarting */
        .long sys_exit
        .long sys_fork
        .long sys_read
        .long sys_write
-       .long sys_open          /* 5 */
+       .long sys_open                  /* 5 */
        .long sys_close
        .long sys_waitpid
        .long sys_creat
        .long sys_link
-       .long sys_unlink        /* 10 */
+       .long sys_unlink                /* 10 */
        .long sys_execve
        .long sys_chdir
        .long sys_time
        .long sys_mknod
-       .long sys_chmod         /* 15 */
+       .long sys_chmod                 /* 15 */
        .long sys_chown16
-       .long sys_ni_syscall    /* old break syscall holder */
+       .long sys_ni_syscall            /* old break syscall holder */
        .long sys_stat
        .long sys_lseek
-       .long sys_getpid        /* 20 */
+       .long sys_getpid                /* 20 */
        .long sys_mount
        .long sys_oldumount
        .long sys_setuid16
        .long sys_getuid16
-       .long sys_stime         /* 25 */
+       .long sys_stime                 /* 25 */
        .long sys_ptrace
        .long sys_alarm
        .long sys_fstat
        .long sys_pause
-       .long sys_utime         /* 30 */
-       .long sys_ni_syscall    /* old stty syscall holder */
-       .long sys_ni_syscall    /* old gtty syscall holder */
+       .long sys_utime                 /* 30 */
+       .long sys_ni_syscall            /* old stty syscall holder */
+       .long sys_ni_syscall            /* old gtty syscall holder */
        .long sys_access
        .long sys_nice
-       .long sys_ni_syscall    /* 35 */ /* old ftime syscall holder */
+       .long sys_ni_syscall            /* 35 - old ftime syscall holder */
        .long sys_sync
        .long sys_kill
        .long sys_rename
        .long sys_mkdir
-       .long sys_rmdir         /* 40 */
+       .long sys_rmdir                 /* 40 */
        .long sys_dup
        .long sys_pipe
        .long sys_times
-       .long sys_ni_syscall    /* old prof syscall holder */
-       .long sys_brk           /* 45 */
+       .long sys_ni_syscall            /* old prof syscall holder */
+       .long sys_brk                   /* 45 */
        .long sys_setgid16
        .long sys_getgid16
        .long sys_signal
        .long sys_geteuid16
-       .long sys_getegid16     /* 50 */
+       .long sys_getegid16             /* 50 */
        .long sys_acct
-       .long sys_umount        /* recycled never used phys() */
-       .long sys_ni_syscall    /* old lock syscall holder */
+       .long sys_umount                /* recycled never used phys() */
+       .long sys_ni_syscall            /* old lock syscall holder */
        .long sys_ioctl
-       .long sys_fcntl         /* 55 */
-       .long sys_ni_syscall    /* old mpx syscall holder */
+       .long sys_fcntl                 /* 55 */
+       .long sys_ni_syscall            /* old mpx syscall holder */
        .long sys_setpgid
-       .long sys_ni_syscall    /* old ulimit syscall holder */
+       .long sys_ni_syscall            /* old ulimit syscall holder */
        .long sys_ni_syscall
-       .long sys_umask         /* 60 */
+       .long sys_umask                 /* 60 */
        .long sys_chroot
        .long sys_ustat
        .long sys_dup2
        .long sys_getppid
-       .long sys_getpgrp       /* 65 */
+       .long sys_getpgrp               /* 65 */
        .long sys_setsid
        .long sys_sigaction
        .long sys_sgetmask
        .long sys_ssetmask
-       .long sys_setreuid16    /* 70 */
+       .long sys_setreuid16            /* 70 */
        .long sys_setregid16
        .long sys_sigsuspend
        .long sys_sigpending
        .long sys_sethostname
-       .long sys_setrlimit     /* 75 */
+       .long sys_setrlimit             /* 75 */
        .long sys_old_getrlimit
        .long sys_getrusage
        .long sys_gettimeofday
        .long sys_settimeofday
-       .long sys_getgroups16   /* 80 */
+       .long sys_getgroups16           /* 80 */
        .long sys_setgroups16
        .long sys_old_select
        .long sys_symlink
        .long sys_lstat
-       .long sys_readlink      /* 85 */
+       .long sys_readlink              /* 85 */
        .long sys_uselib
-       .long sys_ni_syscall    /* sys_swapon */
+       .long sys_swapon
        .long sys_reboot
        .long sys_old_readdir
-       .long sys_old_mmap      /* 90 */
+       .long sys_old_mmap              /* 90 */
        .long sys_munmap
        .long sys_truncate
        .long sys_ftruncate
        .long sys_fchmod
-       .long sys_fchown16      /* 95 */
+       .long sys_fchown16              /* 95 */
        .long sys_getpriority
        .long sys_setpriority
-       .long sys_ni_syscall    /* old profil syscall holder */
+       .long sys_ni_syscall            /* old profil syscall holder */
        .long sys_statfs
-       .long sys_fstatfs       /* 100 */
-       .long sys_ni_syscall    /* ioperm for i386 */
+       .long sys_fstatfs               /* 100 */
+       .long sys_ni_syscall            /* ioperm for i386 */
        .long sys_socketcall
        .long sys_syslog
        .long sys_setitimer
-       .long sys_getitimer     /* 105 */
+       .long sys_getitimer             /* 105 */
        .long sys_newstat
        .long sys_newlstat
        .long sys_newfstat
        .long sys_ni_syscall
-       .long sys_ni_syscall    /* iopl for i386 */ /* 110 */
+       .long sys_ni_syscall            /* 110 - iopl for i386 */
        .long sys_vhangup
-       .long sys_ni_syscall    /* obsolete idle() syscall */
-       .long sys_ni_syscall    /* vm86old for i386 */
+       .long sys_ni_syscall            /* obsolete idle() syscall */
+       .long sys_ni_syscall            /* vm86old for i386 */
        .long sys_wait4
-       .long sys_ni_syscall    /* 115 */ /* sys_swapoff */
+       .long sys_swapoff               /* 115 */
        .long sys_sysinfo
        .long sys_ipc
        .long sys_fsync
        .long sys_sigreturn
-       .long sys_clone         /* 120 */
+       .long sys_clone                 /* 120 */
        .long sys_setdomainname
        .long sys_newuname
-       .long sys_cacheflush    /* modify_ldt for i386 */
+       .long sys_cacheflush            /* modify_ldt for i386 */
        .long sys_adjtimex
-       .long sys_ni_syscall    /* 125 */ /* sys_mprotect */
+       .long sys_mprotect              /* 125 */
        .long sys_sigprocmask
-       .long sys_ni_syscall    /* old "creat_module" */
+       .long sys_ni_syscall            /* old "create_module" */
        .long sys_init_module
        .long sys_delete_module
-       .long sys_ni_syscall    /* 130: old "get_kernel_syms" */
+       .long sys_ni_syscall            /* 130 - old "get_kernel_syms" */
        .long sys_quotactl
        .long sys_getpgid
        .long sys_fchdir
        .long sys_bdflush
-       .long sys_sysfs         /* 135 */
+       .long sys_sysfs                 /* 135 */
        .long sys_personality
-       .long sys_ni_syscall    /* for afs_syscall */
+       .long sys_ni_syscall            /* for afs_syscall */
        .long sys_setfsuid16
        .long sys_setfsgid16
-       .long sys_llseek        /* 140 */
+       .long sys_llseek                /* 140 */
        .long sys_getdents
        .long sys_select
        .long sys_flock
-       .long sys_ni_syscall    /* sys_msync */
-       .long sys_readv         /* 145 */
+       .long sys_msync
+       .long sys_readv                 /* 145 */
        .long sys_writev
        .long sys_getsid
        .long sys_fdatasync
        .long sys_sysctl
-       .long sys_ni_syscall    /* 150 */ /* sys_mlock */
-       .long sys_ni_syscall    /* sys_munlock */
-       .long sys_ni_syscall    /* sys_mlockall */
-       .long sys_ni_syscall    /* sys_munlockall */
+       .long sys_mlock                 /* 150 */
+       .long sys_munlock
+       .long sys_mlockall
+       .long sys_munlockall
        .long sys_sched_setparam
-       .long sys_sched_getparam /* 155 */
+       .long sys_sched_getparam        /* 155 */
        .long sys_sched_setscheduler
        .long sys_sched_getscheduler
        .long sys_sched_yield
@@ -181,124 +184,124 @@ ENTRY(sys_call_table)
        .long sys_sched_get_priority_min  /* 160 */
        .long sys_sched_rr_get_interval
        .long sys_nanosleep
-       .long sys_ni_syscall    /* sys_mremap */
+       .long sys_mremap
        .long sys_setresuid16
-       .long sys_getresuid16   /* 165 */
-       .long sys_getpagesize   /* sys_getpagesize */
-       .long sys_ni_syscall    /* old "query_module" */
+       .long sys_getresuid16           /* 165 */
+       .long sys_getpagesize
+       .long sys_ni_syscall            /* old "query_module" */
        .long sys_poll
-       .long sys_ni_syscall    /* sys_nfsservctl */
-       .long sys_setresgid16   /* 170 */
+       .long sys_nfsservctl
+       .long sys_setresgid16           /* 170 */
        .long sys_getresgid16
        .long sys_prctl
        .long sys_rt_sigreturn
        .long sys_rt_sigaction
-       .long sys_rt_sigprocmask /* 175 */
+       .long sys_rt_sigprocmask        /* 175 */
        .long sys_rt_sigpending
        .long sys_rt_sigtimedwait
        .long sys_rt_sigqueueinfo
        .long sys_rt_sigsuspend
-       .long sys_pread64       /* 180 */
+       .long sys_pread64               /* 180 */
        .long sys_pwrite64
        .long sys_lchown16
        .long sys_getcwd
        .long sys_capget
-       .long sys_capset        /* 185 */
+       .long sys_capset                /* 185 */
        .long sys_sigaltstack
        .long sys_sendfile
-       .long sys_ni_syscall    /* streams1 */
-       .long sys_ni_syscall    /* streams2 */
-       .long sys_vfork         /* 190 */
+       .long sys_ni_syscall            /* streams1 */
+       .long sys_ni_syscall            /* streams2 */
+       .long sys_vfork                 /* 190 */
        .long sys_getrlimit
-       .long sys_mmap_pgoff
+       .long sys_mmap2
        .long sys_truncate64
        .long sys_ftruncate64
-       .long sys_stat64        /* 195 */
+       .long sys_stat64                /* 195 */
        .long sys_lstat64
        .long sys_fstat64
        .long sys_chown
        .long sys_getuid
-       .long sys_getgid        /* 200 */
+       .long sys_getgid                /* 200 */
        .long sys_geteuid
        .long sys_getegid
        .long sys_setreuid
        .long sys_setregid
-       .long sys_getgroups     /* 205 */
+       .long sys_getgroups             /* 205 */
        .long sys_setgroups
        .long sys_fchown
        .long sys_setresuid
        .long sys_getresuid
-       .long sys_setresgid     /* 210 */
+       .long sys_setresgid             /* 210 */
        .long sys_getresgid
        .long sys_lchown
        .long sys_setuid
        .long sys_setgid
-       .long sys_setfsuid      /* 215 */
+       .long sys_setfsuid              /* 215 */
        .long sys_setfsgid
        .long sys_pivot_root
        .long sys_ni_syscall
        .long sys_ni_syscall
-       .long sys_getdents64    /* 220 */
+       .long sys_getdents64            /* 220 */
        .long sys_gettid
        .long sys_tkill
        .long sys_setxattr
        .long sys_lsetxattr
-       .long sys_fsetxattr     /* 225 */
+       .long sys_fsetxattr             /* 225 */
        .long sys_getxattr
        .long sys_lgetxattr
        .long sys_fgetxattr
        .long sys_listxattr
-       .long sys_llistxattr    /* 230 */
+       .long sys_llistxattr            /* 230 */
        .long sys_flistxattr
        .long sys_removexattr
        .long sys_lremovexattr
        .long sys_fremovexattr
-       .long sys_futex         /* 235 */
+       .long sys_futex                 /* 235 */
        .long sys_sendfile64
-       .long sys_ni_syscall    /* sys_mincore */
-       .long sys_ni_syscall    /* sys_madvise */
+       .long sys_mincore
+       .long sys_madvise
        .long sys_fcntl64
-       .long sys_readahead     /* 240 */
+       .long sys_readahead             /* 240 */
        .long sys_io_setup
        .long sys_io_destroy
        .long sys_io_getevents
        .long sys_io_submit
-       .long sys_io_cancel     /* 245 */
+       .long sys_io_cancel             /* 245 */
        .long sys_fadvise64
        .long sys_exit_group
        .long sys_lookup_dcookie
        .long sys_epoll_create
-       .long sys_epoll_ctl     /* 250 */
+       .long sys_epoll_ctl             /* 250 */
        .long sys_epoll_wait
-       .long sys_ni_syscall    /* sys_remap_file_pages */
+       .long sys_remap_file_pages
        .long sys_set_tid_address
        .long sys_timer_create
-       .long sys_timer_settime /* 255 */
+       .long sys_timer_settime         /* 255 */
        .long sys_timer_gettime
        .long sys_timer_getoverrun
        .long sys_timer_delete
        .long sys_clock_settime
-       .long sys_clock_gettime /* 260 */
+       .long sys_clock_gettime         /* 260 */
        .long sys_clock_getres
        .long sys_clock_nanosleep
        .long sys_statfs64
        .long sys_fstatfs64
-       .long sys_tgkill        /* 265 */
+       .long sys_tgkill                /* 265 */
        .long sys_utimes
        .long sys_fadvise64_64
-       .long sys_mbind 
+       .long sys_mbind
        .long sys_get_mempolicy
-       .long sys_set_mempolicy /* 270 */
+       .long sys_set_mempolicy         /* 270 */
        .long sys_mq_open
        .long sys_mq_unlink
        .long sys_mq_timedsend
        .long sys_mq_timedreceive
-       .long sys_mq_notify     /* 275 */
+       .long sys_mq_notify             /* 275 */
        .long sys_mq_getsetattr
        .long sys_waitid
-       .long sys_ni_syscall    /* for sys_vserver */
+       .long sys_ni_syscall            /* for sys_vserver */
        .long sys_add_key
-       .long sys_request_key   /* 280 */
+       .long sys_request_key           /* 280 */
        .long sys_keyctl
        .long sys_ioprio_set
        .long sys_ioprio_get
@@ -319,8 +322,8 @@ ENTRY(sys_call_table)
        .long sys_readlinkat
        .long sys_fchmodat
        .long sys_faccessat             /* 300 */
-       .long sys_ni_syscall            /* Reserved for pselect6 */
-       .long sys_ni_syscall            /* Reserved for ppoll */
+       .long sys_pselect6
+       .long sys_ppoll
        .long sys_unshare
        .long sys_set_robust_list
        .long sys_get_robust_list       /* 305 */
@@ -363,7 +366,3 @@ ENTRY(sys_call_table)
        .long sys_clock_adjtime
        .long sys_syncfs
 
-       .rept NR_syscalls-(.-sys_call_table)/4
-               .long sys_ni_syscall
-       .endr
-
index 878be5f..d099359 100644 (file)
@@ -25,6 +25,8 @@ SECTIONS
 
   EXCEPTION_TABLE(16)
 
+  _sdata = .;                  /* Start of data section */
+
   RODATA
 
   RW_DATA_SECTION(16, PAGE_SIZE, THREAD_SIZE)
index 1ad6b7a..8080469 100644 (file)
@@ -25,6 +25,7 @@ SECTIONS
   _etext = .;                  /* End of text section */
 
   EXCEPTION_TABLE(16) :data
+  _sdata = .;                  /* Start of rw data section */
   RW_DATA_SECTION(16, PAGE_SIZE, THREAD_SIZE) :data
   /* End of data goes *here* so that freeing init code works properly. */
   _edata = .;
index d8a214f..e5550ce 100644 (file)
@@ -217,16 +217,12 @@ static struct clocksource clocksource_microblaze = {
        .rating         = 300,
        .read           = microblaze_read,
        .mask           = CLOCKSOURCE_MASK(32),
-       .shift          = 8, /* I can shift it */
        .flags          = CLOCK_SOURCE_IS_CONTINUOUS,
 };
 
 static int __init microblaze_clocksource_init(void)
 {
-       clocksource_microblaze.mult =
-                       clocksource_hz2mult(timer_clock_freq,
-                                               clocksource_microblaze.shift);
-       if (clocksource_register(&clocksource_microblaze))
+       if (clocksource_register_hz(&clocksource_microblaze, timer_clock_freq))
                panic("failed to register clocksource");
 
        /* stop timer1 */
index 7ff9b54..aef6c91 100644 (file)
@@ -11,6 +11,7 @@ platforms += dec
 platforms += emma
 platforms += jazz
 platforms += jz4740
+platforms += lantiq
 platforms += lasat
 platforms += loongson
 platforms += mipssim
index 8e256cc..cef1a85 100644 (file)
@@ -212,6 +212,24 @@ config MACH_JZ4740
        select HAVE_PWM
        select HAVE_CLK
 
+config LANTIQ
+       bool "Lantiq based platforms"
+       select DMA_NONCOHERENT
+       select IRQ_CPU
+       select CEVT_R4K
+       select CSRC_R4K
+       select SYS_HAS_CPU_MIPS32_R1
+       select SYS_HAS_CPU_MIPS32_R2
+       select SYS_SUPPORTS_BIG_ENDIAN
+       select SYS_SUPPORTS_32BIT_KERNEL
+       select SYS_SUPPORTS_MULTITHREADING
+       select SYS_HAS_EARLY_PRINTK
+       select ARCH_REQUIRE_GPIOLIB
+       select SWAP_IO_SPACE
+       select BOOT_RAW
+       select HAVE_CLK
+       select MIPS_MACHINE
+
 config LASAT
        bool "LASAT Networks platforms"
        select CEVT_R4K
@@ -736,6 +754,33 @@ config CAVIUM_OCTEON_REFERENCE_BOARD
                Hikari
          Say Y here for most Octeon reference boards.
 
+config NLM_XLR_BOARD
+       bool "Netlogic XLR/XLS based systems"
+       depends on EXPERIMENTAL
+       select BOOT_ELF32
+       select NLM_COMMON
+       select NLM_XLR
+       select SYS_HAS_CPU_XLR
+       select SYS_SUPPORTS_SMP
+       select HW_HAS_PCI
+       select SWAP_IO_SPACE
+       select SYS_SUPPORTS_32BIT_KERNEL
+       select SYS_SUPPORTS_64BIT_KERNEL
+       select 64BIT_PHYS_ADDR
+       select SYS_SUPPORTS_BIG_ENDIAN
+       select SYS_SUPPORTS_HIGHMEM
+       select DMA_COHERENT
+       select NR_CPUS_DEFAULT_32
+       select CEVT_R4K
+       select CSRC_R4K
+       select IRQ_CPU
+       select ZONE_DMA if 64BIT
+       select SYNC_R4K
+       select SYS_HAS_EARLY_PRINTK
+       help
+         Support for systems based on Netlogic XLR and XLS processors.
+         Say Y here if you have a XLR or XLS based board.
+
 endchoice
 
 source "arch/mips/alchemy/Kconfig"
@@ -743,6 +788,7 @@ source "arch/mips/ath79/Kconfig"
 source "arch/mips/bcm63xx/Kconfig"
 source "arch/mips/jazz/Kconfig"
 source "arch/mips/jz4740/Kconfig"
+source "arch/mips/lantiq/Kconfig"
 source "arch/mips/lasat/Kconfig"
 source "arch/mips/pmc-sierra/Kconfig"
 source "arch/mips/powertv/Kconfig"
@@ -752,6 +798,7 @@ source "arch/mips/txx9/Kconfig"
 source "arch/mips/vr41xx/Kconfig"
 source "arch/mips/cavium-octeon/Kconfig"
 source "arch/mips/loongson/Kconfig"
+source "arch/mips/netlogic/Kconfig"
 
 endmenu
 
@@ -997,9 +1044,6 @@ config IRQ_GT641XX
 config IRQ_GIC
        bool
 
-config IRQ_CPU_OCTEON
-       bool
-
 config MIPS_BOARDS_GEN
        bool
 
@@ -1359,8 +1403,6 @@ config CPU_SB1
 config CPU_CAVIUM_OCTEON
        bool "Cavium Octeon processor"
        depends on SYS_HAS_CPU_CAVIUM_OCTEON
-       select IRQ_CPU
-       select IRQ_CPU_OCTEON
        select CPU_HAS_PREFETCH
        select CPU_SUPPORTS_64BIT_KERNEL
        select SYS_SUPPORTS_SMP
@@ -1425,6 +1467,17 @@ config CPU_BMIPS5000
        help
          Broadcom BMIPS5000 processors.
 
+config CPU_XLR
+       bool "Netlogic XLR SoC"
+       depends on SYS_HAS_CPU_XLR
+       select CPU_SUPPORTS_32BIT_KERNEL
+       select CPU_SUPPORTS_64BIT_KERNEL
+       select CPU_SUPPORTS_HIGHMEM
+       select WEAK_ORDERING
+       select WEAK_REORDERING_BEYOND_LLSC
+       select CPU_SUPPORTS_HUGEPAGES
+       help
+         Netlogic Microsystems XLR/XLS processors.
 endchoice
 
 if CPU_LOONGSON2F
@@ -1555,6 +1608,9 @@ config SYS_HAS_CPU_BMIPS4380
 config SYS_HAS_CPU_BMIPS5000
        bool
 
+config SYS_HAS_CPU_XLR
+       bool
+
 #
 # CPU may reorder R->R, R->W, W->R, W->W
 # Reordering beyond LL and SC is handled in WEAK_REORDERING_BEYOND_LLSC
@@ -2339,6 +2395,7 @@ config MMU
 
 config I8253
        bool
+       select CLKSRC_I8253
        select MIPS_EXTERNAL_TIMER
 
 config ZONE_DMA32
index 53e3514..884819c 100644 (file)
@@ -191,6 +191,18 @@ endif
 #
 include $(srctree)/arch/mips/Kbuild.platforms
 
+#
+# NETLOGIC SOC Common (common)
+#
+cflags-$(CONFIG_NLM_COMMON)            += -I$(srctree)/arch/mips/include/asm/mach-netlogic
+cflags-$(CONFIG_NLM_COMMON)            += -I$(srctree)/arch/mips/include/asm/netlogic
+
+#
+# NETLOGIC XLR/XLS SoC, Simulator and boards
+#
+core-$(CONFIG_NLM_XLR)                 += arch/mips/netlogic/xlr/
+load-$(CONFIG_NLM_XLR_BOARD)           += 0xffffffff84000000
+
 cflags-y                       += -I$(srctree)/arch/mips/include/asm/mach-generic
 drivers-$(CONFIG_PCI)          += arch/mips/pci/
 
index ca0506a..3a5abb5 100644 (file)
@@ -36,7 +36,7 @@
 #include <linux/spinlock.h>
 #include <linux/interrupt.h>
 #include <linux/module.h>
-#include <linux/sysdev.h>
+#include <linux/syscore_ops.h>
 #include <asm/mach-au1x00/au1000.h>
 #include <asm/mach-au1x00/au1xxx_dbdma.h>
 
@@ -58,7 +58,8 @@ static DEFINE_SPINLOCK(au1xxx_dbdma_spin_lock);
 /* I couldn't find a macro that did this... */
 #define ALIGN_ADDR(x, a)       ((((u32)(x)) + (a-1)) & ~(a-1))
 
-static dbdma_global_t *dbdma_gptr = (dbdma_global_t *)DDMA_GLOBAL_BASE;
+static dbdma_global_t *dbdma_gptr =
+                       (dbdma_global_t *)KSEG1ADDR(AU1550_DBDMA_CONF_PHYS_ADDR);
 static int dbdma_initialized;
 
 static dbdev_tab_t dbdev_tab[] = {
@@ -299,7 +300,7 @@ u32 au1xxx_dbdma_chan_alloc(u32 srcid, u32 destid,
        if (ctp != NULL) {
                memset(ctp, 0, sizeof(chan_tab_t));
                ctp->chan_index = chan = i;
-               dcp = DDMA_CHANNEL_BASE;
+               dcp = KSEG1ADDR(AU1550_DBDMA_PHYS_ADDR);
                dcp += (0x0100 * chan);
                ctp->chan_ptr = (au1x_dma_chan_t *)dcp;
                cp = (au1x_dma_chan_t *)dcp;
@@ -958,105 +959,75 @@ u32 au1xxx_dbdma_put_dscr(u32 chanid, au1x_ddma_desc_t *dscr)
 }
 
 
-struct alchemy_dbdma_sysdev {
-       struct sys_device sysdev;
-       u32 pm_regs[NUM_DBDMA_CHANS + 1][6];
-};
+static unsigned long alchemy_dbdma_pm_data[NUM_DBDMA_CHANS + 1][6];
 
-static int alchemy_dbdma_suspend(struct sys_device *dev,
-                                pm_message_t state)
+static int alchemy_dbdma_suspend(void)
 {
-       struct alchemy_dbdma_sysdev *sdev =
-               container_of(dev, struct alchemy_dbdma_sysdev, sysdev);
        int i;
-       u32 addr;
+       void __iomem *addr;
 
-       addr = DDMA_GLOBAL_BASE;
-       sdev->pm_regs[0][0] = au_readl(addr + 0x00);
-       sdev->pm_regs[0][1] = au_readl(addr + 0x04);
-       sdev->pm_regs[0][2] = au_readl(addr + 0x08);
-       sdev->pm_regs[0][3] = au_readl(addr + 0x0c);
+       addr = (void __iomem *)KSEG1ADDR(AU1550_DBDMA_CONF_PHYS_ADDR);
+       alchemy_dbdma_pm_data[0][0] = __raw_readl(addr + 0x00);
+       alchemy_dbdma_pm_data[0][1] = __raw_readl(addr + 0x04);
+       alchemy_dbdma_pm_data[0][2] = __raw_readl(addr + 0x08);
+       alchemy_dbdma_pm_data[0][3] = __raw_readl(addr + 0x0c);
 
        /* save channel configurations */
-       for (i = 1, addr = DDMA_CHANNEL_BASE; i <= NUM_DBDMA_CHANS; i++) {
-               sdev->pm_regs[i][0] = au_readl(addr + 0x00);
-               sdev->pm_regs[i][1] = au_readl(addr + 0x04);
-               sdev->pm_regs[i][2] = au_readl(addr + 0x08);
-               sdev->pm_regs[i][3] = au_readl(addr + 0x0c);
-               sdev->pm_regs[i][4] = au_readl(addr + 0x10);
-               sdev->pm_regs[i][5] = au_readl(addr + 0x14);
+       addr = (void __iomem *)KSEG1ADDR(AU1550_DBDMA_PHYS_ADDR);
+       for (i = 1; i <= NUM_DBDMA_CHANS; i++) {
+               alchemy_dbdma_pm_data[i][0] = __raw_readl(addr + 0x00);
+               alchemy_dbdma_pm_data[i][1] = __raw_readl(addr + 0x04);
+               alchemy_dbdma_pm_data[i][2] = __raw_readl(addr + 0x08);
+               alchemy_dbdma_pm_data[i][3] = __raw_readl(addr + 0x0c);
+               alchemy_dbdma_pm_data[i][4] = __raw_readl(addr + 0x10);
+               alchemy_dbdma_pm_data[i][5] = __raw_readl(addr + 0x14);
 
                /* halt channel */
-               au_writel(sdev->pm_regs[i][0] & ~1, addr + 0x00);
-               au_sync();
-               while (!(au_readl(addr + 0x14) & 1))
-                       au_sync();
+               __raw_writel(alchemy_dbdma_pm_data[i][0] & ~1, addr + 0x00);
+               wmb();
+               while (!(__raw_readl(addr + 0x14) & 1))
+                       wmb();
 
                addr += 0x100;  /* next channel base */
        }
        /* disable channel interrupts */
-       au_writel(0, DDMA_GLOBAL_BASE + 0x0c);
-       au_sync();
+       addr = (void __iomem *)KSEG1ADDR(AU1550_DBDMA_CONF_PHYS_ADDR);
+       __raw_writel(0, addr + 0x0c);
+       wmb();
 
        return 0;
 }
 
-static int alchemy_dbdma_resume(struct sys_device *dev)
+static void alchemy_dbdma_resume(void)
 {
-       struct alchemy_dbdma_sysdev *sdev =
-               container_of(dev, struct alchemy_dbdma_sysdev, sysdev);
        int i;
-       u32 addr;
+       void __iomem *addr;
 
-       addr = DDMA_GLOBAL_BASE;
-       au_writel(sdev->pm_regs[0][0], addr + 0x00);
-       au_writel(sdev->pm_regs[0][1], addr + 0x04);
-       au_writel(sdev->pm_regs[0][2], addr + 0x08);
-       au_writel(sdev->pm_regs[0][3], addr + 0x0c);
+       addr = (void __iomem *)KSEG1ADDR(AU1550_DBDMA_CONF_PHYS_ADDR);
+       __raw_writel(alchemy_dbdma_pm_data[0][0], addr + 0x00);
+       __raw_writel(alchemy_dbdma_pm_data[0][1], addr + 0x04);
+       __raw_writel(alchemy_dbdma_pm_data[0][2], addr + 0x08);
+       __raw_writel(alchemy_dbdma_pm_data[0][3], addr + 0x0c);
 
        /* restore channel configurations */
-       for (i = 1, addr = DDMA_CHANNEL_BASE; i <= NUM_DBDMA_CHANS; i++) {
-               au_writel(sdev->pm_regs[i][0], addr + 0x00);
-               au_writel(sdev->pm_regs[i][1], addr + 0x04);
-               au_writel(sdev->pm_regs[i][2], addr + 0x08);
-               au_writel(sdev->pm_regs[i][3], addr + 0x0c);
-               au_writel(sdev->pm_regs[i][4], addr + 0x10);
-               au_writel(sdev->pm_regs[i][5], addr + 0x14);
-               au_sync();
+       addr = (void __iomem *)KSEG1ADDR(AU1550_DBDMA_PHYS_ADDR);
+       for (i = 1; i <= NUM_DBDMA_CHANS; i++) {
+               __raw_writel(alchemy_dbdma_pm_data[i][0], addr + 0x00);
+               __raw_writel(alchemy_dbdma_pm_data[i][1], addr + 0x04);
+               __raw_writel(alchemy_dbdma_pm_data[i][2], addr + 0x08);
+               __raw_writel(alchemy_dbdma_pm_data[i][3], addr + 0x0c);
+               __raw_writel(alchemy_dbdma_pm_data[i][4], addr + 0x10);
+               __raw_writel(alchemy_dbdma_pm_data[i][5], addr + 0x14);
+               wmb();
                addr += 0x100;  /* next channel base */
        }
-
-       return 0;
 }
 
-static struct sysdev_class alchemy_dbdma_sysdev_class = {
-       .name           = "dbdma",
+static struct syscore_ops alchemy_dbdma_syscore_ops = {
        .suspend        = alchemy_dbdma_suspend,
        .resume         = alchemy_dbdma_resume,
 };
 
-static int __init alchemy_dbdma_sysdev_init(void)
-{
-       struct alchemy_dbdma_sysdev *sdev;
-       int ret;
-
-       ret = sysdev_class_register(&alchemy_dbdma_sysdev_class);
-       if (ret)
-               return ret;
-
-       sdev = kzalloc(sizeof(struct alchemy_dbdma_sysdev), GFP_KERNEL);
-       if (!sdev)
-               return -ENOMEM;
-
-       sdev->sysdev.id = -1;
-       sdev->sysdev.cls = &alchemy_dbdma_sysdev_class;
-       ret = sysdev_register(&sdev->sysdev);
-       if (ret)
-               kfree(sdev);
-
-       return ret;
-}
-
 static int __init au1xxx_dbdma_init(void)
 {
        int irq_nr, ret;
@@ -1084,11 +1055,7 @@ static int __init au1xxx_dbdma_init(void)
        else {
                dbdma_initialized = 1;
                printk(KERN_INFO "Alchemy DBDMA initialized\n");
-               ret = alchemy_dbdma_sysdev_init();
-               if (ret) {
-                       printk(KERN_ERR "DBDMA PM init failed\n");
-                       ret = 0;
-               }
+               register_syscore_ops(&alchemy_dbdma_syscore_ops);
        }
 
        return ret;
index d527887..347980e 100644 (file)
@@ -58,6 +58,9 @@
  * returned from request_dma.
  */
 
+/* DMA Channel register block spacing */
+#define DMA_CHANNEL_LEN                0x00000100
+
 DEFINE_SPINLOCK(au1000_dma_spin_lock);
 
 struct dma_chan au1000_dma_table[NUM_AU1000_DMA_CHANNELS] = {
@@ -77,22 +80,23 @@ static const struct dma_dev {
        unsigned int fifo_addr;
        unsigned int dma_mode;
 } dma_dev_table[DMA_NUM_DEV] = {
-       {UART0_ADDR + UART_TX, 0},
-       {UART0_ADDR + UART_RX, 0},
-       {0, 0},
-       {0, 0},
-       {AC97C_DATA, DMA_DW16 },          /* coherent */
-       {AC97C_DATA, DMA_DR | DMA_DW16 }, /* coherent */
-       {UART3_ADDR + UART_TX, DMA_DW8 | DMA_NC},
-       {UART3_ADDR + UART_RX, DMA_DR | DMA_DW8 | DMA_NC},
-       {USBD_EP0RD, DMA_DR | DMA_DW8 | DMA_NC},
-       {USBD_EP0WR, DMA_DW8 | DMA_NC},
-       {USBD_EP2WR, DMA_DW8 | DMA_NC},
-       {USBD_EP3WR, DMA_DW8 | DMA_NC},
-       {USBD_EP4RD, DMA_DR | DMA_DW8 | DMA_NC},
-       {USBD_EP5RD, DMA_DR | DMA_DW8 | DMA_NC},
-       {I2S_DATA, DMA_DW32 | DMA_NC},
-       {I2S_DATA, DMA_DR | DMA_DW32 | DMA_NC}
+       { AU1000_UART0_PHYS_ADDR + 0x04, DMA_DW8 },             /* UART0_TX */
+       { AU1000_UART0_PHYS_ADDR + 0x00, DMA_DW8 | DMA_DR },    /* UART0_RX */
+       { 0, 0 },       /* DMA_REQ0 */
+       { 0, 0 },       /* DMA_REQ1 */
+       { AU1000_AC97_PHYS_ADDR + 0x08, DMA_DW16 },             /* AC97 TX c */
+       { AU1000_AC97_PHYS_ADDR + 0x08, DMA_DW16 | DMA_DR },    /* AC97 RX c */
+       { AU1000_UART3_PHYS_ADDR + 0x04, DMA_DW8 | DMA_NC },    /* UART3_TX */
+       { AU1000_UART3_PHYS_ADDR + 0x00, DMA_DW8 | DMA_NC | DMA_DR }, /* UART3_RX */
+       { AU1000_USBD_PHYS_ADDR + 0x00, DMA_DW8 | DMA_NC | DMA_DR }, /* EP0RD */
+       { AU1000_USBD_PHYS_ADDR + 0x04, DMA_DW8 | DMA_NC }, /* EP0WR */
+       { AU1000_USBD_PHYS_ADDR + 0x08, DMA_DW8 | DMA_NC }, /* EP2WR */
+       { AU1000_USBD_PHYS_ADDR + 0x0c, DMA_DW8 | DMA_NC }, /* EP3WR */
+       { AU1000_USBD_PHYS_ADDR + 0x10, DMA_DW8 | DMA_NC | DMA_DR }, /* EP4RD */
+       { AU1000_USBD_PHYS_ADDR + 0x14, DMA_DW8 | DMA_NC | DMA_DR }, /* EP5RD */
+       /* on Au1500, these 2 are DMA_REQ2/3 (GPIO208/209) instead! */
+       { AU1000_I2S_PHYS_ADDR + 0x00, DMA_DW32 | DMA_NC},      /* I2S TX */
+       { AU1000_I2S_PHYS_ADDR + 0x00, DMA_DW32 | DMA_NC | DMA_DR}, /* I2S RX */
 };
 
 int au1000_dma_read_proc(char *buf, char **start, off_t fpos,
@@ -123,10 +127,10 @@ int au1000_dma_read_proc(char *buf, char **start, off_t fpos,
 
 /* Device FIFO addresses and default DMA modes - 2nd bank */
 static const struct dma_dev dma_dev_table_bank2[DMA_NUM_DEV_BANK2] = {
-       { SD0_XMIT_FIFO, DMA_DS | DMA_DW8 },            /* coherent */
-       { SD0_RECV_FIFO, DMA_DS | DMA_DR | DMA_DW8 },   /* coherent */
-       { SD1_XMIT_FIFO, DMA_DS | DMA_DW8 },            /* coherent */
-       { SD1_RECV_FIFO, DMA_DS | DMA_DR | DMA_DW8 }    /* coherent */
+       { AU1100_SD0_PHYS_ADDR + 0x00, DMA_DS | DMA_DW8 },              /* coherent */
+       { AU1100_SD0_PHYS_ADDR + 0x04, DMA_DS | DMA_DW8 | DMA_DR },     /* coherent */
+       { AU1100_SD1_PHYS_ADDR + 0x00, DMA_DS | DMA_DW8 },              /* coherent */
+       { AU1100_SD1_PHYS_ADDR + 0x04, DMA_DS | DMA_DW8 | DMA_DR }      /* coherent */
 };
 
 void dump_au1000_dma_channel(unsigned int dmanr)
@@ -202,7 +206,7 @@ int request_au1000_dma(int dev_id, const char *dev_str,
        }
 
        /* fill it in */
-       chan->io = DMA_CHANNEL_BASE + i * DMA_CHANNEL_LEN;
+       chan->io = KSEG1ADDR(AU1000_DMA_PHYS_ADDR) + i * DMA_CHANNEL_LEN;
        chan->dev_id = dev_id;
        chan->dev_str = dev_str;
        chan->fifo_addr = dev->fifo_addr;
index 55dd7c8..8b60ba0 100644 (file)
@@ -30,7 +30,7 @@
 #include <linux/interrupt.h>
 #include <linux/irq.h>
 #include <linux/slab.h>
-#include <linux/sysdev.h>
+#include <linux/syscore_ops.h>
 
 #include <asm/irq_cpu.h>
 #include <asm/mipsregs.h>
 #include <asm/mach-pb1x00/pb1000.h>
 #endif
 
+/* Interrupt Controller register offsets */
+#define IC_CFG0RD      0x40
+#define IC_CFG0SET     0x40
+#define IC_CFG0CLR     0x44
+#define IC_CFG1RD      0x48
+#define IC_CFG1SET     0x48
+#define IC_CFG1CLR     0x4C
+#define IC_CFG2RD      0x50
+#define IC_CFG2SET     0x50
+#define IC_CFG2CLR     0x54
+#define IC_REQ0INT     0x54
+#define IC_SRCRD       0x58
+#define IC_SRCSET      0x58
+#define IC_SRCCLR      0x5C
+#define IC_REQ1INT     0x5C
+#define IC_ASSIGNRD    0x60
+#define IC_ASSIGNSET   0x60
+#define IC_ASSIGNCLR   0x64
+#define IC_WAKERD      0x68
+#define IC_WAKESET     0x68
+#define IC_WAKECLR     0x6C
+#define IC_MASKRD      0x70
+#define IC_MASKSET     0x70
+#define IC_MASKCLR     0x74
+#define IC_RISINGRD    0x78
+#define IC_RISINGCLR   0x78
+#define IC_FALLINGRD   0x7C
+#define IC_FALLINGCLR  0x7C
+#define IC_TESTBIT     0x80
+
 static int au1x_ic_settype(struct irq_data *d, unsigned int flow_type);
 
 /* NOTE on interrupt priorities: The original writers of this code said:
@@ -221,89 +251,101 @@ struct au1xxx_irqmap au1200_irqmap[] __initdata = {
 static void au1x_ic0_unmask(struct irq_data *d)
 {
        unsigned int bit = d->irq - AU1000_INTC0_INT_BASE;
-       au_writel(1 << bit, IC0_MASKSET);
-       au_writel(1 << bit, IC0_WAKESET);
-       au_sync();
+       void __iomem *base = (void __iomem *)KSEG1ADDR(AU1000_IC0_PHYS_ADDR);
+
+       __raw_writel(1 << bit, base + IC_MASKSET);
+       __raw_writel(1 << bit, base + IC_WAKESET);
+       wmb();
 }
 
 static void au1x_ic1_unmask(struct irq_data *d)
 {
        unsigned int bit = d->irq - AU1000_INTC1_INT_BASE;
-       au_writel(1 << bit, IC1_MASKSET);
-       au_writel(1 << bit, IC1_WAKESET);
+       void __iomem *base = (void __iomem *)KSEG1ADDR(AU1000_IC1_PHYS_ADDR);
+
+       __raw_writel(1 << bit, base + IC_MASKSET);
+       __raw_writel(1 << bit, base + IC_WAKESET);
 
 /* very hacky. does the pb1000 cpld auto-disable this int?
  * nowhere in the current kernel sources is it disabled.       --mlau
  */
 #if defined(CONFIG_MIPS_PB1000)
        if (d->irq == AU1000_GPIO15_INT)
-               au_writel(0x4000, PB1000_MDR); /* enable int */
+               __raw_writel(0x4000, (void __iomem *)PB1000_MDR); /* enable int */
 #endif
-       au_sync();
+       wmb();
 }
 
 static void au1x_ic0_mask(struct irq_data *d)
 {
        unsigned int bit = d->irq - AU1000_INTC0_INT_BASE;
-       au_writel(1 << bit, IC0_MASKCLR);
-       au_writel(1 << bit, IC0_WAKECLR);
-       au_sync();
+       void __iomem *base = (void __iomem *)KSEG1ADDR(AU1000_IC0_PHYS_ADDR);
+
+       __raw_writel(1 << bit, base + IC_MASKCLR);
+       __raw_writel(1 << bit, base + IC_WAKECLR);
+       wmb();
 }
 
 static void au1x_ic1_mask(struct irq_data *d)
 {
        unsigned int bit = d->irq - AU1000_INTC1_INT_BASE;
-       au_writel(1 << bit, IC1_MASKCLR);
-       au_writel(1 << bit, IC1_WAKECLR);
-       au_sync();
+       void __iomem *base = (void __iomem *)KSEG1ADDR(AU1000_IC1_PHYS_ADDR);
+
+       __raw_writel(1 << bit, base + IC_MASKCLR);
+       __raw_writel(1 << bit, base + IC_WAKECLR);
+       wmb();
 }
 
 static void au1x_ic0_ack(struct irq_data *d)
 {
        unsigned int bit = d->irq - AU1000_INTC0_INT_BASE;
+       void __iomem *base = (void __iomem *)KSEG1ADDR(AU1000_IC0_PHYS_ADDR);
 
        /*
         * This may assume that we don't get interrupts from
         * both edges at once, or if we do, that we don't care.
         */
-       au_writel(1 << bit, IC0_FALLINGCLR);
-       au_writel(1 << bit, IC0_RISINGCLR);
-       au_sync();
+       __raw_writel(1 << bit, base + IC_FALLINGCLR);
+       __raw_writel(1 << bit, base + IC_RISINGCLR);
+       wmb();
 }
 
 static void au1x_ic1_ack(struct irq_data *d)
 {
        unsigned int bit = d->irq - AU1000_INTC1_INT_BASE;
+       void __iomem *base = (void __iomem *)KSEG1ADDR(AU1000_IC1_PHYS_ADDR);
 
        /*
         * This may assume that we don't get interrupts from
         * both edges at once, or if we do, that we don't care.
         */
-       au_writel(1 << bit, IC1_FALLINGCLR);
-       au_writel(1 << bit, IC1_RISINGCLR);
-       au_sync();
+       __raw_writel(1 << bit, base + IC_FALLINGCLR);
+       __raw_writel(1 << bit, base + IC_RISINGCLR);
+       wmb();
 }
 
 static void au1x_ic0_maskack(struct irq_data *d)
 {
        unsigned int bit = d->irq - AU1000_INTC0_INT_BASE;
+       void __iomem *base = (void __iomem *)KSEG1ADDR(AU1000_IC0_PHYS_ADDR);
 
-       au_writel(1 << bit, IC0_WAKECLR);
-       au_writel(1 << bit, IC0_MASKCLR);
-       au_writel(1 << bit, IC0_RISINGCLR);
-       au_writel(1 << bit, IC0_FALLINGCLR);
-       au_sync();
+       __raw_writel(1 << bit, base + IC_WAKECLR);
+       __raw_writel(1 << bit, base + IC_MASKCLR);
+       __raw_writel(1 << bit, base + IC_RISINGCLR);
+       __raw_writel(1 << bit, base + IC_FALLINGCLR);
+       wmb();
 }
 
 static void au1x_ic1_maskack(struct irq_data *d)
 {
        unsigned int bit = d->irq - AU1000_INTC1_INT_BASE;
+       void __iomem *base = (void __iomem *)KSEG1ADDR(AU1000_IC1_PHYS_ADDR);
 
-       au_writel(1 << bit, IC1_WAKECLR);
-       au_writel(1 << bit, IC1_MASKCLR);
-       au_writel(1 << bit, IC1_RISINGCLR);
-       au_writel(1 << bit, IC1_FALLINGCLR);
-       au_sync();
+       __raw_writel(1 << bit, base + IC_WAKECLR);
+       __raw_writel(1 << bit, base + IC_MASKCLR);
+       __raw_writel(1 << bit, base + IC_RISINGCLR);
+       __raw_writel(1 << bit, base + IC_FALLINGCLR);
+       wmb();
 }
 
 static int au1x_ic1_setwake(struct irq_data *d, unsigned int on)
@@ -318,13 +360,13 @@ static int au1x_ic1_setwake(struct irq_data *d, unsigned int on)
                return -EINVAL;
 
        local_irq_save(flags);
-       wakemsk = au_readl(SYS_WAKEMSK);
+       wakemsk = __raw_readl((void __iomem *)SYS_WAKEMSK);
        if (on)
                wakemsk |= 1 << bit;
        else
                wakemsk &= ~(1 << bit);
-       au_writel(wakemsk, SYS_WAKEMSK);
-       au_sync();
+       __raw_writel(wakemsk, (void __iomem *)SYS_WAKEMSK);
+       wmb();
        local_irq_restore(flags);
 
        return 0;
@@ -356,81 +398,74 @@ static struct irq_chip au1x_ic1_chip = {
 static int au1x_ic_settype(struct irq_data *d, unsigned int flow_type)
 {
        struct irq_chip *chip;
-       unsigned long icr[6];
-       unsigned int bit, ic, irq = d->irq;
+       unsigned int bit, irq = d->irq;
        irq_flow_handler_t handler = NULL;
        unsigned char *name = NULL;
+       void __iomem *base;
        int ret;
 
        if (irq >= AU1000_INTC1_INT_BASE) {
                bit = irq - AU1000_INTC1_INT_BASE;
                chip = &au1x_ic1_chip;
-               ic = 1;
+               base = (void __iomem *)KSEG1ADDR(AU1000_IC1_PHYS_ADDR);
        } else {
                bit = irq - AU1000_INTC0_INT_BASE;
                chip = &au1x_ic0_chip;
-               ic = 0;
+               base = (void __iomem *)KSEG1ADDR(AU1000_IC0_PHYS_ADDR);
        }
 
        if (bit > 31)
                return -EINVAL;
 
-       icr[0] = ic ? IC1_CFG0SET : IC0_CFG0SET;
-       icr[1] = ic ? IC1_CFG1SET : IC0_CFG1SET;
-       icr[2] = ic ? IC1_CFG2SET : IC0_CFG2SET;
-       icr[3] = ic ? IC1_CFG0CLR : IC0_CFG0CLR;
-       icr[4] = ic ? IC1_CFG1CLR : IC0_CFG1CLR;
-       icr[5] = ic ? IC1_CFG2CLR : IC0_CFG2CLR;
-
        ret = 0;
 
        switch (flow_type) {    /* cfgregs 2:1:0 */
        case IRQ_TYPE_EDGE_RISING:      /* 0:0:1 */
-               au_writel(1 << bit, icr[5]);
-               au_writel(1 << bit, icr[4]);
-               au_writel(1 << bit, icr[0]);
+               __raw_writel(1 << bit, base + IC_CFG2CLR);
+               __raw_writel(1 << bit, base + IC_CFG1CLR);
+               __raw_writel(1 << bit, base + IC_CFG0SET);
                handler = handle_edge_irq;
                name = "riseedge";
                break;
        case IRQ_TYPE_EDGE_FALLING:     /* 0:1:0 */
-               au_writel(1 << bit, icr[5]);
-               au_writel(1 << bit, icr[1]);
-               au_writel(1 << bit, icr[3]);
+               __raw_writel(1 << bit, base + IC_CFG2CLR);
+               __raw_writel(1 << bit, base + IC_CFG1SET);
+               __raw_writel(1 << bit, base + IC_CFG0CLR);
                handler = handle_edge_irq;
                name = "falledge";
                break;
        case IRQ_TYPE_EDGE_BOTH:        /* 0:1:1 */
-               au_writel(1 << bit, icr[5]);
-               au_writel(1 << bit, icr[1]);
-               au_writel(1 << bit, icr[0]);
+               __raw_writel(1 << bit, base + IC_CFG2CLR);
+               __raw_writel(1 << bit, base + IC_CFG1SET);
+               __raw_writel(1 << bit, base + IC_CFG0SET);
                handler = handle_edge_irq;
                name = "bothedge";
                break;
        case IRQ_TYPE_LEVEL_HIGH:       /* 1:0:1 */
-               au_writel(1 << bit, icr[2]);
-               au_writel(1 << bit, icr[4]);
-               au_writel(1 << bit, icr[0]);
+               __raw_writel(1 << bit, base + IC_CFG2SET);
+               __raw_writel(1 << bit, base + IC_CFG1CLR);
+               __raw_writel(1 << bit, base + IC_CFG0SET);
                handler = handle_level_irq;
                name = "hilevel";
                break;
        case IRQ_TYPE_LEVEL_LOW:        /* 1:1:0 */
-               au_writel(1 << bit, icr[2]);
-               au_writel(1 << bit, icr[1]);
-               au_writel(1 << bit, icr[3]);
+               __raw_writel(1 << bit, base + IC_CFG2SET);
+               __raw_writel(1 << bit, base + IC_CFG1SET);
+               __raw_writel(1 << bit, base + IC_CFG0CLR);
                handler = handle_level_irq;
                name = "lowlevel";
                break;
        case IRQ_TYPE_NONE:             /* 0:0:0 */
-               au_writel(1 << bit, icr[5]);
-               au_writel(1 << bit, icr[4]);
-               au_writel(1 << bit, icr[3]);
+               __raw_writel(1 << bit, base + IC_CFG2CLR);
+               __raw_writel(1 << bit, base + IC_CFG1CLR);
+               __raw_writel(1 << bit, base + IC_CFG0CLR);
                break;
        default:
                ret = -EINVAL;
        }
        __irq_set_chip_handler_name_locked(d->irq, chip, handler, name);
 
-       au_sync();
+       wmb();
 
        return ret;
 }
@@ -444,21 +479,21 @@ asmlinkage void plat_irq_dispatch(void)
                off = MIPS_CPU_IRQ_BASE + 7;
                goto handle;
        } else if (pending & CAUSEF_IP2) {
-               s = IC0_REQ0INT;
+               s = KSEG1ADDR(AU1000_IC0_PHYS_ADDR) + IC_REQ0INT;
                off = AU1000_INTC0_INT_BASE;
        } else if (pending & CAUSEF_IP3) {
-               s = IC0_REQ1INT;
+               s = KSEG1ADDR(AU1000_IC0_PHYS_ADDR) + IC_REQ1INT;
                off = AU1000_INTC0_INT_BASE;
        } else if (pending & CAUSEF_IP4) {
-               s = IC1_REQ0INT;
+               s = KSEG1ADDR(AU1000_IC1_PHYS_ADDR) + IC_REQ0INT;
                off = AU1000_INTC1_INT_BASE;
        } else if (pending & CAUSEF_IP5) {
-               s = IC1_REQ1INT;
+               s = KSEG1ADDR(AU1000_IC1_PHYS_ADDR) + IC_REQ1INT;
                off = AU1000_INTC1_INT_BASE;
        } else
                goto spurious;
 
-       s = au_readl(s);
+       s = __raw_readl((void __iomem *)s);
        if (unlikely(!s)) {
 spurious:
                spurious_interrupt();
@@ -469,48 +504,42 @@ handle:
        do_IRQ(off);
 }
 
+
+static inline void ic_init(void __iomem *base)
+{
+       /* initialize interrupt controller to a safe state */
+       __raw_writel(0xffffffff, base + IC_CFG0CLR);
+       __raw_writel(0xffffffff, base + IC_CFG1CLR);
+       __raw_writel(0xffffffff, base + IC_CFG2CLR);
+       __raw_writel(0xffffffff, base + IC_MASKCLR);
+       __raw_writel(0xffffffff, base + IC_ASSIGNCLR);
+       __raw_writel(0xffffffff, base + IC_WAKECLR);
+       __raw_writel(0xffffffff, base + IC_SRCSET);
+       __raw_writel(0xffffffff, base + IC_FALLINGCLR);
+       __raw_writel(0xffffffff, base + IC_RISINGCLR);
+       __raw_writel(0x00000000, base + IC_TESTBIT);
+       wmb();
+}
+
 static void __init au1000_init_irq(struct au1xxx_irqmap *map)
 {
        unsigned int bit, irq_nr;
-       int i;
-
-       /*
-        * Initialize interrupt controllers to a safe state.
-        */
-       au_writel(0xffffffff, IC0_CFG0CLR);
-       au_writel(0xffffffff, IC0_CFG1CLR);
-       au_writel(0xffffffff, IC0_CFG2CLR);
-       au_writel(0xffffffff, IC0_MASKCLR);
-       au_writel(0xffffffff, IC0_ASSIGNCLR);
-       au_writel(0xffffffff, IC0_WAKECLR);
-       au_writel(0xffffffff, IC0_SRCSET);
-       au_writel(0xffffffff, IC0_FALLINGCLR);
-       au_writel(0xffffffff, IC0_RISINGCLR);
-       au_writel(0x00000000, IC0_TESTBIT);
-
-       au_writel(0xffffffff, IC1_CFG0CLR);
-       au_writel(0xffffffff, IC1_CFG1CLR);
-       au_writel(0xffffffff, IC1_CFG2CLR);
-       au_writel(0xffffffff, IC1_MASKCLR);
-       au_writel(0xffffffff, IC1_ASSIGNCLR);
-       au_writel(0xffffffff, IC1_WAKECLR);
-       au_writel(0xffffffff, IC1_SRCSET);
-       au_writel(0xffffffff, IC1_FALLINGCLR);
-       au_writel(0xffffffff, IC1_RISINGCLR);
-       au_writel(0x00000000, IC1_TESTBIT);
+       void __iomem *base;
 
+       ic_init((void __iomem *)KSEG1ADDR(AU1000_IC0_PHYS_ADDR));
+       ic_init((void __iomem *)KSEG1ADDR(AU1000_IC1_PHYS_ADDR));
        mips_cpu_irq_init();
 
        /* register all 64 possible IC0+IC1 irq sources as type "none".
         * Use set_irq_type() to set edge/level behaviour at runtime.
         */
-       for (i = AU1000_INTC0_INT_BASE;
-            (i < AU1000_INTC0_INT_BASE + 32); i++)
-               au1x_ic_settype(irq_get_irq_data(i), IRQ_TYPE_NONE);
+       for (irq_nr = AU1000_INTC0_INT_BASE;
+            (irq_nr < AU1000_INTC0_INT_BASE + 32); irq_nr++)
+               au1x_ic_settype(irq_get_irq_data(irq_nr), IRQ_TYPE_NONE);
 
-       for (i = AU1000_INTC1_INT_BASE;
-            (i < AU1000_INTC1_INT_BASE + 32); i++)
-               au1x_ic_settype(irq_get_irq_data(i), IRQ_TYPE_NONE);
+       for (irq_nr = AU1000_INTC1_INT_BASE;
+            (irq_nr < AU1000_INTC1_INT_BASE + 32); irq_nr++)
+               au1x_ic_settype(irq_get_irq_data(irq_nr), IRQ_TYPE_NONE);
 
        /*
         * Initialize IC0, which is fixed per processor.
@@ -520,13 +549,13 @@ static void __init au1000_init_irq(struct au1xxx_irqmap *map)
 
                if (irq_nr >= AU1000_INTC1_INT_BASE) {
                        bit = irq_nr - AU1000_INTC1_INT_BASE;
-                       if (map->im_request)
-                               au_writel(1 << bit, IC1_ASSIGNSET);
+                       base = (void __iomem *)KSEG1ADDR(AU1000_IC1_PHYS_ADDR);
                } else {
                        bit = irq_nr - AU1000_INTC0_INT_BASE;
-                       if (map->im_request)
-                               au_writel(1 << bit, IC0_ASSIGNSET);
+                       base = (void __iomem *)KSEG1ADDR(AU1000_IC0_PHYS_ADDR);
                }
+               if (map->im_request)
+                       __raw_writel(1 << bit, base + IC_ASSIGNSET);
 
                au1x_ic_settype(irq_get_irq_data(irq_nr), map->im_type);
                ++map;
@@ -556,90 +585,62 @@ void __init arch_init_irq(void)
        }
 }
 
-struct alchemy_ic_sysdev {
-       struct sys_device sysdev;
-       void __iomem *base;
-       unsigned long pmdata[7];
-};
 
-static int alchemy_ic_suspend(struct sys_device *dev, pm_message_t state)
-{
-       struct alchemy_ic_sysdev *icdev =
-                       container_of(dev, struct alchemy_ic_sysdev, sysdev);
+static unsigned long alchemy_ic_pmdata[7 * 2];
 
-       icdev->pmdata[0] = __raw_readl(icdev->base + IC_CFG0RD);
-       icdev->pmdata[1] = __raw_readl(icdev->base + IC_CFG1RD);
-       icdev->pmdata[2] = __raw_readl(icdev->base + IC_CFG2RD);
-       icdev->pmdata[3] = __raw_readl(icdev->base + IC_SRCRD);
-       icdev->pmdata[4] = __raw_readl(icdev->base + IC_ASSIGNRD);
-       icdev->pmdata[5] = __raw_readl(icdev->base + IC_WAKERD);
-       icdev->pmdata[6] = __raw_readl(icdev->base + IC_MASKRD);
-
-       return 0;
+static inline void alchemy_ic_suspend_one(void __iomem *base, unsigned long *d)
+{
+       d[0] = __raw_readl(base + IC_CFG0RD);
+       d[1] = __raw_readl(base + IC_CFG1RD);
+       d[2] = __raw_readl(base + IC_CFG2RD);
+       d[3] = __raw_readl(base + IC_SRCRD);
+       d[4] = __raw_readl(base + IC_ASSIGNRD);
+       d[5] = __raw_readl(base + IC_WAKERD);
+       d[6] = __raw_readl(base + IC_MASKRD);
+       ic_init(base);          /* shut it up too while at it */
 }
 
-static int alchemy_ic_resume(struct sys_device *dev)
+static inline void alchemy_ic_resume_one(void __iomem *base, unsigned long *d)
 {
-       struct alchemy_ic_sysdev *icdev =
-                       container_of(dev, struct alchemy_ic_sysdev, sysdev);
-
-       __raw_writel(0xffffffff, icdev->base + IC_MASKCLR);
-       __raw_writel(0xffffffff, icdev->base + IC_CFG0CLR);
-       __raw_writel(0xffffffff, icdev->base + IC_CFG1CLR);
-       __raw_writel(0xffffffff, icdev->base + IC_CFG2CLR);
-       __raw_writel(0xffffffff, icdev->base + IC_SRCCLR);
-       __raw_writel(0xffffffff, icdev->base + IC_ASSIGNCLR);
-       __raw_writel(0xffffffff, icdev->base + IC_WAKECLR);
-       __raw_writel(0xffffffff, icdev->base + IC_RISINGCLR);
-       __raw_writel(0xffffffff, icdev->base + IC_FALLINGCLR);
-       __raw_writel(0x00000000, icdev->base + IC_TESTBIT);
-       wmb();
-       __raw_writel(icdev->pmdata[0], icdev->base + IC_CFG0SET);
-       __raw_writel(icdev->pmdata[1], icdev->base + IC_CFG1SET);
-       __raw_writel(icdev->pmdata[2], icdev->base + IC_CFG2SET);
-       __raw_writel(icdev->pmdata[3], icdev->base + IC_SRCSET);
-       __raw_writel(icdev->pmdata[4], icdev->base + IC_ASSIGNSET);
-       __raw_writel(icdev->pmdata[5], icdev->base + IC_WAKESET);
+       ic_init(base);
+
+       __raw_writel(d[0], base + IC_CFG0SET);
+       __raw_writel(d[1], base + IC_CFG1SET);
+       __raw_writel(d[2], base + IC_CFG2SET);
+       __raw_writel(d[3], base + IC_SRCSET);
+       __raw_writel(d[4], base + IC_ASSIGNSET);
+       __raw_writel(d[5], base + IC_WAKESET);
        wmb();
 
-       __raw_writel(icdev->pmdata[6], icdev->base + IC_MASKSET);
+       __raw_writel(d[6], base + IC_MASKSET);
        wmb();
+}
 
+static int alchemy_ic_suspend(void)
+{
+       alchemy_ic_suspend_one((void __iomem *)KSEG1ADDR(AU1000_IC0_PHYS_ADDR),
+                              alchemy_ic_pmdata);
+       alchemy_ic_suspend_one((void __iomem *)KSEG1ADDR(AU1000_IC1_PHYS_ADDR),
+                              &alchemy_ic_pmdata[7]);
        return 0;
 }
 
-static struct sysdev_class alchemy_ic_sysdev_class = {
-       .name           = "ic",
+static void alchemy_ic_resume(void)
+{
+       alchemy_ic_resume_one((void __iomem *)KSEG1ADDR(AU1000_IC1_PHYS_ADDR),
+                             &alchemy_ic_pmdata[7]);
+       alchemy_ic_resume_one((void __iomem *)KSEG1ADDR(AU1000_IC0_PHYS_ADDR),
+                             alchemy_ic_pmdata);
+}
+
+static struct syscore_ops alchemy_ic_syscore_ops = {
        .suspend        = alchemy_ic_suspend,
        .resume         = alchemy_ic_resume,
 };
 
-static int __init alchemy_ic_sysdev_init(void)
+static int __init alchemy_ic_pm_init(void)
 {
-       struct alchemy_ic_sysdev *icdev;
-       unsigned long icbase[2] = { IC0_PHYS_ADDR, IC1_PHYS_ADDR };
-       int err, i;
-
-       err = sysdev_class_register(&alchemy_ic_sysdev_class);
-       if (err)
-               return err;
-
-       for (i = 0; i < 2; i++) {
-               icdev = kzalloc(sizeof(struct alchemy_ic_sysdev), GFP_KERNEL);
-               if (!icdev)
-                       return -ENOMEM;
-
-               icdev->base = ioremap(icbase[i], 0x1000);
-
-               icdev->sysdev.id = i;
-               icdev->sysdev.cls = &alchemy_ic_sysdev_class;
-               err = sysdev_register(&icdev->sysdev);
-               if (err) {
-                       kfree(icdev);
-                       return err;
-               }
-       }
-
+       register_syscore_ops(&alchemy_ic_syscore_ops);
        return 0;
 }
-device_initcall(alchemy_ic_sysdev_init);
+device_initcall(alchemy_ic_pm_init);
index 9e7814d..3b2c18b 100644 (file)
 
 #include <linux/dma-mapping.h>
 #include <linux/etherdevice.h>
+#include <linux/init.h>
 #include <linux/platform_device.h>
 #include <linux/serial_8250.h>
-#include <linux/init.h>
+#include <linux/slab.h>
 
 #include <asm/mach-au1x00/au1xxx.h>
 #include <asm/mach-au1x00/au1xxx_dbdma.h>
@@ -30,21 +31,12 @@ static void alchemy_8250_pm(struct uart_port *port, unsigned int state,
 #ifdef CONFIG_SERIAL_8250
        switch (state) {
        case 0:
-               if ((__raw_readl(port->membase + UART_MOD_CNTRL) & 3) != 3) {
-                       /* power-on sequence as suggested in the databooks */
-                       __raw_writel(0, port->membase + UART_MOD_CNTRL);
-                       wmb();
-                       __raw_writel(1, port->membase + UART_MOD_CNTRL);
-                       wmb();
-               }
-               __raw_writel(3, port->membase + UART_MOD_CNTRL); /* full on */
-               wmb();
+               alchemy_uart_enable(CPHYSADDR(port->membase));
                serial8250_do_pm(port, state, old_state);
                break;
        case 3:         /* power off */
                serial8250_do_pm(port, state, old_state);
-               __raw_writel(0, port->membase + UART_MOD_CNTRL);
-               wmb();
+               alchemy_uart_disable(CPHYSADDR(port->membase));
                break;
        default:
                serial8250_do_pm(port, state, old_state);
@@ -65,38 +57,60 @@ static void alchemy_8250_pm(struct uart_port *port, unsigned int state,
                .pm             = alchemy_8250_pm,              \
        }
 
-static struct plat_serial8250_port au1x00_uart_data[] = {
-#if defined(CONFIG_SOC_AU1000)
-       PORT(UART0_PHYS_ADDR, AU1000_UART0_INT),
-       PORT(UART1_PHYS_ADDR, AU1000_UART1_INT),
-       PORT(UART2_PHYS_ADDR, AU1000_UART2_INT),
-       PORT(UART3_PHYS_ADDR, AU1000_UART3_INT),
-#elif defined(CONFIG_SOC_AU1500)
-       PORT(UART0_PHYS_ADDR, AU1500_UART0_INT),
-       PORT(UART3_PHYS_ADDR, AU1500_UART3_INT),
-#elif defined(CONFIG_SOC_AU1100)
-       PORT(UART0_PHYS_ADDR, AU1100_UART0_INT),
-       PORT(UART1_PHYS_ADDR, AU1100_UART1_INT),
-       PORT(UART3_PHYS_ADDR, AU1100_UART3_INT),
-#elif defined(CONFIG_SOC_AU1550)
-       PORT(UART0_PHYS_ADDR, AU1550_UART0_INT),
-       PORT(UART1_PHYS_ADDR, AU1550_UART1_INT),
-       PORT(UART3_PHYS_ADDR, AU1550_UART3_INT),
-#elif defined(CONFIG_SOC_AU1200)
-       PORT(UART0_PHYS_ADDR, AU1200_UART0_INT),
-       PORT(UART1_PHYS_ADDR, AU1200_UART1_INT),
-#endif
-       { },
+static struct plat_serial8250_port au1x00_uart_data[][4] __initdata = {
+       [ALCHEMY_CPU_AU1000] = {
+               PORT(AU1000_UART0_PHYS_ADDR, AU1000_UART0_INT),
+               PORT(AU1000_UART1_PHYS_ADDR, AU1000_UART1_INT),
+               PORT(AU1000_UART2_PHYS_ADDR, AU1000_UART2_INT),
+               PORT(AU1000_UART3_PHYS_ADDR, AU1000_UART3_INT),
+       },
+       [ALCHEMY_CPU_AU1500] = {
+               PORT(AU1000_UART0_PHYS_ADDR, AU1500_UART0_INT),
+               PORT(AU1000_UART3_PHYS_ADDR, AU1500_UART3_INT),
+       },
+       [ALCHEMY_CPU_AU1100] = {
+               PORT(AU1000_UART0_PHYS_ADDR, AU1100_UART0_INT),
+               PORT(AU1000_UART1_PHYS_ADDR, AU1100_UART1_INT),
+               PORT(AU1000_UART3_PHYS_ADDR, AU1100_UART3_INT),
+       },
+       [ALCHEMY_CPU_AU1550] = {
+               PORT(AU1000_UART0_PHYS_ADDR, AU1550_UART0_INT),
+               PORT(AU1000_UART1_PHYS_ADDR, AU1550_UART1_INT),
+               PORT(AU1000_UART3_PHYS_ADDR, AU1550_UART3_INT),
+       },
+       [ALCHEMY_CPU_AU1200] = {
+               PORT(AU1000_UART0_PHYS_ADDR, AU1200_UART0_INT),
+               PORT(AU1000_UART1_PHYS_ADDR, AU1200_UART1_INT),
+       },
 };
 
 static struct platform_device au1xx0_uart_device = {
        .name                   = "serial8250",
        .id                     = PLAT8250_DEV_AU1X00,
-       .dev                    = {
-               .platform_data  = au1x00_uart_data,
-       },
 };
 
+static void __init alchemy_setup_uarts(int ctype)
+{
+       unsigned int uartclk = get_au1x00_uart_baud_base() * 16;
+       int s = sizeof(struct plat_serial8250_port);
+       int c = alchemy_get_uarts(ctype);
+       struct plat_serial8250_port *ports;
+
+       ports = kzalloc(s * (c + 1), GFP_KERNEL);
+       if (!ports) {
+               printk(KERN_INFO "Alchemy: no memory for UART data\n");
+               return;
+       }
+       memcpy(ports, au1x00_uart_data[ctype], s * c);
+       au1xx0_uart_device.dev.platform_data = ports;
+
+       /* Fill up uartclk. */
+       for (s = 0; s < c; s++)
+               ports[s].uartclk = uartclk;
+       if (platform_device_register(&au1xx0_uart_device))
+               printk(KERN_INFO "Alchemy: failed to register UARTs\n");
+}
+
 /* OHCI (USB full speed host controller) */
 static struct resource au1xxx_usb_ohci_resources[] = {
        [0] = {
@@ -269,8 +283,8 @@ extern struct au1xmmc_platform_data au1xmmc_platdata[2];
 
 static struct resource au1200_mmc0_resources[] = {
        [0] = {
-               .start          = SD0_PHYS_ADDR,
-               .end            = SD0_PHYS_ADDR + 0x7ffff,
+               .start          = AU1100_SD0_PHYS_ADDR,
+               .end            = AU1100_SD0_PHYS_ADDR + 0xfff,
                .flags          = IORESOURCE_MEM,
        },
        [1] = {
@@ -305,8 +319,8 @@ static struct platform_device au1200_mmc0_device = {
 #ifndef CONFIG_MIPS_DB1200
 static struct resource au1200_mmc1_resources[] = {
        [0] = {
-               .start          = SD1_PHYS_ADDR,
-               .end            = SD1_PHYS_ADDR + 0x7ffff,
+               .start          = AU1100_SD1_PHYS_ADDR,
+               .end            = AU1100_SD1_PHYS_ADDR + 0xfff,
                .flags          = IORESOURCE_MEM,
        },
        [1] = {
@@ -359,15 +373,16 @@ static struct platform_device pbdb_smbus_device = {
 #endif
 
 /* Macro to help defining the Ethernet MAC resources */
+#define MAC_RES_COUNT  3       /* MAC regs base, MAC enable reg, MAC INT */
 #define MAC_RES(_base, _enable, _irq)                  \
        {                                               \
-               .start  = CPHYSADDR(_base),             \
-               .end    = CPHYSADDR(_base + 0xffff),    \
+               .start  = _base,                        \
+               .end    = _base + 0xffff,               \
                .flags  = IORESOURCE_MEM,               \
        },                                              \
        {                                               \
-               .start  = CPHYSADDR(_enable),           \
-               .end    = CPHYSADDR(_enable + 0x3),     \
+               .start  = _enable,                      \
+               .end    = _enable + 0x3,                \
                .flags  = IORESOURCE_MEM,               \
        },                                              \
        {                                               \
@@ -376,19 +391,29 @@ static struct platform_device pbdb_smbus_device = {
                .flags  = IORESOURCE_IRQ                \
        }
 
-static struct resource au1xxx_eth0_resources[] = {
-#if defined(CONFIG_SOC_AU1000)
-       MAC_RES(AU1000_ETH0_BASE, AU1000_MAC0_ENABLE, AU1000_MAC0_DMA_INT),
-#elif defined(CONFIG_SOC_AU1100)
-       MAC_RES(AU1100_ETH0_BASE, AU1100_MAC0_ENABLE, AU1100_MAC0_DMA_INT),
-#elif defined(CONFIG_SOC_AU1550)
-       MAC_RES(AU1550_ETH0_BASE, AU1550_MAC0_ENABLE, AU1550_MAC0_DMA_INT),
-#elif defined(CONFIG_SOC_AU1500)
-       MAC_RES(AU1500_ETH0_BASE, AU1500_MAC0_ENABLE, AU1500_MAC0_DMA_INT),
-#endif
+static struct resource au1xxx_eth0_resources[][MAC_RES_COUNT] __initdata = {
+       [ALCHEMY_CPU_AU1000] = {
+               MAC_RES(AU1000_MAC0_PHYS_ADDR,
+                       AU1000_MACEN_PHYS_ADDR,
+                       AU1000_MAC0_DMA_INT)
+       },
+       [ALCHEMY_CPU_AU1500] = {
+               MAC_RES(AU1500_MAC0_PHYS_ADDR,
+                       AU1500_MACEN_PHYS_ADDR,
+                       AU1500_MAC0_DMA_INT)
+       },
+       [ALCHEMY_CPU_AU1100] = {
+               MAC_RES(AU1000_MAC0_PHYS_ADDR,
+                       AU1000_MACEN_PHYS_ADDR,
+                       AU1100_MAC0_DMA_INT)
+       },
+       [ALCHEMY_CPU_AU1550] = {
+               MAC_RES(AU1000_MAC0_PHYS_ADDR,
+                       AU1000_MACEN_PHYS_ADDR,
+                       AU1550_MAC0_DMA_INT)
+       },
 };
 
-
 static struct au1000_eth_platform_data au1xxx_eth0_platform_data = {
        .phy1_search_mac0 = 1,
 };
@@ -396,20 +421,26 @@ static struct au1000_eth_platform_data au1xxx_eth0_platform_data = {
 static struct platform_device au1xxx_eth0_device = {
        .name           = "au1000-eth",
        .id             = 0,
-       .num_resources  = ARRAY_SIZE(au1xxx_eth0_resources),
-       .resource       = au1xxx_eth0_resources,
+       .num_resources  = MAC_RES_COUNT,
        .dev.platform_data = &au1xxx_eth0_platform_data,
 };
 
-#ifndef CONFIG_SOC_AU1100
-static struct resource au1xxx_eth1_resources[] = {
-#if defined(CONFIG_SOC_AU1000)
-       MAC_RES(AU1000_ETH1_BASE, AU1000_MAC1_ENABLE, AU1000_MAC1_DMA_INT),
-#elif defined(CONFIG_SOC_AU1550)
-       MAC_RES(AU1550_ETH1_BASE, AU1550_MAC1_ENABLE, AU1550_MAC1_DMA_INT),
-#elif defined(CONFIG_SOC_AU1500)
-       MAC_RES(AU1500_ETH1_BASE, AU1500_MAC1_ENABLE, AU1500_MAC1_DMA_INT),
-#endif
+static struct resource au1xxx_eth1_resources[][MAC_RES_COUNT] __initdata = {
+       [ALCHEMY_CPU_AU1000] = {
+               MAC_RES(AU1000_MAC1_PHYS_ADDR,
+                       AU1000_MACEN_PHYS_ADDR + 4,
+                       AU1000_MAC1_DMA_INT)
+       },
+       [ALCHEMY_CPU_AU1500] = {
+               MAC_RES(AU1500_MAC1_PHYS_ADDR,
+                       AU1500_MACEN_PHYS_ADDR + 4,
+                       AU1500_MAC1_DMA_INT)
+       },
+       [ALCHEMY_CPU_AU1550] = {
+               MAC_RES(AU1000_MAC1_PHYS_ADDR,
+                       AU1000_MACEN_PHYS_ADDR + 4,
+                       AU1550_MAC1_DMA_INT)
+       },
 };
 
 static struct au1000_eth_platform_data au1xxx_eth1_platform_data = {
@@ -419,11 +450,9 @@ static struct au1000_eth_platform_data au1xxx_eth1_platform_data = {
 static struct platform_device au1xxx_eth1_device = {
        .name           = "au1000-eth",
        .id             = 1,
-       .num_resources  = ARRAY_SIZE(au1xxx_eth1_resources),
-       .resource       = au1xxx_eth1_resources,
+       .num_resources  = MAC_RES_COUNT,
        .dev.platform_data = &au1xxx_eth1_platform_data,
 };
-#endif
 
 void __init au1xxx_override_eth_cfg(unsigned int port,
                        struct au1000_eth_platform_data *eth_data)
@@ -434,15 +463,65 @@ void __init au1xxx_override_eth_cfg(unsigned int port,
        if (port == 0)
                memcpy(&au1xxx_eth0_platform_data, eth_data,
                        sizeof(struct au1000_eth_platform_data));
-#ifndef CONFIG_SOC_AU1100
        else
                memcpy(&au1xxx_eth1_platform_data, eth_data,
                        sizeof(struct au1000_eth_platform_data));
-#endif
+}
+
+static void __init alchemy_setup_macs(int ctype)
+{
+       int ret, i;
+       unsigned char ethaddr[6];
+       struct resource *macres;
+
+       /* Handle 1st MAC */
+       if (alchemy_get_macs(ctype) < 1)
+               return;
+
+       macres = kmalloc(sizeof(struct resource) * MAC_RES_COUNT, GFP_KERNEL);
+       if (!macres) {
+               printk(KERN_INFO "Alchemy: no memory for MAC0 resources\n");
+               return;
+       }
+       memcpy(macres, au1xxx_eth0_resources[ctype],
+              sizeof(struct resource) * MAC_RES_COUNT);
+       au1xxx_eth0_device.resource = macres;
+
+       i = prom_get_ethernet_addr(ethaddr);
+       if (!i && !is_valid_ether_addr(au1xxx_eth0_platform_data.mac))
+               memcpy(au1xxx_eth0_platform_data.mac, ethaddr, 6);
+
+       ret = platform_device_register(&au1xxx_eth0_device);
+       if (!ret)
+               printk(KERN_INFO "Alchemy: failed to register MAC0\n");
+
+
+       /* Handle 2nd MAC */
+       if (alchemy_get_macs(ctype) < 2)
+               return;
+
+       macres = kmalloc(sizeof(struct resource) * MAC_RES_COUNT, GFP_KERNEL);
+       if (!macres) {
+               printk(KERN_INFO "Alchemy: no memory for MAC1 resources\n");
+               return;
+       }
+       memcpy(macres, au1xxx_eth1_resources[ctype],
+              sizeof(struct resource) * MAC_RES_COUNT);
+       au1xxx_eth1_device.resource = macres;
+
+       ethaddr[5] += 1;        /* next addr for 2nd MAC */
+       if (!i && !is_valid_ether_addr(au1xxx_eth1_platform_data.mac))
+               memcpy(au1xxx_eth1_platform_data.mac, ethaddr, 6);
+
+       /* Register second MAC if enabled in pinfunc */
+       if (!(au_readl(SYS_PINFUNC) & (u32)SYS_PF_NI2)) {
+               ret = platform_device_register(&au1xxx_eth1_device);
+               if (ret)
+                       printk(KERN_INFO "Alchemy: failed to register MAC1\n");
+       }
 }
 
 static struct platform_device *au1xxx_platform_devices[] __initdata = {
-       &au1xx0_uart_device,
        &au1xxx_usb_ohci_device,
 #ifdef CONFIG_FB_AU1100
        &au1100_lcd_device,
@@ -460,36 +539,17 @@ static struct platform_device *au1xxx_platform_devices[] __initdata = {
 #ifdef SMBUS_PSC_BASE
        &pbdb_smbus_device,
 #endif
-       &au1xxx_eth0_device,
 };
 
 static int __init au1xxx_platform_init(void)
 {
-       unsigned int uartclk = get_au1x00_uart_baud_base() * 16;
-       int err, i;
-       unsigned char ethaddr[6];
+       int err, ctype = alchemy_get_cputype();
 
-       /* Fill up uartclk. */
-       for (i = 0; au1x00_uart_data[i].flags; i++)
-               au1x00_uart_data[i].uartclk = uartclk;
-
-       /* use firmware-provided mac addr if available and necessary */
-       i = prom_get_ethernet_addr(ethaddr);
-       if (!i && !is_valid_ether_addr(au1xxx_eth0_platform_data.mac))
-               memcpy(au1xxx_eth0_platform_data.mac, ethaddr, 6);
+       alchemy_setup_uarts(ctype);
+       alchemy_setup_macs(ctype);
 
        err = platform_add_devices(au1xxx_platform_devices,
                                   ARRAY_SIZE(au1xxx_platform_devices));
-#ifndef CONFIG_SOC_AU1100
-       ethaddr[5] += 1;        /* next addr for 2nd MAC */
-       if (!i && !is_valid_ether_addr(au1xxx_eth1_platform_data.mac))
-               memcpy(au1xxx_eth1_platform_data.mac, ethaddr, 6);
-
-       /* Register second MAC if enabled in pinfunc */
-       if (!err && !(au_readl(SYS_PINFUNC) & (u32)SYS_PF_NI2))
-               err = platform_device_register(&au1xxx_eth1_device);
-#endif
-
        return err;
 }
 
index 561e5da..1b887c8 100644 (file)
@@ -52,8 +52,6 @@ void __init plat_mem_setup(void)
        /* this is faster than wasting cycles trying to approximate it */
        preset_lpj = (est_freq >> 1) / HZ;
 
-       board_setup();  /* board specific setup */
-
        if (au1xxx_cpu_needs_config_od())
                /* Various early Au1xx0 errata corrected by this */
                set_c0_config(1 << 19); /* Set Config[OD] */
@@ -61,6 +59,8 @@ void __init plat_mem_setup(void)
                /* Clear to obtain best system bus performance */
                clear_c0_config(1 << 19); /* Clear Config[OD] */
 
+       board_setup();  /* board specific setup */
+
        /* IO/MEM resources. */
        set_io_port_base(0);
        ioport_resource.start = IOPORT_RESOURCE_START;
index 2aecb2f..d5da6ad 100644 (file)
@@ -141,8 +141,7 @@ static int __init alchemy_time_init(unsigned int m2int)
                goto cntr_err;
 
        /* register counter1 clocksource and event device */
-       clocksource_set_clock(&au1x_counter1_clocksource, 32768);
-       clocksource_register(&au1x_counter1_clocksource);
+       clocksource_register_hz(&au1x_counter1_clocksource, 32768);
 
        cd->shift = 32;
        cd->mult = div_sc(32768, NSEC_PER_SEC, cd->shift);
index 4a89800..1dac4f2 100644 (file)
@@ -23,6 +23,13 @@ void __init board_setup(void)
        unsigned long freq0, clksrc, div, pfc;
        unsigned short whoami;
 
+       /* Set Config[OD] (disable overlapping bus transaction):
+        * This gets rid of a _lot_ of spurious interrupts (especially
+        * wrt. IDE); but incurs ~10% performance hit in some
+        * cpu-bound applications.
+        */
+       set_c0_config(1 << 19);
+
        bcsr_init(DB1200_BCSR_PHYS_ADDR,
                  DB1200_BCSR_PHYS_ADDR + DB1200_BCSR_HEXLED_OFS);
 
index 05f120f..5c956fe 100644 (file)
@@ -127,13 +127,10 @@ const char *get_system_type(void)
 void __init board_setup(void)
 {
        unsigned long bcsr1, bcsr2;
-       u32 pin_func;
 
        bcsr1 = DB1000_BCSR_PHYS_ADDR;
        bcsr2 = DB1000_BCSR_PHYS_ADDR + DB1000_BCSR_HEXLED_OFS;
 
-       pin_func = 0;
-
 #ifdef CONFIG_MIPS_DB1000
        printk(KERN_INFO "AMD Alchemy Au1000/Db1000 Board\n");
 #endif
@@ -164,12 +161,16 @@ void __init board_setup(void)
        /* Not valid for Au1550 */
 #if defined(CONFIG_IRDA) && \
    (defined(CONFIG_SOC_AU1000) || defined(CONFIG_SOC_AU1100))
-       /* Set IRFIRSEL instead of GPIO15 */
-       pin_func = au_readl(SYS_PINFUNC) | SYS_PF_IRF;
-       au_writel(pin_func, SYS_PINFUNC);
-       /* Power off until the driver is in use */
-       bcsr_mod(BCSR_RESETS, BCSR_RESETS_IRDA_MODE_MASK,
-                               BCSR_RESETS_IRDA_MODE_OFF);
+       {
+               u32 pin_func;
+
+               /* Set IRFIRSEL instead of GPIO15 */
+               pin_func = au_readl(SYS_PINFUNC) | SYS_PF_IRF;
+               au_writel(pin_func, SYS_PINFUNC);
+               /* Power off until the driver is in use */
+               bcsr_mod(BCSR_RESETS, BCSR_RESETS_IRDA_MODE_MASK,
+                        BCSR_RESETS_IRDA_MODE_OFF);
+       }
 #endif
        bcsr_write(BCSR_PCMCIA, 0);     /* turn off PCMCIA power */
 
@@ -177,31 +178,35 @@ void __init board_setup(void)
        alchemy_gpio1_input_enable();
 
 #ifdef CONFIG_MIPS_MIRAGE
-       /* GPIO[20] is output */
-       alchemy_gpio_direction_output(20, 0);
+       {
+               u32 pin_func;
 
-       /* Set GPIO[210:208] instead of SSI_0 */
-       pin_func = au_readl(SYS_PINFUNC) | SYS_PF_S0;
+               /* GPIO[20] is output */
+               alchemy_gpio_direction_output(20, 0);
 
-       /* Set GPIO[215:211] for LEDs */
-       pin_func |= 5 << 2;
+               /* Set GPIO[210:208] instead of SSI_0 */
+               pin_func = au_readl(SYS_PINFUNC) | SYS_PF_S0;
 
-       /* Set GPIO[214:213] for more LEDs */
-       pin_func |= 5 << 12;
+               /* Set GPIO[215:211] for LEDs */
+               pin_func |= 5 << 2;
 
-       /* Set GPIO[207:200] instead of PCMCIA/LCD */
-       pin_func |= SYS_PF_LCD | SYS_PF_PC;
-       au_writel(pin_func, SYS_PINFUNC);
+               /* Set GPIO[214:213] for more LEDs */
+               pin_func |= 5 << 12;
 
-       /*
-        * Enable speaker amplifier.  This should
-        * be part of the audio driver.
-        */
-       alchemy_gpio_direction_output(209, 1);
+               /* Set GPIO[207:200] instead of PCMCIA/LCD */
+               pin_func |= SYS_PF_LCD | SYS_PF_PC;
+               au_writel(pin_func, SYS_PINFUNC);
 
-       pm_power_off = mirage_power_off;
-       _machine_halt = mirage_power_off;
-       _machine_restart = (void(*)(char *))mips_softreset;
+               /*
+                * Enable speaker amplifier.  This should
+                * be part of the audio driver.
+                */
+               alchemy_gpio_direction_output(209, 1);
+
+               pm_power_off = mirage_power_off;
+               _machine_halt = mirage_power_off;
+               _machine_restart = (void(*)(char *))mips_softreset;
+       }
 #endif
 
 #ifdef CONFIG_MIPS_BOSPORUS
index 2d85c4b..e64fdcb 100644 (file)
@@ -65,7 +65,7 @@ void __init board_setup(void)
 
        /* Set AUX clock to 12 MHz * 8 = 96 MHz */
        au_writel(8, SYS_AUXPLL);
-       au_writel(0, SYS_PINSTATERD);
+       alchemy_gpio1_input_enable();
        udelay(100);
 
 #if defined(CONFIG_USB_OHCI_HCD) || defined(CONFIG_USB_OHCI_HCD_MODULE)
index 83f4621..3b4fa32 100644 (file)
@@ -56,7 +56,7 @@ void __init board_setup(void)
        sys_clksrc = sys_freqctrl = pin_func = 0;
        /* Set AUX clock to 12 MHz * 8 = 96 MHz */
        au_writel(8, SYS_AUXPLL);
-       au_writel(0, SYS_PINSTATERD);
+       alchemy_gpio1_input_enable();
        udelay(100);
 
        /* GPIO201 is input for PCMCIA card detect */
index baeb213..e5306b5 100644 (file)
@@ -62,5 +62,5 @@ void __init prom_init(void)
 
 void prom_putchar(unsigned char c)
 {
-    alchemy_uart_putchar(UART0_PHYS_ADDR, c);
+       alchemy_uart_putchar(AU1000_UART0_PHYS_ADDR, c);
 }
index ad2e3f1..5f8f069 100644 (file)
@@ -36,9 +36,6 @@
 
 #include <prom.h>
 
-#define UART1_ADDR     KSEG1ADDR(UART1_PHYS_ADDR)
-#define UART3_ADDR     KSEG1ADDR(UART3_PHYS_ADDR)
-
 char irq_tab_alchemy[][5] __initdata = {
        [0] = { -1, AU1500_PCI_INTA, AU1500_PCI_INTB, 0xff, 0xff },
 };
@@ -67,18 +64,15 @@ static void gpr_power_off(void)
 
 void __init board_setup(void)
 {
-       printk(KERN_INFO "Tarpeze ITS GPR board\n");
+       printk(KERN_INFO "Trapeze ITS GPR board\n");
 
        pm_power_off = gpr_power_off;
        _machine_halt = gpr_power_off;
        _machine_restart = gpr_reset;
 
-       /* Enable UART3 */
-       au_writel(0x1, UART3_ADDR + UART_MOD_CNTRL);/* clock enable (CE) */
-       au_writel(0x3, UART3_ADDR + UART_MOD_CNTRL); /* CE and "enable" */
-       /* Enable UART1 */
-       au_writel(0x1, UART1_ADDR + UART_MOD_CNTRL); /* clock enable (CE) */
-       au_writel(0x3, UART1_ADDR + UART_MOD_CNTRL); /* CE and "enable" */
+       /* Enable UART1/3 */
+       alchemy_uart_enable(AU1000_UART3_PHYS_ADDR);
+       alchemy_uart_enable(AU1000_UART1_PHYS_ADDR);
 
        /* Take away Reset of UMTS-card */
        alchemy_gpio_direction_output(215, 1);
index f044f4c..229aafa 100644 (file)
@@ -59,5 +59,5 @@ void __init prom_init(void)
 
 void prom_putchar(unsigned char c)
 {
-       alchemy_uart_putchar(UART0_PHYS_ADDR, c);
+       alchemy_uart_putchar(AU1000_UART0_PHYS_ADDR, c);
 }
index cf436ab..3ae984c 100644 (file)
@@ -87,7 +87,7 @@ void __init board_setup(void)
        au_writel(SYS_PF_NI2, SYS_PINFUNC);
 
        /* Initialize GPIO */
-       au_writel(0xFFFFFFFF, SYS_TRIOUTCLR);
+       au_writel(~0, KSEG1ADDR(AU1000_SYS_PHYS_ADDR) + SYS_TRIOUTCLR);
        alchemy_gpio_direction_output(0, 0);    /* Disable M66EN (PCI 66MHz) */
        alchemy_gpio_direction_output(3, 1);    /* Disable PCI CLKRUN# */
        alchemy_gpio_direction_output(1, 1);    /* Enable EXT_IO3 */
index f8d2557..2e81cc7 100644 (file)
@@ -62,5 +62,5 @@ void __init prom_init(void)
 
 void prom_putchar(unsigned char c)
 {
-       alchemy_uart_putchar(UART0_PHYS_ADDR, c);
+       alchemy_uart_putchar(AU1000_UART0_PHYS_ADDR, c);
 }
index 956f946..55628e3 100644 (file)
@@ -53,8 +53,8 @@ static struct platform_device mtx1_button = {
 
 static struct resource mtx1_wdt_res[] = {
        [0] = {
-               .start  = 15,
-               .end    = 15,
+               .start  = 215,
+               .end    = 215,
                .name   = "mtx1-wdt-gpio",
                .flags  = IORESOURCE_IRQ,
        }
index febfb0f..81e57fa 100644 (file)
@@ -66,13 +66,10 @@ void __init board_setup(void)
        au_writel(pin_func, SYS_PINFUNC);
 
        /* Enable UART */
-       au_writel(0x01, UART3_ADDR + UART_MOD_CNTRL); /* clock enable (CE) */
-       mdelay(10);
-       au_writel(0x03, UART3_ADDR + UART_MOD_CNTRL); /* CE and "enable" */
-       mdelay(10);
-
-       /* Enable DTR = USB power up */
-       au_writel(0x01, UART3_ADDR + UART_MCR); /* UART_MCR_DTR is 0x01??? */
+       alchemy_uart_enable(AU1000_UART3_PHYS_ADDR);
+       /* Enable DTR (MCR bit 0) = USB power up */
+       __raw_writel(1, (void __iomem *)KSEG1ADDR(AU1000_UART3_PHYS_ADDR + 0x18));
+       wmb();
 
 #ifdef CONFIG_PCI
 #if defined(__MIPSEB__)
index 15125c2..0ee02cf 100644 (file)
@@ -51,14 +51,13 @@ void __init prom_init(void)
        prom_init_cmdline();
 
        memsize_str = prom_getenv("memsize");
-       if (!memsize_str)
+       if (!memsize_str || strict_strtoul(memsize_str, 0, &memsize))
                memsize = 0x04000000;
-       else
-               strict_strtoul(memsize_str, 0, &memsize);
+
        add_memory_region(0, memsize, BOOT_MEM_RAM);
 }
 
 void prom_putchar(unsigned char c)
 {
-       alchemy_uart_putchar(UART0_PHYS_ADDR, c);
+       alchemy_uart_putchar(AU1000_UART0_PHYS_ADDR, c);
 }
index 425dfa5..bb571bc 100644 (file)
@@ -325,9 +325,7 @@ int __init ar7_gpio_init(void)
                size = 0x1f;
        }
 
-       gpch->regs = ioremap_nocache(AR7_REGS_GPIO,
-                                       AR7_REGS_GPIO + 0x10);
-
+       gpch->regs = ioremap_nocache(AR7_REGS_GPIO, size);
        if (!gpch->regs) {
                printk(KERN_ERR "%s: failed to ioremap regs\n",
                                        gpch->chip.label);
index e5b6615..54db815 100644 (file)
@@ -3,6 +3,7 @@
  *
  * Copyright (C) 2005 Broadcom Corporation
  * Copyright (C) 2006 Felix Fietkau <nbd@openwrt.org>
+ * Copyright (C) 2010-2011 Hauke Mehrtens <hauke@hauke-m.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
@@ -23,7 +24,7 @@
 static char nvram_buf[NVRAM_SPACE];
 
 /* Probe for NVRAM header */
-static void __init early_nvram_init(void)
+static void early_nvram_init(void)
 {
        struct ssb_mipscore *mcore = &ssb_bcm47xx.mipscore;
        struct nvram_header *header;
index c95f90b..73b529b 100644 (file)
@@ -3,6 +3,7 @@
  *  Copyright (C) 2006 Felix Fietkau <nbd@openwrt.org>
  *  Copyright (C) 2006 Michael Buesch <mb@bu3sch.de>
  *  Copyright (C) 2010 Waldemar Brodkorb <wbx@openadk.org>
+ *  Copyright (C) 2010-2011 Hauke Mehrtens <hauke@hauke-m.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
@@ -57,10 +58,49 @@ static void bcm47xx_machine_halt(void)
 }
 
 #define READ_FROM_NVRAM(_outvar, name, buf) \
-       if (nvram_getenv(name, buf, sizeof(buf)) >= 0)\
+       if (nvram_getprefix(prefix, name, buf, sizeof(buf)) >= 0)\
                sprom->_outvar = simple_strtoul(buf, NULL, 0);
 
-static void bcm47xx_fill_sprom(struct ssb_sprom *sprom)
+#define READ_FROM_NVRAM2(_outvar, name1, name2, buf) \
+       if (nvram_getprefix(prefix, name1, buf, sizeof(buf)) >= 0 || \
+           nvram_getprefix(prefix, name2, buf, sizeof(buf)) >= 0)\
+               sprom->_outvar = simple_strtoul(buf, NULL, 0);
+
+static inline int nvram_getprefix(const char *prefix, char *name,
+                                 char *buf, int len)
+{
+       if (prefix) {
+               char key[100];
+
+               snprintf(key, sizeof(key), "%s%s", prefix, name);
+               return nvram_getenv(key, buf, len);
+       }
+
+       return nvram_getenv(name, buf, len);
+}
+
+static u32 nvram_getu32(const char *name, char *buf, int len)
+{
+       int rv;
+       char key[100];
+       u16 var0, var1;
+
+       snprintf(key, sizeof(key), "%s0", name);
+       rv = nvram_getenv(key, buf, len);
+       /* return 0 here so this looks like unset */
+       if (rv < 0)
+               return 0;
+       var0 = simple_strtoul(buf, NULL, 0);
+
+       snprintf(key, sizeof(key), "%s1", name);
+       rv = nvram_getenv(key, buf, len);
+       if (rv < 0)
+               return 0;
+       var1 = simple_strtoul(buf, NULL, 0);
+       return var1 << 16 | var0;
+}
+
+static void bcm47xx_fill_sprom(struct ssb_sprom *sprom, const char *prefix)
 {
        char buf[100];
        u32 boardflags;
@@ -69,11 +109,12 @@ static void bcm47xx_fill_sprom(struct ssb_sprom *sprom)
 
        sprom->revision = 1; /* Fallback: Old hardware does not define this. */
        READ_FROM_NVRAM(revision, "sromrev", buf);
-       if (nvram_getenv("il0macaddr", buf, sizeof(buf)) >= 0)
+       if (nvram_getprefix(prefix, "il0macaddr", buf, sizeof(buf)) >= 0 ||
+           nvram_getprefix(prefix, "macaddr", buf, sizeof(buf)) >= 0)
                nvram_parse_macaddr(buf, sprom->il0mac);
-       if (nvram_getenv("et0macaddr", buf, sizeof(buf)) >= 0)
+       if (nvram_getprefix(prefix, "et0macaddr", buf, sizeof(buf)) >= 0)
                nvram_parse_macaddr(buf, sprom->et0mac);
-       if (nvram_getenv("et1macaddr", buf, sizeof(buf)) >= 0)
+       if (nvram_getprefix(prefix, "et1macaddr", buf, sizeof(buf)) >= 0)
                nvram_parse_macaddr(buf, sprom->et1mac);
        READ_FROM_NVRAM(et0phyaddr, "et0phyaddr", buf);
        READ_FROM_NVRAM(et1phyaddr, "et1phyaddr", buf);
@@ -95,20 +136,36 @@ static void bcm47xx_fill_sprom(struct ssb_sprom *sprom)
        READ_FROM_NVRAM(pa1hib0, "pa1hib0", buf);
        READ_FROM_NVRAM(pa1hib2, "pa1hib1", buf);
        READ_FROM_NVRAM(pa1hib1, "pa1hib2", buf);
-       READ_FROM_NVRAM(gpio0, "wl0gpio0", buf);
-       READ_FROM_NVRAM(gpio1, "wl0gpio1", buf);
-       READ_FROM_NVRAM(gpio2, "wl0gpio2", buf);
-       READ_FROM_NVRAM(gpio3, "wl0gpio3", buf);
-       READ_FROM_NVRAM(maxpwr_bg, "pa0maxpwr", buf);
-       READ_FROM_NVRAM(maxpwr_al, "pa1lomaxpwr", buf);
-       READ_FROM_NVRAM(maxpwr_a, "pa1maxpwr", buf);
-       READ_FROM_NVRAM(maxpwr_ah, "pa1himaxpwr", buf);
-       READ_FROM_NVRAM(itssi_a, "pa1itssit", buf);
-       READ_FROM_NVRAM(itssi_bg, "pa0itssit", buf);
+       READ_FROM_NVRAM2(gpio0, "ledbh0", "wl0gpio0", buf);
+       READ_FROM_NVRAM2(gpio1, "ledbh1", "wl0gpio1", buf);
+       READ_FROM_NVRAM2(gpio2, "ledbh2", "wl0gpio2", buf);
+       READ_FROM_NVRAM2(gpio3, "ledbh3", "wl0gpio3", buf);
+       READ_FROM_NVRAM2(maxpwr_bg, "maxp2ga0", "pa0maxpwr", buf);
+       READ_FROM_NVRAM2(maxpwr_al, "maxp5gla0", "pa1lomaxpwr", buf);
+       READ_FROM_NVRAM2(maxpwr_a, "maxp5ga0", "pa1maxpwr", buf);
+       READ_FROM_NVRAM2(maxpwr_ah, "maxp5gha0", "pa1himaxpwr", buf);
+       READ_FROM_NVRAM2(itssi_bg, "itt5ga0", "pa0itssit", buf);
+       READ_FROM_NVRAM2(itssi_a, "itt2ga0", "pa1itssit", buf);
        READ_FROM_NVRAM(tri2g, "tri2g", buf);
        READ_FROM_NVRAM(tri5gl, "tri5gl", buf);
        READ_FROM_NVRAM(tri5g, "tri5g", buf);
        READ_FROM_NVRAM(tri5gh, "tri5gh", buf);
+       READ_FROM_NVRAM(txpid2g[0], "txpid2ga0", buf);
+       READ_FROM_NVRAM(txpid2g[1], "txpid2ga1", buf);
+       READ_FROM_NVRAM(txpid2g[2], "txpid2ga2", buf);
+       READ_FROM_NVRAM(txpid2g[3], "txpid2ga3", buf);
+       READ_FROM_NVRAM(txpid5g[0], "txpid5ga0", buf);
+       READ_FROM_NVRAM(txpid5g[1], "txpid5ga1", buf);
+       READ_FROM_NVRAM(txpid5g[2], "txpid5ga2", buf);
+       READ_FROM_NVRAM(txpid5g[3], "txpid5ga3", buf);
+       READ_FROM_NVRAM(txpid5gl[0], "txpid5gla0", buf);
+       READ_FROM_NVRAM(txpid5gl[1], "txpid5gla1", buf);
+       READ_FROM_NVRAM(txpid5gl[2], "txpid5gla2", buf);
+       READ_FROM_NVRAM(txpid5gl[3], "txpid5gla3", buf);
+       READ_FROM_NVRAM(txpid5gh[0], "txpid5gha0", buf);
+       READ_FROM_NVRAM(txpid5gh[1], "txpid5gha1", buf);
+       READ_FROM_NVRAM(txpid5gh[2], "txpid5gha2", buf);
+       READ_FROM_NVRAM(txpid5gh[3], "txpid5gha3", buf);
        READ_FROM_NVRAM(rxpo2g, "rxpo2g", buf);
        READ_FROM_NVRAM(rxpo5g, "rxpo5g", buf);
        READ_FROM_NVRAM(rssisav2g, "rssisav2g", buf);
@@ -120,19 +177,27 @@ static void bcm47xx_fill_sprom(struct ssb_sprom *sprom)
        READ_FROM_NVRAM(rssismf5g, "rssismf5g", buf);
        READ_FROM_NVRAM(bxa5g, "bxa5g", buf);
        READ_FROM_NVRAM(cck2gpo, "cck2gpo", buf);
-       READ_FROM_NVRAM(ofdm2gpo, "ofdm2gpo", buf);
-       READ_FROM_NVRAM(ofdm5glpo, "ofdm5glpo", buf);
-       READ_FROM_NVRAM(ofdm5gpo, "ofdm5gpo", buf);
-       READ_FROM_NVRAM(ofdm5ghpo, "ofdm5ghpo", buf);
 
-       if (nvram_getenv("boardflags", buf, sizeof(buf)) >= 0) {
+       sprom->ofdm2gpo = nvram_getu32("ofdm2gpo", buf, sizeof(buf));
+       sprom->ofdm5glpo = nvram_getu32("ofdm5glpo", buf, sizeof(buf));
+       sprom->ofdm5gpo = nvram_getu32("ofdm5gpo", buf, sizeof(buf));
+       sprom->ofdm5ghpo = nvram_getu32("ofdm5ghpo", buf, sizeof(buf));
+
+       READ_FROM_NVRAM(antenna_gain.ghz24.a0, "ag0", buf);
+       READ_FROM_NVRAM(antenna_gain.ghz24.a1, "ag1", buf);
+       READ_FROM_NVRAM(antenna_gain.ghz24.a2, "ag2", buf);
+       READ_FROM_NVRAM(antenna_gain.ghz24.a3, "ag3", buf);
+       memcpy(&sprom->antenna_gain.ghz5, &sprom->antenna_gain.ghz24,
+              sizeof(sprom->antenna_gain.ghz5));
+
+       if (nvram_getprefix(prefix, "boardflags", buf, sizeof(buf)) >= 0) {
                boardflags = simple_strtoul(buf, NULL, 0);
                if (boardflags) {
                        sprom->boardflags_lo = (boardflags & 0x0000FFFFU);
                        sprom->boardflags_hi = (boardflags & 0xFFFF0000U) >> 16;
                }
        }
-       if (nvram_getenv("boardflags2", buf, sizeof(buf)) >= 0) {
+       if (nvram_getprefix(prefix, "boardflags2", buf, sizeof(buf)) >= 0) {
                boardflags = simple_strtoul(buf, NULL, 0);
                if (boardflags) {
                        sprom->boardflags2_lo = (boardflags & 0x0000FFFFU);
@@ -141,6 +206,22 @@ static void bcm47xx_fill_sprom(struct ssb_sprom *sprom)
        }
 }
 
+int bcm47xx_get_sprom(struct ssb_bus *bus, struct ssb_sprom *out)
+{
+       char prefix[10];
+
+       if (bus->bustype == SSB_BUSTYPE_PCI) {
+               snprintf(prefix, sizeof(prefix), "pci/%u/%u/",
+                        bus->host_pci->bus->number + 1,
+                        PCI_SLOT(bus->host_pci->devfn));
+               bcm47xx_fill_sprom(out, prefix);
+               return 0;
+       } else {
+               printk(KERN_WARNING "bcm47xx: unable to fill SPROM for given bustype.\n");
+               return -EINVAL;
+       }
+}
+
 static int bcm47xx_get_invariants(struct ssb_bus *bus,
                                   struct ssb_init_invariants *iv)
 {
@@ -158,7 +239,7 @@ static int bcm47xx_get_invariants(struct ssb_bus *bus,
        if (nvram_getenv("boardrev", buf, sizeof(buf)) >= 0)
                iv->boardinfo.rev = (u16)simple_strtoul(buf, NULL, 0);
 
-       bcm47xx_fill_sprom(&iv->sprom);
+       bcm47xx_fill_sprom(&iv->sprom, NULL);
 
        if (nvram_getenv("cardbus", buf, sizeof(buf)) >= 0)
                iv->has_cardbus_slot = !!simple_strtoul(buf, NULL, 10);
@@ -172,6 +253,11 @@ void __init plat_mem_setup(void)
        char buf[100];
        struct ssb_mipscore *mcore;
 
+       err = ssb_arch_register_fallback_sprom(&bcm47xx_get_sprom);
+       if (err)
+               printk(KERN_WARNING "bcm47xx: someone else already registered"
+                       " a ssb SPROM callback handler (err %d)\n", err);
+
        err = ssb_bus_ssbbus_register(&ssb_bcm47xx, SSB_ENUM_BASE,
                                      bcm47xx_get_invariants);
        if (err)
index 8dba8cf..40b223b 100644 (file)
@@ -643,6 +643,17 @@ static struct ssb_sprom bcm63xx_sprom = {
        .boardflags_lo          = 0x2848,
        .boardflags_hi          = 0x0000,
 };
+
+int bcm63xx_get_fallback_sprom(struct ssb_bus *bus, struct ssb_sprom *out)
+{
+       if (bus->bustype == SSB_BUSTYPE_PCI) {
+               memcpy(out, &bcm63xx_sprom, sizeof(struct ssb_sprom));
+               return 0;
+       } else {
+               printk(KERN_ERR PFX "unable to fill SPROM for given bustype.\n");
+               return -EINVAL;
+       }
+}
 #endif
 
 /*
@@ -793,8 +804,9 @@ void __init board_prom_init(void)
        if (!board_get_mac_address(bcm63xx_sprom.il0mac)) {
                memcpy(bcm63xx_sprom.et0mac, bcm63xx_sprom.il0mac, ETH_ALEN);
                memcpy(bcm63xx_sprom.et1mac, bcm63xx_sprom.il0mac, ETH_ALEN);
-               if (ssb_arch_set_fallback_sprom(&bcm63xx_sprom) < 0)
-                       printk(KERN_ERR "failed to register fallback SPROM\n");
+               if (ssb_arch_register_fallback_sprom(
+                               &bcm63xx_get_fallback_sprom) < 0)
+                       printk(KERN_ERR PFX "failed to register fallback SPROM\n");
        }
 #endif
 }
index 88c9d96..9a62436 100644 (file)
@@ -16,8 +16,8 @@
 
 int main(int argc, char *argv[])
 {
+       unsigned long long vmlinux_size, vmlinux_load_addr, vmlinuz_load_addr;
        struct stat sb;
-       uint64_t vmlinux_size, vmlinux_load_addr, vmlinuz_load_addr;
 
        if (argc != 3) {
                fprintf(stderr, "Usage: %s <pathname> <vmlinux_load_addr>\n",
index 1bff22f..eb063e6 100644 (file)
@@ -3,5 +3,5 @@
 void putc(char c)
 {
        /* all current (Jan. 2010) in-kernel boards */
-       alchemy_uart_putchar(UART0_PHYS_ADDR, c);
+       alchemy_uart_putchar(AU1000_UART0_PHYS_ADDR, c);
 }
index caae228..cad555e 100644 (file)
@@ -1,11 +1,7 @@
-config CAVIUM_OCTEON_SPECIFIC_OPTIONS
-       bool "Enable Octeon specific options"
-       depends on CPU_CAVIUM_OCTEON
-       default "y"
+if CPU_CAVIUM_OCTEON
 
 config CAVIUM_CN63XXP1
        bool "Enable CN63XXP1 errata worarounds"
-       depends on CAVIUM_OCTEON_SPECIFIC_OPTIONS
        default "n"
        help
          The CN63XXP1 chip requires build time workarounds to
@@ -16,7 +12,6 @@ config CAVIUM_CN63XXP1
 
 config CAVIUM_OCTEON_2ND_KERNEL
        bool "Build the kernel to be used as a 2nd kernel on the same chip"
-       depends on CAVIUM_OCTEON_SPECIFIC_OPTIONS
        default "n"
        help
          This option configures this kernel to be linked at a different
@@ -26,7 +21,6 @@ config CAVIUM_OCTEON_2ND_KERNEL
 
 config CAVIUM_OCTEON_HW_FIX_UNALIGNED
        bool "Enable hardware fixups of unaligned loads and stores"
-       depends on CAVIUM_OCTEON_SPECIFIC_OPTIONS
        default "y"
        help
          Configure the Octeon hardware to automatically fix unaligned loads
@@ -38,7 +32,6 @@ config CAVIUM_OCTEON_HW_FIX_UNALIGNED
 
 config CAVIUM_OCTEON_CVMSEG_SIZE
        int "Number of L1 cache lines reserved for CVMSEG memory"
-       depends on CAVIUM_OCTEON_SPECIFIC_OPTIONS
        range 0 54
        default 1
        help
@@ -50,7 +43,6 @@ config CAVIUM_OCTEON_CVMSEG_SIZE
 
 config CAVIUM_OCTEON_LOCK_L2
        bool "Lock often used kernel code in the L2"
-       depends on CAVIUM_OCTEON_SPECIFIC_OPTIONS
        default "y"
        help
          Enable locking parts of the kernel into the L2 cache.
@@ -93,7 +85,6 @@ config CAVIUM_OCTEON_LOCK_L2_MEMCPY
 config ARCH_SPARSEMEM_ENABLE
        def_bool y
        select SPARSEMEM_STATIC
-       depends on CPU_CAVIUM_OCTEON
 
 config CAVIUM_OCTEON_HELPER
        def_bool y
@@ -107,6 +98,8 @@ config NEED_SG_DMA_LENGTH
 
 config SWIOTLB
        def_bool y
-       depends on CPU_CAVIUM_OCTEON
        select IOMMU_HELPER
        select NEED_SG_DMA_LENGTH
+
+
+endif # CPU_CAVIUM_OCTEON
index 26bf711..29d56af 100644 (file)
@@ -105,8 +105,7 @@ unsigned long long notrace sched_clock(void)
 void __init plat_time_init(void)
 {
        clocksource_mips.rating = 300;
-       clocksource_set_clock(&clocksource_mips, octeon_get_clock_rate());
-       clocksource_register(&clocksource_mips);
+       clocksource_register_hz(&clocksource_mips, octeon_get_clock_rate());
 }
 
 static u64 octeon_udelay_factor;
index 0707fae..2d9028f 100644 (file)
@@ -288,7 +288,6 @@ void octeon_user_io_init(void)
        union octeon_cvmemctl cvmmemctl;
        union cvmx_iob_fau_timeout fau_timeout;
        union cvmx_pow_nw_tim nm_tim;
-       uint64_t cvmctl;
 
        /* Get the current settings for CP0_CVMMEMCTL_REG */
        cvmmemctl.u64 = read_c0_cvmmemctl();
@@ -392,12 +391,6 @@ void octeon_user_io_init(void)
                          CONFIG_CAVIUM_OCTEON_CVMSEG_SIZE,
                          CONFIG_CAVIUM_OCTEON_CVMSEG_SIZE * 128);
 
-       /* Move the performance counter interrupts to IRQ 6 */
-       cvmctl = read_c0_cvmctl();
-       cvmctl &= ~(7 << 7);
-       cvmctl |= 6 << 7;
-       write_c0_cvmctl(cvmctl);
-
        /* Set a default for the hardware timeouts */
        fau_timeout.u64 = 0;
        fau_timeout.s.tout_val = 0xfff;
index ba78b21..8b60642 100644 (file)
@@ -37,13 +37,15 @@ static irqreturn_t mailbox_interrupt(int irq, void *dev_id)
        uint64_t action;
 
        /* Load the mailbox register to figure out what we're supposed to do */
-       action = cvmx_read_csr(CVMX_CIU_MBOX_CLRX(coreid));
+       action = cvmx_read_csr(CVMX_CIU_MBOX_CLRX(coreid)) & 0xffff;
 
        /* Clear the mailbox to clear the interrupt */
        cvmx_write_csr(CVMX_CIU_MBOX_CLRX(coreid), action);
 
        if (action & SMP_CALL_FUNCTION)
                smp_call_function_interrupt();
+       if (action & SMP_RESCHEDULE_YOURSELF)
+               scheduler_ipi();
 
        /* Check if we've been told to flush the icache */
        if (action & SMP_ICACHE_FLUSH)
@@ -200,16 +202,15 @@ void octeon_prepare_cpus(unsigned int max_cpus)
        if (labi->labi_signature != LABI_SIGNATURE)
                panic("The bootloader version on this board is incorrect.");
 #endif
-
-       cvmx_write_csr(CVMX_CIU_MBOX_CLRX(cvmx_get_core_num()), 0xffffffff);
+       /*
+        * Only the low order mailbox bits are used for IPIs, leave
+        * the other bits alone.
+        */
+       cvmx_write_csr(CVMX_CIU_MBOX_CLRX(cvmx_get_core_num()), 0xffff);
        if (request_irq(OCTEON_IRQ_MBOX0, mailbox_interrupt, IRQF_DISABLED,
-                       "mailbox0", mailbox_interrupt)) {
+                       "SMP-IPI", mailbox_interrupt)) {
                panic("Cannot request_irq(OCTEON_IRQ_MBOX0)\n");
        }
-       if (request_irq(OCTEON_IRQ_MBOX1, mailbox_interrupt, IRQF_DISABLED,
-                       "mailbox1", mailbox_interrupt)) {
-               panic("Cannot request_irq(OCTEON_IRQ_MBOX1)\n");
-       }
 }
 
 /**
index 167c1d0..b6acd2f 100644 (file)
@@ -86,8 +86,8 @@ CONFIG_NET_SCHED=y
 CONFIG_NET_EMATCH=y
 CONFIG_NET_CLS_ACT=y
 CONFIG_BT=m
-CONFIG_BT_L2CAP=m
-CONFIG_BT_SCO=m
+CONFIG_BT_L2CAP=y
+CONFIG_BT_SCO=y
 CONFIG_BT_RFCOMM=m
 CONFIG_BT_RFCOMM_TTY=y
 CONFIG_BT_BNEP=m
@@ -329,7 +329,7 @@ CONFIG_USB_LED=m
 CONFIG_USB_GADGET=m
 CONFIG_USB_GADGET_M66592=y
 CONFIG_MMC=m
-CONFIG_LEDS_CLASS=m
+CONFIG_LEDS_CLASS=y
 CONFIG_STAGING=y
 # CONFIG_STAGING_EXCLUDE_BUILD is not set
 CONFIG_FB_SM7XX=y
index 7270f31..5527abb 100644 (file)
@@ -374,7 +374,7 @@ CONFIG_FB_CIRRUS=y
 # CONFIG_VGA_CONSOLE is not set
 CONFIG_FRAMEBUFFER_CONSOLE=y
 CONFIG_HID=m
-CONFIG_LEDS_CLASS=m
+CONFIG_LEDS_CLASS=y
 CONFIG_LEDS_TRIGGER_TIMER=m
 CONFIG_LEDS_TRIGGER_IDE_DISK=y
 CONFIG_LEDS_TRIGGER_HEARTBEAT=m
index a97a42c..37862b2 100644 (file)
@@ -225,8 +225,8 @@ CONFIG_TOSHIBA_FIR=m
 CONFIG_VLSI_FIR=m
 CONFIG_MCS_FIR=m
 CONFIG_BT=m
-CONFIG_BT_L2CAP=m
-CONFIG_BT_SCO=m
+CONFIG_BT_L2CAP=y
+CONFIG_BT_SCO=y
 CONFIG_BT_RFCOMM=m
 CONFIG_BT_RFCOMM_TTY=y
 CONFIG_BT_BNEP=m
diff --git a/arch/mips/configs/nlm_xlr_defconfig b/arch/mips/configs/nlm_xlr_defconfig
new file mode 100644 (file)
index 0000000..e4b399f
--- /dev/null
@@ -0,0 +1,574 @@
+CONFIG_NLM_XLR_BOARD=y
+CONFIG_HIGHMEM=y
+CONFIG_KSM=y
+CONFIG_DEFAULT_MMAP_MIN_ADDR=65536
+CONFIG_SMP=y
+CONFIG_NO_HZ=y
+CONFIG_HIGH_RES_TIMERS=y
+CONFIG_PREEMPT_VOLUNTARY=y
+CONFIG_KEXEC=y
+CONFIG_EXPERIMENTAL=y
+CONFIG_CROSS_COMPILE="mips64-unknown-linux-gnu-"
+# CONFIG_LOCALVERSION_AUTO is not set
+CONFIG_SYSVIPC=y
+CONFIG_POSIX_MQUEUE=y
+CONFIG_BSD_PROCESS_ACCT=y
+CONFIG_BSD_PROCESS_ACCT_V3=y
+CONFIG_TASKSTATS=y
+CONFIG_TASK_DELAY_ACCT=y
+CONFIG_TASK_XACCT=y
+CONFIG_TASK_IO_ACCOUNTING=y
+CONFIG_AUDIT=y
+CONFIG_NAMESPACES=y
+CONFIG_SCHED_AUTOGROUP=y
+CONFIG_BLK_DEV_INITRD=y
+CONFIG_INITRAMFS_SOURCE="usr/dev_file_list usr/rootfs"
+CONFIG_RD_BZIP2=y
+CONFIG_RD_LZMA=y
+CONFIG_INITRAMFS_COMPRESSION_GZIP=y
+# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
+CONFIG_EXPERT=y
+CONFIG_KALLSYMS_ALL=y
+# CONFIG_ELF_CORE is not set
+# CONFIG_PCSPKR_PLATFORM is not set
+# CONFIG_PERF_EVENTS is not set
+# CONFIG_COMPAT_BRK is not set
+CONFIG_PROFILING=y
+CONFIG_MODULES=y
+CONFIG_MODULE_UNLOAD=y
+CONFIG_MODVERSIONS=y
+CONFIG_MODULE_SRCVERSION_ALL=y
+CONFIG_BLK_DEV_INTEGRITY=y
+CONFIG_BINFMT_MISC=m
+CONFIG_PM_RUNTIME=y
+CONFIG_PM_DEBUG=y
+CONFIG_PACKET=y
+CONFIG_UNIX=y
+CONFIG_XFRM_USER=m
+CONFIG_NET_KEY=m
+CONFIG_INET=y
+CONFIG_IP_MULTICAST=y
+CONFIG_IP_ADVANCED_ROUTER=y
+CONFIG_IP_MULTIPLE_TABLES=y
+CONFIG_IP_ROUTE_MULTIPATH=y
+CONFIG_IP_ROUTE_VERBOSE=y
+CONFIG_NET_IPIP=m
+CONFIG_IP_MROUTE=y
+CONFIG_IP_PIMSM_V1=y
+CONFIG_IP_PIMSM_V2=y
+CONFIG_SYN_COOKIES=y
+CONFIG_INET_AH=m
+CONFIG_INET_ESP=m
+CONFIG_INET_IPCOMP=m
+CONFIG_INET_XFRM_MODE_TRANSPORT=m
+CONFIG_INET_XFRM_MODE_TUNNEL=m
+CONFIG_INET_XFRM_MODE_BEET=m
+CONFIG_TCP_CONG_ADVANCED=y
+CONFIG_TCP_CONG_HSTCP=m
+CONFIG_TCP_CONG_HYBLA=m
+CONFIG_TCP_CONG_SCALABLE=m
+CONFIG_TCP_CONG_LP=m
+CONFIG_TCP_CONG_VENO=m
+CONFIG_TCP_CONG_YEAH=m
+CONFIG_TCP_CONG_ILLINOIS=m
+CONFIG_TCP_MD5SIG=y
+CONFIG_IPV6=y
+CONFIG_IPV6_PRIVACY=y
+CONFIG_INET6_AH=m
+CONFIG_INET6_ESP=m
+CONFIG_INET6_IPCOMP=m
+CONFIG_INET6_XFRM_MODE_TRANSPORT=m
+CONFIG_INET6_XFRM_MODE_TUNNEL=m
+CONFIG_INET6_XFRM_MODE_BEET=m
+CONFIG_INET6_XFRM_MODE_ROUTEOPTIMIZATION=m
+CONFIG_IPV6_SIT=m
+CONFIG_IPV6_TUNNEL=m
+CONFIG_IPV6_MULTIPLE_TABLES=y
+CONFIG_NETLABEL=y
+CONFIG_NETFILTER=y
+CONFIG_NF_CONNTRACK=m
+CONFIG_NF_CONNTRACK_SECMARK=y
+CONFIG_NF_CONNTRACK_EVENTS=y
+CONFIG_NF_CT_PROTO_UDPLITE=m
+CONFIG_NF_CONNTRACK_AMANDA=m
+CONFIG_NF_CONNTRACK_FTP=m
+CONFIG_NF_CONNTRACK_H323=m
+CONFIG_NF_CONNTRACK_IRC=m
+CONFIG_NF_CONNTRACK_NETBIOS_NS=m
+CONFIG_NF_CONNTRACK_PPTP=m
+CONFIG_NF_CONNTRACK_SANE=m
+CONFIG_NF_CONNTRACK_SIP=m
+CONFIG_NF_CONNTRACK_TFTP=m
+CONFIG_NF_CT_NETLINK=m
+CONFIG_NETFILTER_TPROXY=m
+CONFIG_NETFILTER_XT_TARGET_CLASSIFY=m
+CONFIG_NETFILTER_XT_TARGET_CONNMARK=m
+CONFIG_NETFILTER_XT_TARGET_CONNSECMARK=m
+CONFIG_NETFILTER_XT_TARGET_DSCP=m
+CONFIG_NETFILTER_XT_TARGET_MARK=m
+CONFIG_NETFILTER_XT_TARGET_NFLOG=m
+CONFIG_NETFILTER_XT_TARGET_NFQUEUE=m
+CONFIG_NETFILTER_XT_TARGET_NOTRACK=m
+CONFIG_NETFILTER_XT_TARGET_TPROXY=m
+CONFIG_NETFILTER_XT_TARGET_TRACE=m
+CONFIG_NETFILTER_XT_TARGET_SECMARK=m
+CONFIG_NETFILTER_XT_TARGET_TCPMSS=m
+CONFIG_NETFILTER_XT_MATCH_CLUSTER=m
+CONFIG_NETFILTER_XT_MATCH_COMMENT=m
+CONFIG_NETFILTER_XT_MATCH_CONNBYTES=m
+CONFIG_NETFILTER_XT_MATCH_CONNLIMIT=m
+CONFIG_NETFILTER_XT_MATCH_CONNMARK=m
+CONFIG_NETFILTER_XT_MATCH_CONNTRACK=m
+CONFIG_NETFILTER_XT_MATCH_DSCP=m
+CONFIG_NETFILTER_XT_MATCH_ESP=m
+CONFIG_NETFILTER_XT_MATCH_HASHLIMIT=m
+CONFIG_NETFILTER_XT_MATCH_HELPER=m
+CONFIG_NETFILTER_XT_MATCH_IPRANGE=m
+CONFIG_NETFILTER_XT_MATCH_LENGTH=m
+CONFIG_NETFILTER_XT_MATCH_LIMIT=m
+CONFIG_NETFILTER_XT_MATCH_MAC=m
+CONFIG_NETFILTER_XT_MATCH_MARK=m
+CONFIG_NETFILTER_XT_MATCH_MULTIPORT=m
+CONFIG_NETFILTER_XT_MATCH_OSF=m
+CONFIG_NETFILTER_XT_MATCH_OWNER=m
+CONFIG_NETFILTER_XT_MATCH_POLICY=m
+CONFIG_NETFILTER_XT_MATCH_PHYSDEV=m
+CONFIG_NETFILTER_XT_MATCH_PKTTYPE=m
+CONFIG_NETFILTER_XT_MATCH_QUOTA=m
+CONFIG_NETFILTER_XT_MATCH_RATEEST=m
+CONFIG_NETFILTER_XT_MATCH_REALM=m
+CONFIG_NETFILTER_XT_MATCH_RECENT=m
+CONFIG_NETFILTER_XT_MATCH_SOCKET=m
+CONFIG_NETFILTER_XT_MATCH_STATE=m
+CONFIG_NETFILTER_XT_MATCH_STATISTIC=m
+CONFIG_NETFILTER_XT_MATCH_STRING=m
+CONFIG_NETFILTER_XT_MATCH_TCPMSS=m
+CONFIG_NETFILTER_XT_MATCH_TIME=m
+CONFIG_NETFILTER_XT_MATCH_U32=m
+CONFIG_IP_VS=m
+CONFIG_IP_VS_IPV6=y
+CONFIG_IP_VS_PROTO_TCP=y
+CONFIG_IP_VS_PROTO_UDP=y
+CONFIG_IP_VS_PROTO_ESP=y
+CONFIG_IP_VS_PROTO_AH=y
+CONFIG_IP_VS_RR=m
+CONFIG_IP_VS_WRR=m
+CONFIG_IP_VS_LC=m
+CONFIG_IP_VS_WLC=m
+CONFIG_IP_VS_LBLC=m
+CONFIG_IP_VS_LBLCR=m
+CONFIG_IP_VS_DH=m
+CONFIG_IP_VS_SH=m
+CONFIG_IP_VS_SED=m
+CONFIG_IP_VS_NQ=m
+CONFIG_IP_VS_FTP=m
+CONFIG_NF_CONNTRACK_IPV4=m
+CONFIG_IP_NF_QUEUE=m
+CONFIG_IP_NF_IPTABLES=m
+CONFIG_IP_NF_MATCH_AH=m
+CONFIG_IP_NF_MATCH_ECN=m
+CONFIG_IP_NF_MATCH_TTL=m
+CONFIG_IP_NF_FILTER=m
+CONFIG_IP_NF_TARGET_REJECT=m
+CONFIG_IP_NF_TARGET_LOG=m
+CONFIG_IP_NF_TARGET_ULOG=m
+CONFIG_NF_NAT=m
+CONFIG_IP_NF_TARGET_MASQUERADE=m
+CONFIG_IP_NF_TARGET_NETMAP=m
+CONFIG_IP_NF_TARGET_REDIRECT=m
+CONFIG_IP_NF_MANGLE=m
+CONFIG_IP_NF_TARGET_CLUSTERIP=m
+CONFIG_IP_NF_TARGET_ECN=m
+CONFIG_IP_NF_TARGET_TTL=m
+CONFIG_IP_NF_RAW=m
+CONFIG_IP_NF_SECURITY=m
+CONFIG_IP_NF_ARPTABLES=m
+CONFIG_IP_NF_ARPFILTER=m
+CONFIG_IP_NF_ARP_MANGLE=m
+CONFIG_NF_CONNTRACK_IPV6=m
+CONFIG_IP6_NF_QUEUE=m
+CONFIG_IP6_NF_IPTABLES=m
+CONFIG_IP6_NF_MATCH_AH=m
+CONFIG_IP6_NF_MATCH_EUI64=m
+CONFIG_IP6_NF_MATCH_FRAG=m
+CONFIG_IP6_NF_MATCH_OPTS=m
+CONFIG_IP6_NF_MATCH_HL=m
+CONFIG_IP6_NF_MATCH_IPV6HEADER=m
+CONFIG_IP6_NF_MATCH_MH=m
+CONFIG_IP6_NF_MATCH_RT=m
+CONFIG_IP6_NF_TARGET_HL=m
+CONFIG_IP6_NF_TARGET_LOG=m
+CONFIG_IP6_NF_FILTER=m
+CONFIG_IP6_NF_TARGET_REJECT=m
+CONFIG_IP6_NF_MANGLE=m
+CONFIG_IP6_NF_RAW=m
+CONFIG_IP6_NF_SECURITY=m
+CONFIG_DECNET_NF_GRABULATOR=m
+CONFIG_BRIDGE_NF_EBTABLES=m
+CONFIG_BRIDGE_EBT_BROUTE=m
+CONFIG_BRIDGE_EBT_T_FILTER=m
+CONFIG_BRIDGE_EBT_T_NAT=m
+CONFIG_BRIDGE_EBT_802_3=m
+CONFIG_BRIDGE_EBT_AMONG=m
+CONFIG_BRIDGE_EBT_ARP=m
+CONFIG_BRIDGE_EBT_IP=m
+CONFIG_BRIDGE_EBT_IP6=m
+CONFIG_BRIDGE_EBT_LIMIT=m
+CONFIG_BRIDGE_EBT_MARK=m
+CONFIG_BRIDGE_EBT_PKTTYPE=m
+CONFIG_BRIDGE_EBT_STP=m
+CONFIG_BRIDGE_EBT_VLAN=m
+CONFIG_BRIDGE_EBT_ARPREPLY=m
+CONFIG_BRIDGE_EBT_DNAT=m
+CONFIG_BRIDGE_EBT_MARK_T=m
+CONFIG_BRIDGE_EBT_REDIRECT=m
+CONFIG_BRIDGE_EBT_SNAT=m
+CONFIG_BRIDGE_EBT_LOG=m
+CONFIG_BRIDGE_EBT_ULOG=m
+CONFIG_BRIDGE_EBT_NFLOG=m
+CONFIG_IP_DCCP=m
+CONFIG_RDS=m
+CONFIG_RDS_TCP=m
+CONFIG_TIPC=m
+CONFIG_ATM=m
+CONFIG_ATM_CLIP=m
+CONFIG_ATM_LANE=m
+CONFIG_ATM_MPOA=m
+CONFIG_ATM_BR2684=m
+CONFIG_BRIDGE=m
+CONFIG_VLAN_8021Q=m
+CONFIG_VLAN_8021Q_GVRP=y
+CONFIG_DECNET=m
+CONFIG_LLC2=m
+CONFIG_IPX=m
+CONFIG_ATALK=m
+CONFIG_DEV_APPLETALK=m
+CONFIG_IPDDP=m
+CONFIG_IPDDP_ENCAP=y
+CONFIG_IPDDP_DECAP=y
+CONFIG_X25=m
+CONFIG_LAPB=m
+CONFIG_ECONET=m
+CONFIG_ECONET_AUNUDP=y
+CONFIG_ECONET_NATIVE=y
+CONFIG_WAN_ROUTER=m
+CONFIG_PHONET=m
+CONFIG_IEEE802154=m
+CONFIG_NET_SCHED=y
+CONFIG_NET_SCH_CBQ=m
+CONFIG_NET_SCH_HTB=m
+CONFIG_NET_SCH_HFSC=m
+CONFIG_NET_SCH_ATM=m
+CONFIG_NET_SCH_PRIO=m
+CONFIG_NET_SCH_MULTIQ=m
+CONFIG_NET_SCH_RED=m
+CONFIG_NET_SCH_SFQ=m
+CONFIG_NET_SCH_TEQL=m
+CONFIG_NET_SCH_TBF=m
+CONFIG_NET_SCH_GRED=m
+CONFIG_NET_SCH_DSMARK=m
+CONFIG_NET_SCH_NETEM=m
+CONFIG_NET_SCH_DRR=m
+CONFIG_NET_SCH_INGRESS=m
+CONFIG_NET_CLS_BASIC=m
+CONFIG_NET_CLS_TCINDEX=m
+CONFIG_NET_CLS_ROUTE4=m
+CONFIG_NET_CLS_FW=m
+CONFIG_NET_CLS_U32=m
+CONFIG_CLS_U32_MARK=y
+CONFIG_NET_CLS_RSVP=m
+CONFIG_NET_CLS_RSVP6=m
+CONFIG_NET_CLS_FLOW=m
+CONFIG_NET_EMATCH=y
+CONFIG_NET_EMATCH_CMP=m
+CONFIG_NET_EMATCH_NBYTE=m
+CONFIG_NET_EMATCH_U32=m
+CONFIG_NET_EMATCH_META=m
+CONFIG_NET_EMATCH_TEXT=m
+CONFIG_NET_CLS_ACT=y
+CONFIG_NET_ACT_POLICE=m
+CONFIG_NET_ACT_GACT=m
+CONFIG_GACT_PROB=y
+CONFIG_NET_ACT_MIRRED=m
+CONFIG_NET_ACT_IPT=m
+CONFIG_NET_ACT_NAT=m
+CONFIG_NET_ACT_PEDIT=m
+CONFIG_NET_ACT_SIMP=m
+CONFIG_NET_ACT_SKBEDIT=m
+CONFIG_DCB=y
+CONFIG_NET_PKTGEN=m
+# CONFIG_WIRELESS is not set
+CONFIG_DEVTMPFS=y
+CONFIG_DEVTMPFS_MOUNT=y
+# CONFIG_STANDALONE is not set
+CONFIG_CONNECTOR=y
+CONFIG_MTD=m
+CONFIG_BLK_DEV_LOOP=y
+CONFIG_BLK_DEV_CRYPTOLOOP=m
+CONFIG_BLK_DEV_NBD=m
+CONFIG_BLK_DEV_OSD=m
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_SIZE=65536
+CONFIG_CDROM_PKTCDVD=y
+CONFIG_MISC_DEVICES=y
+CONFIG_RAID_ATTRS=m
+CONFIG_SCSI=y
+CONFIG_SCSI_TGT=m
+CONFIG_BLK_DEV_SD=y
+CONFIG_CHR_DEV_ST=m
+CONFIG_CHR_DEV_OSST=m
+CONFIG_BLK_DEV_SR=y
+CONFIG_CHR_DEV_SG=y
+CONFIG_CHR_DEV_SCH=m
+CONFIG_SCSI_MULTI_LUN=y
+CONFIG_SCSI_CONSTANTS=y
+CONFIG_SCSI_LOGGING=y
+CONFIG_SCSI_SCAN_ASYNC=y
+CONFIG_SCSI_SPI_ATTRS=m
+CONFIG_SCSI_FC_TGT_ATTRS=y
+CONFIG_SCSI_SAS_LIBSAS=m
+CONFIG_SCSI_SRP_ATTRS=m
+CONFIG_SCSI_SRP_TGT_ATTRS=y
+CONFIG_ISCSI_TCP=m
+CONFIG_LIBFCOE=m
+CONFIG_SCSI_DEBUG=m
+CONFIG_SCSI_DH=y
+CONFIG_SCSI_DH_RDAC=m
+CONFIG_SCSI_DH_HP_SW=m
+CONFIG_SCSI_DH_EMC=m
+CONFIG_SCSI_DH_ALUA=m
+CONFIG_SCSI_OSD_INITIATOR=m
+CONFIG_SCSI_OSD_ULD=m
+# CONFIG_INPUT_MOUSEDEV is not set
+CONFIG_INPUT_EVDEV=y
+CONFIG_INPUT_EVBUG=m
+# CONFIG_INPUT_KEYBOARD is not set
+# CONFIG_INPUT_MOUSE is not set
+# CONFIG_SERIO_I8042 is not set
+CONFIG_SERIO_SERPORT=m
+CONFIG_SERIO_LIBPS2=y
+CONFIG_SERIO_RAW=m
+CONFIG_VT_HW_CONSOLE_BINDING=y
+CONFIG_DEVPTS_MULTIPLE_INSTANCES=y
+CONFIG_LEGACY_PTY_COUNT=0
+CONFIG_SERIAL_NONSTANDARD=y
+CONFIG_N_HDLC=m
+# CONFIG_DEVKMEM is not set
+CONFIG_STALDRV=y
+CONFIG_SERIAL_8250=y
+CONFIG_SERIAL_8250_CONSOLE=y
+CONFIG_SERIAL_8250_NR_UARTS=48
+CONFIG_SERIAL_8250_EXTENDED=y
+CONFIG_SERIAL_8250_MANY_PORTS=y
+CONFIG_SERIAL_8250_SHARE_IRQ=y
+CONFIG_SERIAL_8250_RSA=y
+CONFIG_HW_RANDOM=y
+CONFIG_HW_RANDOM_TIMERIOMEM=m
+CONFIG_RAW_DRIVER=m
+# CONFIG_HWMON is not set
+# CONFIG_VGA_CONSOLE is not set
+# CONFIG_HID_SUPPORT is not set
+# CONFIG_USB_SUPPORT is not set
+CONFIG_UIO=y
+CONFIG_UIO_PDRV=m
+CONFIG_UIO_PDRV_GENIRQ=m
+CONFIG_EXT2_FS=y
+CONFIG_EXT2_FS_XATTR=y
+CONFIG_EXT2_FS_POSIX_ACL=y
+CONFIG_EXT2_FS_SECURITY=y
+CONFIG_EXT3_FS=y
+CONFIG_EXT3_FS_POSIX_ACL=y
+CONFIG_EXT3_FS_SECURITY=y
+CONFIG_EXT4_FS=y
+CONFIG_EXT4_FS_POSIX_ACL=y
+CONFIG_EXT4_FS_SECURITY=y
+CONFIG_GFS2_FS=m
+CONFIG_GFS2_FS_LOCKING_DLM=y
+CONFIG_OCFS2_FS=m
+CONFIG_BTRFS_FS=m
+CONFIG_BTRFS_FS_POSIX_ACL=y
+CONFIG_NILFS2_FS=m
+CONFIG_QUOTA_NETLINK_INTERFACE=y
+# CONFIG_PRINT_QUOTA_WARNING is not set
+CONFIG_QFMT_V1=m
+CONFIG_QFMT_V2=m
+CONFIG_AUTOFS4_FS=m
+CONFIG_FUSE_FS=y
+CONFIG_CUSE=m
+CONFIG_FSCACHE=m
+CONFIG_FSCACHE_STATS=y
+CONFIG_FSCACHE_HISTOGRAM=y
+CONFIG_CACHEFILES=m
+CONFIG_ISO9660_FS=m
+CONFIG_JOLIET=y
+CONFIG_ZISOFS=y
+CONFIG_UDF_FS=m
+CONFIG_MSDOS_FS=m
+CONFIG_VFAT_FS=m
+CONFIG_NTFS_FS=m
+CONFIG_PROC_KCORE=y
+CONFIG_TMPFS=y
+CONFIG_TMPFS_POSIX_ACL=y
+CONFIG_CONFIGFS_FS=y
+CONFIG_ADFS_FS=m
+CONFIG_AFFS_FS=m
+CONFIG_ECRYPT_FS=y
+CONFIG_HFS_FS=m
+CONFIG_HFSPLUS_FS=m
+CONFIG_BEFS_FS=m
+CONFIG_BFS_FS=m
+CONFIG_EFS_FS=m
+CONFIG_CRAMFS=m
+CONFIG_SQUASHFS=m
+CONFIG_VXFS_FS=m
+CONFIG_MINIX_FS=m
+CONFIG_OMFS_FS=m
+CONFIG_HPFS_FS=m
+CONFIG_QNX4FS_FS=m
+CONFIG_ROMFS_FS=m
+CONFIG_SYSV_FS=m
+CONFIG_UFS_FS=m
+CONFIG_EXOFS_FS=m
+CONFIG_NFS_FS=m
+CONFIG_NFS_V3=y
+CONFIG_NFS_V3_ACL=y
+CONFIG_NFS_V4=y
+CONFIG_NFS_FSCACHE=y
+CONFIG_NFSD=m
+CONFIG_NFSD_V3_ACL=y
+CONFIG_NFSD_V4=y
+CONFIG_CIFS=m
+CONFIG_CIFS_WEAK_PW_HASH=y
+CONFIG_CIFS_UPCALL=y
+CONFIG_CIFS_XATTR=y
+CONFIG_CIFS_POSIX=y
+CONFIG_CIFS_DFS_UPCALL=y
+CONFIG_CIFS_EXPERIMENTAL=y
+CONFIG_NCP_FS=m
+CONFIG_NCPFS_PACKET_SIGNING=y
+CONFIG_NCPFS_IOCTL_LOCKING=y
+CONFIG_NCPFS_STRONG=y
+CONFIG_NCPFS_NFS_NS=y
+CONFIG_NCPFS_OS2_NS=y
+CONFIG_NCPFS_NLS=y
+CONFIG_NCPFS_EXTRAS=y
+CONFIG_CODA_FS=m
+CONFIG_AFS_FS=m
+CONFIG_PARTITION_ADVANCED=y
+CONFIG_ACORN_PARTITION=y
+CONFIG_ACORN_PARTITION_ICS=y
+CONFIG_ACORN_PARTITION_RISCIX=y
+CONFIG_OSF_PARTITION=y
+CONFIG_AMIGA_PARTITION=y
+CONFIG_ATARI_PARTITION=y
+CONFIG_MAC_PARTITION=y
+CONFIG_BSD_DISKLABEL=y
+CONFIG_MINIX_SUBPARTITION=y
+CONFIG_SOLARIS_X86_PARTITION=y
+CONFIG_UNIXWARE_DISKLABEL=y
+CONFIG_LDM_PARTITION=y
+CONFIG_SGI_PARTITION=y
+CONFIG_ULTRIX_PARTITION=y
+CONFIG_SUN_PARTITION=y
+CONFIG_KARMA_PARTITION=y
+CONFIG_EFI_PARTITION=y
+CONFIG_SYSV68_PARTITION=y
+CONFIG_NLS=y
+CONFIG_NLS_DEFAULT="cp437"
+CONFIG_NLS_CODEPAGE_437=m
+CONFIG_NLS_CODEPAGE_737=m
+CONFIG_NLS_CODEPAGE_775=m
+CONFIG_NLS_CODEPAGE_850=m
+CONFIG_NLS_CODEPAGE_852=m
+CONFIG_NLS_CODEPAGE_855=m
+CONFIG_NLS_CODEPAGE_857=m
+CONFIG_NLS_CODEPAGE_860=m
+CONFIG_NLS_CODEPAGE_861=m
+CONFIG_NLS_CODEPAGE_862=m
+CONFIG_NLS_CODEPAGE_863=m
+CONFIG_NLS_CODEPAGE_864=m
+CONFIG_NLS_CODEPAGE_865=m
+CONFIG_NLS_CODEPAGE_866=m
+CONFIG_NLS_CODEPAGE_869=m
+CONFIG_NLS_CODEPAGE_936=m
+CONFIG_NLS_CODEPAGE_950=m
+CONFIG_NLS_CODEPAGE_932=m
+CONFIG_NLS_CODEPAGE_949=m
+CONFIG_NLS_CODEPAGE_874=m
+CONFIG_NLS_ISO8859_8=m
+CONFIG_NLS_CODEPAGE_1250=m
+CONFIG_NLS_CODEPAGE_1251=m
+CONFIG_NLS_ASCII=m
+CONFIG_NLS_ISO8859_1=m
+CONFIG_NLS_ISO8859_2=m
+CONFIG_NLS_ISO8859_3=m
+CONFIG_NLS_ISO8859_4=m
+CONFIG_NLS_ISO8859_5=m
+CONFIG_NLS_ISO8859_6=m
+CONFIG_NLS_ISO8859_7=m
+CONFIG_NLS_ISO8859_9=m
+CONFIG_NLS_ISO8859_13=m
+CONFIG_NLS_ISO8859_14=m
+CONFIG_NLS_ISO8859_15=m
+CONFIG_NLS_KOI8_R=m
+CONFIG_NLS_KOI8_U=m
+CONFIG_PRINTK_TIME=y
+# CONFIG_ENABLE_WARN_DEPRECATED is not set
+# CONFIG_ENABLE_MUST_CHECK is not set
+CONFIG_UNUSED_SYMBOLS=y
+CONFIG_DEBUG_KERNEL=y
+CONFIG_DETECT_HUNG_TASK=y
+CONFIG_SCHEDSTATS=y
+CONFIG_TIMER_STATS=y
+CONFIG_DEBUG_INFO=y
+CONFIG_DEBUG_MEMORY_INIT=y
+CONFIG_SYSCTL_SYSCALL_CHECK=y
+CONFIG_SCHED_TRACER=y
+CONFIG_BLK_DEV_IO_TRACE=y
+CONFIG_KGDB=y
+CONFIG_SECURITY=y
+CONFIG_SECURITY_NETWORK=y
+CONFIG_LSM_MMAP_MIN_ADDR=0
+CONFIG_SECURITY_SELINUX=y
+CONFIG_SECURITY_SELINUX_BOOTPARAM=y
+CONFIG_SECURITY_SELINUX_BOOTPARAM_VALUE=0
+CONFIG_SECURITY_SELINUX_DISABLE=y
+CONFIG_SECURITY_SMACK=y
+CONFIG_SECURITY_TOMOYO=y
+CONFIG_CRYPTO_NULL=m
+CONFIG_CRYPTO_CRYPTD=m
+CONFIG_CRYPTO_TEST=m
+CONFIG_CRYPTO_CCM=m
+CONFIG_CRYPTO_GCM=m
+CONFIG_CRYPTO_CTS=m
+CONFIG_CRYPTO_LRW=m
+CONFIG_CRYPTO_PCBC=m
+CONFIG_CRYPTO_XTS=m
+CONFIG_CRYPTO_HMAC=y
+CONFIG_CRYPTO_XCBC=m
+CONFIG_CRYPTO_VMAC=m
+CONFIG_CRYPTO_MICHAEL_MIC=m
+CONFIG_CRYPTO_RMD128=m
+CONFIG_CRYPTO_RMD160=m
+CONFIG_CRYPTO_RMD256=m
+CONFIG_CRYPTO_RMD320=m
+CONFIG_CRYPTO_SHA256=m
+CONFIG_CRYPTO_SHA512=m
+CONFIG_CRYPTO_TGR192=m
+CONFIG_CRYPTO_WP512=m
+CONFIG_CRYPTO_ANUBIS=m
+CONFIG_CRYPTO_BLOWFISH=m
+CONFIG_CRYPTO_CAMELLIA=m
+CONFIG_CRYPTO_CAST5=m
+CONFIG_CRYPTO_CAST6=m
+CONFIG_CRYPTO_FCRYPT=m
+CONFIG_CRYPTO_KHAZAD=m
+CONFIG_CRYPTO_SALSA20=m
+CONFIG_CRYPTO_SEED=m
+CONFIG_CRYPTO_SERPENT=m
+CONFIG_CRYPTO_TEA=m
+CONFIG_CRYPTO_TWOFISH=m
+CONFIG_CRYPTO_ZLIB=m
+CONFIG_CRYPTO_LZO=m
+CONFIG_CRC_CCITT=m
+CONFIG_CRC7=m
index 650ac9b..b4db69f 100644 (file)
@@ -17,6 +17,6 @@
 #define SMP_CACHE_SHIFT                L1_CACHE_SHIFT
 #define SMP_CACHE_BYTES                L1_CACHE_BYTES
 
-#define __read_mostly __attribute__((__section__(".data.read_mostly")))
+#define __read_mostly __attribute__((__section__(".data..read_mostly")))
 
 #endif /* _ASM_CACHE_H */
index fa4328f..65f9bdd 100644 (file)
@@ -14,6 +14,9 @@
 #ifndef __ASM_CEVT_R4K_H
 #define __ASM_CEVT_R4K_H
 
+#include <linux/clockchips.h>
+#include <asm/time.h>
+
 DECLARE_PER_CPU(struct clock_event_device, mips_clockevent_device);
 
 void mips_event_handler(struct clock_event_device *dev);
index 8687753..34c0d3c 100644 (file)
@@ -33,6 +33,7 @@
 #define PRID_COMP_TOSHIBA      0x070000
 #define PRID_COMP_LSI          0x080000
 #define PRID_COMP_LEXRA                0x0b0000
+#define PRID_COMP_NETLOGIC     0x0c0000
 #define PRID_COMP_CAVIUM       0x0d0000
 #define PRID_COMP_INGENIC      0xd00000
 
 #define PRID_IMP_JZRISC        0x0200
 
 /*
+ * These are the PRID's for when 23:16 == PRID_COMP_NETLOGIC
+ */
+#define PRID_IMP_NETLOGIC_XLR732       0x0000
+#define PRID_IMP_NETLOGIC_XLR716       0x0200
+#define PRID_IMP_NETLOGIC_XLR532       0x0900
+#define PRID_IMP_NETLOGIC_XLR308       0x0600
+#define PRID_IMP_NETLOGIC_XLR532C      0x0800
+#define PRID_IMP_NETLOGIC_XLR516C      0x0a00
+#define PRID_IMP_NETLOGIC_XLR508C      0x0b00
+#define PRID_IMP_NETLOGIC_XLR308C      0x0f00
+#define PRID_IMP_NETLOGIC_XLS608       0x8000
+#define PRID_IMP_NETLOGIC_XLS408       0x8800
+#define PRID_IMP_NETLOGIC_XLS404       0x8c00
+#define PRID_IMP_NETLOGIC_XLS208       0x8e00
+#define PRID_IMP_NETLOGIC_XLS204       0x8f00
+#define PRID_IMP_NETLOGIC_XLS108       0xce00
+#define PRID_IMP_NETLOGIC_XLS104       0xcf00
+#define PRID_IMP_NETLOGIC_XLS616B      0x4000
+#define PRID_IMP_NETLOGIC_XLS608B      0x4a00
+#define PRID_IMP_NETLOGIC_XLS416B      0x4400
+#define PRID_IMP_NETLOGIC_XLS412B      0x4c00
+#define PRID_IMP_NETLOGIC_XLS408B      0x4e00
+#define PRID_IMP_NETLOGIC_XLS404B      0x4f00
+
+/*
  * Definitions for 7:0 on legacy processors
  */
 
@@ -234,6 +260,7 @@ enum cpu_type_enum {
         */
        CPU_5KC, CPU_20KC, CPU_25KF, CPU_SB1, CPU_SB1A, CPU_LOONGSON2,
        CPU_CAVIUM_OCTEON, CPU_CAVIUM_OCTEON_PLUS, CPU_CAVIUM_OCTEON2,
+       CPU_XLR,
 
        CPU_LAST
 };
index 655f849..7aa37dd 100644 (file)
@@ -5,7 +5,9 @@
 #include <asm/cache.h>
 #include <asm-generic/dma-coherent.h>
 
+#ifndef CONFIG_SGI_IP27        /* Kludge to fix 2.6.39 build for IP27 */
 #include <dma-coherence.h>
+#endif
 
 extern struct dma_map_ops *mips_dma_map_ops;
 
index f5e8560..c565b7c 100644 (file)
@@ -70,6 +70,7 @@ static inline pte_t huge_ptep_get_and_clear(struct mm_struct *mm,
 static inline void huge_ptep_clear_flush(struct vm_area_struct *vma,
                                         unsigned long addr, pte_t *ptep)
 {
+       flush_tlb_mm(vma->vm_mm);
 }
 
 static inline int huge_pte_none(pte_t pte)
index 48bb823..9ad0113 100644 (file)
 #define PIT_CH0                        0x40
 #define PIT_CH2                        0x42
 
+#define PIT_LATCH              LATCH
+
 extern raw_spinlock_t i8253_lock;
 
 extern void setup_pit_timer(void);
 
+#define inb_pit inb_p
+#define outb_pit outb_p
+
 #endif /* __ASM_I8253_H */
index a697661..f260ebe 100644 (file)
@@ -161,6 +161,45 @@ static inline int alchemy_get_cputype(void)
        return ALCHEMY_CPU_UNKNOWN;
 }
 
+/* return number of uarts on a given cputype */
+static inline int alchemy_get_uarts(int type)
+{
+       switch (type) {
+       case ALCHEMY_CPU_AU1000:
+               return 4;
+       case ALCHEMY_CPU_AU1500:
+       case ALCHEMY_CPU_AU1200:
+               return 2;
+       case ALCHEMY_CPU_AU1100:
+       case ALCHEMY_CPU_AU1550:
+               return 3;
+       }
+       return 0;
+}
+
+/* enable an UART block if it isn't already */
+static inline void alchemy_uart_enable(u32 uart_phys)
+{
+       void __iomem *addr = (void __iomem *)KSEG1ADDR(uart_phys);
+
+       /* reset, enable clock, deassert reset */
+       if ((__raw_readl(addr + 0x100) & 3) != 3) {
+               __raw_writel(0, addr + 0x100);
+               wmb();
+               __raw_writel(1, addr + 0x100);
+               wmb();
+       }
+       __raw_writel(3, addr + 0x100);
+       wmb();
+}
+
+static inline void alchemy_uart_disable(u32 uart_phys)
+{
+       void __iomem *addr = (void __iomem *)KSEG1ADDR(uart_phys);
+       __raw_writel(0, addr + 0x100);  /* UART_MOD_CNTRL */
+       wmb();
+}
+
 static inline void alchemy_uart_putchar(u32 uart_phys, u8 c)
 {
        void __iomem *base = (void __iomem *)KSEG1ADDR(uart_phys);
@@ -180,6 +219,20 @@ static inline void alchemy_uart_putchar(u32 uart_phys, u8 c)
        wmb();
 }
 
+/* return number of ethernet MACs on a given cputype */
+static inline int alchemy_get_macs(int type)
+{
+       switch (type) {
+       case ALCHEMY_CPU_AU1000:
+       case ALCHEMY_CPU_AU1500:
+       case ALCHEMY_CPU_AU1550:
+               return 2;
+       case ALCHEMY_CPU_AU1100:
+               return 1;
+       }
+       return 0;
+}
+
 /* arch/mips/au1000/common/clocks.c */
 extern void set_au1x00_speed(unsigned int new_freq);
 extern unsigned int get_au1x00_speed(void);
@@ -630,38 +683,42 @@ enum soc_au1200_ints {
 
 /*
  * Physical base addresses for integrated peripherals
+ * 0..au1000 1..au1500 2..au1100 3..au1550 4..au1200
  */
 
+#define AU1000_AC97_PHYS_ADDR          0x10000000 /* 012 */
+#define AU1000_USBD_PHYS_ADDR          0x10200000 /* 0123 */
+#define AU1000_IC0_PHYS_ADDR           0x10400000 /* 01234 */
+#define AU1000_MAC0_PHYS_ADDR          0x10500000 /* 023 */
+#define AU1000_MAC1_PHYS_ADDR          0x10510000 /* 023 */
+#define AU1000_MACEN_PHYS_ADDR         0x10520000 /* 023 */
+#define AU1100_SD0_PHYS_ADDR           0x10600000 /* 24 */
+#define AU1100_SD1_PHYS_ADDR           0x10680000 /* 24 */
+#define AU1000_I2S_PHYS_ADDR           0x11000000 /* 02 */
+#define AU1500_MAC0_PHYS_ADDR          0x11500000 /* 1 */
+#define AU1500_MAC1_PHYS_ADDR          0x11510000 /* 1 */
+#define AU1500_MACEN_PHYS_ADDR         0x11520000 /* 1 */
+#define AU1000_UART0_PHYS_ADDR         0x11100000 /* 01234 */
+#define AU1000_UART1_PHYS_ADDR         0x11200000 /* 0234 */
+#define AU1000_UART2_PHYS_ADDR         0x11300000 /* 0 */
+#define AU1000_UART3_PHYS_ADDR         0x11400000 /* 0123 */
+#define AU1500_GPIO2_PHYS_ADDR         0x11700000 /* 1234 */
+#define AU1000_IC1_PHYS_ADDR           0x11800000 /* 01234 */
+#define AU1000_SYS_PHYS_ADDR           0x11900000 /* 01234 */
+#define AU1000_DMA_PHYS_ADDR           0x14002000 /* 012 */
+#define AU1550_DBDMA_PHYS_ADDR         0x14002000 /* 34 */
+#define AU1550_DBDMA_CONF_PHYS_ADDR    0x14003000 /* 34 */
+#define AU1000_MACDMA0_PHYS_ADDR       0x14004000 /* 0123 */
+#define AU1000_MACDMA1_PHYS_ADDR       0x14004200 /* 0123 */
+
+
 #ifdef CONFIG_SOC_AU1000
 #define        MEM_PHYS_ADDR           0x14000000
 #define        STATIC_MEM_PHYS_ADDR    0x14001000
-#define        DMA0_PHYS_ADDR          0x14002000
-#define        DMA1_PHYS_ADDR          0x14002100
-#define        DMA2_PHYS_ADDR          0x14002200
-#define        DMA3_PHYS_ADDR          0x14002300
-#define        DMA4_PHYS_ADDR          0x14002400
-#define        DMA5_PHYS_ADDR          0x14002500
-#define        DMA6_PHYS_ADDR          0x14002600
-#define        DMA7_PHYS_ADDR          0x14002700
-#define        IC0_PHYS_ADDR           0x10400000
-#define        IC1_PHYS_ADDR           0x11800000
-#define        AC97_PHYS_ADDR          0x10000000
 #define        USBH_PHYS_ADDR          0x10100000
-#define        USBD_PHYS_ADDR          0x10200000
 #define        IRDA_PHYS_ADDR          0x10300000
-#define        MAC0_PHYS_ADDR          0x10500000
-#define        MAC1_PHYS_ADDR          0x10510000
-#define        MACEN_PHYS_ADDR         0x10520000
-#define        MACDMA0_PHYS_ADDR       0x14004000
-#define        MACDMA1_PHYS_ADDR       0x14004200
-#define        I2S_PHYS_ADDR           0x11000000
-#define        UART0_PHYS_ADDR         0x11100000
-#define        UART1_PHYS_ADDR         0x11200000
-#define        UART2_PHYS_ADDR         0x11300000
-#define        UART3_PHYS_ADDR         0x11400000
 #define        SSI0_PHYS_ADDR          0x11600000
 #define        SSI1_PHYS_ADDR          0x11680000
-#define        SYS_PHYS_ADDR           0x11900000
 #define PCMCIA_IO_PHYS_ADDR    0xF00000000ULL
 #define PCMCIA_ATTR_PHYS_ADDR  0xF40000000ULL
 #define PCMCIA_MEM_PHYS_ADDR   0xF80000000ULL
@@ -672,30 +729,8 @@ enum soc_au1200_ints {
 #ifdef CONFIG_SOC_AU1500
 #define        MEM_PHYS_ADDR           0x14000000
 #define        STATIC_MEM_PHYS_ADDR    0x14001000
-#define        DMA0_PHYS_ADDR          0x14002000
-#define        DMA1_PHYS_ADDR          0x14002100
-#define        DMA2_PHYS_ADDR          0x14002200
-#define        DMA3_PHYS_ADDR          0x14002300
-#define        DMA4_PHYS_ADDR          0x14002400
-#define        DMA5_PHYS_ADDR          0x14002500
-#define        DMA6_PHYS_ADDR          0x14002600
-#define        DMA7_PHYS_ADDR          0x14002700
-#define        IC0_PHYS_ADDR           0x10400000
-#define        IC1_PHYS_ADDR           0x11800000
-#define        AC97_PHYS_ADDR          0x10000000
 #define        USBH_PHYS_ADDR          0x10100000
-#define        USBD_PHYS_ADDR          0x10200000
 #define PCI_PHYS_ADDR          0x14005000
-#define        MAC0_PHYS_ADDR          0x11500000
-#define        MAC1_PHYS_ADDR          0x11510000
-#define        MACEN_PHYS_ADDR         0x11520000
-#define        MACDMA0_PHYS_ADDR       0x14004000
-#define        MACDMA1_PHYS_ADDR       0x14004200
-#define        I2S_PHYS_ADDR           0x11000000
-#define        UART0_PHYS_ADDR         0x11100000
-#define        UART3_PHYS_ADDR         0x11400000
-#define GPIO2_PHYS_ADDR                0x11700000
-#define        SYS_PHYS_ADDR           0x11900000
 #define PCI_MEM_PHYS_ADDR      0x400000000ULL
 #define PCI_IO_PHYS_ADDR       0x500000000ULL
 #define PCI_CONFIG0_PHYS_ADDR  0x600000000ULL
@@ -710,34 +745,10 @@ enum soc_au1200_ints {
 #ifdef CONFIG_SOC_AU1100
 #define        MEM_PHYS_ADDR           0x14000000
 #define        STATIC_MEM_PHYS_ADDR    0x14001000
-#define        DMA0_PHYS_ADDR          0x14002000
-#define        DMA1_PHYS_ADDR          0x14002100
-#define        DMA2_PHYS_ADDR          0x14002200
-#define        DMA3_PHYS_ADDR          0x14002300
-#define        DMA4_PHYS_ADDR          0x14002400
-#define        DMA5_PHYS_ADDR          0x14002500
-#define        DMA6_PHYS_ADDR          0x14002600
-#define        DMA7_PHYS_ADDR          0x14002700
-#define        IC0_PHYS_ADDR           0x10400000
-#define SD0_PHYS_ADDR          0x10600000
-#define SD1_PHYS_ADDR          0x10680000
-#define        IC1_PHYS_ADDR           0x11800000
-#define        AC97_PHYS_ADDR          0x10000000
 #define        USBH_PHYS_ADDR          0x10100000
-#define        USBD_PHYS_ADDR          0x10200000
 #define        IRDA_PHYS_ADDR          0x10300000
-#define        MAC0_PHYS_ADDR          0x10500000
-#define        MACEN_PHYS_ADDR         0x10520000
-#define        MACDMA0_PHYS_ADDR       0x14004000
-#define        MACDMA1_PHYS_ADDR       0x14004200
-#define        I2S_PHYS_ADDR           0x11000000
-#define        UART0_PHYS_ADDR         0x11100000
-#define        UART1_PHYS_ADDR         0x11200000
-#define        UART3_PHYS_ADDR         0x11400000
 #define        SSI0_PHYS_ADDR          0x11600000
 #define        SSI1_PHYS_ADDR          0x11680000
-#define GPIO2_PHYS_ADDR                0x11700000
-#define        SYS_PHYS_ADDR           0x11900000
 #define LCD_PHYS_ADDR          0x15000000
 #define PCMCIA_IO_PHYS_ADDR    0xF00000000ULL
 #define PCMCIA_ATTR_PHYS_ADDR  0xF40000000ULL
@@ -749,22 +760,8 @@ enum soc_au1200_ints {
 #ifdef CONFIG_SOC_AU1550
 #define        MEM_PHYS_ADDR           0x14000000
 #define        STATIC_MEM_PHYS_ADDR    0x14001000
-#define        IC0_PHYS_ADDR           0x10400000
-#define        IC1_PHYS_ADDR           0x11800000
 #define        USBH_PHYS_ADDR          0x14020000
-#define        USBD_PHYS_ADDR          0x10200000
 #define PCI_PHYS_ADDR          0x14005000
-#define        MAC0_PHYS_ADDR          0x10500000
-#define        MAC1_PHYS_ADDR          0x10510000
-#define        MACEN_PHYS_ADDR         0x10520000
-#define        MACDMA0_PHYS_ADDR       0x14004000
-#define        MACDMA1_PHYS_ADDR       0x14004200
-#define        UART0_PHYS_ADDR         0x11100000
-#define        UART1_PHYS_ADDR         0x11200000
-#define        UART3_PHYS_ADDR         0x11400000
-#define GPIO2_PHYS_ADDR                0x11700000
-#define        SYS_PHYS_ADDR           0x11900000
-#define        DDMA_PHYS_ADDR          0x14002000
 #define PE_PHYS_ADDR           0x14008000
 #define PSC0_PHYS_ADDR         0x11A00000
 #define PSC1_PHYS_ADDR         0x11B00000
@@ -786,19 +783,10 @@ enum soc_au1200_ints {
 #define        STATIC_MEM_PHYS_ADDR    0x14001000
 #define AES_PHYS_ADDR          0x10300000
 #define CIM_PHYS_ADDR          0x14004000
-#define        IC0_PHYS_ADDR           0x10400000
-#define        IC1_PHYS_ADDR           0x11800000
 #define USBM_PHYS_ADDR         0x14020000
 #define        USBH_PHYS_ADDR          0x14020100
-#define        UART0_PHYS_ADDR         0x11100000
-#define        UART1_PHYS_ADDR         0x11200000
-#define GPIO2_PHYS_ADDR                0x11700000
-#define        SYS_PHYS_ADDR           0x11900000
-#define        DDMA_PHYS_ADDR          0x14002000
 #define PSC0_PHYS_ADDR         0x11A00000
 #define PSC1_PHYS_ADDR         0x11B00000
-#define SD0_PHYS_ADDR          0x10600000
-#define SD1_PHYS_ADDR          0x10680000
 #define LCD_PHYS_ADDR          0x15000000
 #define SWCNT_PHYS_ADDR                0x1110010C
 #define MAEFE_PHYS_ADDR                0x14012000
@@ -835,183 +823,43 @@ enum soc_au1200_ints {
 #endif
 
 
-/* Interrupt Controller register offsets */
-#define IC_CFG0RD              0x40
-#define IC_CFG0SET             0x40
-#define IC_CFG0CLR             0x44
-#define IC_CFG1RD              0x48
-#define IC_CFG1SET             0x48
-#define IC_CFG1CLR             0x4C
-#define IC_CFG2RD              0x50
-#define IC_CFG2SET             0x50
-#define IC_CFG2CLR             0x54
-#define IC_REQ0INT             0x54
-#define IC_SRCRD               0x58
-#define IC_SRCSET              0x58
-#define IC_SRCCLR              0x5C
-#define IC_REQ1INT             0x5C
-#define IC_ASSIGNRD            0x60
-#define IC_ASSIGNSET           0x60
-#define IC_ASSIGNCLR           0x64
-#define IC_WAKERD              0x68
-#define IC_WAKESET             0x68
-#define IC_WAKECLR             0x6C
-#define IC_MASKRD              0x70
-#define IC_MASKSET             0x70
-#define IC_MASKCLR             0x74
-#define IC_RISINGRD            0x78
-#define IC_RISINGCLR           0x78
-#define IC_FALLINGRD           0x7C
-#define IC_FALLINGCLR          0x7C
-#define IC_TESTBIT             0x80
-
-
-/* Interrupt Controller 0 */
-#define IC0_CFG0RD             0xB0400040
-#define IC0_CFG0SET            0xB0400040
-#define IC0_CFG0CLR            0xB0400044
-
-#define IC0_CFG1RD             0xB0400048
-#define IC0_CFG1SET            0xB0400048
-#define IC0_CFG1CLR            0xB040004C
-
-#define IC0_CFG2RD             0xB0400050
-#define IC0_CFG2SET            0xB0400050
-#define IC0_CFG2CLR            0xB0400054
-
-#define IC0_REQ0INT            0xB0400054
-#define IC0_SRCRD              0xB0400058
-#define IC0_SRCSET             0xB0400058
-#define IC0_SRCCLR             0xB040005C
-#define IC0_REQ1INT            0xB040005C
-
-#define IC0_ASSIGNRD           0xB0400060
-#define IC0_ASSIGNSET          0xB0400060
-#define IC0_ASSIGNCLR          0xB0400064
-
-#define IC0_WAKERD             0xB0400068
-#define IC0_WAKESET            0xB0400068
-#define IC0_WAKECLR            0xB040006C
-
-#define IC0_MASKRD             0xB0400070
-#define IC0_MASKSET            0xB0400070
-#define IC0_MASKCLR            0xB0400074
-
-#define IC0_RISINGRD           0xB0400078
-#define IC0_RISINGCLR          0xB0400078
-#define IC0_FALLINGRD          0xB040007C
-#define IC0_FALLINGCLR         0xB040007C
-
-#define IC0_TESTBIT            0xB0400080
-
-/* Interrupt Controller 1 */
-#define IC1_CFG0RD             0xB1800040
-#define IC1_CFG0SET            0xB1800040
-#define IC1_CFG0CLR            0xB1800044
-
-#define IC1_CFG1RD             0xB1800048
-#define IC1_CFG1SET            0xB1800048
-#define IC1_CFG1CLR            0xB180004C
-
-#define IC1_CFG2RD             0xB1800050
-#define IC1_CFG2SET            0xB1800050
-#define IC1_CFG2CLR            0xB1800054
-
-#define IC1_REQ0INT            0xB1800054
-#define IC1_SRCRD              0xB1800058
-#define IC1_SRCSET             0xB1800058
-#define IC1_SRCCLR             0xB180005C
-#define IC1_REQ1INT            0xB180005C
-
-#define IC1_ASSIGNRD            0xB1800060
-#define IC1_ASSIGNSET           0xB1800060
-#define IC1_ASSIGNCLR           0xB1800064
-
-#define IC1_WAKERD             0xB1800068
-#define IC1_WAKESET            0xB1800068
-#define IC1_WAKECLR            0xB180006C
-
-#define IC1_MASKRD             0xB1800070
-#define IC1_MASKSET            0xB1800070
-#define IC1_MASKCLR            0xB1800074
-
-#define IC1_RISINGRD           0xB1800078
-#define IC1_RISINGCLR          0xB1800078
-#define IC1_FALLINGRD          0xB180007C
-#define IC1_FALLINGCLR         0xB180007C
-
-#define IC1_TESTBIT            0xB1800080
 
 
 /* Au1000 */
 #ifdef CONFIG_SOC_AU1000
 
-#define UART0_ADDR             0xB1100000
-#define UART3_ADDR             0xB1400000
-
 #define USB_OHCI_BASE          0x10100000      /* phys addr for ioremap */
 #define USB_HOST_CONFIG        0xB017FFFC
 #define FOR_PLATFORM_C_USB_HOST_INT AU1000_USB_HOST_INT
-
-#define AU1000_ETH0_BASE       0xB0500000
-#define AU1000_ETH1_BASE       0xB0510000
-#define AU1000_MAC0_ENABLE     0xB0520000
-#define AU1000_MAC1_ENABLE     0xB0520004
-#define NUM_ETH_INTERFACES 2
 #endif /* CONFIG_SOC_AU1000 */
 
 /* Au1500 */
 #ifdef CONFIG_SOC_AU1500
 
-#define UART0_ADDR             0xB1100000
-#define UART3_ADDR             0xB1400000
-
 #define USB_OHCI_BASE          0x10100000      /* phys addr for ioremap */
 #define USB_HOST_CONFIG        0xB017fffc
 #define FOR_PLATFORM_C_USB_HOST_INT AU1500_USB_HOST_INT
-
-#define AU1500_ETH0_BASE       0xB1500000
-#define AU1500_ETH1_BASE       0xB1510000
-#define AU1500_MAC0_ENABLE     0xB1520000
-#define AU1500_MAC1_ENABLE     0xB1520004
-#define NUM_ETH_INTERFACES 2
 #endif /* CONFIG_SOC_AU1500 */
 
 /* Au1100 */
 #ifdef CONFIG_SOC_AU1100
 
-#define UART0_ADDR             0xB1100000
-#define UART3_ADDR             0xB1400000
-
 #define USB_OHCI_BASE          0x10100000      /* phys addr for ioremap */
 #define USB_HOST_CONFIG        0xB017FFFC
 #define FOR_PLATFORM_C_USB_HOST_INT AU1100_USB_HOST_INT
-
-#define AU1100_ETH0_BASE       0xB0500000
-#define AU1100_MAC0_ENABLE     0xB0520000
-#define NUM_ETH_INTERFACES 1
 #endif /* CONFIG_SOC_AU1100 */
 
 #ifdef CONFIG_SOC_AU1550
-#define UART0_ADDR             0xB1100000
 
 #define USB_OHCI_BASE          0x14020000      /* phys addr for ioremap */
 #define USB_OHCI_LEN           0x00060000
 #define USB_HOST_CONFIG        0xB4027ffc
 #define FOR_PLATFORM_C_USB_HOST_INT AU1550_USB_HOST_INT
-
-#define AU1550_ETH0_BASE       0xB0500000
-#define AU1550_ETH1_BASE       0xB0510000
-#define AU1550_MAC0_ENABLE     0xB0520000
-#define AU1550_MAC1_ENABLE     0xB0520004
-#define NUM_ETH_INTERFACES 2
 #endif /* CONFIG_SOC_AU1550 */
 
 
 #ifdef CONFIG_SOC_AU1200
 
-#define UART0_ADDR             0xB1100000
-
 #define USB_UOC_BASE           0x14020020
 #define USB_UOC_LEN            0x20
 #define USB_OHCI_BASE          0x14020100
@@ -1504,22 +1352,6 @@ enum soc_au1200_ints {
 #define SYS_PINFUNC_S1B        (1 << 2)
 #endif
 
-#define SYS_TRIOUTRD           0xB1900100
-#define SYS_TRIOUTCLR          0xB1900100
-#define SYS_OUTPUTRD           0xB1900108
-#define SYS_OUTPUTSET          0xB1900108
-#define SYS_OUTPUTCLR          0xB190010C
-#define SYS_PINSTATERD         0xB1900110
-#define SYS_PININPUTEN         0xB1900110
-
-/* GPIO2, Au1500, Au1550 only */
-#define GPIO2_BASE             0xB1700000
-#define GPIO2_DIR              (GPIO2_BASE + 0)
-#define GPIO2_OUTPUT           (GPIO2_BASE + 8)
-#define GPIO2_PINSTATE         (GPIO2_BASE + 0xC)
-#define GPIO2_INTENABLE        (GPIO2_BASE + 0x10)
-#define GPIO2_ENABLE           (GPIO2_BASE + 0x14)
-
 /* Power Management */
 #define SYS_SCRATCH0           0xB1900018
 #define SYS_SCRATCH1           0xB190001C
@@ -1635,12 +1467,6 @@ enum soc_au1200_ints {
 #  define AC97C_RS             (1 << 1)
 #  define AC97C_CE             (1 << 0)
 
-/* Secure Digital (SD) Controller */
-#define SD0_XMIT_FIFO  0xB0600000
-#define SD0_RECV_FIFO  0xB0600004
-#define SD1_XMIT_FIFO  0xB0680000
-#define SD1_RECV_FIFO  0xB0680004
-
 #if defined(CONFIG_SOC_AU1500) || defined(CONFIG_SOC_AU1550)
 /* Au1500 PCI Controller */
 #define Au1500_CFG_BASE        0xB4005000      /* virtual, KSEG1 addr */
index c333b4e..59f5b55 100644 (file)
 
 #define NUM_AU1000_DMA_CHANNELS        8
 
-/* DMA Channel Base Addresses */
-#define DMA_CHANNEL_BASE       0xB4002000
-#define DMA_CHANNEL_LEN                0x00000100
-
 /* DMA Channel Register Offsets */
 #define DMA_MODE_SET           0x00000000
 #define DMA_MODE_READ          DMA_MODE_SET
index c8a553a..2fdacfe 100644 (file)
 
 #ifndef _LANGUAGE_ASSEMBLY
 
-/*
- * The DMA base addresses.
- * The channels are every 256 bytes (0x0100) from the channel 0 base.
- * Interrupt status/enable is bits 15:0 for channels 15 to zero.
- */
-#define DDMA_GLOBAL_BASE       0xb4003000
-#define DDMA_CHANNEL_BASE      0xb4002000
-
 typedef volatile struct dbdma_global {
        u32     ddma_config;
        u32     ddma_intstat;
index 62d2f13..1f41a52 100644 (file)
 
 #define MAKE_IRQ(intc, off)    (AU1000_INTC##intc##_INT_BASE + (off))
 
+/* GPIO1 registers within SYS_ area */
+#define SYS_TRIOUTRD           0x100
+#define SYS_TRIOUTCLR          0x100
+#define SYS_OUTPUTRD           0x108
+#define SYS_OUTPUTSET          0x108
+#define SYS_OUTPUTCLR          0x10C
+#define SYS_PINSTATERD         0x110
+#define SYS_PININPUTEN         0x110
+
+/* register offsets within GPIO2 block */
+#define GPIO2_DIR              0x00
+#define GPIO2_OUTPUT           0x08
+#define GPIO2_PINSTATE         0x0C
+#define GPIO2_INTENABLE                0x10
+#define GPIO2_ENABLE           0x14
+
+struct gpio;
 
 static inline int au1000_gpio1_to_irq(int gpio)
 {
@@ -200,23 +217,26 @@ static inline int au1200_irq_to_gpio(int irq)
  */
 static inline void alchemy_gpio1_set_value(int gpio, int v)
 {
+       void __iomem *base = (void __iomem *)KSEG1ADDR(AU1000_SYS_PHYS_ADDR);
        unsigned long mask = 1 << (gpio - ALCHEMY_GPIO1_BASE);
        unsigned long r = v ? SYS_OUTPUTSET : SYS_OUTPUTCLR;
-       au_writel(mask, r);
-       au_sync();
+       __raw_writel(mask, base + r);
+       wmb();
 }
 
 static inline int alchemy_gpio1_get_value(int gpio)
 {
+       void __iomem *base = (void __iomem *)KSEG1ADDR(AU1000_SYS_PHYS_ADDR);
        unsigned long mask = 1 << (gpio - ALCHEMY_GPIO1_BASE);
-       return au_readl(SYS_PINSTATERD) & mask;
+       return __raw_readl(base + SYS_PINSTATERD) & mask;
 }
 
 static inline int alchemy_gpio1_direction_input(int gpio)
 {
+       void __iomem *base = (void __iomem *)KSEG1ADDR(AU1000_SYS_PHYS_ADDR);
        unsigned long mask = 1 << (gpio - ALCHEMY_GPIO1_BASE);
-       au_writel(mask, SYS_TRIOUTCLR);
-       au_sync();
+       __raw_writel(mask, base + SYS_TRIOUTCLR);
+       wmb();
        return 0;
 }
 
@@ -257,27 +277,31 @@ static inline int alchemy_gpio1_to_irq(int gpio)
  */
 static inline void __alchemy_gpio2_mod_dir(int gpio, int to_out)
 {
+       void __iomem *base = (void __iomem *)KSEG1ADDR(AU1500_GPIO2_PHYS_ADDR);
        unsigned long mask = 1 << (gpio - ALCHEMY_GPIO2_BASE);
-       unsigned long d = au_readl(GPIO2_DIR);
+       unsigned long d = __raw_readl(base + GPIO2_DIR);
+
        if (to_out)
                d |= mask;
        else
                d &= ~mask;
-       au_writel(d, GPIO2_DIR);
-       au_sync();
+       __raw_writel(d, base + GPIO2_DIR);
+       wmb();
 }
 
 static inline void alchemy_gpio2_set_value(int gpio, int v)
 {
+       void __iomem *base = (void __iomem *)KSEG1ADDR(AU1500_GPIO2_PHYS_ADDR);
        unsigned long mask;
        mask = ((v) ? 0x00010001 : 0x00010000) << (gpio - ALCHEMY_GPIO2_BASE);
-       au_writel(mask, GPIO2_OUTPUT);
-       au_sync();
+       __raw_writel(mask, base + GPIO2_OUTPUT);
+       wmb();
 }
 
 static inline int alchemy_gpio2_get_value(int gpio)
 {
-       return au_readl(GPIO2_PINSTATE) & (1 << (gpio - ALCHEMY_GPIO2_BASE));
+       void __iomem *base = (void __iomem *)KSEG1ADDR(AU1500_GPIO2_PHYS_ADDR);
+       return __raw_readl(base + GPIO2_PINSTATE) & (1 << (gpio - ALCHEMY_GPIO2_BASE));
 }
 
 static inline int alchemy_gpio2_direction_input(int gpio)
@@ -329,21 +353,23 @@ static inline int alchemy_gpio2_to_irq(int gpio)
  */
 static inline void alchemy_gpio1_input_enable(void)
 {
-       au_writel(0, SYS_PININPUTEN);   /* the write op is key */
-       au_sync();
+       void __iomem *base = (void __iomem *)KSEG1ADDR(AU1000_SYS_PHYS_ADDR);
+       __raw_writel(0, base + SYS_PININPUTEN); /* the write op is key */
+       wmb();
 }
 
 /* GPIO2 shared interrupts and control */
 
 static inline void __alchemy_gpio2_mod_int(int gpio2, int en)
 {
-       unsigned long r = au_readl(GPIO2_INTENABLE);
+       void __iomem *base = (void __iomem *)KSEG1ADDR(AU1500_GPIO2_PHYS_ADDR);
+       unsigned long r = __raw_readl(base + GPIO2_INTENABLE);
        if (en)
                r |= 1 << gpio2;
        else
                r &= ~(1 << gpio2);
-       au_writel(r, GPIO2_INTENABLE);
-       au_sync();
+       __raw_writel(r, base + GPIO2_INTENABLE);
+       wmb();
 }
 
 /**
@@ -418,10 +444,11 @@ static inline void alchemy_gpio2_disable_int(int gpio2)
  */
 static inline void alchemy_gpio2_enable(void)
 {
-       au_writel(3, GPIO2_ENABLE);     /* reset, clock enabled */
-       au_sync();
-       au_writel(1, GPIO2_ENABLE);     /* clock enabled */
-       au_sync();
+       void __iomem *base = (void __iomem *)KSEG1ADDR(AU1500_GPIO2_PHYS_ADDR);
+       __raw_writel(3, base + GPIO2_ENABLE);   /* reset, clock enabled */
+       wmb();
+       __raw_writel(1, base + GPIO2_ENABLE);   /* clock enabled */
+       wmb();
 }
 
 /**
@@ -431,8 +458,9 @@ static inline void alchemy_gpio2_enable(void)
  */
 static inline void alchemy_gpio2_disable(void)
 {
-       au_writel(2, GPIO2_ENABLE);     /* reset, clock disabled */
-       au_sync();
+       void __iomem *base = (void __iomem *)KSEG1ADDR(AU1500_GPIO2_PHYS_ADDR);
+       __raw_writel(2, base + GPIO2_ENABLE);   /* reset, clock disabled */
+       wmb();
 }
 
 /**********************************************************************/
@@ -556,6 +584,16 @@ static inline void gpio_set_value(int gpio, int v)
        alchemy_gpio_set_value(gpio, v);
 }
 
+static inline int gpio_get_value_cansleep(unsigned gpio)
+{
+       return gpio_get_value(gpio);
+}
+
+static inline void gpio_set_value_cansleep(unsigned gpio, int value)
+{
+       gpio_set_value(gpio, value);
+}
+
 static inline int gpio_is_valid(int gpio)
 {
        return alchemy_gpio_is_valid(gpio);
@@ -581,10 +619,50 @@ static inline int gpio_request(unsigned gpio, const char *label)
        return 0;
 }
 
+static inline int gpio_request_one(unsigned gpio,
+                                       unsigned long flags, const char *label)
+{
+       return 0;
+}
+
+static inline int gpio_request_array(struct gpio *array, size_t num)
+{
+       return 0;
+}
+
 static inline void gpio_free(unsigned gpio)
 {
 }
 
+static inline void gpio_free_array(struct gpio *array, size_t num)
+{
+}
+
+static inline int gpio_set_debounce(unsigned gpio, unsigned debounce)
+{
+       return -ENOSYS;
+}
+
+static inline int gpio_export(unsigned gpio, bool direction_may_change)
+{
+       return -ENOSYS;
+}
+
+static inline int gpio_export_link(struct device *dev, const char *name,
+                                  unsigned gpio)
+{
+       return -ENOSYS;
+}
+
+static inline int gpio_sysfs_set_active_low(unsigned gpio, int value)
+{
+       return -ENOSYS;
+}
+
+static inline void gpio_unexport(unsigned gpio)
+{
+}
+
 #endif /* !CONFIG_ALCHEMY_GPIO_INDIRECT */
 
 
index 9759588..184d5ec 100644 (file)
@@ -39,8 +39,16 @@ extern int nvram_getenv(char *name, char *val, size_t val_len);
 
 static inline void nvram_parse_macaddr(char *buf, u8 *macaddr)
 {
-       sscanf(buf, "%hhx:%hhx:%hhx:%hhx:%hhx:%hhx", &macaddr[0], &macaddr[1],
-              &macaddr[2], &macaddr[3], &macaddr[4], &macaddr[5]);
+       if (strchr(buf, ':'))
+               sscanf(buf, "%hhx:%hhx:%hhx:%hhx:%hhx:%hhx", &macaddr[0],
+                       &macaddr[1], &macaddr[2], &macaddr[3], &macaddr[4],
+                       &macaddr[5]);
+       else if (strchr(buf, '-'))
+               sscanf(buf, "%hhx-%hhx-%hhx-%hhx-%hhx-%hhx", &macaddr[0],
+                       &macaddr[1], &macaddr[2], &macaddr[3], &macaddr[4],
+                       &macaddr[5]);
+       else
+               printk(KERN_WARNING "Can not parse mac address: %s\n", buf);
 }
 
 #endif
index 32978d3..ed72e6a 100644 (file)
@@ -88,7 +88,7 @@ struct bcm_tag {
        char kernel_crc[CRC_LEN];
        /* 228-235: Unused at present */
        char reserved1[8];
-       /* 236-239: CRC32 of header excluding tagVersion */
+       /* 236-239: CRC32 of header excluding last 20 bytes */
        char header_crc[CRC_LEN];
        /* 240-255: Unused at present */
        char reserved2[16];
index 0b2b5eb..dedef7d 100644 (file)
        # CN30XX Disable instruction prefetching
        or  v0, v0, 0x2000
 skip:
+       # First clear off CvmCtl[IPPCI] bit and move the performance
+       # counters interrupt to IRQ 6
+       li      v1, ~(7 << 7)
+       and     v0, v0, v1
+       ori     v0, v0, (6 << 7)
        # Write the cavium control register
        dmtc0   v0, CP0_CVMCTL_REG
        sync
diff --git a/arch/mips/include/asm/mach-lantiq/lantiq.h b/arch/mips/include/asm/mach-lantiq/lantiq.h
new file mode 100644 (file)
index 0000000..ce2f029
--- /dev/null
@@ -0,0 +1,63 @@
+/*
+ *  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.
+ *
+ *  Copyright (C) 2010 John Crispin <blogic@openwrt.org>
+ */
+#ifndef _LANTIQ_H__
+#define _LANTIQ_H__
+
+#include <linux/irq.h>
+
+/* generic reg access functions */
+#define ltq_r32(reg)           __raw_readl(reg)
+#define ltq_w32(val, reg)      __raw_writel(val, reg)
+#define ltq_w32_mask(clear, set, reg)  \
+       ltq_w32((ltq_r32(reg) & ~(clear)) | (set), reg)
+#define ltq_r8(reg)            __raw_readb(reg)
+#define ltq_w8(val, reg)       __raw_writeb(val, reg)
+
+/* register access macros for EBU and CGU */
+#define ltq_ebu_w32(x, y)      ltq_w32((x), ltq_ebu_membase + (y))
+#define ltq_ebu_r32(x)         ltq_r32(ltq_ebu_membase + (x))
+#define ltq_cgu_w32(x, y)      ltq_w32((x), ltq_cgu_membase + (y))
+#define ltq_cgu_r32(x)         ltq_r32(ltq_cgu_membase + (x))
+
+extern __iomem void *ltq_ebu_membase;
+extern __iomem void *ltq_cgu_membase;
+
+extern unsigned int ltq_get_cpu_ver(void);
+extern unsigned int ltq_get_soc_type(void);
+
+/* clock speeds */
+#define CLOCK_60M      60000000
+#define CLOCK_83M      83333333
+#define CLOCK_111M     111111111
+#define CLOCK_133M     133333333
+#define CLOCK_167M     166666667
+#define CLOCK_200M     200000000
+#define CLOCK_266M     266666666
+#define CLOCK_333M     333333333
+#define CLOCK_400M     400000000
+
+/* spinlock all ebu i/o */
+extern spinlock_t ebu_lock;
+
+/* some irq helpers */
+extern void ltq_disable_irq(struct irq_data *data);
+extern void ltq_mask_and_ack_irq(struct irq_data *data);
+extern void ltq_enable_irq(struct irq_data *data);
+
+/* find out what caused the last cpu reset */
+extern int ltq_reset_cause(void);
+#define LTQ_RST_CAUSE_WDTRST   0x20
+
+#define IOPORT_RESOURCE_START  0x10000000
+#define IOPORT_RESOURCE_END    0xffffffff
+#define IOMEM_RESOURCE_START   0x10000000
+#define IOMEM_RESOURCE_END     0xffffffff
+#define LTQ_FLASH_START                0x10000000
+#define LTQ_FLASH_MAX          0x04000000
+
+#endif
diff --git a/arch/mips/include/asm/mach-lantiq/lantiq_platform.h b/arch/mips/include/asm/mach-lantiq/lantiq_platform.h
new file mode 100644 (file)
index 0000000..a305f1d
--- /dev/null
@@ -0,0 +1,53 @@
+/*
+ *  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.
+ *
+ *  Copyright (C) 2010 John Crispin <blogic@openwrt.org>
+ */
+
+#ifndef _LANTIQ_PLATFORM_H__
+#define _LANTIQ_PLATFORM_H__
+
+#include <linux/mtd/partitions.h>
+#include <linux/socket.h>
+
+/* struct used to pass info to the pci core */
+enum {
+       PCI_CLOCK_INT = 0,
+       PCI_CLOCK_EXT
+};
+
+#define PCI_EXIN0      0x0001
+#define PCI_EXIN1      0x0002
+#define PCI_EXIN2      0x0004
+#define PCI_EXIN3      0x0008
+#define PCI_EXIN4      0x0010
+#define PCI_EXIN5      0x0020
+#define PCI_EXIN_MAX   6
+
+#define PCI_GNT1       0x0040
+#define PCI_GNT2       0x0080
+#define PCI_GNT3       0x0100
+#define PCI_GNT4       0x0200
+
+#define PCI_REQ1       0x0400
+#define PCI_REQ2       0x0800
+#define PCI_REQ3       0x1000
+#define PCI_REQ4       0x2000
+#define PCI_REQ_SHIFT  10
+#define PCI_REQ_MASK   0xf
+
+struct ltq_pci_data {
+       int clock;
+       int gpio;
+       int irq[16];
+};
+
+/* struct used to pass info to network drivers */
+struct ltq_eth_data {
+       struct sockaddr mac;
+       int mii_mode;
+};
+
+#endif
diff --git a/arch/mips/include/asm/mach-lantiq/war.h b/arch/mips/include/asm/mach-lantiq/war.h
new file mode 100644 (file)
index 0000000..01b08ef
--- /dev/null
@@ -0,0 +1,24 @@
+/*
+ * 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_MIPS_MACH_LANTIQ_WAR_H
+#define __ASM_MIPS_MACH_LANTIQ_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
diff --git a/arch/mips/include/asm/mach-lantiq/xway/irq.h b/arch/mips/include/asm/mach-lantiq/xway/irq.h
new file mode 100644 (file)
index 0000000..a1471d2
--- /dev/null
@@ -0,0 +1,18 @@
+/*
+ *  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.
+ *
+ *  Copyright (C) 2010 John Crispin <blogic@openwrt.org>
+ */
+
+#ifndef __LANTIQ_IRQ_H
+#define __LANTIQ_IRQ_H
+
+#include <lantiq_irq.h>
+
+#define NR_IRQS 256
+
+#include_next <irq.h>
+
+#endif
diff --git a/arch/mips/include/asm/mach-lantiq/xway/lantiq_irq.h b/arch/mips/include/asm/mach-lantiq/xway/lantiq_irq.h
new file mode 100644 (file)
index 0000000..b4465a8
--- /dev/null
@@ -0,0 +1,66 @@
+/*
+ *  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.
+ *
+ *  Copyright (C) 2010 John Crispin <blogic@openwrt.org>
+ */
+
+#ifndef _LANTIQ_XWAY_IRQ_H__
+#define _LANTIQ_XWAY_IRQ_H__
+
+#define INT_NUM_IRQ0           8
+#define INT_NUM_IM0_IRL0       (INT_NUM_IRQ0 + 0)
+#define INT_NUM_IM1_IRL0       (INT_NUM_IRQ0 + 32)
+#define INT_NUM_IM2_IRL0       (INT_NUM_IRQ0 + 64)
+#define INT_NUM_IM3_IRL0       (INT_NUM_IRQ0 + 96)
+#define INT_NUM_IM4_IRL0       (INT_NUM_IRQ0 + 128)
+#define INT_NUM_IM_OFFSET      (INT_NUM_IM1_IRL0 - INT_NUM_IM0_IRL0)
+
+#define LTQ_ASC_TIR(x)         (INT_NUM_IM3_IRL0 + (x * 8))
+#define LTQ_ASC_RIR(x)         (INT_NUM_IM3_IRL0 + (x * 8) + 1)
+#define LTQ_ASC_EIR(x)         (INT_NUM_IM3_IRL0 + (x * 8) + 2)
+
+#define LTQ_ASC_ASE_TIR                INT_NUM_IM2_IRL0
+#define LTQ_ASC_ASE_RIR                (INT_NUM_IM2_IRL0 + 2)
+#define LTQ_ASC_ASE_EIR                (INT_NUM_IM2_IRL0 + 3)
+
+#define LTQ_SSC_TIR            (INT_NUM_IM0_IRL0 + 15)
+#define LTQ_SSC_RIR            (INT_NUM_IM0_IRL0 + 14)
+#define LTQ_SSC_EIR            (INT_NUM_IM0_IRL0 + 16)
+
+#define LTQ_MEI_DYING_GASP_INT (INT_NUM_IM1_IRL0 + 21)
+#define LTQ_MEI_INT            (INT_NUM_IM1_IRL0 + 23)
+
+#define LTQ_TIMER6_INT         (INT_NUM_IM1_IRL0 + 23)
+#define LTQ_USB_INT            (INT_NUM_IM1_IRL0 + 22)
+#define LTQ_USB_OC_INT         (INT_NUM_IM4_IRL0 + 23)
+
+#define MIPS_CPU_TIMER_IRQ             7
+
+#define LTQ_DMA_CH0_INT                (INT_NUM_IM2_IRL0)
+#define LTQ_DMA_CH1_INT                (INT_NUM_IM2_IRL0 + 1)
+#define LTQ_DMA_CH2_INT                (INT_NUM_IM2_IRL0 + 2)
+#define LTQ_DMA_CH3_INT                (INT_NUM_IM2_IRL0 + 3)
+#define LTQ_DMA_CH4_INT                (INT_NUM_IM2_IRL0 + 4)
+#define LTQ_DMA_CH5_INT                (INT_NUM_IM2_IRL0 + 5)
+#define LTQ_DMA_CH6_INT                (INT_NUM_IM2_IRL0 + 6)
+#define LTQ_DMA_CH7_INT                (INT_NUM_IM2_IRL0 + 7)
+#define LTQ_DMA_CH8_INT                (INT_NUM_IM2_IRL0 + 8)
+#define LTQ_DMA_CH9_INT                (INT_NUM_IM2_IRL0 + 9)
+#define LTQ_DMA_CH10_INT       (INT_NUM_IM2_IRL0 + 10)
+#define LTQ_DMA_CH11_INT       (INT_NUM_IM2_IRL0 + 11)
+#define LTQ_DMA_CH12_INT       (INT_NUM_IM2_IRL0 + 25)
+#define LTQ_DMA_CH13_INT       (INT_NUM_IM2_IRL0 + 26)
+#define LTQ_DMA_CH14_INT       (INT_NUM_IM2_IRL0 + 27)
+#define LTQ_DMA_CH15_INT       (INT_NUM_IM2_IRL0 + 28)
+#define LTQ_DMA_CH16_INT       (INT_NUM_IM2_IRL0 + 29)
+#define LTQ_DMA_CH17_INT       (INT_NUM_IM2_IRL0 + 30)
+#define LTQ_DMA_CH18_INT       (INT_NUM_IM2_IRL0 + 16)
+#define LTQ_DMA_CH19_INT       (INT_NUM_IM2_IRL0 + 21)
+
+#define LTQ_PPE_MBOX_INT       (INT_NUM_IM2_IRL0 + 24)
+
+#define INT_NUM_IM4_IRL14      (INT_NUM_IM4_IRL0 + 14)
+
+#endif
diff --git a/arch/mips/include/asm/mach-lantiq/xway/lantiq_soc.h b/arch/mips/include/asm/mach-lantiq/xway/lantiq_soc.h
new file mode 100644 (file)
index 0000000..8a3c6be
--- /dev/null
@@ -0,0 +1,141 @@
+/*
+ *  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.
+ *
+ *  Copyright (C) 2010 John Crispin <blogic@openwrt.org>
+ */
+
+#ifndef _LTQ_XWAY_H__
+#define _LTQ_XWAY_H__
+
+#ifdef CONFIG_SOC_TYPE_XWAY
+
+#include <lantiq.h>
+
+/* Chip IDs */
+#define SOC_ID_DANUBE1         0x129
+#define SOC_ID_DANUBE2         0x12B
+#define SOC_ID_TWINPASS                0x12D
+#define SOC_ID_AMAZON_SE       0x152
+#define SOC_ID_ARX188          0x16C
+#define SOC_ID_ARX168          0x16D
+#define SOC_ID_ARX182          0x16F
+
+/* SoC Types */
+#define SOC_TYPE_DANUBE                0x01
+#define SOC_TYPE_TWINPASS      0x02
+#define SOC_TYPE_AR9           0x03
+#define SOC_TYPE_VR9           0x04
+#define SOC_TYPE_AMAZON_SE     0x05
+
+/* ASC0/1 - serial port */
+#define LTQ_ASC0_BASE_ADDR     0x1E100400
+#define LTQ_ASC1_BASE_ADDR     0x1E100C00
+#define LTQ_ASC_SIZE           0x400
+
+/* RCU - reset control unit */
+#define LTQ_RCU_BASE_ADDR      0x1F203000
+#define LTQ_RCU_SIZE           0x1000
+
+/* GPTU - general purpose timer unit */
+#define LTQ_GPTU_BASE_ADDR     0x18000300
+#define LTQ_GPTU_SIZE          0x100
+
+/* EBU - external bus unit */
+#define LTQ_EBU_GPIO_START     0x14000000
+#define LTQ_EBU_GPIO_SIZE      0x1000
+
+#define LTQ_EBU_BASE_ADDR      0x1E105300
+#define LTQ_EBU_SIZE           0x100
+
+#define LTQ_EBU_BUSCON0                0x0060
+#define LTQ_EBU_PCC_CON                0x0090
+#define LTQ_EBU_PCC_IEN                0x00A4
+#define LTQ_EBU_PCC_ISTAT      0x00A0
+#define LTQ_EBU_BUSCON1                0x0064
+#define LTQ_EBU_ADDRSEL1       0x0024
+#define EBU_WRDIS              0x80000000
+
+/* CGU - clock generation unit */
+#define LTQ_CGU_BASE_ADDR      0x1F103000
+#define LTQ_CGU_SIZE           0x1000
+
+/* ICU - interrupt control unit */
+#define LTQ_ICU_BASE_ADDR      0x1F880200
+#define LTQ_ICU_SIZE           0x100
+
+/* EIU - external interrupt unit */
+#define LTQ_EIU_BASE_ADDR      0x1F101000
+#define LTQ_EIU_SIZE           0x1000
+
+/* PMU - power management unit */
+#define LTQ_PMU_BASE_ADDR      0x1F102000
+#define LTQ_PMU_SIZE           0x1000
+
+#define PMU_DMA                        0x0020
+#define PMU_USB                        0x8041
+#define PMU_LED                        0x0800
+#define PMU_GPT                        0x1000
+#define PMU_PPE                        0x2000
+#define PMU_FPI                        0x4000
+#define PMU_SWITCH             0x10000000
+
+/* ETOP - ethernet */
+#define LTQ_ETOP_BASE_ADDR     0x1E180000
+#define LTQ_ETOP_SIZE          0x40000
+
+/* DMA */
+#define LTQ_DMA_BASE_ADDR      0x1E104100
+#define LTQ_DMA_SIZE           0x800
+
+/* PCI */
+#define PCI_CR_BASE_ADDR       0x1E105400
+#define PCI_CR_SIZE            0x400
+
+/* WDT */
+#define LTQ_WDT_BASE_ADDR      0x1F8803F0
+#define LTQ_WDT_SIZE           0x10
+
+/* STP - serial to parallel conversion unit */
+#define LTQ_STP_BASE_ADDR      0x1E100BB0
+#define LTQ_STP_SIZE           0x40
+
+/* GPIO */
+#define LTQ_GPIO0_BASE_ADDR    0x1E100B10
+#define LTQ_GPIO1_BASE_ADDR    0x1E100B40
+#define LTQ_GPIO2_BASE_ADDR    0x1E100B70
+#define LTQ_GPIO_SIZE          0x30
+
+/* SSC */
+#define LTQ_SSC_BASE_ADDR      0x1e100800
+#define LTQ_SSC_SIZE           0x100
+
+/* MEI - dsl core */
+#define LTQ_MEI_BASE_ADDR      0x1E116000
+
+/* DEU - data encryption unit */
+#define LTQ_DEU_BASE_ADDR      0x1E103100
+
+/* MPS - multi processor unit (voice) */
+#define LTQ_MPS_BASE_ADDR      (KSEG1 + 0x1F107000)
+#define LTQ_MPS_CHIPID         ((u32 *)(LTQ_MPS_BASE_ADDR + 0x0344))
+
+/* request a non-gpio and set the PIO config */
+extern int  ltq_gpio_request(unsigned int pin, unsigned int alt0,
+       unsigned int alt1, unsigned int dir, const char *name);
+extern void ltq_pmu_enable(unsigned int module);
+extern void ltq_pmu_disable(unsigned int module);
+
+static inline int ltq_is_ar9(void)
+{
+       return (ltq_get_soc_type() == SOC_TYPE_AR9);
+}
+
+static inline int ltq_is_vr9(void)
+{
+       return (ltq_get_soc_type() == SOC_TYPE_VR9);
+}
+
+#endif /* CONFIG_SOC_TYPE_XWAY */
+#endif /* _LTQ_XWAY_H__ */
diff --git a/arch/mips/include/asm/mach-lantiq/xway/xway_dma.h b/arch/mips/include/asm/mach-lantiq/xway/xway_dma.h
new file mode 100644 (file)
index 0000000..872943a
--- /dev/null
@@ -0,0 +1,60 @@
+/*
+ *   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 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) 2011 John Crispin <blogic@openwrt.org>
+ */
+
+#ifndef LTQ_DMA_H__
+#define LTQ_DMA_H__
+
+#define LTQ_DESC_SIZE          0x08    /* each descriptor is 64bit */
+#define LTQ_DESC_NUM           0x40    /* 64 descriptors / channel */
+
+#define LTQ_DMA_OWN            BIT(31) /* owner bit */
+#define LTQ_DMA_C              BIT(30) /* complete bit */
+#define LTQ_DMA_SOP            BIT(29) /* start of packet */
+#define LTQ_DMA_EOP            BIT(28) /* end of packet */
+#define LTQ_DMA_TX_OFFSET(x)   ((x & 0x1f) << 23) /* data bytes offset */
+#define LTQ_DMA_RX_OFFSET(x)   ((x & 0x7) << 23) /* data bytes offset */
+#define LTQ_DMA_SIZE_MASK      (0xffff) /* the size field is 16 bit */
+
+struct ltq_dma_desc {
+       u32 ctl;
+       u32 addr;
+};
+
+struct ltq_dma_channel {
+       int nr;                         /* the channel number */
+       int irq;                        /* the mapped irq */
+       int desc;                       /* the current descriptor */
+       struct ltq_dma_desc *desc_base; /* the descriptor base */
+       int phys;                       /* physical addr */
+};
+
+enum {
+       DMA_PORT_ETOP = 0,
+       DMA_PORT_DEU,
+};
+
+extern void ltq_dma_enable_irq(struct ltq_dma_channel *ch);
+extern void ltq_dma_disable_irq(struct ltq_dma_channel *ch);
+extern void ltq_dma_ack_irq(struct ltq_dma_channel *ch);
+extern void ltq_dma_open(struct ltq_dma_channel *ch);
+extern void ltq_dma_close(struct ltq_dma_channel *ch);
+extern void ltq_dma_alloc_tx(struct ltq_dma_channel *ch);
+extern void ltq_dma_alloc_rx(struct ltq_dma_channel *ch);
+extern void ltq_dma_free(struct ltq_dma_channel *ch);
+extern void ltq_dma_init_port(int p);
+
+#endif
diff --git a/arch/mips/include/asm/mach-netlogic/cpu-feature-overrides.h b/arch/mips/include/asm/mach-netlogic/cpu-feature-overrides.h
new file mode 100644 (file)
index 0000000..3b72827
--- /dev/null
@@ -0,0 +1,47 @@
+/*
+ * 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) 2011 Netlogic Microsystems
+ * Copyright (C) 2003 Ralf Baechle
+ */
+#ifndef __ASM_MACH_NETLOGIC_CPU_FEATURE_OVERRIDES_H
+#define __ASM_MACH_NETLOGIC_CPU_FEATURE_OVERRIDES_H
+
+#define cpu_has_4kex           1
+#define cpu_has_4k_cache       1
+#define cpu_has_watch          1
+#define cpu_has_mips16         0
+#define cpu_has_counter                1
+#define cpu_has_divec          1
+#define cpu_has_vce            0
+#define cpu_has_cache_cdex_p   0
+#define cpu_has_cache_cdex_s   0
+#define cpu_has_prefetch       1
+#define cpu_has_mcheck         1
+#define cpu_has_ejtag          1
+
+#define cpu_has_llsc           1
+#define cpu_has_vtag_icache    0
+#define cpu_has_dc_aliases     0
+#define cpu_has_ic_fills_f_dc  0
+#define cpu_has_dsp            0
+#define cpu_has_mipsmt         0
+#define cpu_has_userlocal      0
+#define cpu_icache_snoops_remote_store 0
+
+#define cpu_has_nofpuex                0
+#define cpu_has_64bits         1
+
+#define cpu_has_mips32r1       1
+#define cpu_has_mips32r2       0
+#define cpu_has_mips64r1       1
+#define cpu_has_mips64r2       0
+
+#define cpu_has_inclusive_pcaches      0
+
+#define cpu_dcache_line_size() 32
+#define cpu_icache_line_size() 32
+
+#endif /* __ASM_MACH_NETLOGIC_CPU_FEATURE_OVERRIDES_H */
diff --git a/arch/mips/include/asm/mach-netlogic/irq.h b/arch/mips/include/asm/mach-netlogic/irq.h
new file mode 100644 (file)
index 0000000..b590245
--- /dev/null
@@ -0,0 +1,14 @@
+/*
+ * 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) 2011 Netlogic Microsystems.
+ */
+#ifndef __ASM_NETLOGIC_IRQ_H
+#define __ASM_NETLOGIC_IRQ_H
+
+#define NR_IRQS                        64
+#define MIPS_CPU_IRQ_BASE      0
+
+#endif /* __ASM_NETLOGIC_IRQ_H */
diff --git a/arch/mips/include/asm/mach-netlogic/war.h b/arch/mips/include/asm/mach-netlogic/war.h
new file mode 100644 (file)
index 0000000..22da893
--- /dev/null
@@ -0,0 +1,26 @@
+/*
+ * 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) 2011 Netlogic Microsystems.
+ * Copyright (C) 2002, 2004, 2007 by Ralf Baechle <ralf@linux-mips.org>
+ */
+#ifndef __ASM_MIPS_MACH_NLM_WAR_H
+#define __ASM_MIPS_MACH_NLM_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_NLM_WAR_H */
index d94085a..bc01a02 100644 (file)
@@ -118,6 +118,8 @@ search_module_dbetables(unsigned long addr)
 #define MODULE_PROC_FAMILY "LOONGSON2 "
 #elif defined CONFIG_CPU_CAVIUM_OCTEON
 #define MODULE_PROC_FAMILY "OCTEON "
+#elif defined CONFIG_CPU_XLR
+#define MODULE_PROC_FAMILY "XLR "
 #else
 #error MODULE_PROC_FAMILY undefined for your processor configuration
 #endif
diff --git a/arch/mips/include/asm/netlogic/interrupt.h b/arch/mips/include/asm/netlogic/interrupt.h
new file mode 100644 (file)
index 0000000..a85aadb
--- /dev/null
@@ -0,0 +1,45 @@
+/*
+ * Copyright 2003-2011 NetLogic Microsystems, Inc. (NetLogic). All rights
+ * reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the NetLogic
+ * license below:
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY NETLOGIC ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL NETLOGIC OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _ASM_NLM_INTERRUPT_H
+#define _ASM_NLM_INTERRUPT_H
+
+/* Defines for the IRQ numbers */
+
+#define IRQ_IPI_SMP_FUNCTION   3
+#define IRQ_IPI_SMP_RESCHEDULE 4
+#define IRQ_MSGRING            6
+#define IRQ_TIMER              7
+
+#endif
diff --git a/arch/mips/include/asm/netlogic/mips-extns.h b/arch/mips/include/asm/netlogic/mips-extns.h
new file mode 100644 (file)
index 0000000..8c53d0b
--- /dev/null
@@ -0,0 +1,76 @@
+/*
+ * Copyright 2003-2011 NetLogic Microsystems, Inc. (NetLogic). All rights
+ * reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the NetLogic
+ * license below:
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY NETLOGIC ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL NETLOGIC OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _ASM_NLM_MIPS_EXTS_H
+#define _ASM_NLM_MIPS_EXTS_H
+
+/*
+ * XLR and XLP interrupt request and interrupt mask registers
+ */
+#define read_c0_eirr()         __read_64bit_c0_register($9, 6)
+#define read_c0_eimr()         __read_64bit_c0_register($9, 7)
+#define write_c0_eirr(val)     __write_64bit_c0_register($9, 6, val)
+
+/*
+ * Writing EIMR in 32 bit is a special case, the lower 8 bit of the
+ * EIMR is shadowed in the status register, so we cannot save and
+ * restore status register for split read.
+ */
+#define write_c0_eimr(val)                                             \
+do {                                                                   \
+       if (sizeof(unsigned long) == 4) {                               \
+               unsigned long __flags;                                  \
+                                                                       \
+               local_irq_save(__flags);                                \
+               __asm__ __volatile__(                                   \
+                       ".set\tmips64\n\t"                              \
+                       "dsll\t%L0, %L0, 32\n\t"                        \
+                       "dsrl\t%L0, %L0, 32\n\t"                        \
+                       "dsll\t%M0, %M0, 32\n\t"                        \
+                       "or\t%L0, %L0, %M0\n\t"                         \
+                       "dmtc0\t%L0, $9, 7\n\t"                         \
+                       ".set\tmips0"                                   \
+                       : : "r" (val));                                 \
+               __flags = (__flags & 0xffff00ff) | (((val) & 0xff) << 8);\
+               local_irq_restore(__flags);                             \
+       } else                                                          \
+               __write_64bit_c0_register($9, 7, (val));                \
+} while (0)
+
+static inline int hard_smp_processor_id(void)
+{
+       return __read_32bit_c0_register($15, 1) & 0x3ff;
+}
+
+#endif /*_ASM_NLM_MIPS_EXTS_H */
diff --git a/arch/mips/include/asm/netlogic/psb-bootinfo.h b/arch/mips/include/asm/netlogic/psb-bootinfo.h
new file mode 100644 (file)
index 0000000..6878307
--- /dev/null
@@ -0,0 +1,109 @@
+/*
+ * Copyright 2003-2011 NetLogic Microsystems, Inc. (NetLogic). All rights
+ * reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the NetLogic
+ * license below:
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY NETLOGIC ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL NETLOGIC OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _ASM_NETLOGIC_BOOTINFO_H
+#define _ASM_NETLOGIC_BOOTINFO_H
+
+struct psb_info {
+       uint64_t boot_level;
+       uint64_t io_base;
+       uint64_t output_device;
+       uint64_t uart_print;
+       uint64_t led_output;
+       uint64_t init;
+       uint64_t exit;
+       uint64_t warm_reset;
+       uint64_t wakeup;
+       uint64_t online_cpu_map;
+       uint64_t master_reentry_sp;
+       uint64_t master_reentry_gp;
+       uint64_t master_reentry_fn;
+       uint64_t slave_reentry_fn;
+       uint64_t magic_dword;
+       uint64_t uart_putchar;
+       uint64_t size;
+       uint64_t uart_getchar;
+       uint64_t nmi_handler;
+       uint64_t psb_version;
+       uint64_t mac_addr;
+       uint64_t cpu_frequency;
+       uint64_t board_version;
+       uint64_t malloc;
+       uint64_t free;
+       uint64_t global_shmem_addr;
+       uint64_t global_shmem_size;
+       uint64_t psb_os_cpu_map;
+       uint64_t userapp_cpu_map;
+       uint64_t wakeup_os;
+       uint64_t psb_mem_map;
+       uint64_t board_major_version;
+       uint64_t board_minor_version;
+       uint64_t board_manf_revision;
+       uint64_t board_serial_number;
+       uint64_t psb_physaddr_map;
+       uint64_t xlr_loaderip_config;
+       uint64_t bldr_envp;
+       uint64_t avail_mem_map;
+};
+
+enum {
+       NETLOGIC_IO_SPACE = 0x10,
+       PCIX_IO_SPACE,
+       PCIX_CFG_SPACE,
+       PCIX_MEMORY_SPACE,
+       HT_IO_SPACE,
+       HT_CFG_SPACE,
+       HT_MEMORY_SPACE,
+       SRAM_SPACE,
+       FLASH_CONTROLLER_SPACE
+};
+
+#define NLM_MAX_ARGS   64
+#define NLM_MAX_ENVS   32
+
+/* This is what netlboot passes and linux boot_mem_map is subtly different */
+#define NLM_BOOT_MEM_MAP_MAX   32
+struct nlm_boot_mem_map {
+       int nr_map;
+       struct nlm_boot_mem_map_entry {
+               uint64_t addr;          /* start of memory segment */
+               uint64_t size;          /* size of memory segment */
+               uint32_t type;          /* type of memory segment */
+       } map[NLM_BOOT_MEM_MAP_MAX];
+};
+
+/* Pointer to saved boot loader info */
+extern struct psb_info nlm_prom_info;
+
+#endif
diff --git a/arch/mips/include/asm/netlogic/xlr/gpio.h b/arch/mips/include/asm/netlogic/xlr/gpio.h
new file mode 100644 (file)
index 0000000..51f6ad4
--- /dev/null
@@ -0,0 +1,73 @@
+/*
+ * Copyright 2003-2011 NetLogic Microsystems, Inc. (NetLogic). All rights
+ * reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the NetLogic
+ * license below:
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY NETLOGIC ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL NETLOGIC OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _ASM_NLM_GPIO_H
+#define _ASM_NLM_GPIO_H
+
+#define NETLOGIC_GPIO_INT_EN_REG               0
+#define NETLOGIC_GPIO_INPUT_INVERSION_REG      1
+#define NETLOGIC_GPIO_IO_DIR_REG               2
+#define NETLOGIC_GPIO_IO_DATA_WR_REG           3
+#define NETLOGIC_GPIO_IO_DATA_RD_REG           4
+
+#define NETLOGIC_GPIO_SWRESET_REG              8
+#define NETLOGIC_GPIO_DRAM1_CNTRL_REG          9
+#define NETLOGIC_GPIO_DRAM1_RATIO_REG          10
+#define NETLOGIC_GPIO_DRAM1_RESET_REG          11
+#define NETLOGIC_GPIO_DRAM1_STATUS_REG         12
+#define NETLOGIC_GPIO_DRAM2_CNTRL_REG          13
+#define NETLOGIC_GPIO_DRAM2_RATIO_REG          14
+#define NETLOGIC_GPIO_DRAM2_RESET_REG          15
+#define NETLOGIC_GPIO_DRAM2_STATUS_REG         16
+
+#define NETLOGIC_GPIO_PWRON_RESET_CFG_REG      21
+#define NETLOGIC_GPIO_BIST_ALL_GO_STATUS_REG   24
+#define NETLOGIC_GPIO_BIST_CPU_GO_STATUS_REG   25
+#define NETLOGIC_GPIO_BIST_DEV_GO_STATUS_REG   26
+
+#define NETLOGIC_GPIO_FUSE_BANK_REG            35
+#define NETLOGIC_GPIO_CPU_RESET_REG            40
+#define NETLOGIC_GPIO_RNG_REG                  43
+
+#define NETLOGIC_PWRON_RESET_PCMCIA_BOOT       17
+#define NETLOGIC_GPIO_LED_BITMAP       0x1700000
+#define NETLOGIC_GPIO_LED_0_SHIFT              20
+#define NETLOGIC_GPIO_LED_1_SHIFT              24
+
+#define NETLOGIC_GPIO_LED_OUTPUT_CODE_RESET    0x01
+#define NETLOGIC_GPIO_LED_OUTPUT_CODE_HARD_RESET 0x02
+#define NETLOGIC_GPIO_LED_OUTPUT_CODE_SOFT_RESET 0x03
+#define NETLOGIC_GPIO_LED_OUTPUT_CODE_MAIN     0x04
+
+#endif
diff --git a/arch/mips/include/asm/netlogic/xlr/iomap.h b/arch/mips/include/asm/netlogic/xlr/iomap.h
new file mode 100644 (file)
index 0000000..2e3a4dd
--- /dev/null
@@ -0,0 +1,131 @@
+/*
+ * Copyright 2003-2011 NetLogic Microsystems, Inc. (NetLogic). All rights
+ * reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the NetLogic
+ * license below:
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY NETLOGIC ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL NETLOGIC OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _ASM_NLM_IOMAP_H
+#define _ASM_NLM_IOMAP_H
+
+#define DEFAULT_NETLOGIC_IO_BASE           CKSEG1ADDR(0x1ef00000)
+#define NETLOGIC_IO_DDR2_CHN0_OFFSET       0x01000
+#define NETLOGIC_IO_DDR2_CHN1_OFFSET       0x02000
+#define NETLOGIC_IO_DDR2_CHN2_OFFSET       0x03000
+#define NETLOGIC_IO_DDR2_CHN3_OFFSET       0x04000
+#define NETLOGIC_IO_PIC_OFFSET             0x08000
+#define NETLOGIC_IO_UART_0_OFFSET          0x14000
+#define NETLOGIC_IO_UART_1_OFFSET          0x15100
+
+#define NETLOGIC_IO_SIZE                   0x1000
+
+#define NETLOGIC_IO_BRIDGE_OFFSET          0x00000
+
+#define NETLOGIC_IO_RLD2_CHN0_OFFSET       0x05000
+#define NETLOGIC_IO_RLD2_CHN1_OFFSET       0x06000
+
+#define NETLOGIC_IO_SRAM_OFFSET            0x07000
+
+#define NETLOGIC_IO_PCIX_OFFSET            0x09000
+#define NETLOGIC_IO_HT_OFFSET              0x0A000
+
+#define NETLOGIC_IO_SECURITY_OFFSET        0x0B000
+
+#define NETLOGIC_IO_GMAC_0_OFFSET          0x0C000
+#define NETLOGIC_IO_GMAC_1_OFFSET          0x0D000
+#define NETLOGIC_IO_GMAC_2_OFFSET          0x0E000
+#define NETLOGIC_IO_GMAC_3_OFFSET          0x0F000
+
+/* XLS devices */
+#define NETLOGIC_IO_GMAC_4_OFFSET          0x20000
+#define NETLOGIC_IO_GMAC_5_OFFSET          0x21000
+#define NETLOGIC_IO_GMAC_6_OFFSET          0x22000
+#define NETLOGIC_IO_GMAC_7_OFFSET          0x23000
+
+#define NETLOGIC_IO_PCIE_0_OFFSET          0x1E000
+#define NETLOGIC_IO_PCIE_1_OFFSET          0x1F000
+#define NETLOGIC_IO_SRIO_0_OFFSET          0x1E000
+#define NETLOGIC_IO_SRIO_1_OFFSET          0x1F000
+
+#define NETLOGIC_IO_USB_0_OFFSET           0x24000
+#define NETLOGIC_IO_USB_1_OFFSET           0x25000
+
+#define NETLOGIC_IO_COMP_OFFSET            0x1D000
+/* end XLS devices */
+
+/* XLR devices */
+#define NETLOGIC_IO_SPI4_0_OFFSET          0x10000
+#define NETLOGIC_IO_XGMAC_0_OFFSET         0x11000
+#define NETLOGIC_IO_SPI4_1_OFFSET          0x12000
+#define NETLOGIC_IO_XGMAC_1_OFFSET         0x13000
+/* end XLR devices */
+
+#define NETLOGIC_IO_I2C_0_OFFSET           0x16000
+#define NETLOGIC_IO_I2C_1_OFFSET           0x17000
+
+#define NETLOGIC_IO_GPIO_OFFSET            0x18000
+#define NETLOGIC_IO_FLASH_OFFSET           0x19000
+#define NETLOGIC_IO_TB_OFFSET              0x1C000
+
+#define NETLOGIC_CPLD_OFFSET               KSEG1ADDR(0x1d840000)
+
+/*
+ * Base Address (Virtual) of the PCI Config address space
+ * For now, choose 256M phys in kseg1 = 0xA0000000 + (1<<28)
+ * Config space spans 256 (num of buses) * 256 (num functions) * 256 bytes
+ * ie 1<<24 = 16M
+ */
+#define DEFAULT_PCI_CONFIG_BASE         0x18000000
+#define DEFAULT_HT_TYPE0_CFG_BASE       0x16000000
+#define DEFAULT_HT_TYPE1_CFG_BASE       0x17000000
+
+#ifndef __ASSEMBLY__
+#include <linux/types.h>
+#include <asm/byteorder.h>
+
+typedef volatile __u32 nlm_reg_t;
+extern unsigned long netlogic_io_base;
+
+/* FIXME read once in write_reg */
+#ifdef CONFIG_CPU_LITTLE_ENDIAN
+#define netlogic_read_reg(base, offset)                ((base)[(offset)])
+#define netlogic_write_reg(base, offset, value)        ((base)[(offset)] = (value))
+#else
+#define netlogic_read_reg(base, offset)                (be32_to_cpu((base)[(offset)]))
+#define netlogic_write_reg(base, offset, value) \
+                               ((base)[(offset)] = cpu_to_be32((value)))
+#endif
+
+#define netlogic_read_reg_le32(base, offset) (le32_to_cpu((base)[(offset)]))
+#define netlogic_write_reg_le32(base, offset, value) \
+                               ((base)[(offset)] = cpu_to_le32((value)))
+#define netlogic_io_mmio(offset) ((nlm_reg_t *)(netlogic_io_base+(offset)))
+#endif /* __ASSEMBLY__ */
+#endif
diff --git a/arch/mips/include/asm/netlogic/xlr/pic.h b/arch/mips/include/asm/netlogic/xlr/pic.h
new file mode 100644 (file)
index 0000000..5cceb74
--- /dev/null
@@ -0,0 +1,231 @@
+/*
+ * Copyright 2003-2011 NetLogic Microsystems, Inc. (NetLogic). All rights
+ * reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the NetLogic
+ * license below:
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY NETLOGIC ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL NETLOGIC OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _ASM_NLM_XLR_PIC_H
+#define _ASM_NLM_XLR_PIC_H
+
+#define PIC_CLKS_PER_SEC               66666666ULL
+/* PIC hardware interrupt numbers */
+#define PIC_IRT_WD_INDEX               0
+#define PIC_IRT_TIMER_0_INDEX          1
+#define PIC_IRT_TIMER_1_INDEX          2
+#define PIC_IRT_TIMER_2_INDEX          3
+#define PIC_IRT_TIMER_3_INDEX          4
+#define PIC_IRT_TIMER_4_INDEX          5
+#define PIC_IRT_TIMER_5_INDEX          6
+#define PIC_IRT_TIMER_6_INDEX          7
+#define PIC_IRT_TIMER_7_INDEX          8
+#define PIC_IRT_CLOCK_INDEX            PIC_IRT_TIMER_7_INDEX
+#define PIC_IRT_UART_0_INDEX           9
+#define PIC_IRT_UART_1_INDEX           10
+#define PIC_IRT_I2C_0_INDEX            11
+#define PIC_IRT_I2C_1_INDEX            12
+#define PIC_IRT_PCMCIA_INDEX           13
+#define PIC_IRT_GPIO_INDEX             14
+#define PIC_IRT_HYPER_INDEX            15
+#define PIC_IRT_PCIX_INDEX             16
+/* XLS */
+#define PIC_IRT_CDE_INDEX              15
+#define PIC_IRT_BRIDGE_TB_XLS_INDEX    16
+/* XLS */
+#define PIC_IRT_GMAC0_INDEX            17
+#define PIC_IRT_GMAC1_INDEX            18
+#define PIC_IRT_GMAC2_INDEX            19
+#define PIC_IRT_GMAC3_INDEX            20
+#define PIC_IRT_XGS0_INDEX             21
+#define PIC_IRT_XGS1_INDEX             22
+#define PIC_IRT_HYPER_FATAL_INDEX      23
+#define PIC_IRT_PCIX_FATAL_INDEX       24
+#define PIC_IRT_BRIDGE_AERR_INDEX      25
+#define PIC_IRT_BRIDGE_BERR_INDEX      26
+#define PIC_IRT_BRIDGE_TB_XLR_INDEX    27
+#define PIC_IRT_BRIDGE_AERR_NMI_INDEX  28
+/* XLS */
+#define PIC_IRT_GMAC4_INDEX            21
+#define PIC_IRT_GMAC5_INDEX            22
+#define PIC_IRT_GMAC6_INDEX            23
+#define PIC_IRT_GMAC7_INDEX            24
+#define PIC_IRT_BRIDGE_ERR_INDEX       25
+#define PIC_IRT_PCIE_LINK0_INDEX       26
+#define PIC_IRT_PCIE_LINK1_INDEX       27
+#define PIC_IRT_PCIE_LINK2_INDEX       23
+#define PIC_IRT_PCIE_LINK3_INDEX       24
+#define PIC_IRT_PCIE_XLSB0_LINK2_INDEX 28
+#define PIC_IRT_PCIE_XLSB0_LINK3_INDEX 29
+#define PIC_IRT_SRIO_LINK0_INDEX       26
+#define PIC_IRT_SRIO_LINK1_INDEX       27
+#define PIC_IRT_SRIO_LINK2_INDEX       28
+#define PIC_IRT_SRIO_LINK3_INDEX       29
+#define PIC_IRT_PCIE_INT_INDEX         28
+#define PIC_IRT_PCIE_FATAL_INDEX       29
+#define PIC_IRT_GPIO_B_INDEX           30
+#define PIC_IRT_USB_INDEX              31
+/* XLS */
+#define PIC_NUM_IRTS                   32
+
+
+#define PIC_CLOCK_TIMER                        7
+
+/* PIC Registers */
+#define PIC_CTRL                       0x00
+#define PIC_IPI                                0x04
+#define PIC_INT_ACK                    0x06
+
+#define WD_MAX_VAL_0                   0x08
+#define WD_MAX_VAL_1                   0x09
+#define WD_MASK_0                      0x0a
+#define WD_MASK_1                      0x0b
+#define WD_HEARBEAT_0                  0x0c
+#define WD_HEARBEAT_1                  0x0d
+
+#define PIC_IRT_0_BASE                 0x40
+#define PIC_IRT_1_BASE                 0x80
+#define PIC_TIMER_MAXVAL_0_BASE                0x100
+#define PIC_TIMER_MAXVAL_1_BASE                0x110
+#define PIC_TIMER_COUNT_0_BASE         0x120
+#define PIC_TIMER_COUNT_1_BASE         0x130
+
+#define PIC_IRT_0(picintr)      (PIC_IRT_0_BASE + (picintr))
+#define PIC_IRT_1(picintr)     (PIC_IRT_1_BASE + (picintr))
+
+#define PIC_TIMER_MAXVAL_0(i)  (PIC_TIMER_MAXVAL_0_BASE + (i))
+#define PIC_TIMER_MAXVAL_1(i)  (PIC_TIMER_MAXVAL_1_BASE + (i))
+#define PIC_TIMER_COUNT_0(i)   (PIC_TIMER_COUNT_0_BASE + (i))
+#define PIC_TIMER_COUNT_1(i)   (PIC_TIMER_COUNT_0_BASE + (i))
+
+/*
+ * Mapping between hardware interrupt numbers and IRQs on CPU
+ * we use a simple scheme to map PIC interrupts 0-31 to IRQs
+ * 8-39. This leaves the IRQ 0-7 for cpu interrupts like
+ * count/compare and FMN
+ */
+#define PIC_IRQ_BASE            8
+#define PIC_INTR_TO_IRQ(i)      (PIC_IRQ_BASE + (i))
+#define PIC_IRQ_TO_INTR(i)      ((i) - PIC_IRQ_BASE)
+
+#define PIC_IRT_FIRST_IRQ      PIC_IRQ_BASE
+#define PIC_WD_IRQ             PIC_INTR_TO_IRQ(PIC_IRT_WD_INDEX)
+#define PIC_TIMER_0_IRQ                PIC_INTR_TO_IRQ(PIC_IRT_TIMER_0_INDEX)
+#define PIC_TIMER_1_IRQ                PIC_INTR_TO_IRQ(PIC_IRT_TIMER_1_INDEX)
+#define PIC_TIMER_2_IRQ                PIC_INTR_TO_IRQ(PIC_IRT_TIMER_2_INDEX)
+#define PIC_TIMER_3_IRQ                PIC_INTR_TO_IRQ(PIC_IRT_TIMER_3_INDEX)
+#define PIC_TIMER_4_IRQ                PIC_INTR_TO_IRQ(PIC_IRT_TIMER_4_INDEX)
+#define PIC_TIMER_5_IRQ                PIC_INTR_TO_IRQ(PIC_IRT_TIMER_5_INDEX)
+#define PIC_TIMER_6_IRQ                PIC_INTR_TO_IRQ(PIC_IRT_TIMER_6_INDEX)
+#define PIC_TIMER_7_IRQ                PIC_INTR_TO_IRQ(PIC_IRT_TIMER_7_INDEX)
+#define PIC_CLOCK_IRQ          (PIC_TIMER_7_IRQ)
+#define PIC_UART_0_IRQ         PIC_INTR_TO_IRQ(PIC_IRT_UART_0_INDEX)
+#define PIC_UART_1_IRQ         PIC_INTR_TO_IRQ(PIC_IRT_UART_1_INDEX)
+#define PIC_I2C_0_IRQ          PIC_INTR_TO_IRQ(PIC_IRT_I2C_0_INDEX)
+#define PIC_I2C_1_IRQ          PIC_INTR_TO_IRQ(PIC_IRT_I2C_1_INDEX)
+#define PIC_PCMCIA_IRQ         PIC_INTR_TO_IRQ(PIC_IRT_PCMCIA_INDEX)
+#define PIC_GPIO_IRQ           PIC_INTR_TO_IRQ(PIC_IRT_GPIO_INDEX)
+#define PIC_HYPER_IRQ          PIC_INTR_TO_IRQ(PIC_IRT_HYPER_INDEX)
+#define PIC_PCIX_IRQ           PIC_INTR_TO_IRQ(PIC_IRT_PCIX_INDEX)
+/* XLS */
+#define PIC_CDE_IRQ            PIC_INTR_TO_IRQ(PIC_IRT_CDE_INDEX)
+#define PIC_BRIDGE_TB_XLS_IRQ  PIC_INTR_TO_IRQ(PIC_IRT_BRIDGE_TB_XLS_INDEX)
+/* end XLS */
+#define PIC_GMAC_0_IRQ         PIC_INTR_TO_IRQ(PIC_IRT_GMAC0_INDEX)
+#define PIC_GMAC_1_IRQ         PIC_INTR_TO_IRQ(PIC_IRT_GMAC1_INDEX)
+#define PIC_GMAC_2_IRQ         PIC_INTR_TO_IRQ(PIC_IRT_GMAC2_INDEX)
+#define PIC_GMAC_3_IRQ         PIC_INTR_TO_IRQ(PIC_IRT_GMAC3_INDEX)
+#define PIC_XGS_0_IRQ          PIC_INTR_TO_IRQ(PIC_IRT_XGS0_INDEX)
+#define PIC_XGS_1_IRQ          PIC_INTR_TO_IRQ(PIC_IRT_XGS1_INDEX)
+#define PIC_HYPER_FATAL_IRQ    PIC_INTR_TO_IRQ(PIC_IRT_HYPER_FATAL_INDEX)
+#define PIC_PCIX_FATAL_IRQ     PIC_INTR_TO_IRQ(PIC_IRT_PCIX_FATAL_INDEX)
+#define PIC_BRIDGE_AERR_IRQ    PIC_INTR_TO_IRQ(PIC_IRT_BRIDGE_AERR_INDEX)
+#define PIC_BRIDGE_BERR_IRQ    PIC_INTR_TO_IRQ(PIC_IRT_BRIDGE_BERR_INDEX)
+#define PIC_BRIDGE_TB_XLR_IRQ  PIC_INTR_TO_IRQ(PIC_IRT_BRIDGE_TB_XLR_INDEX)
+#define PIC_BRIDGE_AERR_NMI_IRQ        PIC_INTR_TO_IRQ(PIC_IRT_BRIDGE_AERR_NMI_INDEX)
+/* XLS defines */
+#define PIC_GMAC_4_IRQ         PIC_INTR_TO_IRQ(PIC_IRT_GMAC4_INDEX)
+#define PIC_GMAC_5_IRQ         PIC_INTR_TO_IRQ(PIC_IRT_GMAC5_INDEX)
+#define PIC_GMAC_6_IRQ         PIC_INTR_TO_IRQ(PIC_IRT_GMAC6_INDEX)
+#define PIC_GMAC_7_IRQ         PIC_INTR_TO_IRQ(PIC_IRT_GMAC7_INDEX)
+#define PIC_BRIDGE_ERR_IRQ     PIC_INTR_TO_IRQ(PIC_IRT_BRIDGE_ERR_INDEX)
+#define PIC_PCIE_LINK0_IRQ     PIC_INTR_TO_IRQ(PIC_IRT_PCIE_LINK0_INDEX)
+#define PIC_PCIE_LINK1_IRQ     PIC_INTR_TO_IRQ(PIC_IRT_PCIE_LINK1_INDEX)
+#define PIC_PCIE_LINK2_IRQ     PIC_INTR_TO_IRQ(PIC_IRT_PCIE_LINK2_INDEX)
+#define PIC_PCIE_LINK3_IRQ     PIC_INTR_TO_IRQ(PIC_IRT_PCIE_LINK3_INDEX)
+#define PIC_PCIE_XLSB0_LINK2_IRQ PIC_INTR_TO_IRQ(PIC_IRT_PCIE_XLSB0_LINK2_INDEX)
+#define PIC_PCIE_XLSB0_LINK3_IRQ PIC_INTR_TO_IRQ(PIC_IRT_PCIE_XLSB0_LINK3_INDEX)
+#define PIC_SRIO_LINK0_IRQ     PIC_INTR_TO_IRQ(PIC_IRT_SRIO_LINK0_INDEX)
+#define PIC_SRIO_LINK1_IRQ     PIC_INTR_TO_IRQ(PIC_IRT_SRIO_LINK1_INDEX)
+#define PIC_SRIO_LINK2_IRQ     PIC_INTR_TO_IRQ(PIC_IRT_SRIO_LINK2_INDEX)
+#define PIC_SRIO_LINK3_IRQ     PIC_INTR_TO_IRQ(PIC_IRT_SRIO_LINK3_INDEX)
+#define PIC_PCIE_INT_IRQ       PIC_INTR_TO_IRQ(PIC_IRT_PCIE_INT__INDEX)
+#define PIC_PCIE_FATAL_IRQ     PIC_INTR_TO_IRQ(PIC_IRT_PCIE_FATAL_INDEX)
+#define PIC_GPIO_B_IRQ         PIC_INTR_TO_IRQ(PIC_IRT_GPIO_B_INDEX)
+#define PIC_USB_IRQ            PIC_INTR_TO_IRQ(PIC_IRT_USB_INDEX)
+#define PIC_IRT_LAST_IRQ       PIC_USB_IRQ
+/* end XLS */
+
+#ifndef __ASSEMBLY__
+static inline void pic_send_ipi(u32 ipi)
+{
+       nlm_reg_t *mmio = netlogic_io_mmio(NETLOGIC_IO_PIC_OFFSET);
+
+       netlogic_write_reg(mmio, PIC_IPI, ipi);
+}
+
+static inline u32 pic_read_control(void)
+{
+       nlm_reg_t *mmio = netlogic_io_mmio(NETLOGIC_IO_PIC_OFFSET);
+
+       return netlogic_read_reg(mmio, PIC_CTRL);
+}
+
+static inline void pic_write_control(u32 control)
+{
+       nlm_reg_t *mmio = netlogic_io_mmio(NETLOGIC_IO_PIC_OFFSET);
+
+       netlogic_write_reg(mmio, PIC_CTRL, control);
+}
+
+static inline void pic_update_control(u32 control)
+{
+       nlm_reg_t *mmio = netlogic_io_mmio(NETLOGIC_IO_PIC_OFFSET);
+
+       netlogic_write_reg(mmio, PIC_CTRL,
+               (control | netlogic_read_reg(mmio, PIC_CTRL)));
+}
+
+#define PIC_IRQ_IS_EDGE_TRIGGERED(irq) (((irq) >= PIC_TIMER_0_IRQ) && \
+                                       ((irq) <= PIC_TIMER_7_IRQ))
+#define PIC_IRQ_IS_IRT(irq)            (((irq) >= PIC_IRT_FIRST_IRQ) && \
+                                       ((irq) <= PIC_IRT_LAST_IRQ))
+#endif
+
+#endif /* _ASM_NLM_XLR_PIC_H */
diff --git a/arch/mips/include/asm/netlogic/xlr/xlr.h b/arch/mips/include/asm/netlogic/xlr/xlr.h
new file mode 100644 (file)
index 0000000..3e63726
--- /dev/null
@@ -0,0 +1,75 @@
+/*
+ * Copyright 2003-2011 NetLogic Microsystems, Inc. (NetLogic). All rights
+ * reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the NetLogic
+ * license below:
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY NETLOGIC ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL NETLOGIC OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _ASM_NLM_XLR_H
+#define _ASM_NLM_XLR_H
+
+/* Platform UART functions */
+struct uart_port;
+unsigned int nlm_xlr_uart_in(struct uart_port *, int);
+void nlm_xlr_uart_out(struct uart_port *, int, int);
+
+/* SMP support functions */
+struct irq_desc;
+void nlm_smp_function_ipi_handler(unsigned int irq, struct irq_desc *desc);
+void nlm_smp_resched_ipi_handler(unsigned int irq, struct irq_desc *desc);
+int nlm_wakeup_secondary_cpus(u32 wakeup_mask);
+void nlm_smp_irq_init(void);
+void nlm_boot_smp_nmi(void);
+void prom_pre_boot_secondary_cpus(void);
+
+extern struct plat_smp_ops nlm_smp_ops;
+extern unsigned long nlm_common_ebase;
+
+/* XLS B silicon "Rook" */
+static inline unsigned int nlm_chip_is_xls_b(void)
+{
+       uint32_t prid = read_c0_prid();
+
+       return ((prid & 0xf000) == 0x4000);
+}
+
+/*
+ *  XLR chip types
+ */
+ /* The XLS product line has chip versions 0x[48c]? */
+static inline unsigned int nlm_chip_is_xls(void)
+{
+       uint32_t prid = read_c0_prid();
+
+       return ((prid & 0xf000) == 0x8000 || (prid & 0xf000) == 0x4000 ||
+               (prid & 0xf000) == 0xc000);
+}
+
+#endif /* _ASM_NLM_XLR_H */
index 9f1b8db..de39b1f 100644 (file)
@@ -141,7 +141,8 @@ extern int ptrace_set_watch_regs(struct task_struct *child,
 #define instruction_pointer(regs) ((regs)->cp0_epc)
 #define profile_pc(regs) instruction_pointer(regs)
 
-extern asmlinkage void do_syscall_trace(struct pt_regs *regs, int entryexit);
+extern asmlinkage void syscall_trace_enter(struct pt_regs *regs);
+extern asmlinkage void syscall_trace_leave(struct pt_regs *regs);
 
 extern NORET_TYPE void die(const char *, struct pt_regs *) ATTRIB_NORET;
 
index d71160d..97f8bf6 100644 (file)
@@ -149,6 +149,9 @@ register struct thread_info *__current_thread_info __asm__("$28");
 #define _TIF_FPUBOUND          (1<<TIF_FPUBOUND)
 #define _TIF_LOAD_WATCH                (1<<TIF_LOAD_WATCH)
 
+/* work to do in syscall_trace_leave() */
+#define _TIF_WORK_SYSCALL_EXIT (_TIF_SYSCALL_TRACE | _TIF_SYSCALL_AUDIT)
+
 /* work to do on interrupt/exception return */
 #define _TIF_WORK_MASK         (0x0000ffef &                           \
                                        ~(_TIF_SECCOMP | _TIF_SYSCALL_AUDIT))
index c7f1bfe..bc14447 100644 (file)
@@ -84,12 +84,6 @@ static inline int init_mips_clocksource(void)
 #endif
 }
 
-static inline void clocksource_set_clock(struct clocksource *cs,
-                                        unsigned int clock)
-{
-       clocksource_calc_mult_shift(cs, clock, 4);
-}
-
 static inline void clockevent_set_clock(struct clock_event_device *cd,
                                        unsigned int clock)
 {
index 9ce9f64..2d8e447 100644 (file)
@@ -211,7 +211,7 @@ EXPORT_SYMBOL(vdma_free);
  */
 int vdma_remap(unsigned long laddr, unsigned long paddr, unsigned long size)
 {
-       int first, pages, npages;
+       int first, pages;
 
        if (laddr > 0xffffff) {
                if (vdma_debug)
@@ -228,8 +228,7 @@ int vdma_remap(unsigned long laddr, unsigned long paddr, unsigned long size)
                return -EINVAL; /* invalid physical address */
        }
 
-       npages = pages =
-           (((paddr & (VDMA_PAGESIZE - 1)) + size) >> 12) + 1;
+       pages = (((paddr & (VDMA_PAGESIZE - 1)) + size) >> 12) + 1;
        first = laddr >> 12;
        if (vdma_debug)
                printk("vdma_remap: first=%x, pages=%x\n", first, pages);
index 5ebe75a..d7feb89 100644 (file)
@@ -242,9 +242,7 @@ EXPORT_SYMBOL_GPL(jz4740_dma_get_residue);
 
 static void jz4740_dma_chan_irq(struct jz4740_dma_chan *dma)
 {
-       uint32_t status;
-
-       status = jz4740_dma_read(JZ_REG_DMA_STATUS_CTRL(dma->id));
+       (void) jz4740_dma_read(JZ_REG_DMA_STATUS_CTRL(dma->id));
 
        jz4740_dma_write_mask(JZ_REG_DMA_STATUS_CTRL(dma->id), 0,
                JZ_DMA_STATUS_CTRL_ENABLE | JZ_DMA_STATUS_CTRL_TRANSFER_DONE);
index 6a9e14d..d97cfbf 100644 (file)
@@ -1,5 +1,6 @@
 /*
  *  Copyright (C) 2009-2010, Lars-Peter Clausen <lars@metafoo.de>
+ *  Copyright (C) 2011, Maarten ter Huurne <maarten@treewalker.org>
  *  JZ4740 setup code
  *
  *  This program is free software; you can redistribute it and/or modify it
  */
 
 #include <linux/init.h>
+#include <linux/io.h>
 #include <linux/kernel.h>
 
+#include <asm/bootinfo.h>
+
+#include <asm/mach-jz4740/base.h>
+
 #include "reset.h"
 
+
+#define JZ4740_EMC_SDRAM_CTRL 0x80
+
+
+static void __init jz4740_detect_mem(void)
+{
+       void __iomem *jz_emc_base;
+       u32 ctrl, bus, bank, rows, cols;
+       phys_t size;
+
+       jz_emc_base = ioremap(JZ4740_EMC_BASE_ADDR, 0x100);
+       ctrl = readl(jz_emc_base + JZ4740_EMC_SDRAM_CTRL);
+       bus = 2 - ((ctrl >> 31) & 1);
+       bank = 1 + ((ctrl >> 19) & 1);
+       cols = 8 + ((ctrl >> 26) & 7);
+       rows = 11 + ((ctrl >> 20) & 3);
+       printk(KERN_DEBUG
+               "SDRAM preconfigured: bus:%u bank:%u rows:%u cols:%u\n",
+               bus, bank, rows, cols);
+       iounmap(jz_emc_base);
+
+       size = 1 << (bus + bank + cols + rows);
+       add_memory_region(0, size, BOOT_MEM_RAM);
+}
+
 void __init plat_mem_setup(void)
 {
        jz4740_reset_init();
+       jz4740_detect_mem();
 }
 
 const char *get_system_type(void)
index fe01678..f83c2dd 100644 (file)
@@ -89,7 +89,7 @@ static int jz4740_clockevent_set_next(unsigned long evt,
 
 static struct clock_event_device jz4740_clockevent = {
        .name = "jz4740-timer",
-       .features = CLOCK_EVT_FEAT_PERIODIC,
+       .features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT,
        .set_next_event = jz4740_clockevent_set_next,
        .set_mode = jz4740_clockevent_set_mode,
        .rating = 200,
@@ -121,8 +121,7 @@ void __init plat_time_init(void)
 
        clockevents_register_device(&jz4740_clockevent);
 
-       clocksource_set_clock(&jz4740_clocksource, clk_rate);
-       ret = clocksource_register(&jz4740_clocksource);
+       ret = clocksource_register_hz(&jz4740_clocksource, clk_rate);
 
        if (ret)
                printk(KERN_ERR "Failed to register clocksource: %d\n", ret);
index b2c0151..654d5c3 100644 (file)
@@ -27,11 +27,13 @@ void jz4740_timer_enable_watchdog(void)
 {
        writel(BIT(16), jz4740_timer_base + JZ_REG_TIMER_STOP_CLEAR);
 }
+EXPORT_SYMBOL_GPL(jz4740_timer_enable_watchdog);
 
 void jz4740_timer_disable_watchdog(void)
 {
        writel(BIT(16), jz4740_timer_base + JZ_REG_TIMER_STOP_SET);
 }
+EXPORT_SYMBOL_GPL(jz4740_timer_disable_watchdog);
 
 void __init jz4740_timer_init(void)
 {
index cedee2b..83bba33 100644 (file)
@@ -52,6 +52,7 @@ obj-$(CONFIG_CPU_TX39XX)      += r2300_fpu.o r2300_switch.o
 obj-$(CONFIG_CPU_TX49XX)       += r4k_fpu.o r4k_switch.o
 obj-$(CONFIG_CPU_VR41XX)       += r4k_fpu.o r4k_switch.o
 obj-$(CONFIG_CPU_CAVIUM_OCTEON)        += octeon_switch.o
+obj-$(CONFIG_CPU_XLR)          += r4k_fpu.o r4k_switch.o
 
 obj-$(CONFIG_SMP)              += smp.o
 obj-$(CONFIG_SMP_UP)           += smp-up.o
index 0b73773..f0ab92a 100644 (file)
@@ -51,8 +51,7 @@ void __init txx9_clocksource_init(unsigned long baseaddr,
 {
        struct txx9_tmr_reg __iomem *tmrptr;
 
-       clocksource_set_clock(&txx9_clocksource.cs, TIMER_CLK(imbusclk));
-       clocksource_register(&txx9_clocksource.cs);
+       clocksource_register_hz(&txx9_clocksource.cs, TIMER_CLK(imbusclk));
 
        tmrptr = ioremap(baseaddr, sizeof(struct txx9_tmr_reg));
        __raw_writel(TCR_BASE, &tmrptr->tcr);
index f65d4c8..bb133d1 100644 (file)
@@ -291,6 +291,12 @@ static inline int cpu_has_confreg(void)
 #endif
 }
 
+static inline void set_elf_platform(int cpu, const char *plat)
+{
+       if (cpu == 0)
+               __elf_platform = plat;
+}
+
 /*
  * Get the FPU Implementation/Revision.
  */
@@ -614,6 +620,16 @@ static inline void cpu_probe_legacy(struct cpuinfo_mips *c, unsigned int cpu)
        case PRID_IMP_LOONGSON2:
                c->cputype = CPU_LOONGSON2;
                __cpu_name[cpu] = "ICT Loongson-2";
+
+               switch (c->processor_id & PRID_REV_MASK) {
+               case PRID_REV_LOONGSON2E:
+                       set_elf_platform(cpu, "loongson2e");
+                       break;
+               case PRID_REV_LOONGSON2F:
+                       set_elf_platform(cpu, "loongson2f");
+                       break;
+               }
+
                c->isa_level = MIPS_CPU_ISA_III;
                c->options = R4K_OPTS |
                             MIPS_CPU_FPU | MIPS_CPU_LLSC |
@@ -911,12 +927,14 @@ static inline void cpu_probe_broadcom(struct cpuinfo_mips *c, unsigned int cpu)
        case PRID_IMP_BMIPS32_REV8:
                c->cputype = CPU_BMIPS32;
                __cpu_name[cpu] = "Broadcom BMIPS32";
+               set_elf_platform(cpu, "bmips32");
                break;
        case PRID_IMP_BMIPS3300:
        case PRID_IMP_BMIPS3300_ALT:
        case PRID_IMP_BMIPS3300_BUG:
                c->cputype = CPU_BMIPS3300;
                __cpu_name[cpu] = "Broadcom BMIPS3300";
+               set_elf_platform(cpu, "bmips3300");
                break;
        case PRID_IMP_BMIPS43XX: {
                int rev = c->processor_id & 0xff;
@@ -925,15 +943,18 @@ static inline void cpu_probe_broadcom(struct cpuinfo_mips *c, unsigned int cpu)
                                rev <= PRID_REV_BMIPS4380_HI) {
                        c->cputype = CPU_BMIPS4380;
                        __cpu_name[cpu] = "Broadcom BMIPS4380";
+                       set_elf_platform(cpu, "bmips4380");
                } else {
                        c->cputype = CPU_BMIPS4350;
                        __cpu_name[cpu] = "Broadcom BMIPS4350";
+                       set_elf_platform(cpu, "bmips4350");
                }
                break;
        }
        case PRID_IMP_BMIPS5000:
                c->cputype = CPU_BMIPS5000;
                __cpu_name[cpu] = "Broadcom BMIPS5000";
+               set_elf_platform(cpu, "bmips5000");
                c->options |= MIPS_CPU_ULRI;
                break;
        }
@@ -956,14 +977,12 @@ static inline void cpu_probe_cavium(struct cpuinfo_mips *c, unsigned int cpu)
                c->cputype = CPU_CAVIUM_OCTEON_PLUS;
                __cpu_name[cpu] = "Cavium Octeon+";
 platform:
-               if (cpu == 0)
-                       __elf_platform = "octeon";
+               set_elf_platform(cpu, "octeon");
                break;
        case PRID_IMP_CAVIUM_CN63XX:
                c->cputype = CPU_CAVIUM_OCTEON2;
                __cpu_name[cpu] = "Cavium Octeon II";
-               if (cpu == 0)
-                       __elf_platform = "octeon2";
+               set_elf_platform(cpu, "octeon2");
                break;
        default:
                printk(KERN_INFO "Unknown Octeon chip!\n");
@@ -988,6 +1007,59 @@ static inline void cpu_probe_ingenic(struct cpuinfo_mips *c, unsigned int cpu)
        }
 }
 
+static inline void cpu_probe_netlogic(struct cpuinfo_mips *c, int cpu)
+{
+       decode_configs(c);
+
+       c->options = (MIPS_CPU_TLB       |
+                       MIPS_CPU_4KEX    |
+                       MIPS_CPU_COUNTER |
+                       MIPS_CPU_DIVEC   |
+                       MIPS_CPU_WATCH   |
+                       MIPS_CPU_EJTAG   |
+                       MIPS_CPU_LLSC);
+
+       switch (c->processor_id & 0xff00) {
+       case PRID_IMP_NETLOGIC_XLR732:
+       case PRID_IMP_NETLOGIC_XLR716:
+       case PRID_IMP_NETLOGIC_XLR532:
+       case PRID_IMP_NETLOGIC_XLR308:
+       case PRID_IMP_NETLOGIC_XLR532C:
+       case PRID_IMP_NETLOGIC_XLR516C:
+       case PRID_IMP_NETLOGIC_XLR508C:
+       case PRID_IMP_NETLOGIC_XLR308C:
+               c->cputype = CPU_XLR;
+               __cpu_name[cpu] = "Netlogic XLR";
+               break;
+
+       case PRID_IMP_NETLOGIC_XLS608:
+       case PRID_IMP_NETLOGIC_XLS408:
+       case PRID_IMP_NETLOGIC_XLS404:
+       case PRID_IMP_NETLOGIC_XLS208:
+       case PRID_IMP_NETLOGIC_XLS204:
+       case PRID_IMP_NETLOGIC_XLS108:
+       case PRID_IMP_NETLOGIC_XLS104:
+       case PRID_IMP_NETLOGIC_XLS616B:
+       case PRID_IMP_NETLOGIC_XLS608B:
+       case PRID_IMP_NETLOGIC_XLS416B:
+       case PRID_IMP_NETLOGIC_XLS412B:
+       case PRID_IMP_NETLOGIC_XLS408B:
+       case PRID_IMP_NETLOGIC_XLS404B:
+               c->cputype = CPU_XLR;
+               __cpu_name[cpu] = "Netlogic XLS";
+               break;
+
+       default:
+               printk(KERN_INFO "Unknown Netlogic chip id [%02x]!\n",
+                      c->processor_id);
+               c->cputype = CPU_XLR;
+               break;
+       }
+
+       c->isa_level = MIPS_CPU_ISA_M64R1;
+       c->tlbsize = ((read_c0_config1() >> 25) & 0x3f) + 1;
+}
+
 #ifdef CONFIG_64BIT
 /* For use by uaccess.h */
 u64 __ua_limit;
@@ -1035,6 +1107,9 @@ __cpuinit void cpu_probe(void)
        case PRID_COMP_INGENIC:
                cpu_probe_ingenic(c, cpu);
                break;
+       case PRID_COMP_NETLOGIC:
+               cpu_probe_netlogic(c, cpu);
+               break;
        }
 
        BUG_ON(!__cpu_name[cpu]);
index 51489f8..f96f99c 100644 (file)
@@ -49,6 +49,5 @@ void __init sb1480_clocksource_init(void)
 
        plldiv = G_BCM1480_SYS_PLL_DIV(__raw_readq(IOADDR(A_SCD_SYSTEM_CFG)));
        zbbus = ((plldiv >> 1) * 50000000) + ((plldiv & 1) * 25000000);
-       clocksource_set_clock(cs, zbbus);
-       clocksource_register(cs);
+       clocksource_register_hz(cs, zbbus);
 }
index 23da108..46bd7fa 100644 (file)
@@ -59,7 +59,5 @@ void __init dec_ioasic_clocksource_init(void)
        printk(KERN_INFO "I/O ASIC clock frequency %dHz\n", freq);
 
        clocksource_dec.rating = 200 + freq / 10000000;
-       clocksource_set_clock(&clocksource_dec, freq);
-
-       clocksource_register(&clocksource_dec);
+       clocksource_register_hz(&clocksource_dec, freq);
 }
index a27c16c..2e7c523 100644 (file)
@@ -78,9 +78,7 @@ static void __init powertv_c0_hpt_clocksource_init(void)
 
        clocksource_mips.rating = 200 + mips_hpt_frequency / 10000000;
 
-       clocksource_set_clock(&clocksource_mips, mips_hpt_frequency);
-
-       clocksource_register(&clocksource_mips);
+       clocksource_register_hz(&clocksource_mips, mips_hpt_frequency);
 }
 
 /**
@@ -130,43 +128,16 @@ static struct clocksource clocksource_tim_c = {
 /**
  * powertv_tim_c_clocksource_init - set up a clock source for the TIM_C clock
  *
- * The hard part here is coming up with a constant k and shift s such that
- * the 48-bit TIM_C value multiplied by k doesn't overflow and that value,
- * when shifted right by s, yields the corresponding number of nanoseconds.
  * We know that TIM_C counts at 27 MHz/8, so each cycle corresponds to
- * 1 / (27,000,000/8) seconds. Multiply that by a billion and you get the
- * number of nanoseconds. Since the TIM_C value has 48 bits and the math is
- * done in 64 bits, avoiding an overflow means that k must be less than
- * 64 - 48 = 16 bits.
+ * 1 / (27,000,000/8) seconds.
  */
 static void __init powertv_tim_c_clocksource_init(void)
 {
-       int                     prescale;
-       unsigned long           dividend;
-       unsigned long           k;
-       int                     s;
-       const int               max_k_bits = (64 - 48) - 1;
-       const unsigned long     billion = 1000000000;
        const unsigned long     counts_per_second = 27000000 / 8;
 
-       prescale = BITS_PER_LONG - ilog2(billion) - 1;
-       dividend = billion << prescale;
-       k = dividend / counts_per_second;
-       s = ilog2(k) - max_k_bits;
-
-       if (s < 0)
-               s = prescale;
-
-       else {
-               k >>= s;
-               s += prescale;
-       }
-
-       clocksource_tim_c.mult = k;
-       clocksource_tim_c.shift = s;
        clocksource_tim_c.rating = 200;
 
-       clocksource_register(&clocksource_tim_c);
+       clocksource_register_hz(&clocksource_tim_c, counts_per_second);
        tim_c = (struct tim_c *) asic_reg_addr(tim_ch);
 }
 
index e95a3cd..decd1fa 100644 (file)
@@ -30,9 +30,7 @@ int __init init_r4k_clocksource(void)
        /* Calculate a somewhat reasonable rating value */
        clocksource_mips.rating = 200 + mips_hpt_frequency / 10000000;
 
-       clocksource_set_clock(&clocksource_mips, mips_hpt_frequency);
-
-       clocksource_register(&clocksource_mips);
+       clocksource_register_hz(&clocksource_mips, mips_hpt_frequency);
 
        return 0;
 }
index d14d3d1..e9606d9 100644 (file)
@@ -65,6 +65,5 @@ void __init sb1250_clocksource_init(void)
                     IOADDR(A_SCD_TIMER_REGISTER(SB1250_HPT_NUM,
                                                 R_SCD_TIMER_CFG)));
 
-       clocksource_set_clock(cs, V_SCD_TIMER_FREQ);
-       clocksource_register(cs);
+       clocksource_register_hz(cs, V_SCD_TIMER_FREQ);
 }
index ffa3310..37acfa0 100644 (file)
@@ -167,14 +167,13 @@ work_notifysig:                           # deal with pending signals and
 FEXPORT(syscall_exit_work_partial)
        SAVE_STATIC
 syscall_exit_work:
-       li      t0, _TIF_SYSCALL_TRACE | _TIF_SYSCALL_AUDIT
+       li      t0, _TIF_WORK_SYSCALL_EXIT
        and     t0, a2                  # a2 is preloaded with TI_FLAGS
        beqz    t0, work_pending        # trace bit set?
-       local_irq_enable                # could let do_syscall_trace()
+       local_irq_enable                # could let syscall_trace_leave()
                                        # call schedule() instead
        move    a0, sp
-       li      a1, 1
-       jal     do_syscall_trace
+       jal     syscall_trace_leave
        b       resume_userspace
 
 #if defined(CONFIG_CPU_MIPSR2) || defined(CONFIG_MIPS_MT)
index 94ca2b0..feb8021 100644 (file)
@@ -23,6 +23,7 @@
 
 #define JAL 0x0c000000         /* jump & link: ip --> ra, jump to target */
 #define ADDR_MASK 0x03ffffff   /*  op_code|addr : 31...26|25 ....0 */
+#define JUMP_RANGE_MASK ((1UL << 28) - 1)
 
 #define INSN_NOP 0x00000000    /* nop */
 #define INSN_JAL(addr) \
@@ -44,12 +45,12 @@ static inline void ftrace_dyn_arch_init_insns(void)
 
        /* jal (ftrace_caller + 8), jump over the first two instruction */
        buf = (u32 *)&insn_jal_ftrace_caller;
-       uasm_i_jal(&buf, (FTRACE_ADDR + 8));
+       uasm_i_jal(&buf, (FTRACE_ADDR + 8) & JUMP_RANGE_MASK);
 
 #ifdef CONFIG_FUNCTION_GRAPH_TRACER
        /* j ftrace_graph_caller */
        buf = (u32 *)&insn_j_ftrace_graph_caller;
-       uasm_i_j(&buf, (unsigned long)ftrace_graph_caller);
+       uasm_i_j(&buf, (unsigned long)ftrace_graph_caller & JUMP_RANGE_MASK);
 #endif
 }
 
index 2392a7a..391221b 100644 (file)
@@ -125,87 +125,11 @@ void __init setup_pit_timer(void)
        setup_irq(0, &irq0);
 }
 
-/*
- * Since the PIT overflows every tick, its not very useful
- * to just read by itself. So use jiffies to emulate a free
- * running counter:
- */
-static cycle_t pit_read(struct clocksource *cs)
-{
-       unsigned long flags;
-       int count;
-       u32 jifs;
-       static int old_count;
-       static u32 old_jifs;
-
-       raw_spin_lock_irqsave(&i8253_lock, flags);
-       /*
-        * Although our caller may have the read side of xtime_lock,
-        * this is now a seqlock, and we are cheating in this routine
-        * by having side effects on state that we cannot undo if
-        * there is a collision on the seqlock and our caller has to
-        * retry.  (Namely, old_jifs and old_count.)  So we must treat
-        * jiffies as volatile despite the lock.  We read jiffies
-        * before latching the timer count to guarantee that although
-        * the jiffies value might be older than the count (that is,
-        * the counter may underflow between the last point where
-        * jiffies was incremented and the point where we latch the
-        * count), it cannot be newer.
-        */
-       jifs = jiffies;
-       outb_p(0x00, PIT_MODE); /* latch the count ASAP */
-       count = inb_p(PIT_CH0); /* read the latched count */
-       count |= inb_p(PIT_CH0) << 8;
-
-       /* VIA686a test code... reset the latch if count > max + 1 */
-       if (count > LATCH) {
-               outb_p(0x34, PIT_MODE);
-               outb_p(LATCH & 0xff, PIT_CH0);
-               outb(LATCH >> 8, PIT_CH0);
-               count = LATCH - 1;
-       }
-
-       /*
-        * It's possible for count to appear to go the wrong way for a
-        * couple of reasons:
-        *
-        *  1. The timer counter underflows, but we haven't handled the
-        *     resulting interrupt and incremented jiffies yet.
-        *  2. Hardware problem with the timer, not giving us continuous time,
-        *     the counter does small "jumps" upwards on some Pentium systems,
-        *     (see c't 95/10 page 335 for Neptun bug.)
-        *
-        * Previous attempts to handle these cases intelligently were
-        * buggy, so we just do the simple thing now.
-        */
-       if (count > old_count && jifs == old_jifs) {
-               count = old_count;
-       }
-       old_count = count;
-       old_jifs = jifs;
-
-       raw_spin_unlock_irqrestore(&i8253_lock, flags);
-
-       count = (LATCH - 1) - count;
-
-       return (cycle_t)(jifs * LATCH) + count;
-}
-
-static struct clocksource clocksource_pit = {
-       .name   = "pit",
-       .rating = 110,
-       .read   = pit_read,
-       .mask   = CLOCKSOURCE_MASK(32),
-       .mult   = 0,
-       .shift  = 20,
-};
-
 static int __init init_pit_clocksource(void)
 {
        if (num_possible_cpus() > 1) /* PIT does not scale! */
                return 0;
 
-       clocksource_pit.mult = clocksource_hz2mult(CLOCK_TICK_RATE, 20);
-       return clocksource_register(&clocksource_pit);
+       return clocksource_i8253_init();
 }
 arch_initcall(init_pit_clocksource);
index d21c388..4e6ea1f 100644 (file)
@@ -533,15 +533,10 @@ static inline int audit_arch(void)
  * Notification of system call entry/exit
  * - triggered by current->work.syscall_trace
  */
-asmlinkage void do_syscall_trace(struct pt_regs *regs, int entryexit)
+asmlinkage void syscall_trace_enter(struct pt_regs *regs)
 {
        /* do the secure computing check first */
-       if (!entryexit)
-               secure_computing(regs->regs[2]);
-
-       if (unlikely(current->audit_context) && entryexit)
-               audit_syscall_exit(AUDITSC_RESULT(regs->regs[2]),
-                                  regs->regs[2]);
+       secure_computing(regs->regs[2]);
 
        if (!(current->ptrace & PT_PTRACED))
                goto out;
@@ -565,8 +560,40 @@ asmlinkage void do_syscall_trace(struct pt_regs *regs, int entryexit)
        }
 
 out:
-       if (unlikely(current->audit_context) && !entryexit)
+       if (unlikely(current->audit_context))
                audit_syscall_entry(audit_arch(), regs->regs[2],
                                    regs->regs[4], regs->regs[5],
                                    regs->regs[6], regs->regs[7]);
 }
+
+/*
+ * Notification of system call entry/exit
+ * - triggered by current->work.syscall_trace
+ */
+asmlinkage void syscall_trace_leave(struct pt_regs *regs)
+{
+       if (unlikely(current->audit_context))
+               audit_syscall_exit(AUDITSC_RESULT(regs->regs[7]),
+                                  -regs->regs[2]);
+
+       if (!(current->ptrace & PT_PTRACED))
+               return;
+
+       if (!test_thread_flag(TIF_SYSCALL_TRACE))
+               return;
+
+       /* The 0x80 provides a way for the tracing parent to distinguish
+          between a syscall stop and SIGTRAP delivery */
+       ptrace_notify(SIGTRAP | ((current->ptrace & PT_TRACESYSGOOD) ?
+                                0x80 : 0));
+
+       /*
+        * this isn't the same as continuing with a signal, but it will do
+        * for normal use.  strace only continues with a signal if the
+        * stopping signal is not SIGTRAP.  -brl
+        */
+       if (current->exit_code) {
+               send_sig(current->exit_code, current, 1);
+               current->exit_code = 0;
+       }
+}
index 7f5468b..7a8e1dd 100644 (file)
@@ -88,8 +88,7 @@ syscall_trace_entry:
        SAVE_STATIC
        move    s0, t2
        move    a0, sp
-       li      a1, 0
-       jal     do_syscall_trace
+       jal     syscall_trace_enter
 
        move    t0, s0
        RESTORE_STATIC
@@ -565,7 +564,7 @@ einval:     li      v0, -ENOSYS
        sys     sys_ioprio_get          2       /* 4315 */
        sys     sys_utimensat           4
        sys     sys_signalfd            3
-       sys     sys_ni_syscall          0
+       sys     sys_ni_syscall          0       /* was timerfd */
        sys     sys_eventfd             1
        sys     sys_fallocate           6       /* 4320 */
        sys     sys_timerfd_create      2
index a2e1fcb..2d31c83 100644 (file)
@@ -91,8 +91,7 @@ syscall_trace_entry:
        SAVE_STATIC
        move    s0, t2
        move    a0, sp
-       li      a1, 0
-       jal     do_syscall_trace
+       jal     syscall_trace_enter
 
        move    t0, s0
        RESTORE_STATIC
@@ -404,7 +403,7 @@ sys_call_table:
        PTR     sys_ioprio_get
        PTR     sys_utimensat                   /* 5275 */
        PTR     sys_signalfd
-       PTR     sys_ni_syscall
+       PTR     sys_ni_syscall                  /* was timerfd */
        PTR     sys_eventfd
        PTR     sys_fallocate
        PTR     sys_timerfd_create              /* 5280 */
index b2c7624..38a0503 100644 (file)
@@ -89,8 +89,7 @@ n32_syscall_trace_entry:
        SAVE_STATIC
        move    s0, t2
        move    a0, sp
-       li      a1, 0
-       jal     do_syscall_trace
+       jal     syscall_trace_enter
 
        move    t0, s0
        RESTORE_STATIC
@@ -403,7 +402,7 @@ EXPORT(sysn32_call_table)
        PTR     sys_ioprio_get
        PTR     compat_sys_utimensat
        PTR     compat_sys_signalfd             /* 6280 */
-       PTR     sys_ni_syscall
+       PTR     sys_ni_syscall                  /* was timerfd */
        PTR     sys_eventfd
        PTR     sys_fallocate
        PTR     sys_timerfd_create
index 049a9c8..91ea5e4 100644 (file)
@@ -123,8 +123,7 @@ trace_a_syscall:
 
        move    s0, t2                  # Save syscall pointer
        move    a0, sp
-       li      a1, 0
-       jal     do_syscall_trace
+       jal     syscall_trace_enter
 
        move    t0, s0
        RESTORE_STATIC
@@ -522,7 +521,7 @@ sys_call_table:
        PTR     sys_ioprio_get                  /* 4315 */
        PTR     compat_sys_utimensat
        PTR     compat_sys_signalfd
-       PTR     sys_ni_syscall
+       PTR     sys_ni_syscall                  /* was timerfd */
        PTR     sys_eventfd
        PTR     sys32_fallocate                 /* 4320 */
        PTR     sys_timerfd_create
index 5a88cc4..cedac46 100644 (file)
@@ -929,7 +929,7 @@ static void post_direct_ipi(int cpu, struct smtc_ipi *pipi)
 
 static void ipi_resched_interrupt(void)
 {
-       /* Return from interrupt should be enough to cause scheduler check */
+       scheduler_ipi();
 }
 
 static void ipi_call_interrupt(void)
index 58beabf..d027657 100644 (file)
 #include <linux/capability.h>
 #include <linux/errno.h>
 #include <linux/linkage.h>
-#include <linux/mm.h>
 #include <linux/fs.h>
 #include <linux/smp.h>
-#include <linux/mman.h>
 #include <linux/ptrace.h>
-#include <linux/sched.h>
 #include <linux/string.h>
 #include <linux/syscalls.h>
 #include <linux/file.h>
 #include <linux/msg.h>
 #include <linux/shm.h>
 #include <linux/compiler.h>
-#include <linux/module.h>
 #include <linux/ipc.h>
 #include <linux/uaccess.h>
 #include <linux/slab.h>
-#include <linux/random.h>
 #include <linux/elf.h>
 
 #include <asm/asm.h>
@@ -66,121 +61,6 @@ out:
        return res;
 }
 
-unsigned long shm_align_mask = PAGE_SIZE - 1;  /* Sane caches */
-
-EXPORT_SYMBOL(shm_align_mask);
-
-#define COLOUR_ALIGN(addr,pgoff)                               \
-       ((((addr) + shm_align_mask) & ~shm_align_mask) +        \
-        (((pgoff) << PAGE_SHIFT) & shm_align_mask))
-
-unsigned long arch_get_unmapped_area(struct file *filp, unsigned long addr,
-       unsigned long len, unsigned long pgoff, unsigned long flags)
-{
-       struct vm_area_struct * vmm;
-       int do_color_align;
-       unsigned long task_size;
-
-#ifdef CONFIG_32BIT
-       task_size = TASK_SIZE;
-#else /* Must be CONFIG_64BIT*/
-       task_size = test_thread_flag(TIF_32BIT_ADDR) ? TASK_SIZE32 : TASK_SIZE;
-#endif
-
-       if (len > task_size)
-               return -ENOMEM;
-
-       if (flags & MAP_FIXED) {
-               /* Even MAP_FIXED mappings must reside within task_size.  */
-               if (task_size - len < addr)
-                       return -EINVAL;
-
-               /*
-                * We do not accept a shared mapping if it would violate
-                * cache aliasing constraints.
-                */
-               if ((flags & MAP_SHARED) &&
-                   ((addr - (pgoff << PAGE_SHIFT)) & shm_align_mask))
-                       return -EINVAL;
-               return addr;
-       }
-
-       do_color_align = 0;
-       if (filp || (flags & MAP_SHARED))
-               do_color_align = 1;
-       if (addr) {
-               if (do_color_align)
-                       addr = COLOUR_ALIGN(addr, pgoff);
-               else
-                       addr = PAGE_ALIGN(addr);
-               vmm = find_vma(current->mm, addr);
-               if (task_size - len >= addr &&
-                   (!vmm || addr + len <= vmm->vm_start))
-                       return addr;
-       }
-       addr = current->mm->mmap_base;
-       if (do_color_align)
-               addr = COLOUR_ALIGN(addr, pgoff);
-       else
-               addr = PAGE_ALIGN(addr);
-
-       for (vmm = find_vma(current->mm, addr); ; vmm = vmm->vm_next) {
-               /* At this point:  (!vmm || addr < vmm->vm_end). */
-               if (task_size - len < addr)
-                       return -ENOMEM;
-               if (!vmm || addr + len <= vmm->vm_start)
-                       return addr;
-               addr = vmm->vm_end;
-               if (do_color_align)
-                       addr = COLOUR_ALIGN(addr, pgoff);
-       }
-}
-
-void arch_pick_mmap_layout(struct mm_struct *mm)
-{
-       unsigned long random_factor = 0UL;
-
-       if (current->flags & PF_RANDOMIZE) {
-               random_factor = get_random_int();
-               random_factor = random_factor << PAGE_SHIFT;
-               if (TASK_IS_32BIT_ADDR)
-                       random_factor &= 0xfffffful;
-               else
-                       random_factor &= 0xffffffful;
-       }
-
-       mm->mmap_base = TASK_UNMAPPED_BASE + random_factor;
-       mm->get_unmapped_area = arch_get_unmapped_area;
-       mm->unmap_area = arch_unmap_area;
-}
-
-static inline unsigned long brk_rnd(void)
-{
-       unsigned long rnd = get_random_int();
-
-       rnd = rnd << PAGE_SHIFT;
-       /* 8MB for 32bit, 256MB for 64bit */
-       if (TASK_IS_32BIT_ADDR)
-               rnd = rnd & 0x7ffffful;
-       else
-               rnd = rnd & 0xffffffful;
-
-       return rnd;
-}
-
-unsigned long arch_randomize_brk(struct mm_struct *mm)
-{
-       unsigned long base = mm->brk;
-       unsigned long ret;
-
-       ret = PAGE_ALIGN(base + brk_rnd());
-
-       if (ret < mm->brk)
-               return mm->brk;
-
-       return ret;
-}
-
 SYSCALL_DEFINE6(mips_mmap, unsigned long, addr, unsigned long, len,
        unsigned long, prot, unsigned long, flags, unsigned long,
        fd, off_t, offset)
index 71350f7..e9b3af2 100644 (file)
@@ -374,7 +374,8 @@ void __noreturn die(const char *str, struct pt_regs *regs)
        unsigned long dvpret = dvpe();
 #endif /* CONFIG_MIPS_MT_SMTC */
 
-       notify_die(DIE_OOPS, str, regs, 0, regs_to_trapnr(regs), SIGSEGV);
+       if (notify_die(DIE_OOPS, str, regs, 0, regs_to_trapnr(regs), SIGSEGV) == NOTIFY_STOP)
+               sig = 0;
 
        console_verbose();
        spin_lock_irq(&die_lock);
@@ -383,9 +384,6 @@ void __noreturn die(const char *str, struct pt_regs *regs)
        mips_mt_regdump(dvpret);
 #endif /* CONFIG_MIPS_MT_SMTC */
 
-       if (notify_die(DIE_OOPS, str, regs, 0, regs_to_trapnr(regs), SIGSEGV) == NOTIFY_STOP)
-               sig = 0;
-
        printk("%s[#%d]:\n", str, ++die_counter);
        show_registers(regs);
        add_taint(TAINT_DIE);
index 832afbb..01af387 100644 (file)
@@ -65,15 +65,18 @@ SECTIONS
        NOTES :text :note
        .dummy : { *(.dummy) } :text
 
+       _sdata = .;                     /* Start of data section */
        RODATA
 
        /* writeable */
+       _sdata = .;                             /* Start of data section */
        .data : {       /* Data */
                . = . + DATAOFFSET;             /* for CONFIG_MAPPED_KERNEL */
 
                INIT_TASK_DATA(PAGE_SIZE)
                NOSAVE_DATA
                CACHELINE_ALIGNED_DATA(1 << CONFIG_MIPS_L1_CACHE_SHIFT)
+               READ_MOSTLY_DATA(1 << CONFIG_MIPS_L1_CACHE_SHIFT)
                DATA_DATA
                CONSTRUCTORS
        }
diff --git a/arch/mips/lantiq/Kconfig b/arch/mips/lantiq/Kconfig
new file mode 100644 (file)
index 0000000..3fccf21
--- /dev/null
@@ -0,0 +1,23 @@
+if LANTIQ
+
+config SOC_TYPE_XWAY
+       bool
+       default n
+
+choice
+       prompt "SoC Type"
+       default SOC_XWAY
+
+config SOC_AMAZON_SE
+       bool "Amazon SE"
+       select SOC_TYPE_XWAY
+
+config SOC_XWAY
+       bool "XWAY"
+       select SOC_TYPE_XWAY
+       select HW_HAS_PCI
+endchoice
+
+source "arch/mips/lantiq/xway/Kconfig"
+
+endif
diff --git a/arch/mips/lantiq/Makefile b/arch/mips/lantiq/Makefile
new file mode 100644 (file)
index 0000000..e5dae0e
--- /dev/null
@@ -0,0 +1,11 @@
+# Copyright (C) 2010 John Crispin <blogic@openwrt.org>
+#
+# 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.
+
+obj-y := irq.o setup.o clk.o prom.o devices.o
+
+obj-$(CONFIG_EARLY_PRINTK) += early_printk.o
+
+obj-$(CONFIG_SOC_TYPE_XWAY) += xway/
diff --git a/arch/mips/lantiq/Platform b/arch/mips/lantiq/Platform
new file mode 100644 (file)
index 0000000..f3dff05
--- /dev/null
@@ -0,0 +1,8 @@
+#
+# Lantiq
+#
+
+platform-$(CONFIG_LANTIQ)      += lantiq/
+cflags-$(CONFIG_LANTIQ)                += -I$(srctree)/arch/mips/include/asm/mach-lantiq
+load-$(CONFIG_LANTIQ)          = 0xffffffff80002000
+cflags-$(CONFIG_SOC_TYPE_XWAY) += -I$(srctree)/arch/mips/include/asm/mach-lantiq/xway
diff --git a/arch/mips/lantiq/clk.c b/arch/mips/lantiq/clk.c
new file mode 100644 (file)
index 0000000..9456089
--- /dev/null
@@ -0,0 +1,140 @@
+/*
+ *  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.
+ *
+ * Copyright (C) 2010 Thomas Langer <thomas.langer@lantiq.com>
+ * Copyright (C) 2010 John Crispin <blogic@openwrt.org>
+ */
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/clk.h>
+#include <linux/err.h>
+#include <linux/list.h>
+
+#include <asm/time.h>
+#include <asm/irq.h>
+#include <asm/div64.h>
+
+#include <lantiq_soc.h>
+
+#include "clk.h"
+
+struct clk {
+       const char *name;
+       unsigned long rate;
+       unsigned long (*get_rate) (void);
+};
+
+static struct clk *cpu_clk;
+static int cpu_clk_cnt;
+
+/* lantiq socs have 3 static clocks */
+static struct clk cpu_clk_generic[] = {
+       {
+               .name = "cpu",
+               .get_rate = ltq_get_cpu_hz,
+       }, {
+               .name = "fpi",
+               .get_rate = ltq_get_fpi_hz,
+       }, {
+               .name = "io",
+               .get_rate = ltq_get_io_region_clock,
+       },
+};
+
+static struct resource ltq_cgu_resource = {
+       .name   = "cgu",
+       .start  = LTQ_CGU_BASE_ADDR,
+       .end    = LTQ_CGU_BASE_ADDR + LTQ_CGU_SIZE - 1,
+       .flags  = IORESOURCE_MEM,
+};
+
+/* remapped clock register range */
+void __iomem *ltq_cgu_membase;
+
+void clk_init(void)
+{
+       cpu_clk = cpu_clk_generic;
+       cpu_clk_cnt = ARRAY_SIZE(cpu_clk_generic);
+}
+
+static inline int clk_good(struct clk *clk)
+{
+       return clk && !IS_ERR(clk);
+}
+
+unsigned long clk_get_rate(struct clk *clk)
+{
+       if (unlikely(!clk_good(clk)))
+               return 0;
+
+       if (clk->rate != 0)
+               return clk->rate;
+
+       if (clk->get_rate != NULL)
+               return clk->get_rate();
+
+       return 0;
+}
+EXPORT_SYMBOL(clk_get_rate);
+
+struct clk *clk_get(struct device *dev, const char *id)
+{
+       int i;
+
+       for (i = 0; i < cpu_clk_cnt; i++)
+               if (!strcmp(id, cpu_clk[i].name))
+                       return &cpu_clk[i];
+       BUG();
+       return ERR_PTR(-ENOENT);
+}
+EXPORT_SYMBOL(clk_get);
+
+void clk_put(struct clk *clk)
+{
+       /* not used */
+}
+EXPORT_SYMBOL(clk_put);
+
+static inline u32 ltq_get_counter_resolution(void)
+{
+       u32 res;
+
+       __asm__ __volatile__(
+               ".set   push\n"
+               ".set   mips32r2\n"
+               "rdhwr  %0, $3\n"
+               ".set pop\n"
+               : "=&r" (res)
+               : /* no input */
+               : "memory");
+
+       return res;
+}
+
+void __init plat_time_init(void)
+{
+       struct clk *clk;
+
+       if (insert_resource(&iomem_resource, &ltq_cgu_resource) < 0)
+               panic("Failed to insert cgu memory\n");
+
+       if (request_mem_region(ltq_cgu_resource.start,
+                       resource_size(&ltq_cgu_resource), "cgu") < 0)
+               panic("Failed to request cgu memory\n");
+
+       ltq_cgu_membase = ioremap_nocache(ltq_cgu_resource.start,
+                               resource_size(&ltq_cgu_resource));
+       if (!ltq_cgu_membase) {
+               pr_err("Failed to remap cgu memory\n");
+               unreachable();
+       }
+       clk = clk_get(0, "cpu");
+       mips_hpt_frequency = clk_get_rate(clk) / ltq_get_counter_resolution();
+       write_c0_compare(read_c0_count());
+       clk_put(clk);
+}
diff --git a/arch/mips/lantiq/clk.h b/arch/mips/lantiq/clk.h
new file mode 100644 (file)
index 0000000..3328925
--- /dev/null
@@ -0,0 +1,18 @@
+/*
+ *  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.
+ *
+ * Copyright (C) 2010 John Crispin <blogic@openwrt.org>
+ */
+
+#ifndef _LTQ_CLK_H__
+#define _LTQ_CLK_H__
+
+extern void clk_init(void);
+
+extern unsigned long ltq_get_cpu_hz(void);
+extern unsigned long ltq_get_fpi_hz(void);
+extern unsigned long ltq_get_io_region_clock(void);
+
+#endif
diff --git a/arch/mips/lantiq/devices.c b/arch/mips/lantiq/devices.c
new file mode 100644 (file)
index 0000000..7b82c34
--- /dev/null
@@ -0,0 +1,122 @@
+/*
+ *  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.
+ *
+ *  Copyright (C) 2010 John Crispin <blogic@openwrt.org>
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/string.h>
+#include <linux/kernel.h>
+#include <linux/reboot.h>
+#include <linux/platform_device.h>
+#include <linux/leds.h>
+#include <linux/etherdevice.h>
+#include <linux/reboot.h>
+#include <linux/time.h>
+#include <linux/io.h>
+#include <linux/gpio.h>
+#include <linux/leds.h>
+
+#include <asm/bootinfo.h>
+#include <asm/irq.h>
+
+#include <lantiq_soc.h>
+
+#include "devices.h"
+
+/* nor flash */
+static struct resource ltq_nor_resource = {
+       .name   = "nor",
+       .start  = LTQ_FLASH_START,
+       .end    = LTQ_FLASH_START + LTQ_FLASH_MAX - 1,
+       .flags  = IORESOURCE_MEM,
+};
+
+static struct platform_device ltq_nor = {
+       .name           = "ltq_nor",
+       .resource       = &ltq_nor_resource,
+       .num_resources  = 1,
+};
+
+void __init ltq_register_nor(struct physmap_flash_data *data)
+{
+       ltq_nor.dev.platform_data = data;
+       platform_device_register(&ltq_nor);
+}
+
+/* watchdog */
+static struct resource ltq_wdt_resource = {
+       .name   = "watchdog",
+       .start  = LTQ_WDT_BASE_ADDR,
+       .end    = LTQ_WDT_BASE_ADDR + LTQ_WDT_SIZE - 1,
+       .flags  = IORESOURCE_MEM,
+};
+
+void __init ltq_register_wdt(void)
+{
+       platform_device_register_simple("ltq_wdt", 0, &ltq_wdt_resource, 1);
+}
+
+/* asc ports */
+static struct resource ltq_asc0_resources[] = {
+       {
+               .name   = "asc0",
+               .start  = LTQ_ASC0_BASE_ADDR,
+               .end    = LTQ_ASC0_BASE_ADDR + LTQ_ASC_SIZE - 1,
+               .flags  = IORESOURCE_MEM,
+       },
+       IRQ_RES(tx, LTQ_ASC_TIR(0)),
+       IRQ_RES(rx, LTQ_ASC_RIR(0)),
+       IRQ_RES(err, LTQ_ASC_EIR(0)),
+};
+
+static struct resource ltq_asc1_resources[] = {
+       {
+               .name   = "asc1",
+               .start  = LTQ_ASC1_BASE_ADDR,
+               .end    = LTQ_ASC1_BASE_ADDR + LTQ_ASC_SIZE - 1,
+               .flags  = IORESOURCE_MEM,
+       },
+       IRQ_RES(tx, LTQ_ASC_TIR(1)),
+       IRQ_RES(rx, LTQ_ASC_RIR(1)),
+       IRQ_RES(err, LTQ_ASC_EIR(1)),
+};
+
+void __init ltq_register_asc(int port)
+{
+       switch (port) {
+       case 0:
+               platform_device_register_simple("ltq_asc", 0,
+                       ltq_asc0_resources, ARRAY_SIZE(ltq_asc0_resources));
+               break;
+       case 1:
+               platform_device_register_simple("ltq_asc", 1,
+                       ltq_asc1_resources, ARRAY_SIZE(ltq_asc1_resources));
+               break;
+       default:
+               break;
+       }
+}
+
+#ifdef CONFIG_PCI
+/* pci */
+static struct platform_device ltq_pci = {
+       .name           = "ltq_pci",
+       .num_resources  = 0,
+};
+
+void __init ltq_register_pci(struct ltq_pci_data *data)
+{
+       ltq_pci.dev.platform_data = data;
+       platform_device_register(&ltq_pci);
+}
+#else
+void __init ltq_register_pci(struct ltq_pci_data *data)
+{
+       pr_err("kernel is compiled without PCI support\n");
+}
+#endif
diff --git a/arch/mips/lantiq/devices.h b/arch/mips/lantiq/devices.h
new file mode 100644 (file)
index 0000000..2947bb1
--- /dev/null
@@ -0,0 +1,23 @@
+/*
+ *  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.
+ *
+ *  Copyright (C) 2010 John Crispin <blogic@openwrt.org>
+ */
+
+#ifndef _LTQ_DEVICES_H__
+#define _LTQ_DEVICES_H__
+
+#include <lantiq_platform.h>
+#include <linux/mtd/physmap.h>
+
+#define IRQ_RES(resname, irq) \
+       {.name = #resname, .start = (irq), .flags = IORESOURCE_IRQ}
+
+extern void ltq_register_nor(struct physmap_flash_data *data);
+extern void ltq_register_wdt(void);
+extern void ltq_register_asc(int port);
+extern void ltq_register_pci(struct ltq_pci_data *data);
+
+#endif
diff --git a/arch/mips/lantiq/early_printk.c b/arch/mips/lantiq/early_printk.c
new file mode 100644 (file)
index 0000000..972e05f
--- /dev/null
@@ -0,0 +1,33 @@
+/*
+ *  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.
+ *
+ *  Copyright (C) 2010 John Crispin <blogic@openwrt.org>
+ */
+
+#include <linux/init.h>
+#include <linux/cpu.h>
+
+#include <lantiq.h>
+#include <lantiq_soc.h>
+
+/* no ioremap possible at this early stage, lets use KSEG1 instead  */
+#define LTQ_ASC_BASE   KSEG1ADDR(LTQ_ASC1_BASE_ADDR)
+#define ASC_BUF                1024
+#define LTQ_ASC_FSTAT  ((u32 *)(LTQ_ASC_BASE + 0x0048))
+#define LTQ_ASC_TBUF   ((u32 *)(LTQ_ASC_BASE + 0x0020))
+#define TXMASK         0x3F00
+#define TXOFFSET       8
+
+void prom_putchar(char c)
+{
+       unsigned long flags;
+
+       local_irq_save(flags);
+       do { } while ((ltq_r32(LTQ_ASC_FSTAT) & TXMASK) >> TXOFFSET);
+       if (c == '\n')
+               ltq_w32('\r', LTQ_ASC_TBUF);
+       ltq_w32(c, LTQ_ASC_TBUF);
+       local_irq_restore(flags);
+}
diff --git a/arch/mips/lantiq/irq.c b/arch/mips/lantiq/irq.c
new file mode 100644 (file)
index 0000000..fc89795
--- /dev/null
@@ -0,0 +1,326 @@
+/*
+ *  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.
+ *
+ * Copyright (C) 2010 John Crispin <blogic@openwrt.org>
+ * Copyright (C) 2010 Thomas Langer <thomas.langer@lantiq.com>
+ */
+
+#include <linux/interrupt.h>
+#include <linux/ioport.h>
+
+#include <asm/bootinfo.h>
+#include <asm/irq_cpu.h>
+
+#include <lantiq_soc.h>
+#include <irq.h>
+
+/* register definitions */
+#define LTQ_ICU_IM0_ISR                0x0000
+#define LTQ_ICU_IM0_IER                0x0008
+#define LTQ_ICU_IM0_IOSR       0x0010
+#define LTQ_ICU_IM0_IRSR       0x0018
+#define LTQ_ICU_IM0_IMR                0x0020
+#define LTQ_ICU_IM1_ISR                0x0028
+#define LTQ_ICU_OFFSET         (LTQ_ICU_IM1_ISR - LTQ_ICU_IM0_ISR)
+
+#define LTQ_EIU_EXIN_C         0x0000
+#define LTQ_EIU_EXIN_INIC      0x0004
+#define LTQ_EIU_EXIN_INEN      0x000C
+
+/* irq numbers used by the external interrupt unit (EIU) */
+#define LTQ_EIU_IR0            (INT_NUM_IM4_IRL0 + 30)
+#define LTQ_EIU_IR1            (INT_NUM_IM3_IRL0 + 31)
+#define LTQ_EIU_IR2            (INT_NUM_IM1_IRL0 + 26)
+#define LTQ_EIU_IR3            INT_NUM_IM1_IRL0
+#define LTQ_EIU_IR4            (INT_NUM_IM1_IRL0 + 1)
+#define LTQ_EIU_IR5            (INT_NUM_IM1_IRL0 + 2)
+#define LTQ_EIU_IR6            (INT_NUM_IM2_IRL0 + 30)
+
+#define MAX_EIU                        6
+
+/* irqs generated by device attached to the EBU need to be acked in
+ * a special manner
+ */
+#define LTQ_ICU_EBU_IRQ                22
+
+#define ltq_icu_w32(x, y)      ltq_w32((x), ltq_icu_membase + (y))
+#define ltq_icu_r32(x)         ltq_r32(ltq_icu_membase + (x))
+
+#define ltq_eiu_w32(x, y)      ltq_w32((x), ltq_eiu_membase + (y))
+#define ltq_eiu_r32(x)         ltq_r32(ltq_eiu_membase + (x))
+
+static unsigned short ltq_eiu_irq[MAX_EIU] = {
+       LTQ_EIU_IR0,
+       LTQ_EIU_IR1,
+       LTQ_EIU_IR2,
+       LTQ_EIU_IR3,
+       LTQ_EIU_IR4,
+       LTQ_EIU_IR5,
+};
+
+static struct resource ltq_icu_resource = {
+       .name   = "icu",
+       .start  = LTQ_ICU_BASE_ADDR,
+       .end    = LTQ_ICU_BASE_ADDR + LTQ_ICU_SIZE - 1,
+       .flags  = IORESOURCE_MEM,
+};
+
+static struct resource ltq_eiu_resource = {
+       .name   = "eiu",
+       .start  = LTQ_EIU_BASE_ADDR,
+       .end    = LTQ_EIU_BASE_ADDR + LTQ_ICU_SIZE - 1,
+       .flags  = IORESOURCE_MEM,
+};
+
+static void __iomem *ltq_icu_membase;
+static void __iomem *ltq_eiu_membase;
+
+void ltq_disable_irq(struct irq_data *d)
+{
+       u32 ier = LTQ_ICU_IM0_IER;
+       int irq_nr = d->irq - INT_NUM_IRQ0;
+
+       ier += LTQ_ICU_OFFSET * (irq_nr / INT_NUM_IM_OFFSET);
+       irq_nr %= INT_NUM_IM_OFFSET;
+       ltq_icu_w32(ltq_icu_r32(ier) & ~(1 << irq_nr), ier);
+}
+
+void ltq_mask_and_ack_irq(struct irq_data *d)
+{
+       u32 ier = LTQ_ICU_IM0_IER;
+       u32 isr = LTQ_ICU_IM0_ISR;
+       int irq_nr = d->irq - INT_NUM_IRQ0;
+
+       ier += LTQ_ICU_OFFSET * (irq_nr / INT_NUM_IM_OFFSET);
+       isr += LTQ_ICU_OFFSET * (irq_nr / INT_NUM_IM_OFFSET);
+       irq_nr %= INT_NUM_IM_OFFSET;
+       ltq_icu_w32(ltq_icu_r32(ier) & ~(1 << irq_nr), ier);
+       ltq_icu_w32((1 << irq_nr), isr);
+}
+
+static void ltq_ack_irq(struct irq_data *d)
+{
+       u32 isr = LTQ_ICU_IM0_ISR;
+       int irq_nr = d->irq - INT_NUM_IRQ0;
+
+       isr += LTQ_ICU_OFFSET * (irq_nr / INT_NUM_IM_OFFSET);
+       irq_nr %= INT_NUM_IM_OFFSET;
+       ltq_icu_w32((1 << irq_nr), isr);
+}
+
+void ltq_enable_irq(struct irq_data *d)
+{
+       u32 ier = LTQ_ICU_IM0_IER;
+       int irq_nr = d->irq - INT_NUM_IRQ0;
+
+       ier += LTQ_ICU_OFFSET  * (irq_nr / INT_NUM_IM_OFFSET);
+       irq_nr %= INT_NUM_IM_OFFSET;
+       ltq_icu_w32(ltq_icu_r32(ier) | (1 << irq_nr), ier);
+}
+
+static unsigned int ltq_startup_eiu_irq(struct irq_data *d)
+{
+       int i;
+       int irq_nr = d->irq - INT_NUM_IRQ0;
+
+       ltq_enable_irq(d);
+       for (i = 0; i < MAX_EIU; i++) {
+               if (irq_nr == ltq_eiu_irq[i]) {
+                       /* low level - we should really handle set_type */
+                       ltq_eiu_w32(ltq_eiu_r32(LTQ_EIU_EXIN_C) |
+                               (0x6 << (i * 4)), LTQ_EIU_EXIN_C);
+                       /* clear all pending */
+                       ltq_eiu_w32(ltq_eiu_r32(LTQ_EIU_EXIN_INIC) & ~(1 << i),
+                               LTQ_EIU_EXIN_INIC);
+                       /* enable */
+                       ltq_eiu_w32(ltq_eiu_r32(LTQ_EIU_EXIN_INEN) | (1 << i),
+                               LTQ_EIU_EXIN_INEN);
+                       break;
+               }
+       }
+
+       return 0;
+}
+
+static void ltq_shutdown_eiu_irq(struct irq_data *d)
+{
+       int i;
+       int irq_nr = d->irq - INT_NUM_IRQ0;
+
+       ltq_disable_irq(d);
+       for (i = 0; i < MAX_EIU; i++) {
+               if (irq_nr == ltq_eiu_irq[i]) {
+                       /* disable */
+                       ltq_eiu_w32(ltq_eiu_r32(LTQ_EIU_EXIN_INEN) & ~(1 << i),
+                               LTQ_EIU_EXIN_INEN);
+                       break;
+               }
+       }
+}
+
+static struct irq_chip ltq_irq_type = {
+       "icu",
+       .irq_enable = ltq_enable_irq,
+       .irq_disable = ltq_disable_irq,
+       .irq_unmask = ltq_enable_irq,
+       .irq_ack = ltq_ack_irq,
+       .irq_mask = ltq_disable_irq,
+       .irq_mask_ack = ltq_mask_and_ack_irq,
+};
+
+static struct irq_chip ltq_eiu_type = {
+       "eiu",
+       .irq_startup = ltq_startup_eiu_irq,
+       .irq_shutdown = ltq_shutdown_eiu_irq,
+       .irq_enable = ltq_enable_irq,
+       .irq_disable = ltq_disable_irq,
+       .irq_unmask = ltq_enable_irq,
+       .irq_ack = ltq_ack_irq,
+       .irq_mask = ltq_disable_irq,
+       .irq_mask_ack = ltq_mask_and_ack_irq,
+};
+
+static void ltq_hw_irqdispatch(int module)
+{
+       u32 irq;
+
+       irq = ltq_icu_r32(LTQ_ICU_IM0_IOSR + (module * LTQ_ICU_OFFSET));
+       if (irq == 0)
+               return;
+
+       /* silicon bug causes only the msb set to 1 to be valid. all
+        * other bits might be bogus
+        */
+       irq = __fls(irq);
+       do_IRQ((int)irq + INT_NUM_IM0_IRL0 + (INT_NUM_IM_OFFSET * module));
+
+       /* if this is a EBU irq, we need to ack it or get a deadlock */
+       if ((irq == LTQ_ICU_EBU_IRQ) && (module == 0))
+               ltq_ebu_w32(ltq_ebu_r32(LTQ_EBU_PCC_ISTAT) | 0x10,
+                       LTQ_EBU_PCC_ISTAT);
+}
+
+#define DEFINE_HWx_IRQDISPATCH(x)                                      \
+       static void ltq_hw ## x ## _irqdispatch(void)                   \
+       {                                                               \
+               ltq_hw_irqdispatch(x);                                  \
+       }
+DEFINE_HWx_IRQDISPATCH(0)
+DEFINE_HWx_IRQDISPATCH(1)
+DEFINE_HWx_IRQDISPATCH(2)
+DEFINE_HWx_IRQDISPATCH(3)
+DEFINE_HWx_IRQDISPATCH(4)
+
+static void ltq_hw5_irqdispatch(void)
+{
+       do_IRQ(MIPS_CPU_TIMER_IRQ);
+}
+
+asmlinkage void plat_irq_dispatch(void)
+{
+       unsigned int pending = read_c0_status() & read_c0_cause() & ST0_IM;
+       unsigned int i;
+
+       if (pending & CAUSEF_IP7) {
+               do_IRQ(MIPS_CPU_TIMER_IRQ);
+               goto out;
+       } else {
+               for (i = 0; i < 5; i++) {
+                       if (pending & (CAUSEF_IP2 << i)) {
+                               ltq_hw_irqdispatch(i);
+                               goto out;
+                       }
+               }
+       }
+       pr_alert("Spurious IRQ: CAUSE=0x%08x\n", read_c0_status());
+
+out:
+       return;
+}
+
+static struct irqaction cascade = {
+       .handler = no_action,
+       .flags = IRQF_DISABLED,
+       .name = "cascade",
+};
+
+void __init arch_init_irq(void)
+{
+       int i;
+
+       if (insert_resource(&iomem_resource, &ltq_icu_resource) < 0)
+               panic("Failed to insert icu memory\n");
+
+       if (request_mem_region(ltq_icu_resource.start,
+                       resource_size(&ltq_icu_resource), "icu") < 0)
+               panic("Failed to request icu memory\n");
+
+       ltq_icu_membase = ioremap_nocache(ltq_icu_resource.start,
+                               resource_size(&ltq_icu_resource));
+       if (!ltq_icu_membase)
+               panic("Failed to remap icu memory\n");
+
+       if (insert_resource(&iomem_resource, &ltq_eiu_resource) < 0)
+               panic("Failed to insert eiu memory\n");
+
+       if (request_mem_region(ltq_eiu_resource.start,
+                       resource_size(&ltq_eiu_resource), "eiu") < 0)
+               panic("Failed to request eiu memory\n");
+
+       ltq_eiu_membase = ioremap_nocache(ltq_eiu_resource.start,
+                               resource_size(&ltq_eiu_resource));
+       if (!ltq_eiu_membase)
+               panic("Failed to remap eiu memory\n");
+
+       /* make sure all irqs are turned off by default */
+       for (i = 0; i < 5; i++)
+               ltq_icu_w32(0, LTQ_ICU_IM0_IER + (i * LTQ_ICU_OFFSET));
+
+       /* clear all possibly pending interrupts */
+       ltq_icu_w32(~0, LTQ_ICU_IM0_ISR + (i * LTQ_ICU_OFFSET));
+
+       mips_cpu_irq_init();
+
+       for (i = 2; i <= 6; i++)
+               setup_irq(i, &cascade);
+
+       if (cpu_has_vint) {
+               pr_info("Setting up vectored interrupts\n");
+               set_vi_handler(2, ltq_hw0_irqdispatch);
+               set_vi_handler(3, ltq_hw1_irqdispatch);
+               set_vi_handler(4, ltq_hw2_irqdispatch);
+               set_vi_handler(5, ltq_hw3_irqdispatch);
+               set_vi_handler(6, ltq_hw4_irqdispatch);
+               set_vi_handler(7, ltq_hw5_irqdispatch);
+       }
+
+       for (i = INT_NUM_IRQ0;
+               i <= (INT_NUM_IRQ0 + (5 * INT_NUM_IM_OFFSET)); i++)
+               if ((i == LTQ_EIU_IR0) || (i == LTQ_EIU_IR1) ||
+                       (i == LTQ_EIU_IR2))
+                       irq_set_chip_and_handler(i, &ltq_eiu_type,
+                               handle_level_irq);
+               /* EIU3-5 only exist on ar9 and vr9 */
+               else if (((i == LTQ_EIU_IR3) || (i == LTQ_EIU_IR4) ||
+                       (i == LTQ_EIU_IR5)) && (ltq_is_ar9() || ltq_is_vr9()))
+                       irq_set_chip_and_handler(i, &ltq_eiu_type,
+                               handle_level_irq);
+               else
+                       irq_set_chip_and_handler(i, &ltq_irq_type,
+                               handle_level_irq);
+
+#if !defined(CONFIG_MIPS_MT_SMP) && !defined(CONFIG_MIPS_MT_SMTC)
+       set_c0_status(IE_IRQ0 | IE_IRQ1 | IE_IRQ2 |
+               IE_IRQ3 | IE_IRQ4 | IE_IRQ5);
+#else
+       set_c0_status(IE_SW0 | IE_SW1 | IE_IRQ0 | IE_IRQ1 |
+               IE_IRQ2 | IE_IRQ3 | IE_IRQ4 | IE_IRQ5);
+#endif
+}
+
+unsigned int __cpuinit get_c0_compare_int(void)
+{
+       return CP0_LEGACY_COMPARE_IRQ;
+}
diff --git a/arch/mips/lantiq/machtypes.h b/arch/mips/lantiq/machtypes.h
new file mode 100644 (file)
index 0000000..7e01b8c
--- /dev/null
@@ -0,0 +1,20 @@
+/*
+ *  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.
+ *
+ *  Copyright (C) 2010 John Crispin <blogic@openwrt.org>
+ */
+
+#ifndef _LANTIQ_MACH_H__
+#define _LANTIQ_MACH_H__
+
+#include <asm/mips_machine.h>
+
+enum lantiq_mach_type {
+       LTQ_MACH_GENERIC = 0,
+       LTQ_MACH_EASY50712,     /* Danube evaluation board */
+       LTQ_MACH_EASY50601,     /* Amazon SE evaluation board */
+};
+
+#endif
diff --git a/arch/mips/lantiq/prom.c b/arch/mips/lantiq/prom.c
new file mode 100644 (file)
index 0000000..56ba007
--- /dev/null
@@ -0,0 +1,71 @@
+/*
+ *  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.
+ *
+ * Copyright (C) 2010 John Crispin <blogic@openwrt.org>
+ */
+
+#include <linux/module.h>
+#include <linux/clk.h>
+#include <asm/bootinfo.h>
+#include <asm/time.h>
+
+#include <lantiq.h>
+
+#include "prom.h"
+#include "clk.h"
+
+static struct ltq_soc_info soc_info;
+
+unsigned int ltq_get_cpu_ver(void)
+{
+       return soc_info.rev;
+}
+EXPORT_SYMBOL(ltq_get_cpu_ver);
+
+unsigned int ltq_get_soc_type(void)
+{
+       return soc_info.type;
+}
+EXPORT_SYMBOL(ltq_get_soc_type);
+
+const char *get_system_type(void)
+{
+       return soc_info.sys_type;
+}
+
+void prom_free_prom_memory(void)
+{
+}
+
+static void __init prom_init_cmdline(void)
+{
+       int argc = fw_arg0;
+       char **argv = (char **) KSEG1ADDR(fw_arg1);
+       int i;
+
+       for (i = 0; i < argc; i++) {
+               char *p = (char *)  KSEG1ADDR(argv[i]);
+
+               if (p && *p) {
+                       strlcat(arcs_cmdline, p, sizeof(arcs_cmdline));
+                       strlcat(arcs_cmdline, " ", sizeof(arcs_cmdline));
+               }
+       }
+}
+
+void __init prom_init(void)
+{
+       struct clk *clk;
+
+       ltq_soc_detect(&soc_info);
+       clk_init();
+       clk = clk_get(0, "cpu");
+       snprintf(soc_info.sys_type, LTQ_SYS_TYPE_LEN - 1, "%s rev1.%d",
+               soc_info.name, soc_info.rev);
+       clk_put(clk);
+       soc_info.sys_type[LTQ_SYS_TYPE_LEN - 1] = '\0';
+       pr_info("SoC: %s\n", soc_info.sys_type);
+       prom_init_cmdline();
+}
diff --git a/arch/mips/lantiq/prom.h b/arch/mips/lantiq/prom.h
new file mode 100644 (file)
index 0000000..b4229d9
--- /dev/null
@@ -0,0 +1,25 @@
+/*
+ *  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.
+ *
+ * Copyright (C) 2010 John Crispin <blogic@openwrt.org>
+ */
+
+#ifndef _LTQ_PROM_H__
+#define _LTQ_PROM_H__
+
+#define LTQ_SYS_TYPE_LEN       0x100
+
+struct ltq_soc_info {
+       unsigned char *name;
+       unsigned int rev;
+       unsigned int partnum;
+       unsigned int type;
+       unsigned char sys_type[LTQ_SYS_TYPE_LEN];
+};
+
+extern void ltq_soc_detect(struct ltq_soc_info *i);
+extern void ltq_soc_setup(void);
+
+#endif
diff --git a/arch/mips/lantiq/setup.c b/arch/mips/lantiq/setup.c
new file mode 100644 (file)
index 0000000..9b8af77
--- /dev/null
@@ -0,0 +1,66 @@
+/*
+ *  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.
+ *
+ * Copyright (C) 2010 John Crispin <blogic@openwrt.org>
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/io.h>
+#include <linux/ioport.h>
+#include <asm/bootinfo.h>
+
+#include <lantiq_soc.h>
+
+#include "machtypes.h"
+#include "devices.h"
+#include "prom.h"
+
+void __init plat_mem_setup(void)
+{
+       /* assume 16M as default incase uboot fails to pass proper ramsize */
+       unsigned long memsize = 16;
+       char **envp = (char **) KSEG1ADDR(fw_arg2);
+
+       ioport_resource.start = IOPORT_RESOURCE_START;
+       ioport_resource.end = IOPORT_RESOURCE_END;
+       iomem_resource.start = IOMEM_RESOURCE_START;
+       iomem_resource.end = IOMEM_RESOURCE_END;
+
+       set_io_port_base((unsigned long) KSEG1);
+
+       while (*envp) {
+               char *e = (char *)KSEG1ADDR(*envp);
+               if (!strncmp(e, "memsize=", 8)) {
+                       e += 8;
+                       if (strict_strtoul(e, 0, &memsize))
+                               pr_warn("bad memsize specified\n");
+               }
+               envp++;
+       }
+       memsize *= 1024 * 1024;
+       add_memory_region(0x00000000, memsize, BOOT_MEM_RAM);
+}
+
+static int __init
+lantiq_setup(void)
+{
+       ltq_soc_setup();
+       mips_machine_setup();
+       return 0;
+}
+
+arch_initcall(lantiq_setup);
+
+static void __init
+lantiq_generic_init(void)
+{
+       /* Nothing to do */
+}
+
+MIPS_MACHINE(LTQ_MACH_GENERIC,
+            "Generic",
+            "Generic Lantiq based board",
+            lantiq_generic_init);
diff --git a/arch/mips/lantiq/xway/Kconfig b/arch/mips/lantiq/xway/Kconfig
new file mode 100644 (file)
index 0000000..2b857de
--- /dev/null
@@ -0,0 +1,23 @@
+if SOC_XWAY
+
+menu "MIPS Machine"
+
+config LANTIQ_MACH_EASY50712
+       bool "Easy50712 - Danube"
+       default y
+
+endmenu
+
+endif
+
+if SOC_AMAZON_SE
+
+menu "MIPS Machine"
+
+config LANTIQ_MACH_EASY50601
+       bool "Easy50601 - Amazon SE"
+       default y
+
+endmenu
+
+endif
diff --git a/arch/mips/lantiq/xway/Makefile b/arch/mips/lantiq/xway/Makefile
new file mode 100644 (file)
index 0000000..c517f2e
--- /dev/null
@@ -0,0 +1,7 @@
+obj-y := pmu.o ebu.o reset.o gpio.o gpio_stp.o gpio_ebu.o devices.o dma.o
+
+obj-$(CONFIG_SOC_XWAY) += clk-xway.o prom-xway.o setup-xway.o
+obj-$(CONFIG_SOC_AMAZON_SE) += clk-ase.o prom-ase.o setup-ase.o
+
+obj-$(CONFIG_LANTIQ_MACH_EASY50712) += mach-easy50712.o
+obj-$(CONFIG_LANTIQ_MACH_EASY50601) += mach-easy50601.o
diff --git a/arch/mips/lantiq/xway/clk-ase.c b/arch/mips/lantiq/xway/clk-ase.c
new file mode 100644 (file)
index 0000000..22d823a
--- /dev/null
@@ -0,0 +1,48 @@
+/*
+ *  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.
+ *
+ *  Copyright (C) 2011 John Crispin <blogic@openwrt.org>
+ */
+
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/clk.h>
+
+#include <asm/time.h>
+#include <asm/irq.h>
+#include <asm/div64.h>
+
+#include <lantiq_soc.h>
+
+/* cgu registers */
+#define LTQ_CGU_SYS    0x0010
+
+unsigned int ltq_get_io_region_clock(void)
+{
+       return CLOCK_133M;
+}
+EXPORT_SYMBOL(ltq_get_io_region_clock);
+
+unsigned int ltq_get_fpi_bus_clock(int fpi)
+{
+       return CLOCK_133M;
+}
+EXPORT_SYMBOL(ltq_get_fpi_bus_clock);
+
+unsigned int ltq_get_cpu_hz(void)
+{
+       if (ltq_cgu_r32(LTQ_CGU_SYS) & (1 << 5))
+               return CLOCK_266M;
+       else
+               return CLOCK_133M;
+}
+EXPORT_SYMBOL(ltq_get_cpu_hz);
+
+unsigned int ltq_get_fpi_hz(void)
+{
+       return CLOCK_133M;
+}
+EXPORT_SYMBOL(ltq_get_fpi_hz);
diff --git a/arch/mips/lantiq/xway/clk-xway.c b/arch/mips/lantiq/xway/clk-xway.c
new file mode 100644 (file)
index 0000000..ddd3959
--- /dev/null
@@ -0,0 +1,223 @@
+/*
+ *  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.
+ *
+ *  Copyright (C) 2010 John Crispin <blogic@openwrt.org>
+ */
+
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/clk.h>
+
+#include <asm/time.h>
+#include <asm/irq.h>
+#include <asm/div64.h>
+
+#include <lantiq_soc.h>
+
+static unsigned int ltq_ram_clocks[] = {
+       CLOCK_167M, CLOCK_133M, CLOCK_111M, CLOCK_83M };
+#define DDR_HZ ltq_ram_clocks[ltq_cgu_r32(LTQ_CGU_SYS) & 0x3]
+
+#define BASIC_FREQUENCY_1      35328000
+#define BASIC_FREQUENCY_2      36000000
+#define BASIS_REQUENCY_USB     12000000
+
+#define GET_BITS(x, msb, lsb) \
+       (((x) & ((1 << ((msb) + 1)) - 1)) >> (lsb))
+
+#define LTQ_CGU_PLL0_CFG       0x0004
+#define LTQ_CGU_PLL1_CFG       0x0008
+#define LTQ_CGU_PLL2_CFG       0x000C
+#define LTQ_CGU_SYS            0x0010
+#define LTQ_CGU_UPDATE         0x0014
+#define LTQ_CGU_IF_CLK         0x0018
+#define LTQ_CGU_OSC_CON                0x001C
+#define LTQ_CGU_SMD            0x0020
+#define LTQ_CGU_CT1SR          0x0028
+#define LTQ_CGU_CT2SR          0x002C
+#define LTQ_CGU_PCMCR          0x0030
+#define LTQ_CGU_PCI_CR         0x0034
+#define LTQ_CGU_PD_PC          0x0038
+#define LTQ_CGU_FMR            0x003C
+
+#define CGU_PLL0_PHASE_DIVIDER_ENABLE  \
+       (ltq_cgu_r32(LTQ_CGU_PLL0_CFG) & (1 << 31))
+#define CGU_PLL0_BYPASS                        \
+       (ltq_cgu_r32(LTQ_CGU_PLL0_CFG) & (1 << 30))
+#define CGU_PLL0_CFG_DSMSEL            \
+       (ltq_cgu_r32(LTQ_CGU_PLL0_CFG) & (1 << 28))
+#define CGU_PLL0_CFG_FRAC_EN           \
+       (ltq_cgu_r32(LTQ_CGU_PLL0_CFG) & (1 << 27))
+#define CGU_PLL1_SRC                   \
+       (ltq_cgu_r32(LTQ_CGU_PLL1_CFG) & (1 << 31))
+#define CGU_PLL2_PHASE_DIVIDER_ENABLE  \
+       (ltq_cgu_r32(LTQ_CGU_PLL2_CFG) & (1 << 20))
+#define CGU_SYS_FPI_SEL                        (1 << 6)
+#define CGU_SYS_DDR_SEL                        0x3
+#define CGU_PLL0_SRC                   (1 << 29)
+
+#define CGU_PLL0_CFG_PLLK      GET_BITS(ltq_cgu_r32(LTQ_CGU_PLL0_CFG), 26, 17)
+#define CGU_PLL0_CFG_PLLN      GET_BITS(ltq_cgu_r32(LTQ_CGU_PLL0_CFG), 12, 6)
+#define CGU_PLL0_CFG_PLLM      GET_BITS(ltq_cgu_r32(LTQ_CGU_PLL0_CFG), 5, 2)
+#define CGU_PLL2_SRC           GET_BITS(ltq_cgu_r32(LTQ_CGU_PLL2_CFG), 18, 17)
+#define CGU_PLL2_CFG_INPUT_DIV GET_BITS(ltq_cgu_r32(LTQ_CGU_PLL2_CFG), 16, 13)
+
+static unsigned int ltq_get_pll0_fdiv(void);
+
+static inline unsigned int get_input_clock(int pll)
+{
+       switch (pll) {
+       case 0:
+               if (ltq_cgu_r32(LTQ_CGU_PLL0_CFG) & CGU_PLL0_SRC)
+                       return BASIS_REQUENCY_USB;
+               else if (CGU_PLL0_PHASE_DIVIDER_ENABLE)
+                       return BASIC_FREQUENCY_1;
+               else
+                       return BASIC_FREQUENCY_2;
+       case 1:
+               if (CGU_PLL1_SRC)
+                       return BASIS_REQUENCY_USB;
+               else if (CGU_PLL0_PHASE_DIVIDER_ENABLE)
+                       return BASIC_FREQUENCY_1;
+               else
+                       return BASIC_FREQUENCY_2;
+       case 2:
+               switch (CGU_PLL2_SRC) {
+               case 0:
+                       return ltq_get_pll0_fdiv();
+               case 1:
+                       return CGU_PLL2_PHASE_DIVIDER_ENABLE ?
+                               BASIC_FREQUENCY_1 :
+                               BASIC_FREQUENCY_2;
+               case 2:
+                       return BASIS_REQUENCY_USB;
+               }
+       default:
+               return 0;
+       }
+}
+
+static inline unsigned int cal_dsm(int pll, unsigned int num, unsigned int den)
+{
+       u64 res, clock = get_input_clock(pll);
+
+       res = num * clock;
+       do_div(res, den);
+       return res;
+}
+
+static inline unsigned int mash_dsm(int pll, unsigned int M, unsigned int N,
+       unsigned int K)
+{
+       unsigned int num = ((N + 1) << 10) + K;
+       unsigned int den = (M + 1) << 10;
+
+       return cal_dsm(pll, num, den);
+}
+
+static inline unsigned int ssff_dsm_1(int pll, unsigned int M, unsigned int N,
+       unsigned int K)
+{
+       unsigned int num = ((N + 1) << 11) + K + 512;
+       unsigned int den = (M + 1) << 11;
+
+       return cal_dsm(pll, num, den);
+}
+
+static inline unsigned int ssff_dsm_2(int pll, unsigned int M, unsigned int N,
+       unsigned int K)
+{
+       unsigned int num = K >= 512 ?
+               ((N + 1) << 12) + K - 512 : ((N + 1) << 12) + K + 3584;
+       unsigned int den = (M + 1) << 12;
+
+       return cal_dsm(pll, num, den);
+}
+
+static inline unsigned int dsm(int pll, unsigned int M, unsigned int N,
+       unsigned int K, unsigned int dsmsel, unsigned int phase_div_en)
+{
+       if (!dsmsel)
+               return mash_dsm(pll, M, N, K);
+       else if (!phase_div_en)
+               return mash_dsm(pll, M, N, K);
+       else
+               return ssff_dsm_2(pll, M, N, K);
+}
+
+static inline unsigned int ltq_get_pll0_fosc(void)
+{
+       if (CGU_PLL0_BYPASS)
+               return get_input_clock(0);
+       else
+               return !CGU_PLL0_CFG_FRAC_EN
+                       ? dsm(0, CGU_PLL0_CFG_PLLM, CGU_PLL0_CFG_PLLN, 0,
+                               CGU_PLL0_CFG_DSMSEL,
+                               CGU_PLL0_PHASE_DIVIDER_ENABLE)
+                       : dsm(0, CGU_PLL0_CFG_PLLM, CGU_PLL0_CFG_PLLN,
+                               CGU_PLL0_CFG_PLLK, CGU_PLL0_CFG_DSMSEL,
+                               CGU_PLL0_PHASE_DIVIDER_ENABLE);
+}
+
+static unsigned int ltq_get_pll0_fdiv(void)
+{
+       unsigned int div = CGU_PLL2_CFG_INPUT_DIV + 1;
+
+       return (ltq_get_pll0_fosc() + (div >> 1)) / div;
+}
+
+unsigned int ltq_get_io_region_clock(void)
+{
+       unsigned int ret = ltq_get_pll0_fosc();
+
+       switch (ltq_cgu_r32(LTQ_CGU_PLL2_CFG) & CGU_SYS_DDR_SEL) {
+       default:
+       case 0:
+               return (ret + 1) / 2;
+       case 1:
+               return (ret * 2 + 2) / 5;
+       case 2:
+               return (ret + 1) / 3;
+       case 3:
+               return (ret + 2) / 4;
+       }
+}
+EXPORT_SYMBOL(ltq_get_io_region_clock);
+
+unsigned int ltq_get_fpi_bus_clock(int fpi)
+{
+       unsigned int ret = ltq_get_io_region_clock();
+
+       if ((fpi == 2) && (ltq_cgu_r32(LTQ_CGU_SYS) & CGU_SYS_FPI_SEL))
+               ret >>= 1;
+       return ret;
+}
+EXPORT_SYMBOL(ltq_get_fpi_bus_clock);
+
+unsigned int ltq_get_cpu_hz(void)
+{
+       switch (ltq_cgu_r32(LTQ_CGU_SYS) & 0xc) {
+       case 0:
+               return CLOCK_333M;
+       case 4:
+               return DDR_HZ;
+       case 8:
+               return DDR_HZ << 1;
+       default:
+               return DDR_HZ >> 1;
+       }
+}
+EXPORT_SYMBOL(ltq_get_cpu_hz);
+
+unsigned int ltq_get_fpi_hz(void)
+{
+       unsigned int ddr_clock = DDR_HZ;
+
+       if (ltq_cgu_r32(LTQ_CGU_SYS) & 0x40)
+               return ddr_clock >> 1;
+       return ddr_clock;
+}
+EXPORT_SYMBOL(ltq_get_fpi_hz);
diff --git a/arch/mips/lantiq/xway/devices.c b/arch/mips/lantiq/xway/devices.c
new file mode 100644 (file)
index 0000000..e09e789
--- /dev/null
@@ -0,0 +1,121 @@
+/*
+ *  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.
+ *
+ *  Copyright (C) 2010 John Crispin <blogic@openwrt.org>
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/string.h>
+#include <linux/mtd/physmap.h>
+#include <linux/kernel.h>
+#include <linux/reboot.h>
+#include <linux/platform_device.h>
+#include <linux/leds.h>
+#include <linux/etherdevice.h>
+#include <linux/reboot.h>
+#include <linux/time.h>
+#include <linux/io.h>
+#include <linux/gpio.h>
+#include <linux/leds.h>
+
+#include <asm/bootinfo.h>
+#include <asm/irq.h>
+
+#include <lantiq_soc.h>
+#include <lantiq_irq.h>
+#include <lantiq_platform.h>
+
+#include "devices.h"
+
+/* gpio */
+static struct resource ltq_gpio_resource[] = {
+       {
+               .name   = "gpio0",
+               .start  = LTQ_GPIO0_BASE_ADDR,
+               .end    = LTQ_GPIO0_BASE_ADDR + LTQ_GPIO_SIZE - 1,
+               .flags  = IORESOURCE_MEM,
+       }, {
+               .name   = "gpio1",
+               .start  = LTQ_GPIO1_BASE_ADDR,
+               .end    = LTQ_GPIO1_BASE_ADDR + LTQ_GPIO_SIZE - 1,
+               .flags  = IORESOURCE_MEM,
+       }, {
+               .name   = "gpio2",
+               .start  = LTQ_GPIO2_BASE_ADDR,
+               .end    = LTQ_GPIO2_BASE_ADDR + LTQ_GPIO_SIZE - 1,
+               .flags  = IORESOURCE_MEM,
+       }
+};
+
+void __init ltq_register_gpio(void)
+{
+       platform_device_register_simple("ltq_gpio", 0,
+               &ltq_gpio_resource[0], 1);
+       platform_device_register_simple("ltq_gpio", 1,
+               &ltq_gpio_resource[1], 1);
+
+       /* AR9 and VR9 have an extra gpio block */
+       if (ltq_is_ar9() || ltq_is_vr9()) {
+               platform_device_register_simple("ltq_gpio", 2,
+                       &ltq_gpio_resource[2], 1);
+       }
+}
+
+/* serial to parallel conversion */
+static struct resource ltq_stp_resource = {
+       .name   = "stp",
+       .start  = LTQ_STP_BASE_ADDR,
+       .end    = LTQ_STP_BASE_ADDR + LTQ_STP_SIZE - 1,
+       .flags  = IORESOURCE_MEM,
+};
+
+void __init ltq_register_gpio_stp(void)
+{
+       platform_device_register_simple("ltq_stp", 0, &ltq_stp_resource, 1);
+}
+
+/* asc ports - amazon se has its own serial mapping */
+static struct resource ltq_ase_asc_resources[] = {
+       {
+               .name   = "asc0",
+               .start  = LTQ_ASC1_BASE_ADDR,
+               .end    = LTQ_ASC1_BASE_ADDR + LTQ_ASC_SIZE - 1,
+               .flags  = IORESOURCE_MEM,
+       },
+       IRQ_RES(tx, LTQ_ASC_ASE_TIR),
+       IRQ_RES(rx, LTQ_ASC_ASE_RIR),
+       IRQ_RES(err, LTQ_ASC_ASE_EIR),
+};
+
+void __init ltq_register_ase_asc(void)
+{
+       platform_device_register_simple("ltq_asc", 0,
+               ltq_ase_asc_resources, ARRAY_SIZE(ltq_ase_asc_resources));
+}
+
+/* ethernet */
+static struct resource ltq_etop_resources = {
+       .name   = "etop",
+       .start  = LTQ_ETOP_BASE_ADDR,
+       .end    = LTQ_ETOP_BASE_ADDR + LTQ_ETOP_SIZE - 1,
+       .flags  = IORESOURCE_MEM,
+};
+
+static struct platform_device ltq_etop = {
+       .name           = "ltq_etop",
+       .resource       = &ltq_etop_resources,
+       .num_resources  = 1,
+};
+
+void __init
+ltq_register_etop(struct ltq_eth_data *eth)
+{
+       if (eth) {
+               ltq_etop.dev.platform_data = eth;
+               platform_device_register(&ltq_etop);
+       }
+}
diff --git a/arch/mips/lantiq/xway/devices.h b/arch/mips/lantiq/xway/devices.h
new file mode 100644 (file)
index 0000000..e904934
--- /dev/null
@@ -0,0 +1,20 @@
+/*
+ *  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.
+ *
+ *  Copyright (C) 2010 John Crispin <blogic@openwrt.org>
+ */
+
+#ifndef _LTQ_DEVICES_XWAY_H__
+#define _LTQ_DEVICES_XWAY_H__
+
+#include "../devices.h"
+#include <linux/phy.h>
+
+extern void ltq_register_gpio(void);
+extern void ltq_register_gpio_stp(void);
+extern void ltq_register_ase_asc(void);
+extern void ltq_register_etop(struct ltq_eth_data *eth);
+
+#endif
diff --git a/arch/mips/lantiq/xway/dma.c b/arch/mips/lantiq/xway/dma.c
new file mode 100644 (file)
index 0000000..4278a45
--- /dev/null
@@ -0,0 +1,253 @@
+/*
+ *   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 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) 2011 John Crispin <blogic@openwrt.org>
+ */
+
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/io.h>
+#include <linux/dma-mapping.h>
+
+#include <lantiq_soc.h>
+#include <xway_dma.h>
+
+#define LTQ_DMA_CTRL           0x10
+#define LTQ_DMA_CPOLL          0x14
+#define LTQ_DMA_CS             0x18
+#define LTQ_DMA_CCTRL          0x1C
+#define LTQ_DMA_CDBA           0x20
+#define LTQ_DMA_CDLEN          0x24
+#define LTQ_DMA_CIS            0x28
+#define LTQ_DMA_CIE            0x2C
+#define LTQ_DMA_PS             0x40
+#define LTQ_DMA_PCTRL          0x44
+#define LTQ_DMA_IRNEN          0xf4
+
+#define DMA_DESCPT             BIT(3)          /* descriptor complete irq */
+#define DMA_TX                 BIT(8)          /* TX channel direction */
+#define DMA_CHAN_ON            BIT(0)          /* channel on / off bit */
+#define DMA_PDEN               BIT(6)          /* enable packet drop */
+#define DMA_CHAN_RST           BIT(1)          /* channel on / off bit */
+#define DMA_RESET              BIT(0)          /* channel on / off bit */
+#define DMA_IRQ_ACK            0x7e            /* IRQ status register */
+#define DMA_POLL               BIT(31)         /* turn on channel polling */
+#define DMA_CLK_DIV4           BIT(6)          /* polling clock divider */
+#define DMA_2W_BURST           BIT(1)          /* 2 word burst length */
+#define DMA_MAX_CHANNEL                20              /* the soc has 20 channels */
+#define DMA_ETOP_ENDIANESS     (0xf << 8) /* endianess swap etop channels */
+#define DMA_WEIGHT     (BIT(17) | BIT(16))     /* default channel wheight */
+
+#define ltq_dma_r32(x)                 ltq_r32(ltq_dma_membase + (x))
+#define ltq_dma_w32(x, y)              ltq_w32(x, ltq_dma_membase + (y))
+#define ltq_dma_w32_mask(x, y, z)      ltq_w32_mask(x, y, \
+                                               ltq_dma_membase + (z))
+
+static struct resource ltq_dma_resource = {
+       .name   = "dma",
+       .start  = LTQ_DMA_BASE_ADDR,
+       .end    = LTQ_DMA_BASE_ADDR + LTQ_DMA_SIZE - 1,
+       .flags  = IORESOURCE_MEM,
+};
+
+static void __iomem *ltq_dma_membase;
+
+void
+ltq_dma_enable_irq(struct ltq_dma_channel *ch)
+{
+       unsigned long flags;
+
+       local_irq_save(flags);
+       ltq_dma_w32(ch->nr, LTQ_DMA_CS);
+       ltq_dma_w32_mask(0, 1 << ch->nr, LTQ_DMA_IRNEN);
+       local_irq_restore(flags);
+}
+EXPORT_SYMBOL_GPL(ltq_dma_enable_irq);
+
+void
+ltq_dma_disable_irq(struct ltq_dma_channel *ch)
+{
+       unsigned long flags;
+
+       local_irq_save(flags);
+       ltq_dma_w32(ch->nr, LTQ_DMA_CS);
+       ltq_dma_w32_mask(1 << ch->nr, 0, LTQ_DMA_IRNEN);
+       local_irq_restore(flags);
+}
+EXPORT_SYMBOL_GPL(ltq_dma_disable_irq);
+
+void
+ltq_dma_ack_irq(struct ltq_dma_channel *ch)
+{
+       unsigned long flags;
+
+       local_irq_save(flags);
+       ltq_dma_w32(ch->nr, LTQ_DMA_CS);
+       ltq_dma_w32(DMA_IRQ_ACK, LTQ_DMA_CIS);
+       local_irq_restore(flags);
+}
+EXPORT_SYMBOL_GPL(ltq_dma_ack_irq);
+
+void
+ltq_dma_open(struct ltq_dma_channel *ch)
+{
+       unsigned long flag;
+
+       local_irq_save(flag);
+       ltq_dma_w32(ch->nr, LTQ_DMA_CS);
+       ltq_dma_w32_mask(0, DMA_CHAN_ON, LTQ_DMA_CCTRL);
+       ltq_dma_enable_irq(ch);
+       local_irq_restore(flag);
+}
+EXPORT_SYMBOL_GPL(ltq_dma_open);
+
+void
+ltq_dma_close(struct ltq_dma_channel *ch)
+{
+       unsigned long flag;
+
+       local_irq_save(flag);
+       ltq_dma_w32(ch->nr, LTQ_DMA_CS);
+       ltq_dma_w32_mask(DMA_CHAN_ON, 0, LTQ_DMA_CCTRL);
+       ltq_dma_disable_irq(ch);
+       local_irq_restore(flag);
+}
+EXPORT_SYMBOL_GPL(ltq_dma_close);
+
+static void
+ltq_dma_alloc(struct ltq_dma_channel *ch)
+{
+       unsigned long flags;
+
+       ch->desc = 0;
+       ch->desc_base = dma_alloc_coherent(NULL,
+                               LTQ_DESC_NUM * LTQ_DESC_SIZE,
+                               &ch->phys, GFP_ATOMIC);
+       memset(ch->desc_base, 0, LTQ_DESC_NUM * LTQ_DESC_SIZE);
+
+       local_irq_save(flags);
+       ltq_dma_w32(ch->nr, LTQ_DMA_CS);
+       ltq_dma_w32(ch->phys, LTQ_DMA_CDBA);
+       ltq_dma_w32(LTQ_DESC_NUM, LTQ_DMA_CDLEN);
+       ltq_dma_w32_mask(DMA_CHAN_ON, 0, LTQ_DMA_CCTRL);
+       wmb();
+       ltq_dma_w32_mask(0, DMA_CHAN_RST, LTQ_DMA_CCTRL);
+       while (ltq_dma_r32(LTQ_DMA_CCTRL) & DMA_CHAN_RST)
+               ;
+       local_irq_restore(flags);
+}
+
+void
+ltq_dma_alloc_tx(struct ltq_dma_channel *ch)
+{
+       unsigned long flags;
+
+       ltq_dma_alloc(ch);
+
+       local_irq_save(flags);
+       ltq_dma_w32(DMA_DESCPT, LTQ_DMA_CIE);
+       ltq_dma_w32_mask(0, 1 << ch->nr, LTQ_DMA_IRNEN);
+       ltq_dma_w32(DMA_WEIGHT | DMA_TX, LTQ_DMA_CCTRL);
+       local_irq_restore(flags);
+}
+EXPORT_SYMBOL_GPL(ltq_dma_alloc_tx);
+
+void
+ltq_dma_alloc_rx(struct ltq_dma_channel *ch)
+{
+       unsigned long flags;
+
+       ltq_dma_alloc(ch);
+
+       local_irq_save(flags);
+       ltq_dma_w32(DMA_DESCPT, LTQ_DMA_CIE);
+       ltq_dma_w32_mask(0, 1 << ch->nr, LTQ_DMA_IRNEN);
+       ltq_dma_w32(DMA_WEIGHT, LTQ_DMA_CCTRL);
+       local_irq_restore(flags);
+}
+EXPORT_SYMBOL_GPL(ltq_dma_alloc_rx);
+
+void
+ltq_dma_free(struct ltq_dma_channel *ch)
+{
+       if (!ch->desc_base)
+               return;
+       ltq_dma_close(ch);
+       dma_free_coherent(NULL, LTQ_DESC_NUM * LTQ_DESC_SIZE,
+               ch->desc_base, ch->phys);
+}
+EXPORT_SYMBOL_GPL(ltq_dma_free);
+
+void
+ltq_dma_init_port(int p)
+{
+       ltq_dma_w32(p, LTQ_DMA_PS);
+       switch (p) {
+       case DMA_PORT_ETOP:
+               /*
+                * Tell the DMA engine to swap the endianess of data frames and
+                * drop packets if the channel arbitration fails.
+                */
+               ltq_dma_w32_mask(0, DMA_ETOP_ENDIANESS | DMA_PDEN,
+                       LTQ_DMA_PCTRL);
+               break;
+
+       case DMA_PORT_DEU:
+               ltq_dma_w32((DMA_2W_BURST << 4) | (DMA_2W_BURST << 2),
+                       LTQ_DMA_PCTRL);
+               break;
+
+       default:
+               break;
+       }
+}
+EXPORT_SYMBOL_GPL(ltq_dma_init_port);
+
+int __init
+ltq_dma_init(void)
+{
+       int i;
+
+       /* insert and request the memory region */
+       if (insert_resource(&iomem_resource, &ltq_dma_resource) < 0)
+               panic("Failed to insert dma memory\n");
+
+       if (request_mem_region(ltq_dma_resource.start,
+                       resource_size(&ltq_dma_resource), "dma") < 0)
+               panic("Failed to request dma memory\n");
+
+       /* remap dma register range */
+       ltq_dma_membase = ioremap_nocache(ltq_dma_resource.start,
+                               resource_size(&ltq_dma_resource));
+       if (!ltq_dma_membase)
+               panic("Failed to remap dma memory\n");
+
+       /* power up and reset the dma engine */
+       ltq_pmu_enable(PMU_DMA);
+       ltq_dma_w32_mask(0, DMA_RESET, LTQ_DMA_CTRL);
+
+       /* disable all interrupts */
+       ltq_dma_w32(0, LTQ_DMA_IRNEN);
+
+       /* reset/configure each channel */
+       for (i = 0; i < DMA_MAX_CHANNEL; i++) {
+               ltq_dma_w32(i, LTQ_DMA_CS);
+               ltq_dma_w32(DMA_CHAN_RST, LTQ_DMA_CCTRL);
+               ltq_dma_w32(DMA_POLL | DMA_CLK_DIV4, LTQ_DMA_CPOLL);
+               ltq_dma_w32_mask(DMA_CHAN_ON, 0, LTQ_DMA_CCTRL);
+       }
+       return 0;
+}
+
+postcore_initcall(ltq_dma_init);
diff --git a/arch/mips/lantiq/xway/ebu.c b/arch/mips/lantiq/xway/ebu.c
new file mode 100644 (file)
index 0000000..66eb52f
--- /dev/null
@@ -0,0 +1,53 @@
+/*
+ *  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.
+ *
+ *  EBU - the external bus unit attaches PCI, NOR and NAND
+ *
+ *  Copyright (C) 2010 John Crispin <blogic@openwrt.org>
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/version.h>
+#include <linux/ioport.h>
+
+#include <lantiq_soc.h>
+
+/* all access to the ebu must be locked */
+DEFINE_SPINLOCK(ebu_lock);
+EXPORT_SYMBOL_GPL(ebu_lock);
+
+static struct resource ltq_ebu_resource = {
+       .name   = "ebu",
+       .start  = LTQ_EBU_BASE_ADDR,
+       .end    = LTQ_EBU_BASE_ADDR + LTQ_EBU_SIZE - 1,
+       .flags  = IORESOURCE_MEM,
+};
+
+/* remapped base addr of the clock unit and external bus unit */
+void __iomem *ltq_ebu_membase;
+
+static int __init lantiq_ebu_init(void)
+{
+       /* insert and request the memory region */
+       if (insert_resource(&iomem_resource, &ltq_ebu_resource) < 0)
+               panic("Failed to insert ebu memory\n");
+
+       if (request_mem_region(ltq_ebu_resource.start,
+                       resource_size(&ltq_ebu_resource), "ebu") < 0)
+               panic("Failed to request ebu memory\n");
+
+       /* remap ebu register range */
+       ltq_ebu_membase = ioremap_nocache(ltq_ebu_resource.start,
+                               resource_size(&ltq_ebu_resource));
+       if (!ltq_ebu_membase)
+               panic("Failed to remap ebu memory\n");
+
+       /* make sure to unprotect the memory region where flash is located */
+       ltq_ebu_w32(ltq_ebu_r32(LTQ_EBU_BUSCON0) & ~EBU_WRDIS, LTQ_EBU_BUSCON0);
+       return 0;
+}
+
+postcore_initcall(lantiq_ebu_init);
diff --git a/arch/mips/lantiq/xway/gpio.c b/arch/mips/lantiq/xway/gpio.c
new file mode 100644 (file)
index 0000000..a321451
--- /dev/null
@@ -0,0 +1,195 @@
+/*
+ *  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.
+ *
+ *  Copyright (C) 2010 John Crispin <blogic@openwrt.org>
+ */
+
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/gpio.h>
+#include <linux/ioport.h>
+#include <linux/io.h>
+
+#include <lantiq_soc.h>
+
+#define LTQ_GPIO_OUT           0x00
+#define LTQ_GPIO_IN            0x04
+#define LTQ_GPIO_DIR           0x08
+#define LTQ_GPIO_ALTSEL0       0x0C
+#define LTQ_GPIO_ALTSEL1       0x10
+#define LTQ_GPIO_OD            0x14
+
+#define PINS_PER_PORT          16
+#define MAX_PORTS              3
+
+#define ltq_gpio_getbit(m, r, p)       (!!(ltq_r32(m + r) & (1 << p)))
+#define ltq_gpio_setbit(m, r, p)       ltq_w32_mask(0, (1 << p), m + r)
+#define ltq_gpio_clearbit(m, r, p)     ltq_w32_mask((1 << p), 0, m + r)
+
+struct ltq_gpio {
+       void __iomem *membase;
+       struct gpio_chip chip;
+};
+
+static struct ltq_gpio ltq_gpio_port[MAX_PORTS];
+
+int gpio_to_irq(unsigned int gpio)
+{
+       return -EINVAL;
+}
+EXPORT_SYMBOL(gpio_to_irq);
+
+int irq_to_gpio(unsigned int gpio)
+{
+       return -EINVAL;
+}
+EXPORT_SYMBOL(irq_to_gpio);
+
+int ltq_gpio_request(unsigned int pin, unsigned int alt0,
+       unsigned int alt1, unsigned int dir, const char *name)
+{
+       int id = 0;
+
+       if (pin >= (MAX_PORTS * PINS_PER_PORT))
+               return -EINVAL;
+       if (gpio_request(pin, name)) {
+               pr_err("failed to setup lantiq gpio: %s\n", name);
+               return -EBUSY;
+       }
+       if (dir)
+               gpio_direction_output(pin, 1);
+       else
+               gpio_direction_input(pin);
+       while (pin >= PINS_PER_PORT) {
+               pin -= PINS_PER_PORT;
+               id++;
+       }
+       if (alt0)
+               ltq_gpio_setbit(ltq_gpio_port[id].membase,
+                       LTQ_GPIO_ALTSEL0, pin);
+       else
+               ltq_gpio_clearbit(ltq_gpio_port[id].membase,
+                       LTQ_GPIO_ALTSEL0, pin);
+       if (alt1)
+               ltq_gpio_setbit(ltq_gpio_port[id].membase,
+                       LTQ_GPIO_ALTSEL1, pin);
+       else
+               ltq_gpio_clearbit(ltq_gpio_port[id].membase,
+                       LTQ_GPIO_ALTSEL1, pin);
+       return 0;
+}
+EXPORT_SYMBOL(ltq_gpio_request);
+
+static void ltq_gpio_set(struct gpio_chip *chip, unsigned int offset, int value)
+{
+       struct ltq_gpio *ltq_gpio = container_of(chip, struct ltq_gpio, chip);
+
+       if (value)
+               ltq_gpio_setbit(ltq_gpio->membase, LTQ_GPIO_OUT, offset);
+       else
+               ltq_gpio_clearbit(ltq_gpio->membase, LTQ_GPIO_OUT, offset);
+}
+
+static int ltq_gpio_get(struct gpio_chip *chip, unsigned int offset)
+{
+       struct ltq_gpio *ltq_gpio = container_of(chip, struct ltq_gpio, chip);
+
+       return ltq_gpio_getbit(ltq_gpio->membase, LTQ_GPIO_IN, offset);
+}
+
+static int ltq_gpio_direction_input(struct gpio_chip *chip, unsigned int offset)
+{
+       struct ltq_gpio *ltq_gpio = container_of(chip, struct ltq_gpio, chip);
+
+       ltq_gpio_clearbit(ltq_gpio->membase, LTQ_GPIO_OD, offset);
+       ltq_gpio_clearbit(ltq_gpio->membase, LTQ_GPIO_DIR, offset);
+
+       return 0;
+}
+
+static int ltq_gpio_direction_output(struct gpio_chip *chip,
+       unsigned int offset, int value)
+{
+       struct ltq_gpio *ltq_gpio = container_of(chip, struct ltq_gpio, chip);
+
+       ltq_gpio_setbit(ltq_gpio->membase, LTQ_GPIO_OD, offset);
+       ltq_gpio_setbit(ltq_gpio->membase, LTQ_GPIO_DIR, offset);
+       ltq_gpio_set(chip, offset, value);
+
+       return 0;
+}
+
+static int ltq_gpio_req(struct gpio_chip *chip, unsigned offset)
+{
+       struct ltq_gpio *ltq_gpio = container_of(chip, struct ltq_gpio, chip);
+
+       ltq_gpio_clearbit(ltq_gpio->membase, LTQ_GPIO_ALTSEL0, offset);
+       ltq_gpio_clearbit(ltq_gpio->membase, LTQ_GPIO_ALTSEL1, offset);
+       return 0;
+}
+
+static int ltq_gpio_probe(struct platform_device *pdev)
+{
+       struct resource *res;
+
+       if (pdev->id >= MAX_PORTS) {
+               dev_err(&pdev->dev, "invalid gpio port %d\n",
+                       pdev->id);
+               return -EINVAL;
+       }
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (!res) {
+               dev_err(&pdev->dev, "failed to get memory for gpio port %d\n",
+                       pdev->id);
+               return -ENOENT;
+       }
+       res = devm_request_mem_region(&pdev->dev, res->start,
+               resource_size(res), dev_name(&pdev->dev));
+       if (!res) {
+               dev_err(&pdev->dev,
+                       "failed to request memory for gpio port %d\n",
+                       pdev->id);
+               return -EBUSY;
+       }
+       ltq_gpio_port[pdev->id].membase = devm_ioremap_nocache(&pdev->dev,
+               res->start, resource_size(res));
+       if (!ltq_gpio_port[pdev->id].membase) {
+               dev_err(&pdev->dev, "failed to remap memory for gpio port %d\n",
+                       pdev->id);
+               return -ENOMEM;
+       }
+       ltq_gpio_port[pdev->id].chip.label = "ltq_gpio";
+       ltq_gpio_port[pdev->id].chip.direction_input = ltq_gpio_direction_input;
+       ltq_gpio_port[pdev->id].chip.direction_output =
+               ltq_gpio_direction_output;
+       ltq_gpio_port[pdev->id].chip.get = ltq_gpio_get;
+       ltq_gpio_port[pdev->id].chip.set = ltq_gpio_set;
+       ltq_gpio_port[pdev->id].chip.request = ltq_gpio_req;
+       ltq_gpio_port[pdev->id].chip.base = PINS_PER_PORT * pdev->id;
+       ltq_gpio_port[pdev->id].chip.ngpio = PINS_PER_PORT;
+       platform_set_drvdata(pdev, &ltq_gpio_port[pdev->id]);
+       return gpiochip_add(&ltq_gpio_port[pdev->id].chip);
+}
+
+static struct platform_driver
+ltq_gpio_driver = {
+       .probe = ltq_gpio_probe,
+       .driver = {
+               .name = "ltq_gpio",
+               .owner = THIS_MODULE,
+       },
+};
+
+int __init ltq_gpio_init(void)
+{
+       int ret = platform_driver_register(&ltq_gpio_driver);
+
+       if (ret)
+               pr_info("ltq_gpio : Error registering platfom driver!");
+       return ret;
+}
+
+postcore_initcall(ltq_gpio_init);
diff --git a/arch/mips/lantiq/xway/gpio_ebu.c b/arch/mips/lantiq/xway/gpio_ebu.c
new file mode 100644 (file)
index 0000000..a479355
--- /dev/null
@@ -0,0 +1,126 @@
+/*
+ *  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.
+ *
+ *  Copyright (C) 2010 John Crispin <blogic@openwrt.org>
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/platform_device.h>
+#include <linux/mutex.h>
+#include <linux/gpio.h>
+#include <linux/io.h>
+
+#include <lantiq_soc.h>
+
+/*
+ * By attaching hardware latches to the EBU it is possible to create output
+ * only gpios. This driver configures a special memory address, which when
+ * written to outputs 16 bit to the latches.
+ */
+
+#define LTQ_EBU_BUSCON 0x1e7ff         /* 16 bit access, slowest timing */
+#define LTQ_EBU_WP     0x80000000      /* write protect bit */
+
+/* we keep a shadow value of the last value written to the ebu */
+static int ltq_ebu_gpio_shadow = 0x0;
+static void __iomem *ltq_ebu_gpio_membase;
+
+static void ltq_ebu_apply(void)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&ebu_lock, flags);
+       ltq_ebu_w32(LTQ_EBU_BUSCON, LTQ_EBU_BUSCON1);
+       *((__u16 *)ltq_ebu_gpio_membase) = ltq_ebu_gpio_shadow;
+       ltq_ebu_w32(LTQ_EBU_BUSCON | LTQ_EBU_WP, LTQ_EBU_BUSCON1);
+       spin_unlock_irqrestore(&ebu_lock, flags);
+}
+
+static void ltq_ebu_set(struct gpio_chip *chip, unsigned offset, int value)
+{
+       if (value)
+               ltq_ebu_gpio_shadow |= (1 << offset);
+       else
+               ltq_ebu_gpio_shadow &= ~(1 << offset);
+       ltq_ebu_apply();
+}
+
+static int ltq_ebu_direction_output(struct gpio_chip *chip, unsigned offset,
+       int value)
+{
+       ltq_ebu_set(chip, offset, value);
+
+       return 0;
+}
+
+static struct gpio_chip ltq_ebu_chip = {
+       .label = "ltq_ebu",
+       .direction_output = ltq_ebu_direction_output,
+       .set = ltq_ebu_set,
+       .base = 72,
+       .ngpio = 16,
+       .can_sleep = 1,
+       .owner = THIS_MODULE,
+};
+
+static int ltq_ebu_probe(struct platform_device *pdev)
+{
+       int ret = 0;
+       struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+
+       if (!res) {
+               dev_err(&pdev->dev, "failed to get memory resource\n");
+               return -ENOENT;
+       }
+
+       res = devm_request_mem_region(&pdev->dev, res->start,
+               resource_size(res), dev_name(&pdev->dev));
+       if (!res) {
+               dev_err(&pdev->dev, "failed to request memory resource\n");
+               return -EBUSY;
+       }
+
+       ltq_ebu_gpio_membase = devm_ioremap_nocache(&pdev->dev, res->start,
+               resource_size(res));
+       if (!ltq_ebu_gpio_membase) {
+               dev_err(&pdev->dev, "Failed to ioremap mem region\n");
+               return -ENOMEM;
+       }
+
+       /* grab the default shadow value passed form the platform code */
+       ltq_ebu_gpio_shadow = (unsigned int) pdev->dev.platform_data;
+
+       /* tell the ebu controller which memory address we will be using */
+       ltq_ebu_w32(pdev->resource->start | 0x1, LTQ_EBU_ADDRSEL1);
+
+       /* write protect the region */
+       ltq_ebu_w32(LTQ_EBU_BUSCON | LTQ_EBU_WP, LTQ_EBU_BUSCON1);
+
+       ret = gpiochip_add(&ltq_ebu_chip);
+       if (!ret)
+               ltq_ebu_apply();
+       return ret;
+}
+
+static struct platform_driver ltq_ebu_driver = {
+       .probe = ltq_ebu_probe,
+       .driver = {
+               .name = "ltq_ebu",
+               .owner = THIS_MODULE,
+       },
+};
+
+static int __init ltq_ebu_init(void)
+{
+       int ret = platform_driver_register(&ltq_ebu_driver);
+
+       if (ret)
+               pr_info("ltq_ebu : Error registering platfom driver!");
+       return ret;
+}
+
+postcore_initcall(ltq_ebu_init);
diff --git a/arch/mips/lantiq/xway/gpio_stp.c b/arch/mips/lantiq/xway/gpio_stp.c
new file mode 100644 (file)
index 0000000..67d59d6
--- /dev/null
@@ -0,0 +1,157 @@
+/*
+ *  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.
+ *
+ *  Copyright (C) 2007 John Crispin <blogic@openwrt.org>
+ *
+ */
+
+#include <linux/slab.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/platform_device.h>
+#include <linux/mutex.h>
+#include <linux/io.h>
+#include <linux/gpio.h>
+
+#include <lantiq_soc.h>
+
+#define LTQ_STP_CON0           0x00
+#define LTQ_STP_CON1           0x04
+#define LTQ_STP_CPU0           0x08
+#define LTQ_STP_CPU1           0x0C
+#define LTQ_STP_AR             0x10
+
+#define LTQ_STP_CON_SWU                (1 << 31)
+#define LTQ_STP_2HZ            0
+#define LTQ_STP_4HZ            (1 << 23)
+#define LTQ_STP_8HZ            (2 << 23)
+#define LTQ_STP_10HZ           (3 << 23)
+#define LTQ_STP_SPEED_MASK     (0xf << 23)
+#define LTQ_STP_UPD_FPI                (1 << 31)
+#define LTQ_STP_UPD_MASK       (3 << 30)
+#define LTQ_STP_ADSL_SRC       (3 << 24)
+
+#define LTQ_STP_GROUP0         (1 << 0)
+
+#define LTQ_STP_RISING         0
+#define LTQ_STP_FALLING                (1 << 26)
+#define LTQ_STP_EDGE_MASK      (1 << 26)
+
+#define ltq_stp_r32(reg)       __raw_readl(ltq_stp_membase + reg)
+#define ltq_stp_w32(val, reg)  __raw_writel(val, ltq_stp_membase + reg)
+#define ltq_stp_w32_mask(clear, set, reg) \
+               ltq_w32((ltq_r32(ltq_stp_membase + reg) & ~(clear)) | (set), \
+               ltq_stp_membase + (reg))
+
+static int ltq_stp_shadow = 0xffff;
+static void __iomem *ltq_stp_membase;
+
+static void ltq_stp_set(struct gpio_chip *chip, unsigned offset, int value)
+{
+       if (value)
+               ltq_stp_shadow |= (1 << offset);
+       else
+               ltq_stp_shadow &= ~(1 << offset);
+       ltq_stp_w32(ltq_stp_shadow, LTQ_STP_CPU0);
+}
+
+static int ltq_stp_direction_output(struct gpio_chip *chip, unsigned offset,
+       int value)
+{
+       ltq_stp_set(chip, offset, value);
+
+       return 0;
+}
+
+static struct gpio_chip ltq_stp_chip = {
+       .label = "ltq_stp",
+       .direction_output = ltq_stp_direction_output,
+       .set = ltq_stp_set,
+       .base = 48,
+       .ngpio = 24,
+       .can_sleep = 1,
+       .owner = THIS_MODULE,
+};
+
+static int ltq_stp_hw_init(void)
+{
+       /* the 3 pins used to control the external stp */
+       ltq_gpio_request(4, 1, 0, 1, "stp-st");
+       ltq_gpio_request(5, 1, 0, 1, "stp-d");
+       ltq_gpio_request(6, 1, 0, 1, "stp-sh");
+
+       /* sane defaults */
+       ltq_stp_w32(0, LTQ_STP_AR);
+       ltq_stp_w32(0, LTQ_STP_CPU0);
+       ltq_stp_w32(0, LTQ_STP_CPU1);
+       ltq_stp_w32(LTQ_STP_CON_SWU, LTQ_STP_CON0);
+       ltq_stp_w32(0, LTQ_STP_CON1);
+
+       /* rising or falling edge */
+       ltq_stp_w32_mask(LTQ_STP_EDGE_MASK, LTQ_STP_FALLING, LTQ_STP_CON0);
+
+       /* per default stp 15-0 are set */
+       ltq_stp_w32_mask(0, LTQ_STP_GROUP0, LTQ_STP_CON1);
+
+       /* stp are update periodically by the FPI bus */
+       ltq_stp_w32_mask(LTQ_STP_UPD_MASK, LTQ_STP_UPD_FPI, LTQ_STP_CON1);
+
+       /* set stp update speed */
+       ltq_stp_w32_mask(LTQ_STP_SPEED_MASK, LTQ_STP_8HZ, LTQ_STP_CON1);
+
+       /* tell the hardware that pin (led) 0 and 1 are controlled
+        *  by the dsl arc
+        */
+       ltq_stp_w32_mask(0, LTQ_STP_ADSL_SRC, LTQ_STP_CON0);
+
+       ltq_pmu_enable(PMU_LED);
+       return 0;
+}
+
+static int __devinit ltq_stp_probe(struct platform_device *pdev)
+{
+       struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       int ret = 0;
+
+       if (!res)
+               return -ENOENT;
+       res = devm_request_mem_region(&pdev->dev, res->start,
+               resource_size(res), dev_name(&pdev->dev));
+       if (!res) {
+               dev_err(&pdev->dev, "failed to request STP memory\n");
+               return -EBUSY;
+       }
+       ltq_stp_membase = devm_ioremap_nocache(&pdev->dev, res->start,
+               resource_size(res));
+       if (!ltq_stp_membase) {
+               dev_err(&pdev->dev, "failed to remap STP memory\n");
+               return -ENOMEM;
+       }
+       ret = gpiochip_add(&ltq_stp_chip);
+       if (!ret)
+               ret = ltq_stp_hw_init();
+
+       return ret;
+}
+
+static struct platform_driver ltq_stp_driver = {
+       .probe = ltq_stp_probe,
+       .driver = {
+               .name = "ltq_stp",
+               .owner = THIS_MODULE,
+       },
+};
+
+int __init ltq_stp_init(void)
+{
+       int ret = platform_driver_register(&ltq_stp_driver);
+
+       if (ret)
+               pr_info("ltq_stp: error registering platfom driver");
+       return ret;
+}
+
+postcore_initcall(ltq_stp_init);
diff --git a/arch/mips/lantiq/xway/mach-easy50601.c b/arch/mips/lantiq/xway/mach-easy50601.c
new file mode 100644 (file)
index 0000000..d5aaf63
--- /dev/null
@@ -0,0 +1,57 @@
+/*
+ *  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.
+ *
+ *  Copyright (C) 2010 John Crispin <blogic@openwrt.org>
+ */
+
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/partitions.h>
+#include <linux/mtd/physmap.h>
+#include <linux/input.h>
+
+#include <lantiq.h>
+
+#include "../machtypes.h"
+#include "devices.h"
+
+static struct mtd_partition easy50601_partitions[] = {
+       {
+               .name   = "uboot",
+               .offset = 0x0,
+               .size   = 0x10000,
+       },
+       {
+               .name   = "uboot_env",
+               .offset = 0x10000,
+               .size   = 0x10000,
+       },
+       {
+               .name   = "linux",
+               .offset = 0x20000,
+               .size   = 0xE0000,
+       },
+       {
+               .name   = "rootfs",
+               .offset = 0x100000,
+               .size   = 0x300000,
+       },
+};
+
+static struct physmap_flash_data easy50601_flash_data = {
+       .nr_parts       = ARRAY_SIZE(easy50601_partitions),
+       .parts          = easy50601_partitions,
+};
+
+static void __init easy50601_init(void)
+{
+       ltq_register_nor(&easy50601_flash_data);
+}
+
+MIPS_MACHINE(LTQ_MACH_EASY50601,
+                       "EASY50601",
+                       "EASY50601 Eval Board",
+                       easy50601_init);
diff --git a/arch/mips/lantiq/xway/mach-easy50712.c b/arch/mips/lantiq/xway/mach-easy50712.c
new file mode 100644 (file)
index 0000000..ea5027b
--- /dev/null
@@ -0,0 +1,74 @@
+/*
+ *  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.
+ *
+ *  Copyright (C) 2010 John Crispin <blogic@openwrt.org>
+ */
+
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/partitions.h>
+#include <linux/mtd/physmap.h>
+#include <linux/input.h>
+#include <linux/phy.h>
+
+#include <lantiq_soc.h>
+#include <irq.h>
+
+#include "../machtypes.h"
+#include "devices.h"
+
+static struct mtd_partition easy50712_partitions[] = {
+       {
+               .name   = "uboot",
+               .offset = 0x0,
+               .size   = 0x10000,
+       },
+       {
+               .name   = "uboot_env",
+               .offset = 0x10000,
+               .size   = 0x10000,
+       },
+       {
+               .name   = "linux",
+               .offset = 0x20000,
+               .size   = 0xe0000,
+       },
+       {
+               .name   = "rootfs",
+               .offset = 0x100000,
+               .size   = 0x300000,
+       },
+};
+
+static struct physmap_flash_data easy50712_flash_data = {
+       .nr_parts       = ARRAY_SIZE(easy50712_partitions),
+       .parts          = easy50712_partitions,
+};
+
+static struct ltq_pci_data ltq_pci_data = {
+       .clock  = PCI_CLOCK_INT,
+       .gpio   = PCI_GNT1 | PCI_REQ1,
+       .irq    = {
+               [14] = INT_NUM_IM0_IRL0 + 22,
+       },
+};
+
+static struct ltq_eth_data ltq_eth_data = {
+       .mii_mode = PHY_INTERFACE_MODE_MII,
+};
+
+static void __init easy50712_init(void)
+{
+       ltq_register_gpio_stp();
+       ltq_register_nor(&easy50712_flash_data);
+       ltq_register_pci(&ltq_pci_data);
+       ltq_register_etop(&ltq_eth_data);
+}
+
+MIPS_MACHINE(LTQ_MACH_EASY50712,
+            "EASY50712",
+            "EASY50712 Eval Board",
+             easy50712_init);
diff --git a/arch/mips/lantiq/xway/pmu.c b/arch/mips/lantiq/xway/pmu.c
new file mode 100644 (file)
index 0000000..9d69f01
--- /dev/null
@@ -0,0 +1,70 @@
+/*
+ *  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.
+ *
+ *  Copyright (C) 2010 John Crispin <blogic@openwrt.org>
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/version.h>
+#include <linux/ioport.h>
+
+#include <lantiq_soc.h>
+
+/* PMU - the power management unit allows us to turn part of the core
+ * on and off
+ */
+
+/* the enable / disable registers */
+#define LTQ_PMU_PWDCR  0x1C
+#define LTQ_PMU_PWDSR  0x20
+
+#define ltq_pmu_w32(x, y)      ltq_w32((x), ltq_pmu_membase + (y))
+#define ltq_pmu_r32(x)         ltq_r32(ltq_pmu_membase + (x))
+
+static struct resource ltq_pmu_resource = {
+       .name   = "pmu",
+       .start  = LTQ_PMU_BASE_ADDR,
+       .end    = LTQ_PMU_BASE_ADDR + LTQ_PMU_SIZE - 1,
+       .flags  = IORESOURCE_MEM,
+};
+
+static void __iomem *ltq_pmu_membase;
+
+void ltq_pmu_enable(unsigned int module)
+{
+       int err = 1000000;
+
+       ltq_pmu_w32(ltq_pmu_r32(LTQ_PMU_PWDCR) & ~module, LTQ_PMU_PWDCR);
+       do {} while (--err && (ltq_pmu_r32(LTQ_PMU_PWDSR) & module));
+
+       if (!err)
+               panic("activating PMU module failed!\n");
+}
+EXPORT_SYMBOL(ltq_pmu_enable);
+
+void ltq_pmu_disable(unsigned int module)
+{
+       ltq_pmu_w32(ltq_pmu_r32(LTQ_PMU_PWDCR) | module, LTQ_PMU_PWDCR);
+}
+EXPORT_SYMBOL(ltq_pmu_disable);
+
+int __init ltq_pmu_init(void)
+{
+       if (insert_resource(&iomem_resource, &ltq_pmu_resource) < 0)
+               panic("Failed to insert pmu memory\n");
+
+       if (request_mem_region(ltq_pmu_resource.start,
+                       resource_size(&ltq_pmu_resource), "pmu") < 0)
+               panic("Failed to request pmu memory\n");
+
+       ltq_pmu_membase = ioremap_nocache(ltq_pmu_resource.start,
+                               resource_size(&ltq_pmu_resource));
+       if (!ltq_pmu_membase)
+               panic("Failed to remap pmu memory\n");
+       return 0;
+}
+
+core_initcall(ltq_pmu_init);
diff --git a/arch/mips/lantiq/xway/prom-ase.c b/arch/mips/lantiq/xway/prom-ase.c
new file mode 100644 (file)
index 0000000..abe49f4
--- /dev/null
@@ -0,0 +1,39 @@
+/*
+ *  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.
+ *
+ *  Copyright (C) 2010 John Crispin <blogic@openwrt.org>
+ */
+
+#include <linux/module.h>
+#include <linux/clk.h>
+#include <asm/bootinfo.h>
+#include <asm/time.h>
+
+#include <lantiq_soc.h>
+
+#include "../prom.h"
+
+#define SOC_AMAZON_SE  "Amazon_SE"
+
+#define PART_SHIFT     12
+#define PART_MASK      0x0FFFFFFF
+#define REV_SHIFT      28
+#define REV_MASK       0xF0000000
+
+void __init ltq_soc_detect(struct ltq_soc_info *i)
+{
+       i->partnum = (ltq_r32(LTQ_MPS_CHIPID) & PART_MASK) >> PART_SHIFT;
+       i->rev = (ltq_r32(LTQ_MPS_CHIPID) & REV_MASK) >> REV_SHIFT;
+       switch (i->partnum) {
+       case SOC_ID_AMAZON_SE:
+               i->name = SOC_AMAZON_SE;
+               i->type = SOC_TYPE_AMAZON_SE;
+               break;
+
+       default:
+               unreachable();
+               break;
+       }
+}
diff --git a/arch/mips/lantiq/xway/prom-xway.c b/arch/mips/lantiq/xway/prom-xway.c
new file mode 100644 (file)
index 0000000..1686692
--- /dev/null
@@ -0,0 +1,54 @@
+/*
+ *  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.
+ *
+ *  Copyright (C) 2010 John Crispin <blogic@openwrt.org>
+ */
+
+#include <linux/module.h>
+#include <linux/clk.h>
+#include <asm/bootinfo.h>
+#include <asm/time.h>
+
+#include <lantiq_soc.h>
+
+#include "../prom.h"
+
+#define SOC_DANUBE     "Danube"
+#define SOC_TWINPASS   "Twinpass"
+#define SOC_AR9                "AR9"
+
+#define PART_SHIFT     12
+#define PART_MASK      0x0FFFFFFF
+#define REV_SHIFT      28
+#define REV_MASK       0xF0000000
+
+void __init ltq_soc_detect(struct ltq_soc_info *i)
+{
+       i->partnum = (ltq_r32(LTQ_MPS_CHIPID) & PART_MASK) >> PART_SHIFT;
+       i->rev = (ltq_r32(LTQ_MPS_CHIPID) & REV_MASK) >> REV_SHIFT;
+       switch (i->partnum) {
+       case SOC_ID_DANUBE1:
+       case SOC_ID_DANUBE2:
+               i->name = SOC_DANUBE;
+               i->type = SOC_TYPE_DANUBE;
+               break;
+
+       case SOC_ID_TWINPASS:
+               i->name = SOC_TWINPASS;
+               i->type = SOC_TYPE_DANUBE;
+               break;
+
+       case SOC_ID_ARX188:
+       case SOC_ID_ARX168:
+       case SOC_ID_ARX182:
+               i->name = SOC_AR9;
+               i->type = SOC_TYPE_AR9;
+               break;
+
+       default:
+               unreachable();
+               break;
+       }
+}
diff --git a/arch/mips/lantiq/xway/reset.c b/arch/mips/lantiq/xway/reset.c
new file mode 100644 (file)
index 0000000..a1be36d
--- /dev/null
@@ -0,0 +1,91 @@
+/*
+ *  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.
+ *
+ *  Copyright (C) 2010 John Crispin <blogic@openwrt.org>
+ */
+
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/ioport.h>
+#include <linux/pm.h>
+#include <linux/module.h>
+#include <asm/reboot.h>
+
+#include <lantiq_soc.h>
+
+#define ltq_rcu_w32(x, y)      ltq_w32((x), ltq_rcu_membase + (y))
+#define ltq_rcu_r32(x)         ltq_r32(ltq_rcu_membase + (x))
+
+/* register definitions */
+#define LTQ_RCU_RST            0x0010
+#define LTQ_RCU_RST_ALL                0x40000000
+
+#define LTQ_RCU_RST_STAT       0x0014
+#define LTQ_RCU_STAT_SHIFT     26
+
+static struct resource ltq_rcu_resource = {
+       .name   = "rcu",
+       .start  = LTQ_RCU_BASE_ADDR,
+       .end    = LTQ_RCU_BASE_ADDR + LTQ_RCU_SIZE - 1,
+       .flags  = IORESOURCE_MEM,
+};
+
+/* remapped base addr of the reset control unit */
+static void __iomem *ltq_rcu_membase;
+
+/* This function is used by the watchdog driver */
+int ltq_reset_cause(void)
+{
+       u32 val = ltq_rcu_r32(LTQ_RCU_RST_STAT);
+       return val >> LTQ_RCU_STAT_SHIFT;
+}
+EXPORT_SYMBOL_GPL(ltq_reset_cause);
+
+static void ltq_machine_restart(char *command)
+{
+       pr_notice("System restart\n");
+       local_irq_disable();
+       ltq_rcu_w32(ltq_rcu_r32(LTQ_RCU_RST) | LTQ_RCU_RST_ALL, LTQ_RCU_RST);
+       unreachable();
+}
+
+static void ltq_machine_halt(void)
+{
+       pr_notice("System halted.\n");
+       local_irq_disable();
+       unreachable();
+}
+
+static void ltq_machine_power_off(void)
+{
+       pr_notice("Please turn off the power now.\n");
+       local_irq_disable();
+       unreachable();
+}
+
+static int __init mips_reboot_setup(void)
+{
+       /* insert and request the memory region */
+       if (insert_resource(&iomem_resource, &ltq_rcu_resource) < 0)
+               panic("Failed to insert rcu memory\n");
+
+       if (request_mem_region(ltq_rcu_resource.start,
+                       resource_size(&ltq_rcu_resource), "rcu") < 0)
+               panic("Failed to request rcu memory\n");
+
+       /* remap rcu register range */
+       ltq_rcu_membase = ioremap_nocache(ltq_rcu_resource.start,
+                               resource_size(&ltq_rcu_resource));
+       if (!ltq_rcu_membase)
+               panic("Failed to remap rcu memory\n");
+
+       _machine_restart = ltq_machine_restart;
+       _machine_halt = ltq_machine_halt;
+       pm_power_off = ltq_machine_power_off;
+
+       return 0;
+}
+
+arch_initcall(mips_reboot_setup);
diff --git a/arch/mips/lantiq/xway/setup-ase.c b/arch/mips/lantiq/xway/setup-ase.c
new file mode 100644 (file)
index 0000000..f6f3267
--- /dev/null
@@ -0,0 +1,19 @@
+/*
+ *  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.
+ *
+ *  Copyright (C) 2011 John Crispin <blogic@openwrt.org>
+ */
+
+#include <lantiq_soc.h>
+
+#include "../prom.h"
+#include "devices.h"
+
+void __init ltq_soc_setup(void)
+{
+       ltq_register_ase_asc();
+       ltq_register_gpio();
+       ltq_register_wdt();
+}
diff --git a/arch/mips/lantiq/xway/setup-xway.c b/arch/mips/lantiq/xway/setup-xway.c
new file mode 100644 (file)
index 0000000..c292f64
--- /dev/null
@@ -0,0 +1,20 @@
+/*
+ *  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.
+ *
+ *  Copyright (C) 2011 John Crispin <blogic@openwrt.org>
+ */
+
+#include <lantiq_soc.h>
+
+#include "../prom.h"
+#include "devices.h"
+
+void __init ltq_soc_setup(void)
+{
+       ltq_register_asc(0);
+       ltq_register_asc(1);
+       ltq_register_gpio();
+       ltq_register_wdt();
+}
index 2adead5..b2cad4f 100644 (file)
@@ -28,6 +28,7 @@ obj-$(CONFIG_CPU_TX39XX)      += r3k_dump_tlb.o
 obj-$(CONFIG_CPU_TX49XX)       += dump_tlb.o
 obj-$(CONFIG_CPU_VR41XX)       += dump_tlb.o
 obj-$(CONFIG_CPU_CAVIUM_OCTEON)        += dump_tlb.o
+obj-$(CONFIG_CPU_XLR)          += dump_tlb.o
 
 # libgcc-style stuff needed in the kernel
 obj-y += ashldi3.o ashrdi3.o cmpdi2.o lshrdi3.o ucmpdi2.o
index 8c807c9..0cb1b97 100644 (file)
@@ -201,8 +201,6 @@ static struct clocksource clocksource_mfgpt = {
        .rating = 120, /* Functional for real use, but not desired */
        .read = mfgpt_read,
        .mask = CLOCKSOURCE_MASK(32),
-       .mult = 0,
-       .shift = 22,
 };
 
 int __init init_mfgpt_clocksource(void)
@@ -210,8 +208,7 @@ int __init init_mfgpt_clocksource(void)
        if (num_possible_cpus() > 1)    /* MFGPT does not scale! */
                return 0;
 
-       clocksource_mfgpt.mult = clocksource_hz2mult(MFGPT_TICK_RATE, 22);
-       return clocksource_register(&clocksource_mfgpt);
+       return clocksource_register_hz(&clocksource_mfgpt, MFGPT_TICK_RATE);
 }
 
 arch_initcall(init_mfgpt_clocksource);
index 11b193f..d93830a 100644 (file)
@@ -29,9 +29,10 @@ unsigned long memsize, highmemsize;
 
 #define parse_even_earlier(res, option, p)                             \
 do {                                                                   \
-       int ret;                                                        \
+       unsigned int tmp __maybe_unused;                                \
+                                                                       \
        if (strncmp(option, (char *)p, strlen(option)) == 0)            \
-               ret = strict_strtol((char *)p + strlen(option"="), 10, &res); \
+               tmp = strict_strtol((char *)p + strlen(option"="), 10, &res); \
 } while (0)
 
 void __init prom_init_env(void)
index d679c77..4d8c162 100644 (file)
@@ -3,7 +3,8 @@
 #
 
 obj-y                          += cache.o dma-default.o extable.o fault.o \
-                                  init.o tlbex.o tlbex-fault.o uasm.o page.o
+                                  init.o mmap.o tlbex.o tlbex-fault.o uasm.o \
+                                  page.o
 
 obj-$(CONFIG_32BIT)            += ioremap.o pgtable-32.o
 obj-$(CONFIG_64BIT)            += pgtable-64.o
@@ -29,6 +30,7 @@ obj-$(CONFIG_CPU_TX39XX)      += c-tx39.o tlb-r3k.o
 obj-$(CONFIG_CPU_TX49XX)       += c-r4k.o cex-gen.o tlb-r4k.o
 obj-$(CONFIG_CPU_VR41XX)       += c-r4k.o cex-gen.o tlb-r4k.o
 obj-$(CONFIG_CPU_CAVIUM_OCTEON)        += c-octeon.o cex-oct.o tlb-r4k.o
+obj-$(CONFIG_CPU_XLR)          += c-r4k.o tlb-r4k.o cex-gen.o
 
 obj-$(CONFIG_IP22_CPU_SCACHE)  += sc-ip22.o
 obj-$(CONFIG_R5000_CPU_SCACHE)  += sc-r5k.o
index b4923a7..d9bc5d3 100644 (file)
@@ -1006,6 +1006,7 @@ static void __cpuinit probe_pcache(void)
        case CPU_25KF:
        case CPU_SB1:
        case CPU_SB1A:
+       case CPU_XLR:
                c->dcache.flags |= MIPS_CACHE_PINDEX;
                break;
 
@@ -1075,7 +1076,6 @@ static int __cpuinit probe_scache(void)
        unsigned long flags, addr, begin, end, pow2;
        unsigned int config = read_c0_config();
        struct cpuinfo_mips *c = &current_cpu_data;
-       int tmp;
 
        if (config & CONF_SC)
                return 0;
@@ -1108,7 +1108,6 @@ static int __cpuinit probe_scache(void)
 
        /* Now search for the wrap around point. */
        pow2 = (128 * 1024);
-       tmp = 0;
        for (addr = begin + (128 * 1024); addr < end; addr = begin + pow2) {
                cache_op(Index_Load_Tag_SD, addr);
                __asm__ __volatile__("nop; nop; nop; nop;"); /* hazard... */
diff --git a/arch/mips/mm/mmap.c b/arch/mips/mm/mmap.c
new file mode 100644 (file)
index 0000000..ae3c20a
--- /dev/null
@@ -0,0 +1,122 @@
+/*
+ * 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) 2011 Wind River Systems,
+ *   written by Ralf Baechle <ralf@linux-mips.org>
+ */
+#include <linux/errno.h>
+#include <linux/mm.h>
+#include <linux/mman.h>
+#include <linux/module.h>
+#include <linux/random.h>
+#include <linux/sched.h>
+
+unsigned long shm_align_mask = PAGE_SIZE - 1;  /* Sane caches */
+
+EXPORT_SYMBOL(shm_align_mask);
+
+#define COLOUR_ALIGN(addr,pgoff)                               \
+       ((((addr) + shm_align_mask) & ~shm_align_mask) +        \
+        (((pgoff) << PAGE_SHIFT) & shm_align_mask))
+
+unsigned long arch_get_unmapped_area(struct file *filp, unsigned long addr,
+       unsigned long len, unsigned long pgoff, unsigned long flags)
+{
+       struct vm_area_struct * vmm;
+       int do_color_align;
+
+       if (len > TASK_SIZE)
+               return -ENOMEM;
+
+       if (flags & MAP_FIXED) {
+               /* Even MAP_FIXED mappings must reside within TASK_SIZE.  */
+               if (TASK_SIZE - len < addr)
+                       return -EINVAL;
+
+               /*
+                * We do not accept a shared mapping if it would violate
+                * cache aliasing constraints.
+                */
+               if ((flags & MAP_SHARED) &&
+                   ((addr - (pgoff << PAGE_SHIFT)) & shm_align_mask))
+                       return -EINVAL;
+               return addr;
+       }
+
+       do_color_align = 0;
+       if (filp || (flags & MAP_SHARED))
+               do_color_align = 1;
+       if (addr) {
+               if (do_color_align)
+                       addr = COLOUR_ALIGN(addr, pgoff);
+               else
+                       addr = PAGE_ALIGN(addr);
+               vmm = find_vma(current->mm, addr);
+               if (TASK_SIZE - len >= addr &&
+                   (!vmm || addr + len <= vmm->vm_start))
+                       return addr;
+       }
+       addr = current->mm->mmap_base;
+       if (do_color_align)
+               addr = COLOUR_ALIGN(addr, pgoff);
+       else
+               addr = PAGE_ALIGN(addr);
+
+       for (vmm = find_vma(current->mm, addr); ; vmm = vmm->vm_next) {
+               /* At this point:  (!vmm || addr < vmm->vm_end). */
+               if (TASK_SIZE - len < addr)
+                       return -ENOMEM;
+               if (!vmm || addr + len <= vmm->vm_start)
+                       return addr;
+               addr = vmm->vm_end;
+               if (do_color_align)
+                       addr = COLOUR_ALIGN(addr, pgoff);
+       }
+}
+
+void arch_pick_mmap_layout(struct mm_struct *mm)
+{
+       unsigned long random_factor = 0UL;
+
+       if (current->flags & PF_RANDOMIZE) {
+               random_factor = get_random_int();
+               random_factor = random_factor << PAGE_SHIFT;
+               if (TASK_IS_32BIT_ADDR)
+                       random_factor &= 0xfffffful;
+               else
+                       random_factor &= 0xffffffful;
+       }
+
+       mm->mmap_base = TASK_UNMAPPED_BASE + random_factor;
+       mm->get_unmapped_area = arch_get_unmapped_area;
+       mm->unmap_area = arch_unmap_area;
+}
+
+static inline unsigned long brk_rnd(void)
+{
+       unsigned long rnd = get_random_int();
+
+       rnd = rnd << PAGE_SHIFT;
+       /* 8MB for 32bit, 256MB for 64bit */
+       if (TASK_IS_32BIT_ADDR)
+               rnd = rnd & 0x7ffffful;
+       else
+               rnd = rnd & 0xffffffful;
+
+       return rnd;
+}
+
+unsigned long arch_randomize_brk(struct mm_struct *mm)
+{
+       unsigned long base = mm->brk;
+       unsigned long ret;
+
+       ret = PAGE_ALIGN(base + brk_rnd());
+
+       if (ret < mm->brk)
+               return mm->brk;
+
+       return ret;
+}
index 5ef294f..424ed4b 100644 (file)
@@ -404,6 +404,7 @@ static void __cpuinit build_tlb_write_entry(u32 **p, struct uasm_label **l,
        case CPU_5KC:
        case CPU_TX49XX:
        case CPU_PR4450:
+       case CPU_XLR:
                uasm_i_nop(p);
                tlbw(p);
                break;
@@ -1151,8 +1152,8 @@ static void __cpuinit build_r4000_tlb_refill_handler(void)
        struct uasm_reloc *r = relocs;
        u32 *f;
        unsigned int final_len;
-       struct mips_huge_tlb_info htlb_info;
-       enum vmalloc64_mode vmalloc_mode;
+       struct mips_huge_tlb_info htlb_info __maybe_unused;
+       enum vmalloc64_mode vmalloc_mode __maybe_unused;
 
        memset(tlb_handler, 0, sizeof(tlb_handler));
        memset(labels, 0, sizeof(labels));
index 414f0c9..31180c3 100644 (file)
@@ -193,8 +193,6 @@ 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;
@@ -360,20 +358,14 @@ 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
-       if (result)
+       /* Early detection of CMP support */
+       if (gcmp_probe(GCMP_BASE_ADDR, GCMP_ADDRSPACE_SZ))
                register_smp_ops(&cmp_smp_ops);
+       else
 #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);
index 9027061..1d36c51 100644 (file)
@@ -56,7 +56,6 @@ static DEFINE_RAW_SPINLOCK(mips_irq_lock);
 static inline int mips_pcibios_iack(void)
 {
        int irq;
-       u32 dummy;
 
        /*
         * Determine highest priority pending interrupt by performing
@@ -83,7 +82,7 @@ static inline int mips_pcibios_iack(void)
                BONITO_PCIMAP_CFG = 0x20000;
 
                /* Flush Bonito register block */
-               dummy = BONITO_PCIMAP_CFG;
+               (void) BONITO_PCIMAP_CFG;
                iob();    /* sync */
 
                irq = __raw_readl((u32 *)_pcictrl_bonito_pcicfg);
@@ -309,6 +308,8 @@ static void ipi_call_dispatch(void)
 
 static irqreturn_t ipi_resched_interrupt(int irq, void *dev_id)
 {
+       scheduler_ipi();
+
        return IRQ_HANDLED;
 }
 
diff --git a/arch/mips/netlogic/Kconfig b/arch/mips/netlogic/Kconfig
new file mode 100644 (file)
index 0000000..a5ca743
--- /dev/null
@@ -0,0 +1,5 @@
+config NLM_COMMON
+       bool
+
+config NLM_XLR
+       bool
diff --git a/arch/mips/netlogic/xlr/Makefile b/arch/mips/netlogic/xlr/Makefile
new file mode 100644 (file)
index 0000000..9bd3f73
--- /dev/null
@@ -0,0 +1,5 @@
+obj-y                          += setup.o platform.o irq.o setup.o time.o
+obj-$(CONFIG_SMP)              += smp.o smpboot.o
+obj-$(CONFIG_EARLY_PRINTK)     += xlr_console.o
+
+EXTRA_CFLAGS                   += -Werror
diff --git a/arch/mips/netlogic/xlr/irq.c b/arch/mips/netlogic/xlr/irq.c
new file mode 100644 (file)
index 0000000..1446d58
--- /dev/null
@@ -0,0 +1,300 @@
+/*
+ * Copyright 2003-2011 NetLogic Microsystems, Inc. (NetLogic). All rights
+ * reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the NetLogic
+ * license below:
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY NETLOGIC ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL NETLOGIC OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/linkage.h>
+#include <linux/interrupt.h>
+#include <linux/spinlock.h>
+#include <linux/mm.h>
+
+#include <asm/mipsregs.h>
+
+#include <asm/netlogic/xlr/iomap.h>
+#include <asm/netlogic/xlr/pic.h>
+#include <asm/netlogic/xlr/xlr.h>
+
+#include <asm/netlogic/interrupt.h>
+#include <asm/netlogic/mips-extns.h>
+
+static u64 nlm_irq_mask;
+static DEFINE_SPINLOCK(nlm_pic_lock);
+
+static void xlr_pic_enable(struct irq_data *d)
+{
+       nlm_reg_t *mmio = netlogic_io_mmio(NETLOGIC_IO_PIC_OFFSET);
+       unsigned long flags;
+       nlm_reg_t reg;
+       int irq = d->irq;
+
+       WARN(!PIC_IRQ_IS_IRT(irq), "Bad irq %d", irq);
+
+       spin_lock_irqsave(&nlm_pic_lock, flags);
+       reg = netlogic_read_reg(mmio, PIC_IRT_1_BASE + irq - PIC_IRQ_BASE);
+       netlogic_write_reg(mmio, PIC_IRT_1_BASE + irq - PIC_IRQ_BASE,
+                         reg | (1 << 6) | (1 << 30) | (1 << 31));
+       spin_unlock_irqrestore(&nlm_pic_lock, flags);
+}
+
+static void xlr_pic_mask(struct irq_data *d)
+{
+       nlm_reg_t *mmio = netlogic_io_mmio(NETLOGIC_IO_PIC_OFFSET);
+       unsigned long flags;
+       nlm_reg_t reg;
+       int irq = d->irq;
+
+       WARN(!PIC_IRQ_IS_IRT(irq), "Bad irq %d", irq);
+
+       spin_lock_irqsave(&nlm_pic_lock, flags);
+       reg = netlogic_read_reg(mmio, PIC_IRT_1_BASE + irq - PIC_IRQ_BASE);
+       netlogic_write_reg(mmio, PIC_IRT_1_BASE + irq - PIC_IRQ_BASE,
+                         reg | (1 << 6) | (1 << 30) | (0 << 31));
+       spin_unlock_irqrestore(&nlm_pic_lock, flags);
+}
+
+#ifdef CONFIG_PCI
+/* Extra ACK needed for XLR on chip PCI controller */
+static void xlr_pci_ack(struct irq_data *d)
+{
+       nlm_reg_t *pci_mmio = netlogic_io_mmio(NETLOGIC_IO_PCIX_OFFSET);
+
+       netlogic_read_reg(pci_mmio, (0x140 >> 2));
+}
+
+/* Extra ACK needed for XLS on chip PCIe controller */
+static void xls_pcie_ack(struct irq_data *d)
+{
+       nlm_reg_t *pcie_mmio_le = netlogic_io_mmio(NETLOGIC_IO_PCIE_1_OFFSET);
+
+       switch (d->irq) {
+       case PIC_PCIE_LINK0_IRQ:
+               netlogic_write_reg(pcie_mmio_le, (0x90 >> 2), 0xffffffff);
+               break;
+       case PIC_PCIE_LINK1_IRQ:
+               netlogic_write_reg(pcie_mmio_le, (0x94 >> 2), 0xffffffff);
+               break;
+       case PIC_PCIE_LINK2_IRQ:
+               netlogic_write_reg(pcie_mmio_le, (0x190 >> 2), 0xffffffff);
+               break;
+       case PIC_PCIE_LINK3_IRQ:
+               netlogic_write_reg(pcie_mmio_le, (0x194 >> 2), 0xffffffff);
+               break;
+       }
+}
+
+/* For XLS B silicon, the 3,4 PCI interrupts are different */
+static void xls_pcie_ack_b(struct irq_data *d)
+{
+       nlm_reg_t *pcie_mmio_le = netlogic_io_mmio(NETLOGIC_IO_PCIE_1_OFFSET);
+
+       switch (d->irq) {
+       case PIC_PCIE_LINK0_IRQ:
+               netlogic_write_reg(pcie_mmio_le, (0x90 >> 2), 0xffffffff);
+               break;
+       case PIC_PCIE_LINK1_IRQ:
+               netlogic_write_reg(pcie_mmio_le, (0x94 >> 2), 0xffffffff);
+               break;
+       case PIC_PCIE_XLSB0_LINK2_IRQ:
+               netlogic_write_reg(pcie_mmio_le, (0x190 >> 2), 0xffffffff);
+               break;
+       case PIC_PCIE_XLSB0_LINK3_IRQ:
+               netlogic_write_reg(pcie_mmio_le, (0x194 >> 2), 0xffffffff);
+               break;
+       }
+}
+#endif
+
+static void xlr_pic_ack(struct irq_data *d)
+{
+       unsigned long flags;
+       nlm_reg_t *mmio;
+       int irq = d->irq;
+       void *hd = irq_data_get_irq_handler_data(d);
+
+       WARN(!PIC_IRQ_IS_IRT(irq), "Bad irq %d", irq);
+
+       if (hd) {
+               void (*extra_ack)(void *) = hd;
+               extra_ack(d);
+       }
+       mmio = netlogic_io_mmio(NETLOGIC_IO_PIC_OFFSET);
+       spin_lock_irqsave(&nlm_pic_lock, flags);
+       netlogic_write_reg(mmio, PIC_INT_ACK, (1 << (irq - PIC_IRQ_BASE)));
+       spin_unlock_irqrestore(&nlm_pic_lock, flags);
+}
+
+/*
+ * This chip definition handles interrupts routed thru the XLR
+ * hardware PIC, currently IRQs 8-39 are mapped to hardware intr
+ * 0-31 wired the XLR PIC
+ */
+static struct irq_chip xlr_pic = {
+       .name           = "XLR-PIC",
+       .irq_enable     = xlr_pic_enable,
+       .irq_mask       = xlr_pic_mask,
+       .irq_ack        = xlr_pic_ack,
+};
+
+static void rsvd_irq_handler(struct irq_data *d)
+{
+       WARN(d->irq >= PIC_IRQ_BASE, "Bad irq %d", d->irq);
+}
+
+/*
+ * Chip definition for CPU originated interrupts(timer, msg) and
+ * IPIs
+ */
+struct irq_chip nlm_cpu_intr = {
+       .name           = "XLR-CPU-INTR",
+       .irq_enable     = rsvd_irq_handler,
+       .irq_mask       = rsvd_irq_handler,
+       .irq_ack        = rsvd_irq_handler,
+};
+
+void __init init_xlr_irqs(void)
+{
+       nlm_reg_t *mmio = netlogic_io_mmio(NETLOGIC_IO_PIC_OFFSET);
+       uint32_t thread_mask = 1;
+       int level, i;
+
+       pr_info("Interrupt thread mask [%x]\n", thread_mask);
+       for (i = 0; i < PIC_NUM_IRTS; i++) {
+               level = PIC_IRQ_IS_EDGE_TRIGGERED(i);
+
+               /* Bind all PIC irqs to boot cpu */
+               netlogic_write_reg(mmio, PIC_IRT_0_BASE + i, thread_mask);
+
+               /*
+                * Use local scheduling and high polarity for all IRTs
+                * Invalidate all IRTs, by default
+                */
+               netlogic_write_reg(mmio, PIC_IRT_1_BASE + i,
+                               (level << 30) | (1 << 6) | (PIC_IRQ_BASE + i));
+       }
+
+       /* Make all IRQs as level triggered by default */
+       for (i = 0; i < NR_IRQS; i++) {
+               if (PIC_IRQ_IS_IRT(i))
+                       irq_set_chip_and_handler(i, &xlr_pic, handle_level_irq);
+               else
+                       irq_set_chip_and_handler(i, &nlm_cpu_intr,
+                                               handle_level_irq);
+       }
+#ifdef CONFIG_SMP
+       irq_set_chip_and_handler(IRQ_IPI_SMP_FUNCTION, &nlm_cpu_intr,
+                        nlm_smp_function_ipi_handler);
+       irq_set_chip_and_handler(IRQ_IPI_SMP_RESCHEDULE, &nlm_cpu_intr,
+                        nlm_smp_resched_ipi_handler);
+       nlm_irq_mask |=
+           ((1ULL << IRQ_IPI_SMP_FUNCTION) | (1ULL << IRQ_IPI_SMP_RESCHEDULE));
+#endif
+
+#ifdef CONFIG_PCI
+       /*
+        * For PCI interrupts, we need to ack the PIC controller too, overload
+        * irq handler data to do this
+        */
+       if (nlm_chip_is_xls()) {
+               if (nlm_chip_is_xls_b()) {
+                       irq_set_handler_data(PIC_PCIE_LINK0_IRQ,
+                                                       xls_pcie_ack_b);
+                       irq_set_handler_data(PIC_PCIE_LINK1_IRQ,
+                                                       xls_pcie_ack_b);
+                       irq_set_handler_data(PIC_PCIE_XLSB0_LINK2_IRQ,
+                                                       xls_pcie_ack_b);
+                       irq_set_handler_data(PIC_PCIE_XLSB0_LINK3_IRQ,
+                                                       xls_pcie_ack_b);
+               } else {
+                       irq_set_handler_data(PIC_PCIE_LINK0_IRQ, xls_pcie_ack);
+                       irq_set_handler_data(PIC_PCIE_LINK1_IRQ, xls_pcie_ack);
+                       irq_set_handler_data(PIC_PCIE_LINK2_IRQ, xls_pcie_ack);
+                       irq_set_handler_data(PIC_PCIE_LINK3_IRQ, xls_pcie_ack);
+               }
+       } else {
+               /* XLR PCI controller ACK */
+               irq_set_handler_data(PIC_PCIE_XLSB0_LINK3_IRQ, xlr_pci_ack);
+       }
+#endif
+       /* unmask all PIC related interrupts. If no handler is installed by the
+        * drivers, it'll just ack the interrupt and return
+        */
+       for (i = PIC_IRT_FIRST_IRQ; i <= PIC_IRT_LAST_IRQ; i++)
+               nlm_irq_mask |= (1ULL << i);
+
+       nlm_irq_mask |= (1ULL << IRQ_TIMER);
+}
+
+void __init arch_init_irq(void)
+{
+       /* Initialize the irq descriptors */
+       init_xlr_irqs();
+       write_c0_eimr(nlm_irq_mask);
+}
+
+void __cpuinit nlm_smp_irq_init(void)
+{
+       /* set interrupt mask for non-zero cpus */
+       write_c0_eimr(nlm_irq_mask);
+}
+
+asmlinkage void plat_irq_dispatch(void)
+{
+       uint64_t eirr;
+       int i;
+
+       eirr = read_c0_eirr() & read_c0_eimr();
+       if (!eirr)
+               return;
+
+       /* no need of EIRR here, writing compare clears interrupt */
+       if (eirr & (1 << IRQ_TIMER)) {
+               do_IRQ(IRQ_TIMER);
+               return;
+       }
+
+       /* use dcltz: optimize below code */
+       for (i = 63; i != -1; i--) {
+               if (eirr & (1ULL << i))
+                       break;
+       }
+       if (i == -1) {
+               pr_err("no interrupt !!\n");
+               return;
+       }
+
+       /* Ack eirr */
+       write_c0_eirr(1ULL << i);
+
+       do_IRQ(i);
+}
diff --git a/arch/mips/netlogic/xlr/platform.c b/arch/mips/netlogic/xlr/platform.c
new file mode 100644 (file)
index 0000000..609ec25
--- /dev/null
@@ -0,0 +1,98 @@
+/*
+ * Copyright 2011, Netlogic Microsystems.
+ * Copyright 2004, Matt Porter <mporter@kernel.crashing.org>
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2.  This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/resource.h>
+#include <linux/serial_8250.h>
+#include <linux/serial_reg.h>
+
+#include <asm/netlogic/xlr/iomap.h>
+#include <asm/netlogic/xlr/pic.h>
+#include <asm/netlogic/xlr/xlr.h>
+
+unsigned int nlm_xlr_uart_in(struct uart_port *p, int offset)
+{
+       nlm_reg_t *mmio;
+       unsigned int value;
+
+       /* XLR uart does not need any mapping of regs */
+       mmio = (nlm_reg_t *)(p->membase + (offset << p->regshift));
+       value = netlogic_read_reg(mmio, 0);
+
+       /* See XLR/XLS errata */
+       if (offset == UART_MSR)
+               value ^= 0xF0;
+       else if (offset == UART_MCR)
+               value ^= 0x3;
+
+       return value;
+}
+
+void nlm_xlr_uart_out(struct uart_port *p, int offset, int value)
+{
+       nlm_reg_t *mmio;
+
+       /* XLR uart does not need any mapping of regs */
+       mmio = (nlm_reg_t *)(p->membase + (offset << p->regshift));
+
+       /* See XLR/XLS errata */
+       if (offset == UART_MSR)
+               value ^= 0xF0;
+       else if (offset == UART_MCR)
+               value ^= 0x3;
+
+       netlogic_write_reg(mmio, 0, value);
+}
+
+#define PORT(_irq)                                     \
+       {                                               \
+               .irq            = _irq,                 \
+               .regshift       = 2,                    \
+               .iotype         = UPIO_MEM32,           \
+               .flags          = (UPF_SKIP_TEST |      \
+                        UPF_FIXED_TYPE | UPF_BOOT_AUTOCONF),\
+               .uartclk        = PIC_CLKS_PER_SEC,     \
+               .type           = PORT_16550A,          \
+               .serial_in      = nlm_xlr_uart_in,      \
+               .serial_out     = nlm_xlr_uart_out,     \
+       }
+
+static struct plat_serial8250_port xlr_uart_data[] = {
+       PORT(PIC_UART_0_IRQ),
+       PORT(PIC_UART_1_IRQ),
+       {},
+};
+
+static struct platform_device uart_device = {
+       .name           = "serial8250",
+       .id             = PLAT8250_DEV_PLATFORM,
+       .dev = {
+               .platform_data = xlr_uart_data,
+       },
+};
+
+static int __init nlm_uart_init(void)
+{
+       nlm_reg_t *mmio;
+
+       mmio = netlogic_io_mmio(NETLOGIC_IO_UART_0_OFFSET);
+       xlr_uart_data[0].membase = (void __iomem *)mmio;
+       xlr_uart_data[0].mapbase = CPHYSADDR((unsigned long)mmio);
+
+       mmio = netlogic_io_mmio(NETLOGIC_IO_UART_1_OFFSET);
+       xlr_uart_data[1].membase = (void __iomem *)mmio;
+       xlr_uart_data[1].mapbase = CPHYSADDR((unsigned long)mmio);
+
+       return platform_device_register(&uart_device);
+}
+
+arch_initcall(nlm_uart_init);
diff --git a/arch/mips/netlogic/xlr/setup.c b/arch/mips/netlogic/xlr/setup.c
new file mode 100644 (file)
index 0000000..4828025
--- /dev/null
@@ -0,0 +1,188 @@
+/*
+ * Copyright 2003-2011 NetLogic Microsystems, Inc. (NetLogic). All rights
+ * reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the NetLogic
+ * license below:
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY NETLOGIC ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL NETLOGIC OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <linux/kernel.h>
+#include <linux/serial_8250.h>
+#include <linux/pm.h>
+
+#include <asm/reboot.h>
+#include <asm/time.h>
+#include <asm/bootinfo.h>
+#include <asm/smp-ops.h>
+
+#include <asm/netlogic/interrupt.h>
+#include <asm/netlogic/psb-bootinfo.h>
+
+#include <asm/netlogic/xlr/xlr.h>
+#include <asm/netlogic/xlr/iomap.h>
+#include <asm/netlogic/xlr/pic.h>
+#include <asm/netlogic/xlr/gpio.h>
+
+unsigned long netlogic_io_base = (unsigned long)(DEFAULT_NETLOGIC_IO_BASE);
+unsigned long nlm_common_ebase = 0x0;
+struct psb_info nlm_prom_info;
+
+static void nlm_early_serial_setup(void)
+{
+       struct uart_port s;
+       nlm_reg_t *uart_base;
+
+       uart_base = netlogic_io_mmio(NETLOGIC_IO_UART_0_OFFSET);
+       memset(&s, 0, sizeof(s));
+       s.flags         = ASYNC_BOOT_AUTOCONF | ASYNC_SKIP_TEST;
+       s.iotype        = UPIO_MEM32;
+       s.regshift      = 2;
+       s.irq           = PIC_UART_0_IRQ;
+       s.uartclk       = PIC_CLKS_PER_SEC;
+       s.serial_in     = nlm_xlr_uart_in;
+       s.serial_out    = nlm_xlr_uart_out;
+       s.mapbase       = (unsigned long)uart_base;
+       s.membase       = (unsigned char __iomem *)uart_base;
+       early_serial_setup(&s);
+}
+
+static void nlm_linux_exit(void)
+{
+       nlm_reg_t *mmio;
+
+       mmio = netlogic_io_mmio(NETLOGIC_IO_GPIO_OFFSET);
+       /* trigger a chip reset by writing 1 to GPIO_SWRESET_REG */
+       netlogic_write_reg(mmio, NETLOGIC_GPIO_SWRESET_REG, 1);
+       for ( ; ; )
+               cpu_wait();
+}
+
+void __init plat_mem_setup(void)
+{
+       panic_timeout   = 5;
+       _machine_restart = (void (*)(char *))nlm_linux_exit;
+       _machine_halt   = nlm_linux_exit;
+       pm_power_off    = nlm_linux_exit;
+}
+
+const char *get_system_type(void)
+{
+       return "Netlogic XLR/XLS Series";
+}
+
+void __init prom_free_prom_memory(void)
+{
+       /* Nothing yet */
+}
+
+static void build_arcs_cmdline(int *argv)
+{
+       int i, remain, len;
+       char *arg;
+
+       remain = sizeof(arcs_cmdline) - 1;
+       arcs_cmdline[0] = '\0';
+       for (i = 0; argv[i] != 0; i++) {
+               arg = (char *)(long)argv[i];
+               len = strlen(arg);
+               if (len + 1 > remain)
+                       break;
+               strcat(arcs_cmdline, arg);
+               strcat(arcs_cmdline, " ");
+               remain -=  len + 1;
+       }
+
+       /* Add the default options here */
+       if ((strstr(arcs_cmdline, "console=")) == NULL) {
+               arg = "console=ttyS0,38400 ";
+               len = strlen(arg);
+               if (len > remain)
+                       goto fail;
+               strcat(arcs_cmdline, arg);
+               remain -= len;
+       }
+#ifdef CONFIG_BLK_DEV_INITRD
+       if ((strstr(arcs_cmdline, "rdinit=")) == NULL) {
+               arg = "rdinit=/sbin/init ";
+               len = strlen(arg);
+               if (len > remain)
+                       goto fail;
+               strcat(arcs_cmdline, arg);
+               remain -= len;
+       }
+#endif
+       return;
+fail:
+       panic("Cannot add %s, command line too big!", arg);
+}
+
+static void prom_add_memory(void)
+{
+       struct nlm_boot_mem_map *bootm;
+       u64 start, size;
+       u64 pref_backup = 512;  /* avoid pref walking beyond end */
+       int i;
+
+       bootm = (void *)(long)nlm_prom_info.psb_mem_map;
+       for (i = 0; i < bootm->nr_map; i++) {
+               if (bootm->map[i].type != BOOT_MEM_RAM)
+                       continue;
+               start = bootm->map[i].addr;
+               size   = bootm->map[i].size;
+
+               /* Work around for using bootloader mem */
+               if (i == 0 && start == 0 && size == 0x0c000000)
+                       size = 0x0ff00000;
+
+               add_memory_region(start, size - pref_backup, BOOT_MEM_RAM);
+       }
+}
+
+void __init prom_init(void)
+{
+       int *argv, *envp;               /* passed as 32 bit ptrs */
+       struct psb_info *prom_infop;
+
+       /* truncate to 32 bit and sign extend all args */
+       argv = (int *)(long)(int)fw_arg1;
+       envp = (int *)(long)(int)fw_arg2;
+       prom_infop = (struct psb_info *)(long)(int)fw_arg3;
+
+       nlm_prom_info = *prom_infop;
+
+       nlm_early_serial_setup();
+       build_arcs_cmdline(argv);
+       nlm_common_ebase = read_c0_ebase() & (~((1 << 12) - 1));
+       prom_add_memory();
+
+#ifdef CONFIG_SMP
+       nlm_wakeup_secondary_cpus(nlm_prom_info.online_cpu_map);
+       register_smp_ops(&nlm_smp_ops);
+#endif
+}
diff --git a/arch/mips/netlogic/xlr/smp.c b/arch/mips/netlogic/xlr/smp.c
new file mode 100644 (file)
index 0000000..b495a7f
--- /dev/null
@@ -0,0 +1,225 @@
+/*
+ * Copyright 2003-2011 NetLogic Microsystems, Inc. (NetLogic). All rights
+ * reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the NetLogic
+ * license below:
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY NETLOGIC ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL NETLOGIC OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/init.h>
+#include <linux/smp.h>
+#include <linux/irq.h>
+
+#include <asm/mmu_context.h>
+
+#include <asm/netlogic/interrupt.h>
+#include <asm/netlogic/mips-extns.h>
+
+#include <asm/netlogic/xlr/iomap.h>
+#include <asm/netlogic/xlr/pic.h>
+#include <asm/netlogic/xlr/xlr.h>
+
+void core_send_ipi(int logical_cpu, unsigned int action)
+{
+       int cpu = cpu_logical_map(logical_cpu);
+       u32 tid = cpu & 0x3;
+       u32 pid = (cpu >> 2) & 0x07;
+       u32 ipi = (tid << 16) | (pid << 20);
+
+       if (action & SMP_CALL_FUNCTION)
+               ipi |= IRQ_IPI_SMP_FUNCTION;
+       else if (action & SMP_RESCHEDULE_YOURSELF)
+               ipi |= IRQ_IPI_SMP_RESCHEDULE;
+       else
+               return;
+
+       pic_send_ipi(ipi);
+}
+
+void nlm_send_ipi_single(int cpu, unsigned int action)
+{
+       core_send_ipi(cpu, action);
+}
+
+void nlm_send_ipi_mask(const struct cpumask *mask, unsigned int action)
+{
+       int cpu;
+
+       for_each_cpu(cpu, mask) {
+               core_send_ipi(cpu, action);
+       }
+}
+
+/* IRQ_IPI_SMP_FUNCTION Handler */
+void nlm_smp_function_ipi_handler(unsigned int irq, struct irq_desc *desc)
+{
+       smp_call_function_interrupt();
+}
+
+/* IRQ_IPI_SMP_RESCHEDULE  handler */
+void nlm_smp_resched_ipi_handler(unsigned int irq, struct irq_desc *desc)
+{
+       set_need_resched();
+}
+
+void nlm_common_ipi_handler(int irq, struct pt_regs *regs)
+{
+       if (irq == IRQ_IPI_SMP_FUNCTION) {
+               smp_call_function_interrupt();
+       } else {
+               /* Announce that we are for reschduling */
+               set_need_resched();
+       }
+}
+
+/*
+ * Called before going into mips code, early cpu init
+ */
+void nlm_early_init_secondary(void)
+{
+       write_c0_ebase((uint32_t)nlm_common_ebase);
+       /* TLB partition here later */
+}
+
+/*
+ * Code to run on secondary just after probing the CPU
+ */
+static void __cpuinit nlm_init_secondary(void)
+{
+       nlm_smp_irq_init();
+}
+
+void nlm_smp_finish(void)
+{
+#ifdef notyet
+       nlm_common_msgring_cpu_init();
+#endif
+}
+
+void nlm_cpus_done(void)
+{
+}
+
+/*
+ * Boot all other cpus in the system, initialize them, and bring them into
+ * the boot function
+ */
+int nlm_cpu_unblock[NR_CPUS];
+int nlm_cpu_ready[NR_CPUS];
+unsigned long nlm_next_gp;
+unsigned long nlm_next_sp;
+cpumask_t phys_cpu_present_map;
+
+void nlm_boot_secondary(int logical_cpu, struct task_struct *idle)
+{
+       unsigned long gp = (unsigned long)task_thread_info(idle);
+       unsigned long sp = (unsigned long)__KSTK_TOS(idle);
+       int cpu = cpu_logical_map(logical_cpu);
+
+       nlm_next_sp = sp;
+       nlm_next_gp = gp;
+
+       /* barrier */
+       __sync();
+       nlm_cpu_unblock[cpu] = 1;
+}
+
+void __init nlm_smp_setup(void)
+{
+       unsigned int boot_cpu;
+       int num_cpus, i;
+
+       boot_cpu = hard_smp_processor_id();
+       cpus_clear(phys_cpu_present_map);
+
+       cpu_set(boot_cpu, phys_cpu_present_map);
+       __cpu_number_map[boot_cpu] = 0;
+       __cpu_logical_map[0] = boot_cpu;
+       cpu_set(0, cpu_possible_map);
+
+       num_cpus = 1;
+       for (i = 0; i < NR_CPUS; i++) {
+               if (nlm_cpu_ready[i]) {
+                       cpu_set(i, phys_cpu_present_map);
+                       __cpu_number_map[i] = num_cpus;
+                       __cpu_logical_map[num_cpus] = i;
+                       cpu_set(num_cpus, cpu_possible_map);
+                       ++num_cpus;
+               }
+       }
+
+       pr_info("Phys CPU present map: %lx, possible map %lx\n",
+               (unsigned long)phys_cpu_present_map.bits[0],
+               (unsigned long)cpu_possible_map.bits[0]);
+
+       pr_info("Detected %i Slave CPU(s)\n", num_cpus);
+}
+
+void nlm_prepare_cpus(unsigned int max_cpus)
+{
+}
+
+struct plat_smp_ops nlm_smp_ops = {
+       .send_ipi_single        = nlm_send_ipi_single,
+       .send_ipi_mask          = nlm_send_ipi_mask,
+       .init_secondary         = nlm_init_secondary,
+       .smp_finish             = nlm_smp_finish,
+       .cpus_done              = nlm_cpus_done,
+       .boot_secondary         = nlm_boot_secondary,
+       .smp_setup              = nlm_smp_setup,
+       .prepare_cpus           = nlm_prepare_cpus,
+};
+
+unsigned long secondary_entry_point;
+
+int nlm_wakeup_secondary_cpus(u32 wakeup_mask)
+{
+       unsigned int tid, pid, ipi, i, boot_cpu;
+       void *reset_vec;
+
+       secondary_entry_point = (unsigned long)prom_pre_boot_secondary_cpus;
+       reset_vec = (void *)CKSEG1ADDR(0x1fc00000);
+       memcpy(reset_vec, nlm_boot_smp_nmi, 0x80);
+       boot_cpu = hard_smp_processor_id();
+
+       for (i = 0; i < NR_CPUS; i++) {
+               if (i == boot_cpu)
+                       continue;
+               if (wakeup_mask & (1u << i)) {
+                       tid = i & 0x3;
+                       pid = (i >> 2) & 0x7;
+                       ipi = (tid << 16) | (pid << 20) | (1 << 8);
+                       pic_send_ipi(ipi);
+               }
+       }
+
+       return 0;
+}
diff --git a/arch/mips/netlogic/xlr/smpboot.S b/arch/mips/netlogic/xlr/smpboot.S
new file mode 100644 (file)
index 0000000..b8e0744
--- /dev/null
@@ -0,0 +1,94 @@
+/*
+ * Copyright 2003-2011 NetLogic Microsystems, Inc. (NetLogic). All rights
+ * reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the NetLogic
+ * license below:
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY NETLOGIC ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL NETLOGIC OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <asm/asm.h>
+#include <asm/asm-offsets.h>
+#include <asm/regdef.h>
+#include <asm/mipsregs.h>
+
+
+/* Don't jump to linux function from Bootloader stack. Change it
+ * here. Kernel might allocate bootloader memory before all the CPUs are
+ * brought up (eg: Inode cache region) and we better don't overwrite this
+ * memory
+ */
+NESTED(prom_pre_boot_secondary_cpus, 16, sp)
+       .set    mips64
+       mfc0    t0, $15, 1      # read ebase
+       andi    t0, 0x1f        # t0 has the processor_id()
+       sll     t0, 2           # offset in cpu array
+
+       PTR_LA  t1, nlm_cpu_ready # mark CPU ready
+       PTR_ADDU t1, t0
+       li      t2, 1
+       sw      t2, 0(t1)
+
+       PTR_LA  t1, nlm_cpu_unblock
+       PTR_ADDU t1, t0
+1:     lw      t2, 0(t1)       # wait till unblocked
+       beqz    t2, 1b
+       nop
+
+       PTR_LA  t1, nlm_next_sp
+       PTR_L   sp, 0(t1)
+       PTR_LA  t1, nlm_next_gp
+       PTR_L   gp, 0(t1)
+
+       PTR_LA  t0, nlm_early_init_secondary
+       jalr    t0
+       nop
+
+       PTR_LA  t0, smp_bootstrap
+       jr      t0
+       nop
+END(prom_pre_boot_secondary_cpus)
+
+NESTED(nlm_boot_smp_nmi, 0, sp)
+       .set push
+       .set noat
+       .set mips64
+       .set noreorder
+
+       /* Clear the  NMI and BEV bits */
+       MFC0    k0, CP0_STATUS
+       li      k1, 0xffb7ffff
+       and     k0, k0, k1
+       MTC0    k0, CP0_STATUS
+
+       PTR_LA  k1, secondary_entry_point
+       PTR_L   k0, 0(k1)
+       jr      k0
+       nop
+       .set pop
+END(nlm_boot_smp_nmi)
diff --git a/arch/mips/netlogic/xlr/time.c b/arch/mips/netlogic/xlr/time.c
new file mode 100644 (file)
index 0000000..0d81b26
--- /dev/null
@@ -0,0 +1,51 @@
+/*
+ * Copyright 2003-2011 NetLogic Microsystems, Inc. (NetLogic). All rights
+ * reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the NetLogic
+ * license below:
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY NETLOGIC ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL NETLOGIC OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <linux/init.h>
+
+#include <asm/time.h>
+#include <asm/netlogic/interrupt.h>
+#include <asm/netlogic/psb-bootinfo.h>
+
+unsigned int __cpuinit get_c0_compare_int(void)
+{
+       return IRQ_TIMER;
+}
+
+void __init plat_time_init(void)
+{
+       mips_hpt_frequency = nlm_prom_info.cpu_frequency;
+       pr_info("MIPS counter frequency [%ld]\n",
+               (unsigned long)mips_hpt_frequency);
+}
diff --git a/arch/mips/netlogic/xlr/xlr_console.c b/arch/mips/netlogic/xlr/xlr_console.c
new file mode 100644 (file)
index 0000000..759df06
--- /dev/null
@@ -0,0 +1,46 @@
+/*
+ * Copyright 2003-2011 NetLogic Microsystems, Inc. (NetLogic). All rights
+ * reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the NetLogic
+ * license below:
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY NETLOGIC ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL NETLOGIC OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <linux/types.h>
+#include <asm/netlogic/xlr/iomap.h>
+
+void prom_putchar(char c)
+{
+       nlm_reg_t *mmio;
+
+       mmio = netlogic_io_mmio(NETLOGIC_IO_UART_0_OFFSET);
+       while (netlogic_read_reg(mmio, 0x5) == 0)
+               ;
+       netlogic_write_reg(mmio, 0x0, c);
+}
index c9209ca..4df8799 100644 (file)
@@ -41,6 +41,7 @@ obj-$(CONFIG_SIBYTE_SB1250)   += fixup-sb1250.o pci-sb1250.o
 obj-$(CONFIG_SIBYTE_BCM112X)   += fixup-sb1250.o pci-sb1250.o
 obj-$(CONFIG_SIBYTE_BCM1x80)   += pci-bcm1480.o pci-bcm1480ht.o
 obj-$(CONFIG_SNI_RM)           += fixup-sni.o ops-sni.o
+obj-$(CONFIG_SOC_XWAY)         += pci-lantiq.o ops-lantiq.o
 obj-$(CONFIG_TANBAC_TB0219)    += fixup-tb0219.o
 obj-$(CONFIG_TANBAC_TB0226)    += fixup-tb0226.o
 obj-$(CONFIG_TANBAC_TB0287)    += fixup-tb0287.o
@@ -55,6 +56,7 @@ 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
+obj-$(CONFIG_NLM_XLR)          += pci-xlr.o
 
 ifdef CONFIG_PCI_MSI
 obj-$(CONFIG_CPU_CAVIUM_OCTEON)        += msi-octeon.o
diff --git a/arch/mips/pci/ops-lantiq.c b/arch/mips/pci/ops-lantiq.c
new file mode 100644 (file)
index 0000000..1f2afb5
--- /dev/null
@@ -0,0 +1,116 @@
+/*
+ *  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.
+ *
+ *  Copyright (C) 2010 John Crispin <blogic@openwrt.org>
+ */
+
+#include <linux/types.h>
+#include <linux/pci.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/mm.h>
+#include <asm/addrspace.h>
+#include <linux/vmalloc.h>
+
+#include <lantiq_soc.h>
+
+#include "pci-lantiq.h"
+
+#define LTQ_PCI_CFG_BUSNUM_SHF 16
+#define LTQ_PCI_CFG_DEVNUM_SHF 11
+#define LTQ_PCI_CFG_FUNNUM_SHF 8
+
+#define PCI_ACCESS_READ  0
+#define PCI_ACCESS_WRITE 1
+
+static int ltq_pci_config_access(unsigned char access_type, struct pci_bus *bus,
+       unsigned int devfn, unsigned int where, u32 *data)
+{
+       unsigned long cfg_base;
+       unsigned long flags;
+       u32 temp;
+
+       /* we support slot from 0 to 15 dev_fn & 0x68 (AD29) is the
+          SoC itself */
+       if ((bus->number != 0) || ((devfn & 0xf8) > 0x78)
+               || ((devfn & 0xf8) == 0) || ((devfn & 0xf8) == 0x68))
+               return 1;
+
+       spin_lock_irqsave(&ebu_lock, flags);
+
+       cfg_base = (unsigned long) ltq_pci_mapped_cfg;
+       cfg_base |= (bus->number << LTQ_PCI_CFG_BUSNUM_SHF) | (devfn <<
+                       LTQ_PCI_CFG_FUNNUM_SHF) | (where & ~0x3);
+
+       /* Perform access */
+       if (access_type == PCI_ACCESS_WRITE) {
+               ltq_w32(swab32(*data), ((u32 *)cfg_base));
+       } else {
+               *data = ltq_r32(((u32 *)(cfg_base)));
+               *data = swab32(*data);
+       }
+       wmb();
+
+       /* clean possible Master abort */
+       cfg_base = (unsigned long) ltq_pci_mapped_cfg;
+       cfg_base |= (0x0 << LTQ_PCI_CFG_FUNNUM_SHF) + 4;
+       temp = ltq_r32(((u32 *)(cfg_base)));
+       temp = swab32(temp);
+       cfg_base = (unsigned long) ltq_pci_mapped_cfg;
+       cfg_base |= (0x68 << LTQ_PCI_CFG_FUNNUM_SHF) + 4;
+       ltq_w32(temp, ((u32 *)cfg_base));
+
+       spin_unlock_irqrestore(&ebu_lock, flags);
+
+       if (((*data) == 0xffffffff) && (access_type == PCI_ACCESS_READ))
+               return 1;
+
+       return 0;
+}
+
+int ltq_pci_read_config_dword(struct pci_bus *bus, unsigned int devfn,
+       int where, int size, u32 *val)
+{
+       u32 data = 0;
+
+       if (ltq_pci_config_access(PCI_ACCESS_READ, bus, devfn, where, &data))
+               return PCIBIOS_DEVICE_NOT_FOUND;
+
+       if (size == 1)
+               *val = (data >> ((where & 3) << 3)) & 0xff;
+       else if (size == 2)
+               *val = (data >> ((where & 3) << 3)) & 0xffff;
+       else
+               *val = data;
+
+       return PCIBIOS_SUCCESSFUL;
+}
+
+int ltq_pci_write_config_dword(struct pci_bus *bus, unsigned int devfn,
+       int where, int size, u32 val)
+{
+       u32 data = 0;
+
+       if (size == 4) {
+               data = val;
+       } else {
+               if (ltq_pci_config_access(PCI_ACCESS_READ, bus,
+                               devfn, where, &data))
+                       return PCIBIOS_DEVICE_NOT_FOUND;
+
+               if (size == 1)
+                       data = (data & ~(0xff << ((where & 3) << 3))) |
+                               (val << ((where & 3) << 3));
+               else if (size == 2)
+                       data = (data & ~(0xffff << ((where & 3) << 3))) |
+                               (val << ((where & 3) << 3));
+       }
+
+       if (ltq_pci_config_access(PCI_ACCESS_WRITE, bus, devfn, where, &data))
+               return PCIBIOS_DEVICE_NOT_FOUND;
+
+       return PCIBIOS_SUCCESSFUL;
+}
diff --git a/arch/mips/pci/pci-lantiq.c b/arch/mips/pci/pci-lantiq.c
new file mode 100644 (file)
index 0000000..603d749
--- /dev/null
@@ -0,0 +1,297 @@
+/*
+ *  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.
+ *
+ *  Copyright (C) 2010 John Crispin <blogic@openwrt.org>
+ */
+
+#include <linux/types.h>
+#include <linux/pci.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/mm.h>
+#include <linux/vmalloc.h>
+#include <linux/platform_device.h>
+
+#include <asm/pci.h>
+#include <asm/gpio.h>
+#include <asm/addrspace.h>
+
+#include <lantiq_soc.h>
+#include <lantiq_irq.h>
+#include <lantiq_platform.h>
+
+#include "pci-lantiq.h"
+
+#define LTQ_PCI_CFG_BASE               0x17000000
+#define LTQ_PCI_CFG_SIZE               0x00008000
+#define LTQ_PCI_MEM_BASE               0x18000000
+#define LTQ_PCI_MEM_SIZE               0x02000000
+#define LTQ_PCI_IO_BASE                        0x1AE00000
+#define LTQ_PCI_IO_SIZE                        0x00200000
+
+#define PCI_CR_FCI_ADDR_MAP0           0x00C0
+#define PCI_CR_FCI_ADDR_MAP1           0x00C4
+#define PCI_CR_FCI_ADDR_MAP2           0x00C8
+#define PCI_CR_FCI_ADDR_MAP3           0x00CC
+#define PCI_CR_FCI_ADDR_MAP4           0x00D0
+#define PCI_CR_FCI_ADDR_MAP5           0x00D4
+#define PCI_CR_FCI_ADDR_MAP6           0x00D8
+#define PCI_CR_FCI_ADDR_MAP7           0x00DC
+#define PCI_CR_CLK_CTRL                        0x0000
+#define PCI_CR_PCI_MOD                 0x0030
+#define PCI_CR_PC_ARB                  0x0080
+#define PCI_CR_FCI_ADDR_MAP11hg                0x00E4
+#define PCI_CR_BAR11MASK               0x0044
+#define PCI_CR_BAR12MASK               0x0048
+#define PCI_CR_BAR13MASK               0x004C
+#define PCI_CS_BASE_ADDR1              0x0010
+#define PCI_CR_PCI_ADDR_MAP11          0x0064
+#define PCI_CR_FCI_BURST_LENGTH                0x00E8
+#define PCI_CR_PCI_EOI                 0x002C
+#define PCI_CS_STS_CMD                 0x0004
+
+#define PCI_MASTER0_REQ_MASK_2BITS     8
+#define PCI_MASTER1_REQ_MASK_2BITS     10
+#define PCI_MASTER2_REQ_MASK_2BITS     12
+#define INTERNAL_ARB_ENABLE_BIT                0
+
+#define LTQ_CGU_IFCCR          0x0018
+#define LTQ_CGU_PCICR          0x0034
+
+#define ltq_pci_w32(x, y)      ltq_w32((x), ltq_pci_membase + (y))
+#define ltq_pci_r32(x)         ltq_r32(ltq_pci_membase + (x))
+
+#define ltq_pci_cfg_w32(x, y)  ltq_w32((x), ltq_pci_mapped_cfg + (y))
+#define ltq_pci_cfg_r32(x)     ltq_r32(ltq_pci_mapped_cfg + (x))
+
+struct ltq_pci_gpio_map {
+       int pin;
+       int alt0;
+       int alt1;
+       int dir;
+       char *name;
+};
+
+/* the pci core can make use of the following gpios */
+static struct ltq_pci_gpio_map ltq_pci_gpio_map[] = {
+       { 0, 1, 0, 0, "pci-exin0" },
+       { 1, 1, 0, 0, "pci-exin1" },
+       { 2, 1, 0, 0, "pci-exin2" },
+       { 39, 1, 0, 0, "pci-exin3" },
+       { 10, 1, 0, 0, "pci-exin4" },
+       { 9, 1, 0, 0, "pci-exin5" },
+       { 30, 1, 0, 1, "pci-gnt1" },
+       { 23, 1, 0, 1, "pci-gnt2" },
+       { 19, 1, 0, 1, "pci-gnt3" },
+       { 38, 1, 0, 1, "pci-gnt4" },
+       { 29, 1, 0, 0, "pci-req1" },
+       { 31, 1, 0, 0, "pci-req2" },
+       { 3, 1, 0, 0, "pci-req3" },
+       { 37, 1, 0, 0, "pci-req4" },
+};
+
+__iomem void *ltq_pci_mapped_cfg;
+static __iomem void *ltq_pci_membase;
+
+int (*ltqpci_plat_dev_init)(struct pci_dev *dev) = NULL;
+
+/* Since the PCI REQ pins can be reused for other functionality, make it
+   possible to exclude those from interpretation by the PCI controller */
+static int ltq_pci_req_mask = 0xf;
+
+static int *ltq_pci_irq_map;
+
+struct pci_ops ltq_pci_ops = {
+       .read   = ltq_pci_read_config_dword,
+       .write  = ltq_pci_write_config_dword
+};
+
+static struct resource pci_io_resource = {
+       .name   = "pci io space",
+       .start  = LTQ_PCI_IO_BASE,
+       .end    = LTQ_PCI_IO_BASE + LTQ_PCI_IO_SIZE - 1,
+       .flags  = IORESOURCE_IO
+};
+
+static struct resource pci_mem_resource = {
+       .name   = "pci memory space",
+       .start  = LTQ_PCI_MEM_BASE,
+       .end    = LTQ_PCI_MEM_BASE + LTQ_PCI_MEM_SIZE - 1,
+       .flags  = IORESOURCE_MEM
+};
+
+static struct pci_controller ltq_pci_controller = {
+       .pci_ops        = &ltq_pci_ops,
+       .mem_resource   = &pci_mem_resource,
+       .mem_offset     = 0x00000000UL,
+       .io_resource    = &pci_io_resource,
+       .io_offset      = 0x00000000UL,
+};
+
+int pcibios_plat_dev_init(struct pci_dev *dev)
+{
+       if (ltqpci_plat_dev_init)
+               return ltqpci_plat_dev_init(dev);
+
+       return 0;
+}
+
+static u32 ltq_calc_bar11mask(void)
+{
+       u32 mem, bar11mask;
+
+       /* BAR11MASK value depends on available memory on system. */
+       mem = num_physpages * PAGE_SIZE;
+       bar11mask = (0x0ffffff0 & ~((1 << (fls(mem) - 1)) - 1)) | 8;
+
+       return bar11mask;
+}
+
+static void ltq_pci_setup_gpio(int gpio)
+{
+       int i;
+       for (i = 0; i < ARRAY_SIZE(ltq_pci_gpio_map); i++) {
+               if (gpio & (1 << i)) {
+                       ltq_gpio_request(ltq_pci_gpio_map[i].pin,
+                               ltq_pci_gpio_map[i].alt0,
+                               ltq_pci_gpio_map[i].alt1,
+                               ltq_pci_gpio_map[i].dir,
+                               ltq_pci_gpio_map[i].name);
+               }
+       }
+       ltq_gpio_request(21, 0, 0, 1, "pci-reset");
+       ltq_pci_req_mask = (gpio >> PCI_REQ_SHIFT) & PCI_REQ_MASK;
+}
+
+static int __devinit ltq_pci_startup(struct ltq_pci_data *conf)
+{
+       u32 temp_buffer;
+
+       /* set clock to 33Mhz */
+       ltq_cgu_w32(ltq_cgu_r32(LTQ_CGU_IFCCR) & ~0xf00000, LTQ_CGU_IFCCR);
+       ltq_cgu_w32(ltq_cgu_r32(LTQ_CGU_IFCCR) | 0x800000, LTQ_CGU_IFCCR);
+
+       /* external or internal clock ? */
+       if (conf->clock) {
+               ltq_cgu_w32(ltq_cgu_r32(LTQ_CGU_IFCCR) & ~(1 << 16),
+                       LTQ_CGU_IFCCR);
+               ltq_cgu_w32((1 << 30), LTQ_CGU_PCICR);
+       } else {
+               ltq_cgu_w32(ltq_cgu_r32(LTQ_CGU_IFCCR) | (1 << 16),
+                       LTQ_CGU_IFCCR);
+               ltq_cgu_w32((1 << 31) | (1 << 30), LTQ_CGU_PCICR);
+       }
+
+       /* setup pci clock and gpis used by pci */
+       ltq_pci_setup_gpio(conf->gpio);
+
+       /* enable auto-switching between PCI and EBU */
+       ltq_pci_w32(0xa, PCI_CR_CLK_CTRL);
+
+       /* busy, i.e. configuration is not done, PCI access has to be retried */
+       ltq_pci_w32(ltq_pci_r32(PCI_CR_PCI_MOD) & ~(1 << 24), PCI_CR_PCI_MOD);
+       wmb();
+       /* BUS Master/IO/MEM access */
+       ltq_pci_cfg_w32(ltq_pci_cfg_r32(PCI_CS_STS_CMD) | 7, PCI_CS_STS_CMD);
+
+       /* enable external 2 PCI masters */
+       temp_buffer = ltq_pci_r32(PCI_CR_PC_ARB);
+       temp_buffer &= (~(ltq_pci_req_mask << 16));
+       /* enable internal arbiter */
+       temp_buffer |= (1 << INTERNAL_ARB_ENABLE_BIT);
+       /* enable internal PCI master reqest */
+       temp_buffer &= (~(3 << PCI_MASTER0_REQ_MASK_2BITS));
+
+       /* enable EBU request */
+       temp_buffer &= (~(3 << PCI_MASTER1_REQ_MASK_2BITS));
+
+       /* enable all external masters request */
+       temp_buffer &= (~(3 << PCI_MASTER2_REQ_MASK_2BITS));
+       ltq_pci_w32(temp_buffer, PCI_CR_PC_ARB);
+       wmb();
+
+       /* setup BAR memory regions */
+       ltq_pci_w32(0x18000000, PCI_CR_FCI_ADDR_MAP0);
+       ltq_pci_w32(0x18400000, PCI_CR_FCI_ADDR_MAP1);
+       ltq_pci_w32(0x18800000, PCI_CR_FCI_ADDR_MAP2);
+       ltq_pci_w32(0x18c00000, PCI_CR_FCI_ADDR_MAP3);
+       ltq_pci_w32(0x19000000, PCI_CR_FCI_ADDR_MAP4);
+       ltq_pci_w32(0x19400000, PCI_CR_FCI_ADDR_MAP5);
+       ltq_pci_w32(0x19800000, PCI_CR_FCI_ADDR_MAP6);
+       ltq_pci_w32(0x19c00000, PCI_CR_FCI_ADDR_MAP7);
+       ltq_pci_w32(0x1ae00000, PCI_CR_FCI_ADDR_MAP11hg);
+       ltq_pci_w32(ltq_calc_bar11mask(), PCI_CR_BAR11MASK);
+       ltq_pci_w32(0, PCI_CR_PCI_ADDR_MAP11);
+       ltq_pci_w32(0, PCI_CS_BASE_ADDR1);
+       /* both TX and RX endian swap are enabled */
+       ltq_pci_w32(ltq_pci_r32(PCI_CR_PCI_EOI) | 3, PCI_CR_PCI_EOI);
+       wmb();
+       ltq_pci_w32(ltq_pci_r32(PCI_CR_BAR12MASK) | 0x80000000,
+               PCI_CR_BAR12MASK);
+       ltq_pci_w32(ltq_pci_r32(PCI_CR_BAR13MASK) | 0x80000000,
+               PCI_CR_BAR13MASK);
+       /*use 8 dw burst length */
+       ltq_pci_w32(0x303, PCI_CR_FCI_BURST_LENGTH);
+       ltq_pci_w32(ltq_pci_r32(PCI_CR_PCI_MOD) | (1 << 24), PCI_CR_PCI_MOD);
+       wmb();
+
+       /* setup irq line */
+       ltq_ebu_w32(ltq_ebu_r32(LTQ_EBU_PCC_CON) | 0xc, LTQ_EBU_PCC_CON);
+       ltq_ebu_w32(ltq_ebu_r32(LTQ_EBU_PCC_IEN) | 0x10, LTQ_EBU_PCC_IEN);
+
+       /* toggle reset pin */
+       __gpio_set_value(21, 0);
+       wmb();
+       mdelay(1);
+       __gpio_set_value(21, 1);
+       return 0;
+}
+
+int __init pcibios_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
+{
+       if (ltq_pci_irq_map[slot])
+               return ltq_pci_irq_map[slot];
+       printk(KERN_ERR "lq_pci: trying to map irq for unknown slot %d\n",
+               slot);
+
+       return 0;
+}
+
+static int __devinit ltq_pci_probe(struct platform_device *pdev)
+{
+       struct ltq_pci_data *ltq_pci_data =
+               (struct ltq_pci_data *) pdev->dev.platform_data;
+       pci_probe_only = 0;
+       ltq_pci_irq_map = ltq_pci_data->irq;
+       ltq_pci_membase = ioremap_nocache(PCI_CR_BASE_ADDR, PCI_CR_SIZE);
+       ltq_pci_mapped_cfg =
+               ioremap_nocache(LTQ_PCI_CFG_BASE, LTQ_PCI_CFG_BASE);
+       ltq_pci_controller.io_map_base =
+               (unsigned long)ioremap(LTQ_PCI_IO_BASE, LTQ_PCI_IO_SIZE - 1);
+       ltq_pci_startup(ltq_pci_data);
+       register_pci_controller(&ltq_pci_controller);
+
+       return 0;
+}
+
+static struct platform_driver
+ltq_pci_driver = {
+       .probe = ltq_pci_probe,
+       .driver = {
+               .name = "ltq_pci",
+               .owner = THIS_MODULE,
+       },
+};
+
+int __init pcibios_init(void)
+{
+       int ret = platform_driver_register(&ltq_pci_driver);
+       if (ret)
+               printk(KERN_INFO "ltq_pci: Error registering platfom driver!");
+       return ret;
+}
+
+arch_initcall(pcibios_init);
diff --git a/arch/mips/pci/pci-lantiq.h b/arch/mips/pci/pci-lantiq.h
new file mode 100644 (file)
index 0000000..66bf6cd
--- /dev/null
@@ -0,0 +1,18 @@
+/*
+ *  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.
+ *
+ *  Copyright (C) 2010 John Crispin <blogic@openwrt.org>
+ */
+
+#ifndef _LTQ_PCI_H__
+#define _LTQ_PCI_H__
+
+extern __iomem void *ltq_pci_mapped_cfg;
+extern int ltq_pci_read_config_dword(struct pci_bus *bus,
+       unsigned int devfn, int where, int size, u32 *val);
+extern int ltq_pci_write_config_dword(struct pci_bus *bus,
+       unsigned int devfn, int where, int size, u32 val);
+
+#endif
diff --git a/arch/mips/pci/pci-xlr.c b/arch/mips/pci/pci-xlr.c
new file mode 100644 (file)
index 0000000..38fece1
--- /dev/null
@@ -0,0 +1,214 @@
+/*
+ * Copyright 2003-2011 NetLogic Microsystems, Inc. (NetLogic). All rights
+ * reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the NetLogic
+ * license below:
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY NETLOGIC ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL NETLOGIC OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <linux/types.h>
+#include <linux/pci.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/mm.h>
+#include <linux/console.h>
+
+#include <asm/io.h>
+
+#include <asm/netlogic/interrupt.h>
+#include <asm/netlogic/xlr/iomap.h>
+#include <asm/netlogic/xlr/pic.h>
+#include <asm/netlogic/xlr/xlr.h>
+
+static void *pci_config_base;
+
+#define        pci_cfg_addr(bus, devfn, off) (((bus) << 16) | ((devfn) << 8) | (off))
+
+/* PCI ops */
+static inline u32 pci_cfg_read_32bit(struct pci_bus *bus, unsigned int devfn,
+       int where)
+{
+       u32 data;
+       u32 *cfgaddr;
+
+       cfgaddr = (u32 *)(pci_config_base +
+                       pci_cfg_addr(bus->number, devfn, where & ~3));
+       data = *cfgaddr;
+       return cpu_to_le32(data);
+}
+
+static inline void pci_cfg_write_32bit(struct pci_bus *bus, unsigned int devfn,
+       int where, u32 data)
+{
+       u32 *cfgaddr;
+
+       cfgaddr = (u32 *)(pci_config_base +
+                       pci_cfg_addr(bus->number, devfn, where & ~3));
+       *cfgaddr = cpu_to_le32(data);
+}
+
+static int nlm_pcibios_read(struct pci_bus *bus, unsigned int devfn,
+       int where, int size, u32 *val)
+{
+       u32 data;
+
+       if ((size == 2) && (where & 1))
+               return PCIBIOS_BAD_REGISTER_NUMBER;
+       else if ((size == 4) && (where & 3))
+               return PCIBIOS_BAD_REGISTER_NUMBER;
+
+       data = pci_cfg_read_32bit(bus, devfn, where);
+
+       if (size == 1)
+               *val = (data >> ((where & 3) << 3)) & 0xff;
+       else if (size == 2)
+               *val = (data >> ((where & 3) << 3)) & 0xffff;
+       else
+               *val = data;
+
+       return PCIBIOS_SUCCESSFUL;
+}
+
+
+static int nlm_pcibios_write(struct pci_bus *bus, unsigned int devfn,
+               int where, int size, u32 val)
+{
+       u32 data;
+
+       if ((size == 2) && (where & 1))
+               return PCIBIOS_BAD_REGISTER_NUMBER;
+       else if ((size == 4) && (where & 3))
+               return PCIBIOS_BAD_REGISTER_NUMBER;
+
+       data = pci_cfg_read_32bit(bus, devfn, where);
+
+       if (size == 1)
+               data = (data & ~(0xff << ((where & 3) << 3))) |
+                       (val << ((where & 3) << 3));
+       else if (size == 2)
+               data = (data & ~(0xffff << ((where & 3) << 3))) |
+                       (val << ((where & 3) << 3));
+       else
+               data = val;
+
+       pci_cfg_write_32bit(bus, devfn, where, data);
+
+       return PCIBIOS_SUCCESSFUL;
+}
+
+struct pci_ops nlm_pci_ops = {
+       .read  = nlm_pcibios_read,
+       .write = nlm_pcibios_write
+};
+
+static struct resource nlm_pci_mem_resource = {
+       .name           = "XLR PCI MEM",
+       .start          = 0xd0000000UL, /* 256MB PCI mem @ 0xd000_0000 */
+       .end            = 0xdfffffffUL,
+       .flags          = IORESOURCE_MEM,
+};
+
+static struct resource nlm_pci_io_resource = {
+       .name           = "XLR IO MEM",
+       .start          = 0x10000000UL, /* 16MB PCI IO @ 0x1000_0000 */
+       .end            = 0x100fffffUL,
+       .flags          = IORESOURCE_IO,
+};
+
+struct pci_controller nlm_pci_controller = {
+       .index          = 0,
+       .pci_ops        = &nlm_pci_ops,
+       .mem_resource   = &nlm_pci_mem_resource,
+       .mem_offset     = 0x00000000UL,
+       .io_resource    = &nlm_pci_io_resource,
+       .io_offset      = 0x00000000UL,
+};
+
+int __init pcibios_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
+{
+       if (!nlm_chip_is_xls())
+               return  PIC_PCIX_IRQ;   /* for XLR just one IRQ*/
+
+       /*
+        * For XLS PCIe, there is an IRQ per Link, find out which
+        * link the device is on to assign interrupts
+       */
+       if (dev->bus->self == NULL)
+               return 0;
+
+       switch  (dev->bus->self->devfn) {
+       case 0x0:
+               return PIC_PCIE_LINK0_IRQ;
+       case 0x8:
+               return PIC_PCIE_LINK1_IRQ;
+       case 0x10:
+               if (nlm_chip_is_xls_b())
+                       return PIC_PCIE_XLSB0_LINK2_IRQ;
+               else
+                       return PIC_PCIE_LINK2_IRQ;
+       case 0x18:
+               if (nlm_chip_is_xls_b())
+                       return PIC_PCIE_XLSB0_LINK3_IRQ;
+               else
+                       return PIC_PCIE_LINK3_IRQ;
+       }
+       WARN(1, "Unexpected devfn %d\n", dev->bus->self->devfn);
+       return 0;
+}
+
+/* Do platform specific device initialization at pci_enable_device() time */
+int pcibios_plat_dev_init(struct pci_dev *dev)
+{
+       return 0;
+}
+
+static int __init pcibios_init(void)
+{
+       /* PSB assigns PCI resources */
+       pci_probe_only = 1;
+       pci_config_base = ioremap(DEFAULT_PCI_CONFIG_BASE, 16 << 20);
+
+       /* Extend IO port for memory mapped io */
+       ioport_resource.start =  0;
+       ioport_resource.end   = ~0;
+
+       set_io_port_base(CKSEG1);
+       nlm_pci_controller.io_map_base = CKSEG1;
+
+       pr_info("Registering XLR/XLS PCIX/PCIE Controller.\n");
+       register_pci_controller(&nlm_pci_controller);
+
+       return 0;
+}
+
+arch_initcall(pcibios_init);
+
+struct pci_fixup pcibios_fixups[] = {
+       {0}
+};
index f9b9dcd..98fd009 100644 (file)
@@ -97,7 +97,7 @@ static int msp_per_irq_set_affinity(struct irq_data *d,
 
 static struct irq_chip msp_per_irq_controller = {
        .name = "MSP_PER",
-       .irq_enable = unmask_per_irq.
+       .irq_enable = unmask_per_irq,
        .irq_disable = mask_per_irq,
        .irq_ack = msp_per_irq_ack,
 #ifdef CONFIG_SMP
index efc9e88..2608752 100644 (file)
@@ -55,6 +55,8 @@ void titan_mailbox_irq(void)
 
                if (status & 0x2)
                        smp_call_function_interrupt();
+               if (status & 0x4)
+                       scheduler_ipi();
                break;
 
        case 1:
@@ -63,6 +65,8 @@ void titan_mailbox_irq(void)
 
                if (status & 0x2)
                        smp_call_function_interrupt();
+               if (status & 0x4)
+                       scheduler_ipi();
                break;
        }
 }
index dbb5c7b..f8a751c 100644 (file)
@@ -35,7 +35,7 @@ LEAF(swsusp_arch_resume)
 0:
        PTR_L t1, PBE_ADDRESS(t0)   /* source */
        PTR_L t2, PBE_ORIG_ADDRESS(t0) /* destination */
-       PTR_ADDIU t3, t1, PAGE_SIZE
+       PTR_ADDU t3, t1, PAGE_SIZE
 1:
        REG_L t8, (t1)
        REG_S t8, (t2)
index 37de05d..6c47dfe 100644 (file)
@@ -185,7 +185,7 @@ int __init rb532_gpio_init(void)
        struct resource *r;
 
        r = rb532_gpio_reg0_res;
-       rb532_gpio_chip->regbase = ioremap_nocache(r->start, r->end - r->start);
+       rb532_gpio_chip->regbase = ioremap_nocache(r->start, resource_size(r));
 
        if (!rb532_gpio_chip->regbase) {
                printk(KERN_ERR "rb532: cannot remap GPIO register 0\n");
index deddbf0..698904d 100644 (file)
@@ -132,7 +132,7 @@ static struct platform_device eth1_device = {
  */
 static int __init sgiseeq_devinit(void)
 {
-       unsigned int tmp;
+       unsigned int pbdma __maybe_unused;
        int res, i;
 
        eth0_pd.hpc = hpc3c0;
@@ -151,7 +151,7 @@ static int __init sgiseeq_devinit(void)
 
        /* Second HPC is missing? */
        if (ip22_is_fullhouse() ||
-           get_dbe(tmp, (unsigned int *)&hpc3c1->pbdma[1]))
+           get_dbe(pbdma, (unsigned int *)&hpc3c1->pbdma[1]))
                return 0;
 
        sgimc->giopar |= SGIMC_GIOPAR_MASTEREXP1 | SGIMC_GIOPAR_EXP164 |
index 603fc91..1a94c98 100644 (file)
@@ -32,7 +32,7 @@
 static unsigned long dosample(void)
 {
        u32 ct0, ct1;
-       u8 msb, lsb;
+       u8 msb;
 
        /* Start the counter. */
        sgint->tcword = (SGINT_TCWORD_CNT2 | SGINT_TCWORD_CALL |
@@ -46,7 +46,7 @@ static unsigned long dosample(void)
        /* Latch and spin until top byte of counter2 is zero */
        do {
                writeb(SGINT_TCWORD_CNT2 | SGINT_TCWORD_CLAT, &sgint->tcword);
-               lsb = readb(&sgint->tcnt2);
+               (void) readb(&sgint->tcnt2);
                msb = readb(&sgint->tcnt2);
                ct1 = read_c0_count();
        } while (msb);
index a1fa4ab..cd0d5b0 100644 (file)
@@ -29,7 +29,6 @@ unsigned long hub_pio_map(cnodeid_t cnode, xwidgetnum_t widget,
                          unsigned long xtalk_addr, size_t size)
 {
        nasid_t nasid = COMPACT_TO_NASID_NODEID(cnode);
-       volatile hubreg_t junk;
        unsigned i;
 
        /* use small-window mapping if possible */
@@ -64,7 +63,7 @@ unsigned long hub_pio_map(cnodeid_t cnode, xwidgetnum_t widget,
                 * after we write it.
                 */
                IIO_ITTE_PUT(nasid, i, HUB_PIO_MAP_TO_MEM, widget, xtalk_addr);
-               junk = HUB_L(IIO_ITTE_GET(nasid, i));
+               (void) HUB_L(IIO_ITTE_GET(nasid, i));
 
                return NODE_BWIN_BASE(nasid, widget) + (xtalk_addr % BWIN_SIZE);
        }
index 0a04603..b18b04e 100644 (file)
@@ -147,8 +147,10 @@ static void ip27_do_irq_mask0(void)
 #ifdef CONFIG_SMP
        if (pend0 & (1UL << CPU_RESCHED_A_IRQ)) {
                LOCAL_HUB_CLR_INTR(CPU_RESCHED_A_IRQ);
+               scheduler_ipi();
        } else if (pend0 & (1UL << CPU_RESCHED_B_IRQ)) {
                LOCAL_HUB_CLR_INTR(CPU_RESCHED_B_IRQ);
+               scheduler_ipi();
        } else if (pend0 & (1UL << CPU_CALL_A_IRQ)) {
                LOCAL_HUB_CLR_INTR(CPU_CALL_A_IRQ);
                smp_call_function_interrupt();
index c3d30a8..1d1919a 100644 (file)
@@ -54,11 +54,8 @@ void __init setup_replication_mask(void)
 
 static __init void set_ktext_source(nasid_t client_nasid, nasid_t server_nasid)
 {
-       cnodeid_t client_cnode;
        kern_vars_t *kvp;
 
-       client_cnode = NASID_TO_COMPACT_NODEID(client_nasid);
-
        kvp = &hub_data(client_nasid)->kern_vars;
 
        KERN_VARS_ADDR(client_nasid) = (unsigned long)kvp;
index a152538..ef74f32 100644 (file)
@@ -66,18 +66,7 @@ static int rt_next_event(unsigned long delta, struct clock_event_device *evt)
 static void rt_set_mode(enum clock_event_mode mode,
                struct clock_event_device *evt)
 {
-       switch (mode) {
-       case CLOCK_EVT_MODE_ONESHOT:
-               /* The only mode supported */
-               break;
-
-       case CLOCK_EVT_MODE_PERIODIC:
-       case CLOCK_EVT_MODE_UNUSED:
-       case CLOCK_EVT_MODE_SHUTDOWN:
-       case CLOCK_EVT_MODE_RESUME:
-               /* Nothing to do  */
-               break;
-       }
+       /* Nothing to do ...  */
 }
 
 int rt_timer_irq;
@@ -174,8 +163,7 @@ static void __init hub_rt_clocksource_init(void)
 {
        struct clocksource *cs = &hub_rt_clocksource;
 
-       clocksource_set_clock(cs, CYCLES_PER_SEC);
-       clocksource_register(cs);
+       clocksource_register_hz(cs, CYCLES_PER_SEC);
 }
 
 void __init plat_time_init(void)
index 47b347c..d667875 100644 (file)
@@ -20,6 +20,7 @@
 #include <linux/delay.h>
 #include <linux/smp.h>
 #include <linux/kernel_stat.h>
+#include <linux/sched.h>
 
 #include <asm/mmu_context.h>
 #include <asm/io.h>
@@ -189,10 +190,8 @@ void bcm1480_mailbox_interrupt(void)
        /* Clear the mailbox to clear the interrupt */
        __raw_writeq(((u64)action)<<48, mailbox_0_clear_regs[cpu]);
 
-       /*
-        * Nothing to do for SMP_RESCHEDULE_YOURSELF; returning from the
-        * interrupt will do the reschedule for us
-        */
+       if (action & SMP_RESCHEDULE_YOURSELF)
+               scheduler_ipi();
 
        if (action & SMP_CALL_FUNCTION)
                smp_call_function_interrupt();
index c00a5cb..38e7f6b 100644 (file)
@@ -21,6 +21,7 @@
 #include <linux/interrupt.h>
 #include <linux/smp.h>
 #include <linux/kernel_stat.h>
+#include <linux/sched.h>
 
 #include <asm/mmu_context.h>
 #include <asm/io.h>
@@ -177,10 +178,8 @@ void sb1250_mailbox_interrupt(void)
        /* Clear the mailbox to clear the interrupt */
        ____raw_writeq(((u64)action) << 48, mailbox_clear_regs[cpu]);
 
-       /*
-        * Nothing to do for SMP_RESCHEDULE_YOURSELF; returning from the
-        * interrupt will do the reschedule for us
-        */
+       if (action & SMP_RESCHEDULE_YOURSELF)
+               scheduler_ipi();
 
        if (action & SMP_CALL_FUNCTION)
                smp_call_function_interrupt();
index c76151b..0904d4d 100644 (file)
@@ -95,7 +95,7 @@ static void __init sni_a20r_timer_setup(void)
 static __init unsigned long dosample(void)
 {
        u32 ct0, ct1;
-       volatile u8 msb, lsb;
+       volatile u8 msb;
 
        /* Start the counter. */
        outb_p(0x34, 0x43);
@@ -108,7 +108,7 @@ static __init unsigned long dosample(void)
        /* Latch and spin until top byte of counter0 is zero */
        do {
                outb(0x00, 0x43);
-               lsb = inb(0x40);
+               (void) inb(0x40);
                msb = inb(0x40);
                ct1 = read_c0_count();
        } while (msb);
index 226c826..83fb279 100644 (file)
@@ -494,14 +494,11 @@ void smp_send_stop(void)
  * @irq: The interrupt number.
  * @dev_id: The device ID.
  *
- * We need do nothing here, since the scheduling will be effected on our way
- * back through entry.S.
- *
  * Returns IRQ_HANDLED to indicate we handled the interrupt successfully.
  */
 static irqreturn_t smp_reschedule_interrupt(int irq, void *dev_id)
 {
-       /* do nothing */
+       scheduler_ipi();
        return IRQ_HANDLED;
 }
 
index 69d63d3..828305f 100644 (file)
@@ -155,10 +155,7 @@ ipi_interrupt(int irq, void *dev_id)
                                
                        case IPI_RESCHEDULE:
                                smp_debug(100, KERN_DEBUG "CPU%d IPI_RESCHEDULE\n", this_cpu);
-                               /*
-                                * Reschedule callback.  Everything to be
-                                * done is done by the interrupt return path.
-                                */
+                               scheduler_ipi();
                                break;
 
                        case IPI_CALL_FUNC:
index 8f1e4ef..2d9a5c7 100644 (file)
@@ -69,6 +69,9 @@ SECTIONS
        /* End of text section */
        _etext = .;
 
+       /* Start of data section */
+       _sdata = .;
+
        RODATA
 
        /* writeable */
index 7005ee0..49baddc 100644 (file)
@@ -3,7 +3,6 @@
 #ifdef __KERNEL__
 
 #include <linux/irq.h>
-#include <linux/sysdev.h>
 #include <asm/dcr.h>
 #include <asm/msi_bitmap.h>
 
@@ -320,8 +319,6 @@ struct mpic
        /* link */
        struct mpic             *next;
 
-       struct sys_device       sysdev;
-
 #ifdef CONFIG_PM
        struct mpic_irq_save    *save_data;
 #endif
index cbdbb14..9f9c204 100644 (file)
@@ -116,7 +116,7 @@ void smp_message_recv(int msg)
                generic_smp_call_function_interrupt();
                break;
        case PPC_MSG_RESCHEDULE:
-               /* we notice need_resched on exit */
+               scheduler_ipi();
                break;
        case PPC_MSG_CALL_FUNC_SINGLE:
                generic_smp_call_function_single_interrupt();
@@ -146,7 +146,7 @@ static irqreturn_t call_function_action(int irq, void *data)
 
 static irqreturn_t reschedule_action(int irq, void *data)
 {
-       /* we just need the return path side effect of checking need_resched */
+       scheduler_ipi();
        return IRQ_HANDLED;
 }
 
index 5ddb801..d782cd7 100644 (file)
@@ -143,7 +143,6 @@ int die(const char *str, struct pt_regs *regs, long err)
 #endif
                printk("%s\n", ppc_md.name ? ppc_md.name : "");
 
-               sysfs_printk_last_file();
                if (notify_die(DIE_OOPS, str, regs, err, 255,
                               SIGSEGV) == NOTIFY_STOP)
                        return 1;
index 1882729..104faa8 100644 (file)
@@ -318,17 +318,20 @@ static const struct platform_suspend_ops mpc83xx_suspend_ops = {
        .end = mpc83xx_suspend_end,
 };
 
+static struct of_device_id pmc_match[];
 static int pmc_probe(struct platform_device *ofdev)
 {
+       const struct of_device_id *match;
        struct device_node *np = ofdev->dev.of_node;
        struct resource res;
        struct pmc_type *type;
        int ret = 0;
 
-       if (!ofdev->dev.of_match)
+       match = of_match_device(pmc_match, &ofdev->dev);
+       if (!match)
                return -EINVAL;
 
-       type = ofdev->dev.of_match->data;
+       type = match->data;
 
        if (!of_device_is_available(np))
                return -ENODEV;
index acfacce..3675da7 100644 (file)
@@ -32,6 +32,7 @@
 #include <linux/io.h>
 #include <linux/mutex.h>
 #include <linux/linux_logo.h>
+#include <linux/syscore_ops.h>
 #include <asm/spu.h>
 #include <asm/spu_priv1.h>
 #include <asm/spu_csa.h>
@@ -521,18 +522,8 @@ void spu_init_channels(struct spu *spu)
 }
 EXPORT_SYMBOL_GPL(spu_init_channels);
 
-static int spu_shutdown(struct sys_device *sysdev)
-{
-       struct spu *spu = container_of(sysdev, struct spu, sysdev);
-
-       spu_free_irqs(spu);
-       spu_destroy_spu(spu);
-       return 0;
-}
-
 static struct sysdev_class spu_sysdev_class = {
        .name = "spu",
-       .shutdown = spu_shutdown,
 };
 
 int spu_add_sysdev_attr(struct sysdev_attribute *attr)
@@ -797,6 +788,22 @@ static inline void crash_register_spus(struct list_head *list)
 }
 #endif
 
+static void spu_shutdown(void)
+{
+       struct spu *spu;
+
+       mutex_lock(&spu_full_list_mutex);
+       list_for_each_entry(spu, &spu_full_list, full_list) {
+               spu_free_irqs(spu);
+               spu_destroy_spu(spu);
+       }
+       mutex_unlock(&spu_full_list_mutex);
+}
+
+static struct syscore_ops spu_syscore_ops = {
+       .shutdown = spu_shutdown,
+};
+
 static int __init init_spu_base(void)
 {
        int i, ret = 0;
@@ -830,6 +837,7 @@ static int __init init_spu_base(void)
        crash_register_spus(&spu_full_list);
        mutex_unlock(&spu_full_list_mutex);
        spu_add_sysdev_attr(&attr_stat);
+       register_syscore_ops(&spu_syscore_ops);
 
        spu_init_affinity();
 
index 023f240..7c18a16 100644 (file)
@@ -21,7 +21,7 @@
 #include <linux/signal.h>
 #include <linux/pci.h>
 #include <linux/interrupt.h>
-#include <linux/sysdev.h>
+#include <linux/syscore_ops.h>
 #include <linux/adb.h>
 #include <linux/pmu.h>
 #include <linux/module.h>
@@ -677,7 +677,7 @@ not_found:
        return viaint;
 }
 
-static int pmacpic_suspend(struct sys_device *sysdev, pm_message_t state)
+static int pmacpic_suspend(void)
 {
        int viaint = pmacpic_find_viaint();
 
@@ -698,7 +698,7 @@ static int pmacpic_suspend(struct sys_device *sysdev, pm_message_t state)
         return 0;
 }
 
-static int pmacpic_resume(struct sys_device *sysdev)
+static void pmacpic_resume(void)
 {
        int i;
 
@@ -709,39 +709,19 @@ static int pmacpic_resume(struct sys_device *sysdev)
        for (i = 0; i < max_real_irqs; ++i)
                if (test_bit(i, sleep_save_mask))
                        pmac_unmask_irq(irq_get_irq_data(i));
-
-       return 0;
 }
 
-#endif /* CONFIG_PM && CONFIG_PPC32 */
-
-static struct sysdev_class pmacpic_sysclass = {
-       .name = "pmac_pic",
+static struct syscore_ops pmacpic_syscore_ops = {
+       .suspend        = pmacpic_suspend,
+       .resume         = pmacpic_resume,
 };
 
-static struct sys_device device_pmacpic = {
-       .id             = 0,
-       .cls            = &pmacpic_sysclass,
-};
-
-static struct sysdev_driver driver_pmacpic = {
-#if defined(CONFIG_PM) && defined(CONFIG_PPC32)
-       .suspend        = &pmacpic_suspend,
-       .resume         = &pmacpic_resume,
-#endif /* CONFIG_PM && CONFIG_PPC32 */
-};
-
-static int __init init_pmacpic_sysfs(void)
+static int __init init_pmacpic_syscore(void)
 {
-#ifdef CONFIG_PPC32
-       if (max_irqs == 0)
-               return -ENODEV;
-#endif
-       printk(KERN_DEBUG "Registering pmac pic with sysfs...\n");
-       sysdev_class_register(&pmacpic_sysclass);
-       sysdev_register(&device_pmacpic);
-       sysdev_driver_register(&pmacpic_sysclass, &driver_pmacpic);
+       register_syscore_ops(&pmacpic_syscore_ops);
        return 0;
 }
-machine_subsys_initcall(powermac, init_pmacpic_sysfs);
 
+machine_subsys_initcall(powermac, init_pmacpic_syscore);
+
+#endif /* CONFIG_PM && CONFIG_PPC32 */
index d5679dc..01cd2f0 100644 (file)
@@ -304,8 +304,10 @@ static int __devinit fsl_msi_setup_hwirq(struct fsl_msi *msi,
        return 0;
 }
 
+static const struct of_device_id fsl_of_msi_ids[];
 static int __devinit fsl_of_msi_probe(struct platform_device *dev)
 {
+       const struct of_device_id *match;
        struct fsl_msi *msi;
        struct resource res;
        int err, i, j, irq_index, count;
@@ -316,9 +318,10 @@ static int __devinit fsl_of_msi_probe(struct platform_device *dev)
        u32 offset;
        static const u32 all_avail[] = { 0, NR_MSI_IRQS };
 
-       if (!dev->dev.of_match)
+       match = of_match_device(fsl_of_msi_ids, &dev->dev);
+       if (!match)
                return -EINVAL;
-       features = dev->dev.of_match->data;
+       features = match->data;
 
        printk(KERN_DEBUG "Setting up Freescale MSI support\n");
 
index fa438be..596554a 100644 (file)
@@ -18,7 +18,7 @@
 #include <linux/stddef.h>
 #include <linux/sched.h>
 #include <linux/signal.h>
-#include <linux/sysdev.h>
+#include <linux/syscore_ops.h>
 #include <linux/device.h>
 #include <linux/bootmem.h>
 #include <linux/spinlock.h>
@@ -902,7 +902,7 @@ static struct {
        u32 sercr;
 } ipic_saved_state;
 
-static int ipic_suspend(struct sys_device *sdev, pm_message_t state)
+static int ipic_suspend(void)
 {
        struct ipic *ipic = primary_ipic;
 
@@ -933,7 +933,7 @@ static int ipic_suspend(struct sys_device *sdev, pm_message_t state)
        return 0;
 }
 
-static int ipic_resume(struct sys_device *sdev)
+static void ipic_resume(void)
 {
        struct ipic *ipic = primary_ipic;
 
@@ -949,44 +949,26 @@ static int ipic_resume(struct sys_device *sdev)
        ipic_write(ipic->regs, IPIC_SECNR, ipic_saved_state.secnr);
        ipic_write(ipic->regs, IPIC_SERMR, ipic_saved_state.sermr);
        ipic_write(ipic->regs, IPIC_SERCR, ipic_saved_state.sercr);
-
-       return 0;
 }
 #else
 #define ipic_suspend NULL
 #define ipic_resume NULL
 #endif
 
-static struct sysdev_class ipic_sysclass = {
-       .name = "ipic",
+static struct syscore_ops ipic_syscore_ops = {
        .suspend = ipic_suspend,
        .resume = ipic_resume,
 };
 
-static struct sys_device device_ipic = {
-       .id             = 0,
-       .cls            = &ipic_sysclass,
-};
-
-static int __init init_ipic_sysfs(void)
+static int __init init_ipic_syscore(void)
 {
-       int rc;
-
        if (!primary_ipic || !primary_ipic->regs)
                return -ENODEV;
-       printk(KERN_DEBUG "Registering ipic with sysfs...\n");
 
-       rc = sysdev_class_register(&ipic_sysclass);
-       if (rc) {
-               printk(KERN_ERR "Failed registering ipic sys class\n");
-               return -ENODEV;
-       }
-       rc = sysdev_register(&device_ipic);
-       if (rc) {
-               printk(KERN_ERR "Failed registering ipic sys device\n");
-               return -ENODEV;
-       }
+       printk(KERN_DEBUG "Registering ipic system core operations\n");
+       register_syscore_ops(&ipic_syscore_ops);
+
        return 0;
 }
 
-subsys_initcall(init_ipic_sysfs);
+subsys_initcall(init_ipic_syscore);
index f91c065..7e5dc8f 100644 (file)
@@ -27,6 +27,7 @@
 #include <linux/spinlock.h>
 #include <linux/pci.h>
 #include <linux/slab.h>
+#include <linux/syscore_ops.h>
 
 #include <asm/ptrace.h>
 #include <asm/signal.h>
@@ -1702,9 +1703,8 @@ void mpic_reset_core(int cpu)
 #endif /* CONFIG_SMP */
 
 #ifdef CONFIG_PM
-static int mpic_suspend(struct sys_device *dev, pm_message_t state)
+static void mpic_suspend_one(struct mpic *mpic)
 {
-       struct mpic *mpic = container_of(dev, struct mpic, sysdev);
        int i;
 
        for (i = 0; i < mpic->num_sources; i++) {
@@ -1713,13 +1713,22 @@ static int mpic_suspend(struct sys_device *dev, pm_message_t state)
                mpic->save_data[i].dest =
                        mpic_irq_read(i, MPIC_INFO(IRQ_DESTINATION));
        }
+}
+
+static int mpic_suspend(void)
+{
+       struct mpic *mpic = mpics;
+
+       while (mpic) {
+               mpic_suspend_one(mpic);
+               mpic = mpic->next;
+       }
 
        return 0;
 }
 
-static int mpic_resume(struct sys_device *dev)
+static void mpic_resume_one(struct mpic *mpic)
 {
-       struct mpic *mpic = container_of(dev, struct mpic, sysdev);
        int i;
 
        for (i = 0; i < mpic->num_sources; i++) {
@@ -1746,33 +1755,28 @@ static int mpic_resume(struct sys_device *dev)
        }
 #endif
        } /* end for loop */
+}
 
-       return 0;
+static void mpic_resume(void)
+{
+       struct mpic *mpic = mpics;
+
+       while (mpic) {
+               mpic_resume_one(mpic);
+               mpic = mpic->next;
+       }
 }
-#endif
 
-static struct sysdev_class mpic_sysclass = {
-#ifdef CONFIG_PM
+static struct syscore_ops mpic_syscore_ops = {
        .resume = mpic_resume,
        .suspend = mpic_suspend,
-#endif
-       .name = "mpic",
 };
 
 static int mpic_init_sys(void)
 {
-       struct mpic *mpic = mpics;
-       int error, id = 0;
-
-       error = sysdev_class_register(&mpic_sysclass);
-
-       while (mpic && !error) {
-               mpic->sysdev.cls = &mpic_sysclass;
-               mpic->sysdev.id = id++;
-               error = sysdev_register(&mpic->sysdev);
-               mpic = mpic->next;
-       }
-       return error;
+       register_syscore_ops(&mpic_syscore_ops);
+       return 0;
 }
 
 device_initcall(mpic_init_sys);
+#endif
index 43a5c78..3e20383 100644 (file)
@@ -11,5 +11,6 @@ void kernel_map_pages(struct page *page, int numpages, int enable);
 int set_memory_ro(unsigned long addr, int numpages);
 int set_memory_rw(unsigned long addr, int numpages);
 int set_memory_nx(unsigned long addr, int numpages);
+int set_memory_x(unsigned long addr, int numpages);
 
 #endif /* _S390_CACHEFLUSH_H */
index 72b2e2f..7e91c58 100644 (file)
@@ -9,9 +9,22 @@
 #define _ASM_S390_DIAG_H
 
 /*
- * Diagnose 10: Release pages
+ * Diagnose 10: Release page range
  */
-extern void diag10(unsigned long addr);
+static inline void diag10_range(unsigned long start_pfn, unsigned long num_pfn)
+{
+       unsigned long start_addr, end_addr;
+
+       start_addr = start_pfn << PAGE_SHIFT;
+       end_addr = (start_pfn + num_pfn - 1) << PAGE_SHIFT;
+
+       asm volatile(
+               "0:     diag    %0,%1,0x10\n"
+               "1:\n"
+               EX_TABLE(0b, 1b)
+               EX_TABLE(1b, 1b)
+               : : "a" (start_addr), "a" (end_addr));
+}
 
 /*
  * Diagnose 14: Input spool file manipulation
index a6f0e7c..8c277ca 100644 (file)
@@ -23,7 +23,7 @@ static inline int init_new_context(struct task_struct *tsk,
 #ifdef CONFIG_64BIT
        mm->context.asce_bits |= _ASCE_TYPE_REGION3;
 #endif
-       if (current->mm->context.alloc_pgste) {
+       if (current->mm && current->mm->context.alloc_pgste) {
                /*
                 * alloc_pgste indicates, that any NEW context will be created
                 * with extended page tables. The old context is unchanged. The
index c032d11..8237fc0 100644 (file)
@@ -9,27 +9,6 @@
 #include <asm/diag.h>
 
 /*
- * Diagnose 10: Release pages
- */
-void diag10(unsigned long addr)
-{
-       if (addr >= 0x7ff00000)
-               return;
-       asm volatile(
-#ifdef CONFIG_64BIT
-               "       sam31\n"
-               "       diag    %0,%0,0x10\n"
-               "0:     sam64\n"
-#else
-               "       diag    %0,%0,0x10\n"
-               "0:\n"
-#endif
-               EX_TABLE(0b, 0b)
-               : : "a" (addr));
-}
-EXPORT_SYMBOL(diag10);
-
-/*
  * Diagnose 14: Input spool file manipulation
  */
 int diag14(unsigned long rx, unsigned long ry1, unsigned long subcode)
index c83726c..3d4a78f 100644 (file)
@@ -672,6 +672,7 @@ static struct insn opcode_b2[] = {
        { "rp", 0x77, INSTR_S_RD },
        { "stcke", 0x78, INSTR_S_RD },
        { "sacf", 0x79, INSTR_S_RD },
+       { "spp", 0x80, INSTR_S_RD },
        { "stsi", 0x7d, INSTR_S_RD },
        { "srnm", 0x99, INSTR_S_RD },
        { "stfpc", 0x9c, INSTR_S_RD },
index 648f642..1b67fc6 100644 (file)
@@ -836,7 +836,7 @@ restart_base:
        stosm   __SF_EMPTY(%r15),0x04   # now we can turn dat on
        basr    %r14,0
        l       %r14,restart_addr-.(%r14)
-       br      %r14                    # branch to start_secondary
+       basr    %r14,%r14               # branch to start_secondary
 restart_addr:
        .long   start_secondary
        .align  8
index 9d3603d..9fd8645 100644 (file)
@@ -841,7 +841,7 @@ restart_base:
        mvc     __LC_SYSTEM_TIMER(8),__TI_system_timer(%r1)
        xc      __LC_STEAL_TIMER(8),__LC_STEAL_TIMER
        stosm   __SF_EMPTY(%r15),0x04   # now we can turn dat on
-       jg      start_secondary
+       brasl   %r14,start_secondary
        .align  8
 restart_vtime:
        .long   0x7fffffff,0xffffffff
index 63a97db..63c7d9f 100644 (file)
@@ -165,12 +165,12 @@ static void do_ext_call_interrupt(unsigned int ext_int_code,
        kstat_cpu(smp_processor_id()).irqs[EXTINT_IPI]++;
        /*
         * handle bit signal external calls
-        *
-        * For the ec_schedule signal we have to do nothing. All the work
-        * is done automatically when we return from the interrupt.
         */
        bits = xchg(&S390_lowcore.ext_call_fast, 0);
 
+       if (test_bit(ec_schedule, &bits))
+               scheduler_ipi();
+
        if (test_bit(ec_call_function, &bits))
                generic_smp_call_function_interrupt();
 
index c66ffd8..1f1dba9 100644 (file)
@@ -91,7 +91,7 @@ static long cmm_alloc_pages(long nr, long *counter,
                        } else
                                free_page((unsigned long) npa);
                }
-               diag10(addr);
+               diag10_range(addr >> PAGE_SHIFT, 1);
                pa->pages[pa->index++] = addr;
                (*counter)++;
                spin_unlock(&cmm_lock);
index 0607e4b..f05edcc 100644 (file)
@@ -54,3 +54,8 @@ int set_memory_nx(unsigned long addr, int numpages)
        return 0;
 }
 EXPORT_SYMBOL_GPL(set_memory_nx);
+
+int set_memory_x(unsigned long addr, int numpages)
+{
+       return 0;
+}
index 4952872..33cbd37 100644 (file)
@@ -1021,20 +1021,14 @@ deallocate_exit:
        return rc;
 }
 
-long hwsampler_query_min_interval(void)
+unsigned long hwsampler_query_min_interval(void)
 {
-       if (min_sampler_rate)
-               return min_sampler_rate;
-       else
-               return -EINVAL;
+       return min_sampler_rate;
 }
 
-long hwsampler_query_max_interval(void)
+unsigned long hwsampler_query_max_interval(void)
 {
-       if (max_sampler_rate)
-               return max_sampler_rate;
-       else
-               return -EINVAL;
+       return max_sampler_rate;
 }
 
 unsigned long hwsampler_get_sample_overflow_count(unsigned int cpu)
index 8c72b59..1912f3b 100644 (file)
@@ -102,8 +102,8 @@ int hwsampler_setup(void);
 int hwsampler_shutdown(void);
 int hwsampler_allocate(unsigned long sdbt, unsigned long sdb);
 int hwsampler_deallocate(void);
-long hwsampler_query_min_interval(void);
-long hwsampler_query_max_interval(void);
+unsigned long hwsampler_query_min_interval(void);
+unsigned long hwsampler_query_max_interval(void);
 int hwsampler_start_all(unsigned long interval);
 int hwsampler_stop_all(void);
 int hwsampler_deactivate(unsigned int cpu);
index c63d7e5..5995e9b 100644 (file)
@@ -145,15 +145,11 @@ static int oprofile_hwsampler_init(struct oprofile_operations *ops)
         * create hwsampler files only if hwsampler_setup() succeeds.
         */
        oprofile_min_interval = hwsampler_query_min_interval();
-       if (oprofile_min_interval < 0) {
-               oprofile_min_interval = 0;
+       if (oprofile_min_interval == 0)
                return -ENODEV;
-       }
        oprofile_max_interval = hwsampler_query_max_interval();
-       if (oprofile_max_interval < 0) {
-               oprofile_max_interval = 0;
+       if (oprofile_max_interval == 0)
                return -ENODEV;
-       }
 
        if (oprofile_timer_init(ops))
                return -ENODEV;
index 4b89da2..bc439de 100644 (file)
@@ -24,7 +24,6 @@ config SUPERH
        select RTC_LIB
        select GENERIC_ATOMIC64
        select GENERIC_IRQ_SHOW
-       select ARCH_NO_SYSDEV_OPS
        help
          The SuperH is a RISC processor targeted for use in embedded systems
          and consumer electronics; it was also used in the Sega Dreamcast
index e71a531..77ec0e7 100644 (file)
@@ -48,7 +48,6 @@ CONFIG_PREEMPT=y
 CONFIG_BINFMT_MISC=y
 CONFIG_PM=y
 CONFIG_PM_DEBUG=y
-CONFIG_PM_VERBOSE=y
 CONFIG_PM_RUNTIME=y
 CONFIG_CPU_IDLE=y
 CONFIG_NET=y
index dc4a2eb..c416505 100644 (file)
@@ -83,7 +83,6 @@ CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS=y
 CONFIG_BINFMT_MISC=y
 CONFIG_PM=y
 CONFIG_PM_DEBUG=y
-CONFIG_PM_VERBOSE=y
 CONFIG_PM_RUNTIME=y
 CONFIG_CPU_IDLE=y
 CONFIG_NET=y
index 6dcb816..22db127 100644 (file)
@@ -139,7 +139,7 @@ void platform_pm_runtime_suspend_idle(void)
        queue_work(pm_wq, &hwblk_work);
 }
 
-int platform_pm_runtime_suspend(struct device *dev)
+static int default_platform_runtime_suspend(struct device *dev)
 {
        struct platform_device *pdev = to_platform_device(dev);
        struct pdev_archdata *ad = &pdev->archdata;
@@ -147,7 +147,7 @@ int platform_pm_runtime_suspend(struct device *dev)
        int hwblk = ad->hwblk_id;
        int ret = 0;
 
-       dev_dbg(dev, "platform_pm_runtime_suspend() [%d]\n", hwblk);
+       dev_dbg(dev, "%s() [%d]\n", __func__, hwblk);
 
        /* ignore off-chip platform devices */
        if (!hwblk)
@@ -183,20 +183,20 @@ int platform_pm_runtime_suspend(struct device *dev)
        mutex_unlock(&ad->mutex);
 
 out:
-       dev_dbg(dev, "platform_pm_runtime_suspend() [%d] returns %d\n",
-               hwblk, ret);
+       dev_dbg(dev, "%s() [%d] returns %d\n",
+                __func__, hwblk, ret);
 
        return ret;
 }
 
-int platform_pm_runtime_resume(struct device *dev)
+static int default_platform_runtime_resume(struct device *dev)
 {
        struct platform_device *pdev = to_platform_device(dev);
        struct pdev_archdata *ad = &pdev->archdata;
        int hwblk = ad->hwblk_id;
        int ret = 0;
 
-       dev_dbg(dev, "platform_pm_runtime_resume() [%d]\n", hwblk);
+       dev_dbg(dev, "%s() [%d]\n", __func__, hwblk);
 
        /* ignore off-chip platform devices */
        if (!hwblk)
@@ -228,19 +228,19 @@ int platform_pm_runtime_resume(struct device *dev)
         */
        mutex_unlock(&ad->mutex);
 out:
-       dev_dbg(dev, "platform_pm_runtime_resume() [%d] returns %d\n",
-               hwblk, ret);
+       dev_dbg(dev, "%s() [%d] returns %d\n",
+               __func__, hwblk, ret);
 
        return ret;
 }
 
-int platform_pm_runtime_idle(struct device *dev)
+static int default_platform_runtime_idle(struct device *dev)
 {
        struct platform_device *pdev = to_platform_device(dev);
        int hwblk = pdev->archdata.hwblk_id;
        int ret = 0;
 
-       dev_dbg(dev, "platform_pm_runtime_idle() [%d]\n", hwblk);
+       dev_dbg(dev, "%s() [%d]\n", __func__, hwblk);
 
        /* ignore off-chip platform devices */
        if (!hwblk)
@@ -252,10 +252,19 @@ int platform_pm_runtime_idle(struct device *dev)
        /* suspend synchronously to disable clocks immediately */
        ret = pm_runtime_suspend(dev);
 out:
-       dev_dbg(dev, "platform_pm_runtime_idle() [%d] done!\n", hwblk);
+       dev_dbg(dev, "%s() [%d] done!\n", __func__, hwblk);
        return ret;
 }
 
+static struct dev_power_domain default_power_domain = {
+       .ops = {
+               .runtime_suspend = default_platform_runtime_suspend,
+               .runtime_resume = default_platform_runtime_resume,
+               .runtime_idle = default_platform_runtime_idle,
+               USE_PLATFORM_PM_SLEEP_OPS
+       },
+};
+
 static int platform_bus_notify(struct notifier_block *nb,
                               unsigned long action, void *data)
 {
@@ -276,6 +285,7 @@ static int platform_bus_notify(struct notifier_block *nb,
                hwblk_disable(hwblk_info, hwblk);
                /* make sure driver re-inits itself once */
                __set_bit(PDEV_ARCHDATA_FLAG_INIT, &pdev->archdata.flags);
+               dev->pwr_domain = &default_power_domain;
                break;
        /* TODO: add BUS_NOTIFY_BIND_DRIVER and increase idle count */
        case BUS_NOTIFY_BOUND_DRIVER:
@@ -289,6 +299,7 @@ static int platform_bus_notify(struct notifier_block *nb,
                __set_bit(PDEV_ARCHDATA_FLAG_INIT, &pdev->archdata.flags);
                break;
        case BUS_NOTIFY_DEL_DEVICE:
+               dev->pwr_domain = NULL;
                break;
        }
        return 0;
index 509b36b..6207561 100644 (file)
@@ -20,6 +20,7 @@
 #include <linux/module.h>
 #include <linux/cpu.h>
 #include <linux/interrupt.h>
+#include <linux/sched.h>
 #include <asm/atomic.h>
 #include <asm/processor.h>
 #include <asm/system.h>
@@ -323,6 +324,7 @@ void smp_message_recv(unsigned int msg)
                generic_smp_call_function_interrupt();
                break;
        case SMP_MSG_RESCHEDULE:
+               scheduler_ipi();
                break;
        case SMP_MSG_FUNCTION_SINGLE:
                generic_smp_call_function_single_interrupt();
index 3484c2f..b51a171 100644 (file)
@@ -87,7 +87,6 @@ void die(const char * str, struct pt_regs * regs, long err)
        bust_spinlocks(1);
 
        printk("%s: %04lx [#%d]\n", str, err & 0xffff, ++die_counter);
-       sysfs_printk_last_file();
        print_modules();
        show_regs(regs);
 
index 1c79f32..8b9c556 100644 (file)
@@ -65,6 +65,10 @@ static inline int pcibus_to_node(struct pci_bus *pbus)
 #define smt_capable()                          (sparc64_multi_core)
 #endif /* CONFIG_SMP */
 
-#define cpu_coregroup_mask(cpu)                        (&cpu_core_map[cpu])
+extern cpumask_t cpu_core_map[NR_CPUS];
+static inline const struct cpumask *cpu_coregroup_mask(int cpu)
+{
+        return &cpu_core_map[cpu];
+}
 
 #endif /* _ASM_SPARC64_TOPOLOGY_H */
index f679c57..1e34f29 100644 (file)
@@ -165,7 +165,7 @@ static int __devinit apc_probe(struct platform_device *op)
        return 0;
 }
 
-static struct of_device_id __initdata apc_match[] = {
+static struct of_device_id apc_match[] = {
        {
                .name = APC_OBPNAME,
        },
index 948068a..d1840db 100644 (file)
@@ -452,8 +452,10 @@ static void __devinit sabre_pbm_init(struct pci_pbm_info *pbm,
        sabre_scan_bus(pbm, &op->dev);
 }
 
+static const struct of_device_id sabre_match[];
 static int __devinit sabre_probe(struct platform_device *op)
 {
+       const struct of_device_id *match;
        const struct linux_prom64_registers *pr_regs;
        struct device_node *dp = op->dev.of_node;
        struct pci_pbm_info *pbm;
@@ -463,7 +465,8 @@ static int __devinit sabre_probe(struct platform_device *op)
        const u32 *vdma;
        u64 clear_irq;
 
-       hummingbird_p = op->dev.of_match && (op->dev.of_match->data != NULL);
+       match = of_match_device(sabre_match, &op->dev);
+       hummingbird_p = match && (match->data != NULL);
        if (!hummingbird_p) {
                struct device_node *cpu_dp;
 
index fecfcb2..283fbc3 100644 (file)
@@ -1458,11 +1458,15 @@ out_err:
        return err;
 }
 
+static const struct of_device_id schizo_match[];
 static int __devinit schizo_probe(struct platform_device *op)
 {
-       if (!op->dev.of_match)
+       const struct of_device_id *match;
+
+       match = of_match_device(schizo_match, &op->dev);
+       if (!match)
                return -EINVAL;
-       return __schizo_init(op, (unsigned long) op->dev.of_match->data);
+       return __schizo_init(op, (unsigned long)match->data);
 }
 
 /* The ordering of this table is very important.  Some Tomatillo
index 93d7b44..6a585d3 100644 (file)
@@ -69,7 +69,7 @@ static int __devinit pmc_probe(struct platform_device *op)
        return 0;
 }
 
-static struct of_device_id __initdata pmc_match[] = {
+static struct of_device_id pmc_match[] = {
        {
                .name = PMC_OBPNAME,
        },
index 91c10fb..442286d 100644 (file)
@@ -53,6 +53,7 @@ cpumask_t smp_commenced_mask = CPU_MASK_NONE;
 void __cpuinit smp_store_cpu_info(int id)
 {
        int cpu_node;
+       int mid;
 
        cpu_data(id).udelay_val = loops_per_jiffy;
 
@@ -60,10 +61,13 @@ void __cpuinit smp_store_cpu_info(int id)
        cpu_data(id).clock_tick = prom_getintdefault(cpu_node,
                                                     "clock-frequency", 0);
        cpu_data(id).prom_node = cpu_node;
-       cpu_data(id).mid = cpu_get_hwmid(cpu_node);
+       mid = cpu_get_hwmid(cpu_node);
 
-       if (cpu_data(id).mid < 0)
-               panic("No MID found for CPU%d at node 0x%08d", id, cpu_node);
+       if (mid < 0) {
+               printk(KERN_NOTICE "No MID found for CPU%d at node 0x%08d", id, cpu_node);
+               mid = 0;
+       }
+       cpu_data(id).mid = mid;
 }
 
 void __init smp_cpus_done(unsigned int max_cpus)
@@ -125,7 +129,9 @@ struct linux_prom_registers smp_penguin_ctable __cpuinitdata = { 0 };
 
 void smp_send_reschedule(int cpu)
 {
-       /* See sparc64 */
+       /*
+        * XXX missing reschedule IPI, see scheduler_ipi()
+        */
 }
 
 void smp_send_stop(void)
index 3e94a8c..9478da7 100644 (file)
@@ -1368,6 +1368,7 @@ void smp_send_reschedule(int cpu)
 void __irq_entry smp_receive_signal_client(int irq, struct pt_regs *regs)
 {
        clear_softint(1 << irq);
+       scheduler_ipi();
 }
 
 /* This is a nop because we capture all other cpus
index 4e23639..96046a4 100644 (file)
@@ -168,7 +168,7 @@ static int __devinit clock_probe(struct platform_device *op)
        return 0;
 }
 
-static struct of_device_id __initdata clock_match[] = {
+static struct of_device_id clock_match[] = {
        {
                .name = "eeprom",
        },
index 3632cb3..0084c33 100644 (file)
@@ -289,10 +289,16 @@ cc_end_cruft:
 
        /* Also, handle the alignment code out of band. */
 cc_dword_align:
-       cmp     %g1, 6
-       bl,a    ccte
+       cmp     %g1, 16
+       bge     1f
+        srl    %g1, 1, %o3
+2:     cmp     %o3, 0
+       be,a    ccte
         andcc  %g1, 0xf, %o3
-       andcc   %o0, 0x1, %g0
+       andcc   %o3, %o0, %g0   ! Check %o0 only (%o1 has the same last 2 bits)
+       be,a    2b
+        srl    %o3, 1, %o3
+1:     andcc   %o0, 0x1, %g0
        bne     ccslow
         andcc  %o0, 0x2, %g0
        be      1f
index a429310..c52224d 100644 (file)
@@ -189,12 +189,8 @@ void flush_icache_range(unsigned long start, unsigned long end)
 /* Called when smp_send_reschedule() triggers IRQ_RESCHEDULE. */
 static irqreturn_t handle_reschedule_ipi(int irq, void *token)
 {
-       /*
-        * Nothing to do here; when we return from interrupt, the
-        * rescheduling will occur there. But do bump the interrupt
-        * profiler count in the meantime.
-        */
        __get_cpu_var(irq_stat).irq_resched_count++;
+       scheduler_ipi();
 
        return IRQ_HANDLED;
 }
index 106bf27..eefb107 100644 (file)
@@ -173,7 +173,7 @@ void IPI_handler(int cpu)
                        break;
 
                case 'R':
-                       set_tsk_need_resched(current);
+                       scheduler_ipi();
                        break;
 
                case 'S':
index 6ea7797..42827ca 100644 (file)
@@ -5,6 +5,7 @@
 
 #include <stdio.h>
 #include <stdlib.h>
+#include <unistd.h>
 #include <errno.h>
 #include <signal.h>
 #include <string.h>
@@ -75,6 +76,26 @@ void setup_hostinfo(char *buf, int len)
                 host.release, host.version, host.machine);
 }
 
+/*
+ * We cannot use glibc's abort(). It makes use of tgkill() which
+ * has no effect within UML's kernel threads.
+ * After that glibc would execute an invalid instruction to kill
+ * the calling process and UML crashes with SIGSEGV.
+ */
+static inline void __attribute__ ((noreturn)) uml_abort(void)
+{
+       sigset_t sig;
+
+       fflush(NULL);
+
+       if (!sigemptyset(&sig) && !sigaddset(&sig, SIGABRT))
+               sigprocmask(SIG_UNBLOCK, &sig, 0);
+
+       for (;;)
+               if (kill(getpid(), SIGABRT) < 0)
+                       exit(127);
+}
+
 void os_dump_core(void)
 {
        int pid;
@@ -116,5 +137,5 @@ void os_dump_core(void)
        while ((pid = waitpid(-1, NULL, WNOHANG | __WALL)) > 0)
                os_kill_ptraced_process(pid, 0);
 
-       abort();
+       uml_abort();
 }
index 2aa30a3..d4efa7d 100644 (file)
@@ -23,7 +23,7 @@
 #include <linux/list.h>
 #include <linux/kallsyms.h>
 #include <linux/proc_fs.h>
-#include <linux/sysdev.h>
+#include <linux/syscore_ops.h>
 #include <linux/gpio.h>
 
 #include <asm/system.h>
@@ -237,7 +237,7 @@ static struct puv3_irq_state {
        unsigned int    iccr;
 } puv3_irq_state;
 
-static int puv3_irq_suspend(struct sys_device *dev, pm_message_t state)
+static int puv3_irq_suspend(void)
 {
        struct puv3_irq_state *st = &puv3_irq_state;
 
@@ -265,7 +265,7 @@ static int puv3_irq_suspend(struct sys_device *dev, pm_message_t state)
        return 0;
 }
 
-static int puv3_irq_resume(struct sys_device *dev)
+static void puv3_irq_resume(void)
 {
        struct puv3_irq_state *st = &puv3_irq_state;
 
@@ -278,27 +278,20 @@ static int puv3_irq_resume(struct sys_device *dev)
 
                writel(st->icmr, INTC_ICMR);
        }
-       return 0;
 }
 
-static struct sysdev_class puv3_irq_sysclass = {
-       .name           = "pkunity-irq",
+static struct syscore_ops puv3_irq_syscore_ops = {
        .suspend        = puv3_irq_suspend,
        .resume         = puv3_irq_resume,
 };
 
-static struct sys_device puv3_irq_device = {
-       .id             = 0,
-       .cls            = &puv3_irq_sysclass,
-};
-
-static int __init puv3_irq_init_devicefs(void)
+static int __init puv3_irq_init_syscore(void)
 {
-       sysdev_class_register(&puv3_irq_sysclass);
-       return sysdev_register(&puv3_irq_device);
+       register_syscore_ops(&puv3_irq_syscore_ops);
+       return 0;
 }
 
-device_initcall(puv3_irq_init_devicefs);
+device_initcall(puv3_irq_init_syscore);
 
 void __init init_IRQ(void)
 {
index 254e36f..b9a2646 100644 (file)
@@ -192,7 +192,6 @@ static int __die(const char *str, int err, struct thread_info *thread,
 
        printk(KERN_EMERG "Internal error: %s: %x [#%d]\n",
               str, err, ++die_counter);
-       sysfs_printk_last_file();
 
        /* trap and error numbers are mostly meaningless on UniCore */
        ret = notify_die(DIE_OOPS, str, regs, err, tsk->thread.trap_no, \
index cc6c53a..4168e5d 100644 (file)
@@ -8,6 +8,7 @@ config 64BIT
 
 config X86_32
        def_bool !64BIT
+       select CLKSRC_I8253
 
 config X86_64
        def_bool 64BIT
@@ -71,7 +72,6 @@ config X86
        select GENERIC_IRQ_SHOW
        select IRQ_FORCED_THREADING
        select USE_GENERIC_SMP_HELPERS if SMP
-       select ARCH_NO_SYSDEV_OPS
 
 config INSTRUCTION_DECODER
        def_bool (KPROBES || PERF_EVENTS)
@@ -112,7 +112,14 @@ config MMU
        def_bool y
 
 config ZONE_DMA
-       def_bool y
+       bool "DMA memory allocation support" if EXPERT
+       default y
+       help
+         DMA memory allocation support allows devices with less than 32-bit
+         addressing to allocate within the first 16MB of address space.
+         Disable if no such devices will be used.
+
+         If unsure, say Y.
 
 config SBUS
        bool
@@ -365,17 +372,6 @@ config X86_UV
 # Following is an alphabetically sorted list of 32 bit extended platforms
 # Please maintain the alphabetic order if and when there are additions
 
-config X86_ELAN
-       bool "AMD Elan"
-       depends on X86_32
-       depends on X86_EXTENDED_PLATFORM
-       ---help---
-         Select this for an AMD Elan processor.
-
-         Do not use this option for K6/Athlon/Opteron processors!
-
-         If unsure, choose "PC-compatible" instead.
-
 config X86_INTEL_CE
        bool "CE4100 TV platform"
        depends on PCI
@@ -690,6 +686,7 @@ config AMD_IOMMU
        bool "AMD IOMMU support"
        select SWIOTLB
        select PCI_MSI
+       select PCI_IOV
        depends on X86_64 && PCI && ACPI
        ---help---
          With this option you can enable support for AMD IOMMU hardware in
@@ -1174,7 +1171,7 @@ comment "NUMA (Summit) requires SMP, 64GB highmem support, ACPI"
 config AMD_NUMA
        def_bool y
        prompt "Old style AMD Opteron NUMA detection"
-       depends on X86_64 && NUMA && PCI
+       depends on NUMA && PCI
        ---help---
          Enable AMD NUMA node topology detection.  You should say Y here if
          you have a multi processor AMD system. This uses an old method to
@@ -1201,7 +1198,7 @@ config NODES_SPAN_OTHER_NODES
 
 config NUMA_EMU
        bool "NUMA emulation"
-       depends on X86_64 && NUMA
+       depends on NUMA
        ---help---
          Enable NUMA emulation. A flat machine will be split
          into virtual nodes when booted with "numa=fake=N", where N is the
@@ -1223,6 +1220,10 @@ config HAVE_ARCH_BOOTMEM
        def_bool y
        depends on X86_32 && NUMA
 
+config HAVE_ARCH_ALLOC_REMAP
+       def_bool y
+       depends on X86_32 && NUMA
+
 config ARCH_HAVE_MEMORY_PRESENT
        def_bool y
        depends on X86_32 && DISCONTIGMEM
@@ -1231,13 +1232,9 @@ config NEED_NODE_MEMMAP_SIZE
        def_bool y
        depends on X86_32 && (DISCONTIGMEM || SPARSEMEM)
 
-config HAVE_ARCH_ALLOC_REMAP
-       def_bool y
-       depends on X86_32 && NUMA
-
 config ARCH_FLATMEM_ENABLE
        def_bool y
-       depends on X86_32 && ARCH_SELECT_MEMORY_MODEL && !NUMA
+       depends on X86_32 && !NUMA
 
 config ARCH_DISCONTIGMEM_ENABLE
        def_bool y
@@ -1247,20 +1244,16 @@ config ARCH_DISCONTIGMEM_DEFAULT
        def_bool y
        depends on NUMA && X86_32
 
-config ARCH_PROC_KCORE_TEXT
-       def_bool y
-       depends on X86_64 && PROC_KCORE
-
-config ARCH_SPARSEMEM_DEFAULT
-       def_bool y
-       depends on X86_64
-
 config ARCH_SPARSEMEM_ENABLE
        def_bool y
        depends on X86_64 || NUMA || (EXPERIMENTAL && X86_32) || X86_32_NON_STANDARD
        select SPARSEMEM_STATIC if X86_32
        select SPARSEMEM_VMEMMAP_ENABLE if X86_64
 
+config ARCH_SPARSEMEM_DEFAULT
+       def_bool y
+       depends on X86_64
+
 config ARCH_SELECT_MEMORY_MODEL
        def_bool y
        depends on ARCH_SPARSEMEM_ENABLE
@@ -1269,6 +1262,10 @@ config ARCH_MEMORY_PROBE
        def_bool X86_64
        depends on MEMORY_HOTPLUG
 
+config ARCH_PROC_KCORE_TEXT
+       def_bool y
+       depends on X86_64 && PROC_KCORE
+
 config ILLEGAL_POINTER_VALUE
        hex
        default 0 if X86_32
@@ -1703,10 +1700,6 @@ config ARCH_ENABLE_MEMORY_HOTREMOVE
        def_bool y
        depends on MEMORY_HOTPLUG
 
-config HAVE_ARCH_EARLY_PFN_TO_NID
-       def_bool X86_64
-       depends on NUMA
-
 config USE_PERCPU_NUMA_NODE_ID
        def_bool y
        depends on NUMA
@@ -1848,7 +1841,7 @@ config APM_ALLOW_INTS
 
 endif # APM
 
-source "arch/x86/kernel/cpu/cpufreq/Kconfig"
+source "drivers/cpufreq/Kconfig"
 
 source "drivers/cpuidle/Kconfig"
 
@@ -2076,7 +2069,7 @@ config OLPC
        depends on !X86_PAE
        select GPIOLIB
        select OF
-       select OF_PROMTREE if PROC_DEVICETREE
+       select OF_PROMTREE
        ---help---
          Add support for detecting the unique features of the OLPC
          XO hardware.
index d161e93..6a7cfdf 100644 (file)
@@ -1,6 +1,4 @@
 # Put here option for CPU selection and depending optimization
-if !X86_ELAN
-
 choice
        prompt "Processor family"
        default M686 if X86_32
@@ -203,6 +201,14 @@ config MWINCHIP3D
          stores for this CPU, which can increase performance of some
          operations.
 
+config MELAN
+       bool "AMD Elan"
+       depends on X86_32
+       ---help---
+         Select this for an AMD Elan processor.
+
+         Do not use this option for K6/Athlon/Opteron processors!
+
 config MGEODEGX1
        bool "GeodeGX1"
        depends on X86_32
@@ -292,8 +298,6 @@ config X86_GENERIC
          This is really intended for distributors who need more
          generic optimizations.
 
-endif
-
 #
 # Define implied options from the CPU selection here
 config X86_INTERNODE_CACHE_SHIFT
@@ -312,7 +316,7 @@ config X86_L1_CACHE_SHIFT
        int
        default "7" if MPENTIUM4 || MPSC
        default "6" if MK7 || MK8 || MPENTIUMM || MCORE2 || MATOM || MVIAC7 || X86_GENERIC || GENERIC_CPU
-       default "4" if X86_ELAN || M486 || M386 || MGEODEGX1
+       default "4" if MELAN || M486 || M386 || MGEODEGX1
        default "5" if MWINCHIP3D || MWINCHIPC6 || MCRUSOE || MEFFICEON || MCYRIXIII || MK6 || MPENTIUMIII || MPENTIUMII || M686 || M586MMX || M586TSC || M586 || MVIAC3_2 || MGEODE_LX
 
 config X86_XADD
@@ -358,7 +362,7 @@ config X86_POPAD_OK
 
 config X86_ALIGNMENT_16
        def_bool y
-       depends on MWINCHIP3D || MWINCHIPC6 || MCYRIXIII || X86_ELAN || MK6 || M586MMX || M586TSC || M586 || M486 || MVIAC3_2 || MGEODEGX1
+       depends on MWINCHIP3D || MWINCHIPC6 || MCYRIXIII || MELAN || MK6 || M586MMX || M586TSC || M586 || M486 || MVIAC3_2 || MGEODEGX1
 
 config X86_INTEL_USERCOPY
        def_bool y
index f2ee1ab..86cee7b 100644 (file)
@@ -37,7 +37,7 @@ cflags-$(CONFIG_MATOM)                += $(call cc-option,-march=atom,$(call cc-option,-march=
        $(call cc-option,-mtune=atom,$(call cc-option,-mtune=generic))
 
 # AMD Elan support
-cflags-$(CONFIG_X86_ELAN)      += -march=i486
+cflags-$(CONFIG_MELAN)         += -march=i486
 
 # Geode GX1 support
 cflags-$(CONFIG_MGEODEGX1)     += -march=pentium-mmx
index 12e0e7d..416d865 100644 (file)
@@ -183,8 +183,6 @@ static inline void disable_acpi(void) { }
 
 #define ARCH_HAS_POWER_INIT    1
 
-struct bootnode;
-
 #ifdef CONFIG_ACPI_NUMA
 extern int acpi_numa;
 extern int x86_acpi_numa_init(void);
index 8cdd1e2..bf535f9 100644 (file)
@@ -190,12 +190,4 @@ extern void *text_poke(void *addr, const void *opcode, size_t len);
 extern void *text_poke_smp(void *addr, const void *opcode, size_t len);
 extern void text_poke_smp_batch(struct text_poke_param *params, int n);
 
-#if defined(CONFIG_DYNAMIC_FTRACE) || defined(CONFIG_JUMP_LABEL)
-#define IDEAL_NOP_SIZE_5 5
-extern unsigned char ideal_nop5[IDEAL_NOP_SIZE_5];
-extern void arch_init_ideal_nop5(void);
-#else
-static inline void arch_init_ideal_nop5(void) {}
-#endif
-
 #endif /* _ASM_X86_ALTERNATIVE_H */
index 916bc81..55d95eb 100644 (file)
 #ifndef _ASM_X86_AMD_IOMMU_PROTO_H
 #define _ASM_X86_AMD_IOMMU_PROTO_H
 
-struct amd_iommu;
+#include <asm/amd_iommu_types.h>
 
 extern int amd_iommu_init_dma_ops(void);
 extern int amd_iommu_init_passthrough(void);
+extern irqreturn_t amd_iommu_int_thread(int irq, void *data);
 extern irqreturn_t amd_iommu_int_handler(int irq, void *data);
-extern void amd_iommu_flush_all_domains(void);
-extern void amd_iommu_flush_all_devices(void);
 extern void amd_iommu_apply_erratum_63(u16 devid);
 extern void amd_iommu_reset_cmd_buffer(struct amd_iommu *iommu);
 extern int amd_iommu_init_devices(void);
@@ -44,4 +43,12 @@ static inline bool is_rd890_iommu(struct pci_dev *pdev)
               (pdev->device == PCI_DEVICE_ID_RD890_IOMMU);
 }
 
+static inline bool iommu_feature(struct amd_iommu *iommu, u64 f)
+{
+       if (!(iommu->cap & (1 << IOMMU_CAP_EFR)))
+               return false;
+
+       return !!(iommu->features & f);
+}
+
 #endif /* _ASM_X86_AMD_IOMMU_PROTO_H  */
index e3509fc..4c99829 100644 (file)
 #define MMIO_CONTROL_OFFSET     0x0018
 #define MMIO_EXCL_BASE_OFFSET   0x0020
 #define MMIO_EXCL_LIMIT_OFFSET  0x0028
+#define MMIO_EXT_FEATURES      0x0030
 #define MMIO_CMD_HEAD_OFFSET   0x2000
 #define MMIO_CMD_TAIL_OFFSET   0x2008
 #define MMIO_EVT_HEAD_OFFSET   0x2010
 #define MMIO_EVT_TAIL_OFFSET   0x2018
 #define MMIO_STATUS_OFFSET     0x2020
 
+
+/* Extended Feature Bits */
+#define FEATURE_PREFETCH       (1ULL<<0)
+#define FEATURE_PPR            (1ULL<<1)
+#define FEATURE_X2APIC         (1ULL<<2)
+#define FEATURE_NX             (1ULL<<3)
+#define FEATURE_GT             (1ULL<<4)
+#define FEATURE_IA             (1ULL<<6)
+#define FEATURE_GA             (1ULL<<7)
+#define FEATURE_HE             (1ULL<<8)
+#define FEATURE_PC             (1ULL<<9)
+
 /* MMIO status bits */
 #define MMIO_STATUS_COM_WAIT_INT_MASK  0x04
 
 /* command specific defines */
 #define CMD_COMPL_WAIT          0x01
 #define CMD_INV_DEV_ENTRY       0x02
-#define CMD_INV_IOMMU_PAGES     0x03
+#define CMD_INV_IOMMU_PAGES    0x03
+#define CMD_INV_IOTLB_PAGES    0x04
+#define CMD_INV_ALL            0x08
 
 #define CMD_COMPL_WAIT_STORE_MASK      0x01
 #define CMD_COMPL_WAIT_INT_MASK                0x02
 #define IOMMU_PTE_IR (1ULL << 61)
 #define IOMMU_PTE_IW (1ULL << 62)
 
+#define DTE_FLAG_IOTLB 0x01
+
 #define IOMMU_PAGE_MASK (((1ULL << 52) - 1) & ~0xfffULL)
 #define IOMMU_PTE_PRESENT(pte) ((pte) & IOMMU_PTE_P)
 #define IOMMU_PTE_PAGE(pte) (phys_to_virt((pte) & IOMMU_PAGE_MASK))
 /* IOMMU capabilities */
 #define IOMMU_CAP_IOTLB   24
 #define IOMMU_CAP_NPCACHE 26
+#define IOMMU_CAP_EFR     27
 
 #define MAX_DOMAIN_ID 65536
 
@@ -249,6 +267,8 @@ extern bool amd_iommu_dump;
 
 /* global flag if IOMMUs cache non-present entries */
 extern bool amd_iommu_np_cache;
+/* Only true if all IOMMUs support device IOTLBs */
+extern bool amd_iommu_iotlb_sup;
 
 /*
  * Make iterating over all IOMMUs easier
@@ -371,6 +391,9 @@ struct amd_iommu {
        /* flags read from acpi table */
        u8 acpi_flags;
 
+       /* Extended features */
+       u64 features;
+
        /*
         * Capability pointer. There could be more than one IOMMU per PCI
         * device function if there are more than one AMD IOMMU capability
@@ -409,9 +432,6 @@ struct amd_iommu {
        /* if one, we need to send a completion wait command */
        bool need_sync;
 
-       /* becomes true if a command buffer reset is running */
-       bool reset_in_progress;
-
        /* default dma_ops domain for that IOMMU */
        struct dma_ops_domain *default_dom;
 
index 3316822..67f87f2 100644 (file)
@@ -11,7 +11,6 @@ struct amd_nb_bus_dev_range {
 
 extern const struct pci_device_id amd_nb_misc_ids[];
 extern const struct amd_nb_bus_dev_range amd_nb_bus_dev_ranges[];
-struct bootnode;
 
 extern bool early_is_amd_nb(u32 value);
 extern int amd_cache_northbridges(void);
index 2b7d573..a0c46f0 100644 (file)
@@ -363,7 +363,12 @@ struct apic {
         */
        int (*x86_32_early_logical_apicid)(int cpu);
 
-       /* determine CPU -> NUMA node mapping */
+       /*
+        * Optional method called from setup_local_APIC() after logical
+        * apicid is guaranteed to be known to initialize apicid -> node
+        * mapping if NUMA initialization hasn't done so already.  Don't
+        * add new users.
+        */
        int (*x86_32_numa_cpu_node)(int cpu);
 #endif
 };
@@ -537,8 +542,6 @@ static inline int default_phys_pkg_id(int cpuid_apic, int index_msb)
        return cpuid_apic >> index_msb;
 }
 
-extern int default_x86_32_numa_cpu_node(int cpu);
-
 #endif
 
 static inline unsigned int
index d87988b..34595d5 100644 (file)
@@ -78,6 +78,7 @@
 #define                APIC_DEST_LOGICAL       0x00800
 #define                APIC_DEST_PHYSICAL      0x00000
 #define                APIC_DM_FIXED           0x00000
+#define                APIC_DM_FIXED_MASK      0x00700
 #define                APIC_DM_LOWEST          0x00100
 #define                APIC_DM_SMI             0x00200
 #define                APIC_DM_REMRD           0x00300
index 3c75210..aa6a317 100644 (file)
@@ -4,16 +4,40 @@
 #include <asm/io.h>
 
 /*
- * there is a real-mode segmented pointer pointing to the
- * 4K EBDA area at 0x40E.
+ * Returns physical address of EBDA.  Returns 0 if there is no EBDA.
  */
 static inline unsigned int get_bios_ebda(void)
 {
+       /*
+        * There is a real-mode segmented pointer pointing to the
+        * 4K EBDA area at 0x40E.
+        */
        unsigned int address = *(unsigned short *)phys_to_virt(0x40E);
        address <<= 4;
        return address; /* 0 means none */
 }
 
+/*
+ * Return the sanitized length of the EBDA in bytes, if it exists.
+ */
+static inline unsigned int get_bios_ebda_length(void)
+{
+       unsigned int address;
+       unsigned int length;
+
+       address = get_bios_ebda();
+       if (!address)
+               return 0;
+
+       /* EBDA length is byte 0 of the EBDA (stored in KiB) */
+       length = *(unsigned char *)phys_to_virt(address);
+       length <<= 10;
+
+       /* Trim the length if it extends beyond 640KiB */
+       length = min_t(unsigned int, (640 * 1024) - address, length);
+       return length;
+}
+
 void reserve_ebda_region(void);
 
 #ifdef CONFIG_X86_CHECK_BIOS_CORRUPTION
index 7f2f7b1..5dc6acc 100644 (file)
 
 /* Intel-defined CPU features, CPUID level 0x00000007:0 (ebx), word 9 */
 #define X86_FEATURE_FSGSBASE   (9*32+ 0) /* {RD/WR}{FS/GS}BASE instructions*/
+#define X86_FEATURE_SMEP       (9*32+ 7) /* Supervisor Mode Execution Protection */
 #define X86_FEATURE_ERMS       (9*32+ 9) /* Enhanced REP MOVSB/STOSB */
 
 #if defined(__KERNEL__) && !defined(__ASSEMBLY__)
@@ -208,8 +209,7 @@ extern const char * const x86_power_flags[32];
 #define test_cpu_cap(c, bit)                                           \
         test_bit(bit, (unsigned long *)((c)->x86_capability))
 
-#define cpu_has(c, bit)                                                        \
-       (__builtin_constant_p(bit) &&                                   \
+#define REQUIRED_MASK_BIT_SET(bit)                                     \
         ( (((bit)>>5)==0 && (1UL<<((bit)&31) & REQUIRED_MASK0)) ||     \
           (((bit)>>5)==1 && (1UL<<((bit)&31) & REQUIRED_MASK1)) ||     \
           (((bit)>>5)==2 && (1UL<<((bit)&31) & REQUIRED_MASK2)) ||     \
@@ -219,10 +219,16 @@ extern const char * const x86_power_flags[32];
           (((bit)>>5)==6 && (1UL<<((bit)&31) & REQUIRED_MASK6)) ||     \
           (((bit)>>5)==7 && (1UL<<((bit)&31) & REQUIRED_MASK7)) ||     \
           (((bit)>>5)==8 && (1UL<<((bit)&31) & REQUIRED_MASK8)) ||     \
-          (((bit)>>5)==9 && (1UL<<((bit)&31) & REQUIRED_MASK9)) )      \
-         ? 1 :                                                         \
+          (((bit)>>5)==9 && (1UL<<((bit)&31) & REQUIRED_MASK9)) )
+
+#define cpu_has(c, bit)                                                        \
+       (__builtin_constant_p(bit) && REQUIRED_MASK_BIT_SET(bit) ? 1 :  \
         test_cpu_cap(c, bit))
 
+#define this_cpu_has(bit)                                              \
+       (__builtin_constant_p(bit) && REQUIRED_MASK_BIT_SET(bit) ? 1 :  \
+        x86_this_cpu_test_bit(bit, (unsigned long *)&cpu_info.x86_capability))
+
 #define boot_cpu_has(bit)      cpu_has(&boot_cpu_data, bit)
 
 #define set_cpu_cap(c, bit)    set_bit(bit, (unsigned long *)((c)->x86_capability))
index 057099e..0bdb0c5 100644 (file)
 
 #define MAX_DMA_CHANNELS       8
 
-#ifdef CONFIG_X86_32
-
-/* The maximum address that we can perform a DMA transfer to on this platform */
-#define MAX_DMA_ADDRESS      (PAGE_OFFSET + 0x1000000)
-
-#else
-
 /* 16MB ISA DMA zone */
 #define MAX_DMA_PFN   ((16 * 1024 * 1024) >> PAGE_SHIFT)
 
 /* 4GB broken PCI/AGP hardware bus master zone */
 #define MAX_DMA32_PFN ((4UL * 1024 * 1024 * 1024) >> PAGE_SHIFT)
 
+#ifdef CONFIG_X86_32
+/* The maximum address that we can perform a DMA transfer to on this platform */
+#define MAX_DMA_ADDRESS      (PAGE_OFFSET + 0x1000000)
+#else
 /* Compat define for old dma zone */
 #define MAX_DMA_ADDRESS ((unsigned long)__va(MAX_DMA_PFN << PAGE_SHIFT))
-
 #endif
 
 /* 8237 DMA controllers */
index 8e4a165..7093e4a 100644 (file)
@@ -90,6 +90,7 @@ extern void __iomem *efi_ioremap(unsigned long addr, unsigned long size,
 #endif /* CONFIG_X86_32 */
 
 extern int add_efi_memmap;
+extern void efi_set_executable(efi_memory_desc_t *md, bool executable);
 extern void efi_memblock_x86_reserve_range(void);
 extern void efi_call_phys_prelog(void);
 extern void efi_call_phys_epilog(void);
index fc1f579..65aaa91 100644 (file)
@@ -6,6 +6,8 @@
 #define PIT_CH0                        0x40
 #define PIT_CH2                        0x42
 
+#define PIT_LATCH      LATCH
+
 extern raw_spinlock_t i8253_lock;
 
 extern struct clock_event_device *global_clock_event;
index eb16e94..021979a 100644 (file)
@@ -142,8 +142,6 @@ static inline void winchip_mcheck_init(struct cpuinfo_x86 *c) {}
 static inline void enable_p5_mce(void) {}
 #endif
 
-extern void (*x86_mce_decode_callback)(struct mce *m);
-
 void mce_setup(struct mce *m);
 void mce_log(struct mce *m);
 DECLARE_PER_CPU(struct sys_device, mce_dev);
index 91df7c5..5e83a41 100644 (file)
@@ -13,31 +13,11 @@ extern struct pglist_data *node_data[];
 #define NODE_DATA(nid) (node_data[nid])
 
 #include <asm/numaq.h>
-/* summit or generic arch */
-#include <asm/srat.h>
-
-extern int get_memcfg_numa_flat(void);
-/*
- * This allows any one NUMA architecture to be compiled
- * for, and still fall back to the flat function if it
- * fails.
- */
-static inline void get_memcfg_numa(void)
-{
-
-       if (get_memcfg_numaq())
-               return;
-       if (get_memcfg_from_srat())
-               return;
-       get_memcfg_numa_flat();
-}
 
 extern void resume_map_numa_kva(pgd_t *pgd);
 
 #else /* !CONFIG_NUMA */
 
-#define get_memcfg_numa get_memcfg_numa_flat
-
 static inline void resume_map_numa_kva(pgd_t *pgd) {}
 
 #endif /* CONFIG_NUMA */
index 288b96f..b3f88d7 100644 (file)
@@ -4,36 +4,13 @@
 #ifndef _ASM_X86_MMZONE_64_H
 #define _ASM_X86_MMZONE_64_H
 
-
 #ifdef CONFIG_NUMA
 
 #include <linux/mmdebug.h>
-
 #include <asm/smp.h>
 
-/* Simple perfect hash to map physical addresses to node numbers */
-struct memnode {
-       int shift;
-       unsigned int mapsize;
-       s16 *map;
-       s16 embedded_map[64 - 8];
-} ____cacheline_aligned; /* total size = 128 bytes */
-extern struct memnode memnode;
-#define memnode_shift memnode.shift
-#define memnodemap memnode.map
-#define memnodemapsize memnode.mapsize
-
 extern struct pglist_data *node_data[];
 
-static inline __attribute__((pure)) int phys_to_nid(unsigned long addr)
-{
-       unsigned nid;
-       VIRTUAL_BUG_ON(!memnodemap);
-       nid = memnodemap[addr >> memnode_shift];
-       VIRTUAL_BUG_ON(nid >= MAX_NUMNODES || !node_data[nid]);
-       return nid;
-}
-
 #define NODE_DATA(nid)         (node_data[nid])
 
 #define node_start_pfn(nid)    (NODE_DATA(nid)->node_start_pfn)
index 67763c5..9eae775 100644 (file)
@@ -35,7 +35,7 @@
 #define MODULE_PROC_FAMILY "K7 "
 #elif defined CONFIG_MK8
 #define MODULE_PROC_FAMILY "K8 "
-#elif defined CONFIG_X86_ELAN
+#elif defined CONFIG_MELAN
 #define MODULE_PROC_FAMILY "ELAN "
 #elif defined CONFIG_MCRUSOE
 #define MODULE_PROC_FAMILY "CRUSOE "
index af78849..405b403 100644 (file)
@@ -1,7 +1,13 @@
 #ifndef _ASM_X86_NOPS_H
 #define _ASM_X86_NOPS_H
 
-/* Define nops for use with alternative() */
+/*
+ * Define nops for use with alternative() and for tracing.
+ *
+ * *_NOP5_ATOMIC must be a single instruction.
+ */
+
+#define NOP_DS_PREFIX 0x3e
 
 /* generic versions from gas
    1: nop
    6: leal 0x00000000(%esi),%esi
    7: leal 0x00000000(,%esi,1),%esi
 */
-#define GENERIC_NOP1 ".byte 0x90\n"
-#define GENERIC_NOP2 ".byte 0x89,0xf6\n"
-#define GENERIC_NOP3 ".byte 0x8d,0x76,0x00\n"
-#define GENERIC_NOP4 ".byte 0x8d,0x74,0x26,0x00\n"
-#define GENERIC_NOP5 GENERIC_NOP1 GENERIC_NOP4
-#define GENERIC_NOP6 ".byte 0x8d,0xb6,0x00,0x00,0x00,0x00\n"
-#define GENERIC_NOP7 ".byte 0x8d,0xb4,0x26,0x00,0x00,0x00,0x00\n"
-#define GENERIC_NOP8 GENERIC_NOP1 GENERIC_NOP7
+#define GENERIC_NOP1 0x90
+#define GENERIC_NOP2 0x89,0xf6
+#define GENERIC_NOP3 0x8d,0x76,0x00
+#define GENERIC_NOP4 0x8d,0x74,0x26,0x00
+#define GENERIC_NOP5 GENERIC_NOP1,GENERIC_NOP4
+#define GENERIC_NOP6 0x8d,0xb6,0x00,0x00,0x00,0x00
+#define GENERIC_NOP7 0x8d,0xb4,0x26,0x00,0x00,0x00,0x00
+#define GENERIC_NOP8 GENERIC_NOP1,GENERIC_NOP7
+#define GENERIC_NOP5_ATOMIC NOP_DS_PREFIX,GENERIC_NOP4
 
 /* Opteron 64bit nops
    1: nop
    4: osp osp osp nop
 */
 #define K8_NOP1 GENERIC_NOP1
-#define K8_NOP2        ".byte 0x66,0x90\n"
-#define K8_NOP3        ".byte 0x66,0x66,0x90\n"
-#define K8_NOP4        ".byte 0x66,0x66,0x66,0x90\n"
-#define K8_NOP5        K8_NOP3 K8_NOP2
-#define K8_NOP6        K8_NOP3 K8_NOP3
-#define K8_NOP7        K8_NOP4 K8_NOP3
-#define K8_NOP8        K8_NOP4 K8_NOP4
+#define K8_NOP2        0x66,K8_NOP1
+#define K8_NOP3        0x66,K8_NOP2
+#define K8_NOP4        0x66,K8_NOP3
+#define K8_NOP5        K8_NOP3,K8_NOP2
+#define K8_NOP6        K8_NOP3,K8_NOP3
+#define K8_NOP7        K8_NOP4,K8_NOP3
+#define K8_NOP8        K8_NOP4,K8_NOP4
+#define K8_NOP5_ATOMIC 0x66,K8_NOP4
 
 /* K7 nops
    uses eax dependencies (arbitrary choice)
    7: leal 0x00000000(,%eax,1),%eax
 */
 #define K7_NOP1        GENERIC_NOP1
-#define K7_NOP2        ".byte 0x8b,0xc0\n"
-#define K7_NOP3        ".byte 0x8d,0x04,0x20\n"
-#define K7_NOP4        ".byte 0x8d,0x44,0x20,0x00\n"
-#define K7_NOP5        K7_NOP4 ASM_NOP1
-#define K7_NOP6        ".byte 0x8d,0x80,0,0,0,0\n"
-#define K7_NOP7        ".byte 0x8D,0x04,0x05,0,0,0,0\n"
-#define K7_NOP8        K7_NOP7 ASM_NOP1
+#define K7_NOP2        0x8b,0xc0
+#define K7_NOP3        0x8d,0x04,0x20
+#define K7_NOP4        0x8d,0x44,0x20,0x00
+#define K7_NOP5        K7_NOP4,K7_NOP1
+#define K7_NOP6        0x8d,0x80,0,0,0,0
+#define K7_NOP7        0x8D,0x04,0x05,0,0,0,0
+#define K7_NOP8        K7_NOP7,K7_NOP1
+#define K7_NOP5_ATOMIC NOP_DS_PREFIX,K7_NOP4
 
 /* P6 nops
    uses eax dependencies (Intel-recommended choice)
        There is kernel code that depends on this.
 */
 #define P6_NOP1        GENERIC_NOP1
-#define P6_NOP2        ".byte 0x66,0x90\n"
-#define P6_NOP3        ".byte 0x0f,0x1f,0x00\n"
-#define P6_NOP4        ".byte 0x0f,0x1f,0x40,0\n"
-#define P6_NOP5        ".byte 0x0f,0x1f,0x44,0x00,0\n"
-#define P6_NOP6        ".byte 0x66,0x0f,0x1f,0x44,0x00,0\n"
-#define P6_NOP7        ".byte 0x0f,0x1f,0x80,0,0,0,0\n"
-#define P6_NOP8        ".byte 0x0f,0x1f,0x84,0x00,0,0,0,0\n"
+#define P6_NOP2        0x66,0x90
+#define P6_NOP3        0x0f,0x1f,0x00
+#define P6_NOP4        0x0f,0x1f,0x40,0
+#define P6_NOP5        0x0f,0x1f,0x44,0x00,0
+#define P6_NOP6        0x66,0x0f,0x1f,0x44,0x00,0
+#define P6_NOP7        0x0f,0x1f,0x80,0,0,0,0
+#define P6_NOP8        0x0f,0x1f,0x84,0x00,0,0,0,0
+#define P6_NOP5_ATOMIC P6_NOP5
+
+#define _ASM_MK_NOP(x) ".byte " __stringify(x) "\n"
 
 #if defined(CONFIG_MK7)
-#define ASM_NOP1 K7_NOP1
-#define ASM_NOP2 K7_NOP2
-#define ASM_NOP3 K7_NOP3
-#define ASM_NOP4 K7_NOP4
-#define ASM_NOP5 K7_NOP5
-#define ASM_NOP6 K7_NOP6
-#define ASM_NOP7 K7_NOP7
-#define ASM_NOP8 K7_NOP8
+#define ASM_NOP1 _ASM_MK_NOP(K7_NOP1)
+#define ASM_NOP2 _ASM_MK_NOP(K7_NOP2)
+#define ASM_NOP3 _ASM_MK_NOP(K7_NOP3)
+#define ASM_NOP4 _ASM_MK_NOP(K7_NOP4)
+#define ASM_NOP5 _ASM_MK_NOP(K7_NOP5)
+#define ASM_NOP6 _ASM_MK_NOP(K7_NOP6)
+#define ASM_NOP7 _ASM_MK_NOP(K7_NOP7)
+#define ASM_NOP8 _ASM_MK_NOP(K7_NOP8)
+#define ASM_NOP5_ATOMIC _ASM_MK_NOP(K7_NOP5_ATOMIC)
 #elif defined(CONFIG_X86_P6_NOP)
-#define ASM_NOP1 P6_NOP1
-#define ASM_NOP2 P6_NOP2
-#define ASM_NOP3 P6_NOP3
-#define ASM_NOP4 P6_NOP4
-#define ASM_NOP5 P6_NOP5
-#define ASM_NOP6 P6_NOP6
-#define ASM_NOP7 P6_NOP7
-#define ASM_NOP8 P6_NOP8
+#define ASM_NOP1 _ASM_MK_NOP(P6_NOP1)
+#define ASM_NOP2 _ASM_MK_NOP(P6_NOP2)
+#define ASM_NOP3 _ASM_MK_NOP(P6_NOP3)
+#define ASM_NOP4 _ASM_MK_NOP(P6_NOP4)
+#define ASM_NOP5 _ASM_MK_NOP(P6_NOP5)
+#define ASM_NOP6 _ASM_MK_NOP(P6_NOP6)
+#define ASM_NOP7 _ASM_MK_NOP(P6_NOP7)
+#define ASM_NOP8 _ASM_MK_NOP(P6_NOP8)
+#define ASM_NOP5_ATOMIC _ASM_MK_NOP(P6_NOP5_ATOMIC)
 #elif defined(CONFIG_X86_64)
-#define ASM_NOP1 K8_NOP1
-#define ASM_NOP2 K8_NOP2
-#define ASM_NOP3 K8_NOP3
-#define ASM_NOP4 K8_NOP4
-#define ASM_NOP5 K8_NOP5
-#define ASM_NOP6 K8_NOP6
-#define ASM_NOP7 K8_NOP7
-#define ASM_NOP8 K8_NOP8
+#define ASM_NOP1 _ASM_MK_NOP(K8_NOP1)
+#define ASM_NOP2 _ASM_MK_NOP(K8_NOP2)
+#define ASM_NOP3 _ASM_MK_NOP(K8_NOP3)
+#define ASM_NOP4 _ASM_MK_NOP(K8_NOP4)
+#define ASM_NOP5 _ASM_MK_NOP(K8_NOP5)
+#define ASM_NOP6 _ASM_MK_NOP(K8_NOP6)
+#define ASM_NOP7 _ASM_MK_NOP(K8_NOP7)
+#define ASM_NOP8 _ASM_MK_NOP(K8_NOP8)
+#define ASM_NOP5_ATOMIC _ASM_MK_NOP(K8_NOP5_ATOMIC)
 #else
-#define ASM_NOP1 GENERIC_NOP1
-#define ASM_NOP2 GENERIC_NOP2
-#define ASM_NOP3 GENERIC_NOP3
-#define ASM_NOP4 GENERIC_NOP4
-#define ASM_NOP5 GENERIC_NOP5
-#define ASM_NOP6 GENERIC_NOP6
-#define ASM_NOP7 GENERIC_NOP7
-#define ASM_NOP8 GENERIC_NOP8
+#define ASM_NOP1 _ASM_MK_NOP(GENERIC_NOP1)
+#define ASM_NOP2 _ASM_MK_NOP(GENERIC_NOP2)
+#define ASM_NOP3 _ASM_MK_NOP(GENERIC_NOP3)
+#define ASM_NOP4 _ASM_MK_NOP(GENERIC_NOP4)
+#define ASM_NOP5 _ASM_MK_NOP(GENERIC_NOP5)
+#define ASM_NOP6 _ASM_MK_NOP(GENERIC_NOP6)
+#define ASM_NOP7 _ASM_MK_NOP(GENERIC_NOP7)
+#define ASM_NOP8 _ASM_MK_NOP(GENERIC_NOP8)
+#define ASM_NOP5_ATOMIC _ASM_MK_NOP(GENERIC_NOP5_ATOMIC)
 #endif
 
 #define ASM_NOP_MAX 8
+#define NOP_ATOMIC5 (ASM_NOP_MAX+1)    /* Entry for the 5-byte atomic NOP */
+
+#ifndef __ASSEMBLY__
+extern const unsigned char * const *ideal_nops;
+extern void arch_init_ideal_nops(void);
+#endif
 
 #endif /* _ASM_X86_NOPS_H */
index a50fc9f..bfacd2c 100644 (file)
@@ -1,12 +1,24 @@
 #ifndef _ASM_X86_NUMA_H
 #define _ASM_X86_NUMA_H
 
+#include <linux/nodemask.h>
+
 #include <asm/topology.h>
 #include <asm/apicdef.h>
 
 #ifdef CONFIG_NUMA
 
 #define NR_NODE_MEMBLKS                (MAX_NUMNODES*2)
+#define ZONE_ALIGN (1UL << (MAX_ORDER+PAGE_SHIFT))
+
+/*
+ * Too small node sizes may confuse the VM badly. Usually they
+ * result from BIOS bugs. So dont recognize nodes as standalone
+ * NUMA entities that have less than this amount of RAM listed:
+ */
+#define NODE_MIN_SIZE (4*1024*1024)
+
+extern int numa_off;
 
 /*
  * __apicid_to_node[] stores the raw mapping between physical apicid and
  * numa_cpu_node().
  */
 extern s16 __apicid_to_node[MAX_LOCAL_APIC];
+extern nodemask_t numa_nodes_parsed __initdata;
+
+extern int __init numa_add_memblk(int nodeid, u64 start, u64 end);
+extern void __init numa_set_distance(int from, int to, int distance);
 
 static inline void set_apicid_to_node(int apicid, s16 node)
 {
        __apicid_to_node[apicid] = node;
 }
+
+extern int __cpuinit numa_cpu_node(int cpu);
+
 #else  /* CONFIG_NUMA */
 static inline void set_apicid_to_node(int apicid, s16 node)
 {
 }
+
+static inline int numa_cpu_node(int cpu)
+{
+       return NUMA_NO_NODE;
+}
 #endif /* CONFIG_NUMA */
 
 #ifdef CONFIG_X86_32
@@ -37,14 +61,12 @@ static inline void set_apicid_to_node(int apicid, s16 node)
 #ifdef CONFIG_NUMA
 extern void __cpuinit numa_set_node(int cpu, int node);
 extern void __cpuinit numa_clear_node(int cpu);
-extern void __init numa_init_array(void);
 extern void __init init_cpu_to_node(void);
 extern void __cpuinit numa_add_cpu(int cpu);
 extern void __cpuinit numa_remove_cpu(int cpu);
 #else  /* CONFIG_NUMA */
 static inline void numa_set_node(int cpu, int node)    { }
 static inline void numa_clear_node(int cpu)            { }
-static inline void numa_init_array(void)               { }
 static inline void init_cpu_to_node(void)              { }
 static inline void numa_add_cpu(int cpu)               { }
 static inline void numa_remove_cpu(int cpu)            { }
@@ -54,4 +76,10 @@ static inline void numa_remove_cpu(int cpu)          { }
 void debug_cpumask_set_cpu(int cpu, int node, bool enable);
 #endif
 
+#ifdef CONFIG_NUMA_EMU
+#define FAKE_NODE_MIN_SIZE     ((u64)32 << 20)
+#define FAKE_NODE_MIN_HASH_MASK        (~(FAKE_NODE_MIN_SIZE - 1UL))
+void numa_emu_cmdline(char *);
+#endif /* CONFIG_NUMA_EMU */
+
 #endif /* _ASM_X86_NUMA_H */
index c6beed1..e7d6b82 100644 (file)
@@ -1,16 +1,6 @@
 #ifndef _ASM_X86_NUMA_32_H
 #define _ASM_X86_NUMA_32_H
 
-extern int numa_off;
-
-extern int pxm_to_nid(int pxm);
-
-#ifdef CONFIG_NUMA
-extern int __cpuinit numa_cpu_node(int cpu);
-#else  /* CONFIG_NUMA */
-static inline int numa_cpu_node(int cpu)               { return NUMA_NO_NODE; }
-#endif /* CONFIG_NUMA */
-
 #ifdef CONFIG_HIGHMEM
 extern void set_highmem_pages_init(void);
 #else
index 344eb17..0c05f7a 100644 (file)
@@ -1,42 +1,6 @@
 #ifndef _ASM_X86_NUMA_64_H
 #define _ASM_X86_NUMA_64_H
 
-#include <linux/nodemask.h>
-
-struct bootnode {
-       u64 start;
-       u64 end;
-};
-
-#define ZONE_ALIGN (1UL << (MAX_ORDER+PAGE_SHIFT))
-
-extern int numa_off;
-
 extern unsigned long numa_free_all_bootmem(void);
-extern void setup_node_bootmem(int nodeid, unsigned long start,
-                              unsigned long end);
-
-#ifdef CONFIG_NUMA
-/*
- * Too small node sizes may confuse the VM badly. Usually they
- * result from BIOS bugs. So dont recognize nodes as standalone
- * NUMA entities that have less than this amount of RAM listed:
- */
-#define NODE_MIN_SIZE (4*1024*1024)
-
-extern nodemask_t numa_nodes_parsed __initdata;
-
-extern int __cpuinit numa_cpu_node(int cpu);
-extern int __init numa_add_memblk(int nodeid, u64 start, u64 end);
-extern void __init numa_set_distance(int from, int to, int distance);
-
-#ifdef CONFIG_NUMA_EMU
-#define FAKE_NODE_MIN_SIZE     ((u64)32 << 20)
-#define FAKE_NODE_MIN_HASH_MASK        (~(FAKE_NODE_MIN_SIZE - 1UL))
-void numa_emu_cmdline(char *);
-#endif /* CONFIG_NUMA_EMU */
-#else
-static inline int numa_cpu_node(int cpu)               { return NUMA_NO_NODE; }
-#endif
 
 #endif /* _ASM_X86_NUMA_64_H */
index 37c5165..c3b3c32 100644 (file)
@@ -29,7 +29,7 @@
 #ifdef CONFIG_X86_NUMAQ
 
 extern int found_numaq;
-extern int get_memcfg_numaq(void);
+extern int numaq_numa_init(void);
 extern int pci_numaq_init(void);
 
 extern void *xquad_portio;
@@ -166,11 +166,6 @@ struct sys_cfg_data {
 
 void numaq_tsc_disable(void);
 
-#else
-static inline int get_memcfg_numaq(void)
-{
-       return 0;
-}
 #endif /* CONFIG_X86_NUMAQ */
 #endif /* _ASM_X86_NUMAQ_H */
 
index c5d3a5a..2448771 100644 (file)
@@ -26,15 +26,12 @@ extern void setup_olpc_ofw_pgd(void);
 /* check if OFW was detected during boot */
 extern bool olpc_ofw_present(void);
 
+extern void olpc_dt_build_devicetree(void);
+
 #else /* !CONFIG_OLPC */
 static inline void olpc_ofw_detect(void) { }
 static inline void setup_olpc_ofw_pgd(void) { }
-#endif /* !CONFIG_OLPC */
-
-#ifdef CONFIG_OF_PROMTREE
-extern void olpc_dt_build_devicetree(void);
-#else
 static inline void olpc_dt_build_devicetree(void) { }
-#endif
+#endif /* !CONFIG_OLPC */
 
 #endif /* _ASM_X86_OLPC_OFW_H */
index d475b43..53278b0 100644 (file)
@@ -517,7 +517,7 @@ do {                                                                        \
        typeof(o2) __o2 = o2;                                           \
        typeof(o2) __n2 = n2;                                           \
        typeof(o2) __dummy;                                             \
-       alternative_io("call this_cpu_cmpxchg16b_emu\n\t" P6_NOP4,      \
+       alternative_io("call this_cpu_cmpxchg16b_emu\n\t" ASM_NOP4,     \
                       "cmpxchg16b " __percpu_prefix "(%%rsi)\n\tsetz %0\n\t",  \
                       X86_FEATURE_CX16,                                \
                       ASM_OUTPUT2("=a"(__ret), "=d"(__dummy)),         \
@@ -542,6 +542,33 @@ do {                                                                       \
        old__;                                                          \
 })
 
+static __always_inline int x86_this_cpu_constant_test_bit(unsigned int nr,
+                        const unsigned long __percpu *addr)
+{
+       unsigned long __percpu *a = (unsigned long *)addr + nr / BITS_PER_LONG;
+
+       return ((1UL << (nr % BITS_PER_LONG)) & percpu_read(*a)) != 0;
+}
+
+static inline int x86_this_cpu_variable_test_bit(int nr,
+                        const unsigned long __percpu *addr)
+{
+       int oldbit;
+
+       asm volatile("bt "__percpu_arg(2)",%1\n\t"
+                       "sbb %0,%0"
+                       : "=r" (oldbit)
+                       : "m" (*(unsigned long *)addr), "Ir" (nr));
+
+       return oldbit;
+}
+
+#define x86_this_cpu_test_bit(nr, addr)                        \
+       (__builtin_constant_p((nr))                     \
+        ? x86_this_cpu_constant_test_bit((nr), (addr)) \
+        : x86_this_cpu_variable_test_bit((nr), (addr)))
+
+
 #include <asm-generic/percpu.h>
 
 /* We can use this directly for local CPU (faster). */
index 7db7723..d56187c 100644 (file)
@@ -299,6 +299,7 @@ int phys_mem_access_prot_allowed(struct file *file, unsigned long pfn,
 /* Install a pte for a particular vaddr in kernel space. */
 void set_pte_vaddr(unsigned long vaddr, pte_t pte);
 
+extern void native_pagetable_reserve(u64 start, u64 end);
 #ifdef CONFIG_X86_32
 extern void native_pagetable_setup_start(pgd_t *base);
 extern void native_pagetable_setup_done(pgd_t *base);
diff --git a/arch/x86/include/asm/probe_roms.h b/arch/x86/include/asm/probe_roms.h
new file mode 100644 (file)
index 0000000..4950a0b
--- /dev/null
@@ -0,0 +1,8 @@
+#ifndef _PROBE_ROMS_H_
+#define _PROBE_ROMS_H_
+struct pci_dev;
+
+extern void __iomem *pci_map_biosrom(struct pci_dev *pdev);
+extern void pci_unmap_biosrom(void __iomem *rom);
+extern size_t pci_biosrom_size(struct pci_dev *pdev);
+#endif
index a898a2b..59ab4df 100644 (file)
@@ -60,6 +60,7 @@
 #define X86_CR4_OSXMMEXCPT 0x00000400 /* enable unmasked SSE exceptions */
 #define X86_CR4_VMXE   0x00002000 /* enable VMX virtualization */
 #define X86_CR4_OSXSAVE 0x00040000 /* enable xsave and xrestore */
+#define X86_CR4_SMEP   0x00100000 /* enable SMEP support */
 
 /*
  * x86-64 Task Priority Register, CR8
index 647d8a0..9756551 100644 (file)
@@ -104,10 +104,10 @@ void *extend_brk(size_t size, size_t align);
        type *name;                                     \
        RESERVE_BRK(name, sizeof(type) * entries)
 
+extern void probe_roms(void);
 #ifdef __i386__
 
 void __init i386_start_kernel(void);
-extern void probe_roms(void);
 
 #else
 void __init x86_64_start_kernel(char *real_mode);
diff --git a/arch/x86/include/asm/srat.h b/arch/x86/include/asm/srat.h
deleted file mode 100644 (file)
index b508d63..0000000
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * Some of the code in this file has been gleaned from the 64 bit
- * discontigmem support code base.
- *
- * Copyright (C) 2002, IBM Corp.
- *
- * All rights reserved.
- *
- * 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, GOOD TITLE or
- * NON INFRINGEMENT.  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.
- *
- * Send feedback to Pat Gaughen <gone@us.ibm.com>
- */
-
-#ifndef _ASM_X86_SRAT_H
-#define _ASM_X86_SRAT_H
-
-#ifdef CONFIG_ACPI_NUMA
-extern int get_memcfg_from_srat(void);
-#else
-static inline int get_memcfg_from_srat(void)
-{
-       return 0;
-}
-#endif
-
-#endif /* _ASM_X86_SRAT_H */
index 12569e6..c2ff2a1 100644 (file)
@@ -303,24 +303,81 @@ static inline void native_wbinvd(void)
 #ifdef CONFIG_PARAVIRT
 #include <asm/paravirt.h>
 #else
-#define read_cr0()     (native_read_cr0())
-#define write_cr0(x)   (native_write_cr0(x))
-#define read_cr2()     (native_read_cr2())
-#define write_cr2(x)   (native_write_cr2(x))
-#define read_cr3()     (native_read_cr3())
-#define write_cr3(x)   (native_write_cr3(x))
-#define read_cr4()     (native_read_cr4())
-#define read_cr4_safe()        (native_read_cr4_safe())
-#define write_cr4(x)   (native_write_cr4(x))
-#define wbinvd()       (native_wbinvd())
+
+static inline unsigned long read_cr0(void)
+{
+       return native_read_cr0();
+}
+
+static inline void write_cr0(unsigned long x)
+{
+       native_write_cr0(x);
+}
+
+static inline unsigned long read_cr2(void)
+{
+       return native_read_cr2();
+}
+
+static inline void write_cr2(unsigned long x)
+{
+       native_write_cr2(x);
+}
+
+static inline unsigned long read_cr3(void)
+{
+       return native_read_cr3();
+}
+
+static inline void write_cr3(unsigned long x)
+{
+       native_write_cr3(x);
+}
+
+static inline unsigned long read_cr4(void)
+{
+       return native_read_cr4();
+}
+
+static inline unsigned long read_cr4_safe(void)
+{
+       return native_read_cr4_safe();
+}
+
+static inline void write_cr4(unsigned long x)
+{
+       native_write_cr4(x);
+}
+
+static inline void wbinvd(void)
+{
+       native_wbinvd();
+}
+
 #ifdef CONFIG_X86_64
-#define read_cr8()     (native_read_cr8())
-#define write_cr8(x)   (native_write_cr8(x))
-#define load_gs_index   native_load_gs_index
+
+static inline unsigned long read_cr8(void)
+{
+       return native_read_cr8();
+}
+
+static inline void write_cr8(unsigned long x)
+{
+       native_write_cr8(x);
+}
+
+static inline void load_gs_index(unsigned selector)
+{
+       native_load_gs_index(selector);
+}
+
 #endif
 
 /* Clear the 'TS' bit */
-#define clts()         (native_clts())
+static inline void clts(void)
+{
+       native_clts();
+}
 
 #endif/* CONFIG_PARAVIRT */
 
index 910a708..c006924 100644 (file)
@@ -93,19 +93,11 @@ extern void setup_node_to_cpumask_map(void);
 #define pcibus_to_node(bus) __pcibus_to_node(bus)
 
 #ifdef CONFIG_X86_32
-extern unsigned long node_start_pfn[];
-extern unsigned long node_end_pfn[];
-extern unsigned long node_remap_size[];
-#define node_has_online_mem(nid) (node_start_pfn[nid] != node_end_pfn[nid])
-
 # define SD_CACHE_NICE_TRIES   1
 # define SD_IDLE_IDX           1
-
 #else
-
 # define SD_CACHE_NICE_TRIES   2
 # define SD_IDLE_IDX           2
-
 #endif
 
 /* sched_domains SD_NODE_INIT for NUMA machines */
index 3e094af..130f1ee 100644 (file)
@@ -94,6 +94,8 @@
 /* after this # consecutive successes, bump up the throttle if it was lowered */
 #define COMPLETE_THRESHOLD 5
 
+#define UV_LB_SUBNODEID 0x10
+
 /*
  * number of entries in the destination side payload queue
  */
  * The distribution specification (32 bytes) is interpreted as a 256-bit
  * distribution vector. Adjacent bits correspond to consecutive even numbered
  * nodeIDs. The result of adding the index of a given bit to the 15-bit
- * 'base_dest_nodeid' field of the header corresponds to the
+ * 'base_dest_nasid' field of the header corresponds to the
  * destination nodeID associated with that specified bit.
  */
 struct bau_target_uvhubmask {
@@ -176,7 +178,7 @@ struct bau_msg_payload {
 struct bau_msg_header {
        unsigned int dest_subnodeid:6;  /* must be 0x10, for the LB */
        /* bits 5:0 */
-       unsigned int base_dest_nodeid:15; /* nasid of the */
+       unsigned int base_dest_nasid:15; /* nasid of the */
        /* bits 20:6 */                   /* first bit in uvhub map */
        unsigned int command:8; /* message type */
        /* bits 28:21 */
@@ -378,6 +380,10 @@ struct ptc_stats {
        unsigned long d_rcanceled; /* number of messages canceled by resets */
 };
 
+struct hub_and_pnode {
+       short uvhub;
+       short pnode;
+};
 /*
  * one per-cpu; to locate the software tables
  */
@@ -399,10 +405,12 @@ struct bau_control {
        int baudisabled;
        int set_bau_off;
        short cpu;
+       short osnode;
        short uvhub_cpu;
        short uvhub;
        short cpus_in_socket;
        short cpus_in_uvhub;
+       short partition_base_pnode;
        unsigned short message_number;
        unsigned short uvhub_quiesce;
        short socket_acknowledge_count[DEST_Q_SIZE];
@@ -422,15 +430,16 @@ struct bau_control {
        int congested_period;
        cycles_t period_time;
        long period_requests;
+       struct hub_and_pnode *target_hub_and_pnode;
 };
 
 static inline int bau_uvhub_isset(int uvhub, struct bau_target_uvhubmask *dstp)
 {
        return constant_test_bit(uvhub, &dstp->bits[0]);
 }
-static inline void bau_uvhub_set(int uvhub, struct bau_target_uvhubmask *dstp)
+static inline void bau_uvhub_set(int pnode, struct bau_target_uvhubmask *dstp)
 {
-       __set_bit(uvhub, &dstp->bits[0]);
+       __set_bit(pnode, &dstp->bits[0]);
 }
 static inline void bau_uvhubs_clear(struct bau_target_uvhubmask *dstp,
                                    int nbits)
index a501741..4298002 100644 (file)
@@ -398,6 +398,8 @@ struct uv_blade_info {
        unsigned short  nr_online_cpus;
        unsigned short  pnode;
        short           memory_nid;
+       spinlock_t      nmi_lock;
+       unsigned long   nmi_count;
 };
 extern struct uv_blade_info *uv_blade_info;
 extern short *uv_node_to_blade;
index 20cafea..f5bb64a 100644 (file)
@@ -5,7 +5,7 @@
  *
  * SGI UV MMR definitions
  *
- * Copyright (C) 2007-2010 Silicon Graphics, Inc. All rights reserved.
+ * Copyright (C) 2007-2011 Silicon Graphics, Inc. All rights reserved.
  */
 
 #ifndef _ASM_X86_UV_UV_MMRS_H
@@ -1099,5 +1099,19 @@ union uvh_rtc1_int_config_u {
     } s;
 };
 
+/* ========================================================================= */
+/*                               UVH_SCRATCH5                                */
+/* ========================================================================= */
+#define UVH_SCRATCH5 0x2d0200UL
+#define UVH_SCRATCH5_32 0x00778
+
+#define UVH_SCRATCH5_SCRATCH5_SHFT 0
+#define UVH_SCRATCH5_SCRATCH5_MASK 0xffffffffffffffffUL
+union uvh_scratch5_u {
+    unsigned long      v;
+    struct uvh_scratch5_s {
+       unsigned long   scratch5 : 64;  /* RW, W1CS */
+    } s;
+};
 
 #endif /* __ASM_UV_MMRS_X86_H__ */
index 643ebf2..d3d8590 100644 (file)
@@ -68,6 +68,17 @@ struct x86_init_oem {
 };
 
 /**
+ * struct x86_init_mapping - platform specific initial kernel pagetable setup
+ * @pagetable_reserve: reserve a range of addresses for kernel pagetable usage
+ *
+ * For more details on the purpose of this hook, look in
+ * init_memory_mapping and the commit that added it.
+ */
+struct x86_init_mapping {
+       void (*pagetable_reserve)(u64 start, u64 end);
+};
+
+/**
  * struct x86_init_paging - platform specific paging functions
  * @pagetable_setup_start:     platform specific pre paging_init() call
  * @pagetable_setup_done:      platform specific post paging_init() call
@@ -123,6 +134,7 @@ struct x86_init_ops {
        struct x86_init_mpparse         mpparse;
        struct x86_init_irqs            irqs;
        struct x86_init_oem             oem;
+       struct x86_init_mapping         mapping;
        struct x86_init_paging          paging;
        struct x86_init_timers          timers;
        struct x86_init_iommu           iommu;
index c61934f..64a619d 100644 (file)
@@ -47,8 +47,9 @@ extern bool __set_phys_to_machine(unsigned long pfn, unsigned long mfn);
 extern unsigned long set_phys_range_identity(unsigned long pfn_s,
                                             unsigned long pfn_e);
 
-extern int m2p_add_override(unsigned long mfn, struct page *page);
-extern int m2p_remove_override(struct page *page);
+extern int m2p_add_override(unsigned long mfn, struct page *page,
+                           bool clear_pte);
+extern int m2p_remove_override(struct page *page, bool clear_pte);
 extern struct page *m2p_find_override(unsigned long mfn);
 extern unsigned long m2p_find_override_pfn(unsigned long mfn, unsigned long pfn);
 
index aa86209..4fbda9a 100644 (file)
@@ -15,10 +15,26 @@ static inline int pci_xen_hvm_init(void)
 #endif
 #if defined(CONFIG_XEN_DOM0)
 void __init xen_setup_pirqs(void);
+int xen_find_device_domain_owner(struct pci_dev *dev);
+int xen_register_device_domain_owner(struct pci_dev *dev, uint16_t domain);
+int xen_unregister_device_domain_owner(struct pci_dev *dev);
 #else
 static inline void __init xen_setup_pirqs(void)
 {
 }
+static inline int xen_find_device_domain_owner(struct pci_dev *dev)
+{
+       return -1;
+}
+static inline int xen_register_device_domain_owner(struct pci_dev *dev,
+                                                  uint16_t domain)
+{
+       return -1;
+}
+static inline int xen_unregister_device_domain_owner(struct pci_dev *dev)
+{
+       return -1;
+}
 #endif
 
 #if defined(CONFIG_PCI_MSI)
index 7338ef2..2508064 100644 (file)
@@ -36,7 +36,7 @@ obj-y                 += traps.o irq.o irq_$(BITS).o dumpstack_$(BITS).o
 obj-y                  += time.o ioport.o ldt.o dumpstack.o
 obj-y                  += setup.o x86_init.o i8259.o irqinit.o jump_label.o
 obj-$(CONFIG_IRQ_WORK)  += irq_work.o
-obj-$(CONFIG_X86_32)   += probe_roms_32.o
+obj-y                  += probe_roms.o
 obj-$(CONFIG_X86_32)   += sys_i386_32.o i386_ksyms_32.o
 obj-$(CONFIG_X86_64)   += sys_x86_64.o x8664_ksyms_64.o
 obj-$(CONFIG_X86_64)   += syscall_64.o vsyscall_64.o
@@ -117,7 +117,7 @@ obj-$(CONFIG_OF)                    += devicetree.o
 ifeq ($(CONFIG_X86_64),y)
        obj-$(CONFIG_AUDIT)             += audit_64.o
 
-       obj-$(CONFIG_GART_IOMMU)        += pci-gart_64.o aperture_64.o
+       obj-$(CONFIG_GART_IOMMU)        += amd_gart_64.o aperture_64.o
        obj-$(CONFIG_CALGARY_IOMMU)     += pci-calgary_64.o tce_64.o
        obj-$(CONFIG_AMD_IOMMU)         += amd_iommu_init.o amd_iommu.o
 
index ff93bc1..18a857b 100644 (file)
@@ -112,11 +112,6 @@ static int __init acpi_sleep_setup(char *str)
 #ifdef CONFIG_HIBERNATION
                if (strncmp(str, "s4_nohwsig", 10) == 0)
                        acpi_no_s4_hw_signature();
-               if (strncmp(str, "s4_nonvs", 8) == 0) {
-                       pr_warning("ACPI: acpi_sleep=s4_nonvs is deprecated, "
-                                       "please use acpi_sleep=nonvs instead");
-                       acpi_nvs_nosave();
-               }
 #endif
                if (strncmp(str, "nonvs", 5) == 0)
                        acpi_nvs_nosave();
index 1eeeafc..a81f2d5 100644 (file)
@@ -67,17 +67,30 @@ __setup("noreplace-paravirt", setup_noreplace_paravirt);
 #define DPRINTK(fmt, args...) if (debug_alternative) \
        printk(KERN_DEBUG fmt, args)
 
+/*
+ * Each GENERIC_NOPX is of X bytes, and defined as an array of bytes
+ * that correspond to that nop. Getting from one nop to the next, we
+ * add to the array the offset that is equal to the sum of all sizes of
+ * nops preceding the one we are after.
+ *
+ * Note: The GENERIC_NOP5_ATOMIC is at the end, as it breaks the
+ * nice symmetry of sizes of the previous nops.
+ */
 #if defined(GENERIC_NOP1) && !defined(CONFIG_X86_64)
-/* Use inline assembly to define this because the nops are defined
-   as inline assembly strings in the include files and we cannot
-   get them easily into strings. */
-asm("\t" __stringify(__INITRODATA_OR_MODULE) "\nintelnops: "
-       GENERIC_NOP1 GENERIC_NOP2 GENERIC_NOP3 GENERIC_NOP4 GENERIC_NOP5 GENERIC_NOP6
-       GENERIC_NOP7 GENERIC_NOP8
-    "\t.previous");
-extern const unsigned char intelnops[];
-static const unsigned char *const __initconst_or_module
-intel_nops[ASM_NOP_MAX+1] = {
+static const unsigned char intelnops[] =
+{
+       GENERIC_NOP1,
+       GENERIC_NOP2,
+       GENERIC_NOP3,
+       GENERIC_NOP4,
+       GENERIC_NOP5,
+       GENERIC_NOP6,
+       GENERIC_NOP7,
+       GENERIC_NOP8,
+       GENERIC_NOP5_ATOMIC
+};
+static const unsigned char * const intel_nops[ASM_NOP_MAX+2] =
+{
        NULL,
        intelnops,
        intelnops + 1,
@@ -87,17 +100,25 @@ intel_nops[ASM_NOP_MAX+1] = {
        intelnops + 1 + 2 + 3 + 4 + 5,
        intelnops + 1 + 2 + 3 + 4 + 5 + 6,
        intelnops + 1 + 2 + 3 + 4 + 5 + 6 + 7,
+       intelnops + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8,
 };
 #endif
 
 #ifdef K8_NOP1
-asm("\t" __stringify(__INITRODATA_OR_MODULE) "\nk8nops: "
-       K8_NOP1 K8_NOP2 K8_NOP3 K8_NOP4 K8_NOP5 K8_NOP6
-       K8_NOP7 K8_NOP8
-    "\t.previous");
-extern const unsigned char k8nops[];
-static const unsigned char *const __initconst_or_module
-k8_nops[ASM_NOP_MAX+1] = {
+static const unsigned char k8nops[] =
+{
+       K8_NOP1,
+       K8_NOP2,
+       K8_NOP3,
+       K8_NOP4,
+       K8_NOP5,
+       K8_NOP6,
+       K8_NOP7,
+       K8_NOP8,
+       K8_NOP5_ATOMIC
+};
+static const unsigned char * const k8_nops[ASM_NOP_MAX+2] =
+{
        NULL,
        k8nops,
        k8nops + 1,
@@ -107,17 +128,25 @@ k8_nops[ASM_NOP_MAX+1] = {
        k8nops + 1 + 2 + 3 + 4 + 5,
        k8nops + 1 + 2 + 3 + 4 + 5 + 6,
        k8nops + 1 + 2 + 3 + 4 + 5 + 6 + 7,
+       k8nops + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8,
 };
 #endif
 
 #if defined(K7_NOP1) && !defined(CONFIG_X86_64)
-asm("\t" __stringify(__INITRODATA_OR_MODULE) "\nk7nops: "
-       K7_NOP1 K7_NOP2 K7_NOP3 K7_NOP4 K7_NOP5 K7_NOP6
-       K7_NOP7 K7_NOP8
-    "\t.previous");
-extern const unsigned char k7nops[];
-static const unsigned char *const __initconst_or_module
-k7_nops[ASM_NOP_MAX+1] = {
+static const unsigned char k7nops[] =
+{
+       K7_NOP1,
+       K7_NOP2,
+       K7_NOP3,
+       K7_NOP4,
+       K7_NOP5,
+       K7_NOP6,
+       K7_NOP7,
+       K7_NOP8,
+       K7_NOP5_ATOMIC
+};
+static const unsigned char * const k7_nops[ASM_NOP_MAX+2] =
+{
        NULL,
        k7nops,
        k7nops + 1,
@@ -127,17 +156,25 @@ k7_nops[ASM_NOP_MAX+1] = {
        k7nops + 1 + 2 + 3 + 4 + 5,
        k7nops + 1 + 2 + 3 + 4 + 5 + 6,
        k7nops + 1 + 2 + 3 + 4 + 5 + 6 + 7,
+       k7nops + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8,
 };
 #endif
 
 #ifdef P6_NOP1
-asm("\t" __stringify(__INITRODATA_OR_MODULE) "\np6nops: "
-       P6_NOP1 P6_NOP2 P6_NOP3 P6_NOP4 P6_NOP5 P6_NOP6
-       P6_NOP7 P6_NOP8
-    "\t.previous");
-extern const unsigned char p6nops[];
-static const unsigned char *const __initconst_or_module
-p6_nops[ASM_NOP_MAX+1] = {
+static const unsigned char  __initconst_or_module p6nops[] =
+{
+       P6_NOP1,
+       P6_NOP2,
+       P6_NOP3,
+       P6_NOP4,
+       P6_NOP5,
+       P6_NOP6,
+       P6_NOP7,
+       P6_NOP8,
+       P6_NOP5_ATOMIC
+};
+static const unsigned char * const p6_nops[ASM_NOP_MAX+2] =
+{
        NULL,
        p6nops,
        p6nops + 1,
@@ -147,47 +184,65 @@ p6_nops[ASM_NOP_MAX+1] = {
        p6nops + 1 + 2 + 3 + 4 + 5,
        p6nops + 1 + 2 + 3 + 4 + 5 + 6,
        p6nops + 1 + 2 + 3 + 4 + 5 + 6 + 7,
+       p6nops + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8,
 };
 #endif
 
+/* Initialize these to a safe default */
 #ifdef CONFIG_X86_64
+const unsigned char * const *ideal_nops = p6_nops;
+#else
+const unsigned char * const *ideal_nops = intel_nops;
+#endif
 
-extern char __vsyscall_0;
-static const unsigned char *const *__init_or_module find_nop_table(void)
+void __init arch_init_ideal_nops(void)
 {
-       if (boot_cpu_data.x86_vendor == X86_VENDOR_INTEL &&
-           boot_cpu_has(X86_FEATURE_NOPL))
-               return p6_nops;
-       else
-               return k8_nops;
-}
-
-#else /* CONFIG_X86_64 */
+       switch (boot_cpu_data.x86_vendor) {
+       case X86_VENDOR_INTEL:
+               /*
+                * Due to a decoder implementation quirk, some
+                * specific Intel CPUs actually perform better with
+                * the "k8_nops" than with the SDM-recommended NOPs.
+                */
+               if (boot_cpu_data.x86 == 6 &&
+                   boot_cpu_data.x86_model >= 0x0f &&
+                   boot_cpu_data.x86_model != 0x1c &&
+                   boot_cpu_data.x86_model != 0x26 &&
+                   boot_cpu_data.x86_model != 0x27 &&
+                   boot_cpu_data.x86_model < 0x30) {
+                       ideal_nops = k8_nops;
+               } else if (boot_cpu_has(X86_FEATURE_NOPL)) {
+                          ideal_nops = p6_nops;
+               } else {
+#ifdef CONFIG_X86_64
+                       ideal_nops = k8_nops;
+#else
+                       ideal_nops = intel_nops;
+#endif
+               }
 
-static const unsigned char *const *__init_or_module find_nop_table(void)
-{
-       if (boot_cpu_has(X86_FEATURE_K8))
-               return k8_nops;
-       else if (boot_cpu_has(X86_FEATURE_K7))
-               return k7_nops;
-       else if (boot_cpu_has(X86_FEATURE_NOPL))
-               return p6_nops;
-       else
-               return intel_nops;
+       default:
+#ifdef CONFIG_X86_64
+               ideal_nops = k8_nops;
+#else
+               if (boot_cpu_has(X86_FEATURE_K8))
+                       ideal_nops = k8_nops;
+               else if (boot_cpu_has(X86_FEATURE_K7))
+                       ideal_nops = k7_nops;
+               else
+                       ideal_nops = intel_nops;
+#endif
+       }
 }
 
-#endif /* CONFIG_X86_64 */
-
 /* Use this to add nops to a buffer, then text_poke the whole buffer. */
 static void __init_or_module add_nops(void *insns, unsigned int len)
 {
-       const unsigned char *const *noptable = find_nop_table();
-
        while (len > 0) {
                unsigned int noplen = len;
                if (noplen > ASM_NOP_MAX)
                        noplen = ASM_NOP_MAX;
-               memcpy(insns, noptable[noplen], noplen);
+               memcpy(insns, ideal_nops[noplen], noplen);
                insns += noplen;
                len -= noplen;
        }
@@ -195,6 +250,7 @@ static void __init_or_module add_nops(void *insns, unsigned int len)
 
 extern struct alt_instr __alt_instructions[], __alt_instructions_end[];
 extern s32 __smp_locks[], __smp_locks_end[];
+extern char __vsyscall_0;
 void *text_poke_early(void *addr, const void *opcode, size_t len);
 
 /* Replace instructions with better alternatives for this CPU type.
@@ -687,29 +743,3 @@ void __kprobes text_poke_smp_batch(struct text_poke_param *params, int n)
        wrote_text = 0;
        __stop_machine(stop_machine_text_poke, (void *)&tpp, NULL);
 }
-
-#if defined(CONFIG_DYNAMIC_FTRACE) || defined(CONFIG_JUMP_LABEL)
-
-#ifdef CONFIG_X86_64
-unsigned char ideal_nop5[5] = { 0x66, 0x66, 0x66, 0x66, 0x90 };
-#else
-unsigned char ideal_nop5[5] = { 0x3e, 0x8d, 0x74, 0x26, 0x00 };
-#endif
-
-void __init arch_init_ideal_nop5(void)
-{
-       /*
-        * There is no good nop for all x86 archs.  This selection
-        * algorithm should be unified with the one in find_nop_table(),
-        * but this should be good enough for now.
-        *
-        * For cases other than the ones below, use the safe (as in
-        * always functional) defaults above.
-        */
-#ifdef CONFIG_X86_64
-       /* Don't use these on 32 bits due to broken virtualizers */
-       if (boot_cpu_data.x86_vendor == X86_VENDOR_INTEL)
-               memcpy(ideal_nop5, p6_nops[5], 5);
-#endif
-}
-#endif
index 57ca777..873e7e1 100644 (file)
@@ -18,6 +18,7 @@
  */
 
 #include <linux/pci.h>
+#include <linux/pci-ats.h>
 #include <linux/bitmap.h>
 #include <linux/slab.h>
 #include <linux/debugfs.h>
@@ -25,6 +26,7 @@
 #include <linux/dma-mapping.h>
 #include <linux/iommu-helper.h>
 #include <linux/iommu.h>
+#include <linux/delay.h>
 #include <asm/proto.h>
 #include <asm/iommu.h>
 #include <asm/gart.h>
@@ -34,7 +36,7 @@
 
 #define CMD_SET_TYPE(cmd, t) ((cmd)->data[1] |= ((t) << 28))
 
-#define EXIT_LOOP_COUNT 10000000
+#define LOOP_TIMEOUT   100000
 
 static DEFINE_RWLOCK(amd_iommu_devtable_lock);
 
@@ -57,7 +59,6 @@ struct iommu_cmd {
        u32 data[4];
 };
 
-static void reset_iommu_command_buffer(struct amd_iommu *iommu);
 static void update_domain(struct protection_domain *domain);
 
 /****************************************************************************
@@ -322,8 +323,6 @@ static void iommu_print_event(struct amd_iommu *iommu, void *__evt)
                break;
        case EVENT_TYPE_ILL_CMD:
                printk("ILLEGAL_COMMAND_ERROR address=0x%016llx]\n", address);
-               iommu->reset_in_progress = true;
-               reset_iommu_command_buffer(iommu);
                dump_command(address);
                break;
        case EVENT_TYPE_CMD_HARD_ERR:
@@ -367,7 +366,7 @@ static void iommu_poll_events(struct amd_iommu *iommu)
        spin_unlock_irqrestore(&iommu->lock, flags);
 }
 
-irqreturn_t amd_iommu_int_handler(int irq, void *data)
+irqreturn_t amd_iommu_int_thread(int irq, void *data)
 {
        struct amd_iommu *iommu;
 
@@ -377,192 +376,300 @@ irqreturn_t amd_iommu_int_handler(int irq, void *data)
        return IRQ_HANDLED;
 }
 
+irqreturn_t amd_iommu_int_handler(int irq, void *data)
+{
+       return IRQ_WAKE_THREAD;
+}
+
 /****************************************************************************
  *
  * IOMMU command queuing functions
  *
  ****************************************************************************/
 
-/*
- * Writes the command to the IOMMUs command buffer and informs the
- * hardware about the new command. Must be called with iommu->lock held.
- */
-static int __iommu_queue_command(struct amd_iommu *iommu, struct iommu_cmd *cmd)
+static int wait_on_sem(volatile u64 *sem)
+{
+       int i = 0;
+
+       while (*sem == 0 && i < LOOP_TIMEOUT) {
+               udelay(1);
+               i += 1;
+       }
+
+       if (i == LOOP_TIMEOUT) {
+               pr_alert("AMD-Vi: Completion-Wait loop timed out\n");
+               return -EIO;
+       }
+
+       return 0;
+}
+
+static void copy_cmd_to_buffer(struct amd_iommu *iommu,
+                              struct iommu_cmd *cmd,
+                              u32 tail)
 {
-       u32 tail, head;
        u8 *target;
 
-       WARN_ON(iommu->cmd_buf_size & CMD_BUFFER_UNINITIALIZED);
-       tail = readl(iommu->mmio_base + MMIO_CMD_TAIL_OFFSET);
        target = iommu->cmd_buf + tail;
-       memcpy_toio(target, cmd, sizeof(*cmd));
-       tail = (tail + sizeof(*cmd)) % iommu->cmd_buf_size;
-       head = readl(iommu->mmio_base + MMIO_CMD_HEAD_OFFSET);
-       if (tail == head)
-               return -ENOMEM;
+       tail   = (tail + sizeof(*cmd)) % iommu->cmd_buf_size;
+
+       /* Copy command to buffer */
+       memcpy(target, cmd, sizeof(*cmd));
+
+       /* Tell the IOMMU about it */
        writel(tail, iommu->mmio_base + MMIO_CMD_TAIL_OFFSET);
+}
 
-       return 0;
+static void build_completion_wait(struct iommu_cmd *cmd, u64 address)
+{
+       WARN_ON(address & 0x7ULL);
+
+       memset(cmd, 0, sizeof(*cmd));
+       cmd->data[0] = lower_32_bits(__pa(address)) | CMD_COMPL_WAIT_STORE_MASK;
+       cmd->data[1] = upper_32_bits(__pa(address));
+       cmd->data[2] = 1;
+       CMD_SET_TYPE(cmd, CMD_COMPL_WAIT);
+}
+
+static void build_inv_dte(struct iommu_cmd *cmd, u16 devid)
+{
+       memset(cmd, 0, sizeof(*cmd));
+       cmd->data[0] = devid;
+       CMD_SET_TYPE(cmd, CMD_INV_DEV_ENTRY);
+}
+
+static void build_inv_iommu_pages(struct iommu_cmd *cmd, u64 address,
+                                 size_t size, u16 domid, int pde)
+{
+       u64 pages;
+       int s;
+
+       pages = iommu_num_pages(address, size, PAGE_SIZE);
+       s     = 0;
+
+       if (pages > 1) {
+               /*
+                * If we have to flush more than one page, flush all
+                * TLB entries for this domain
+                */
+               address = CMD_INV_IOMMU_ALL_PAGES_ADDRESS;
+               s = 1;
+       }
+
+       address &= PAGE_MASK;
+
+       memset(cmd, 0, sizeof(*cmd));
+       cmd->data[1] |= domid;
+       cmd->data[2]  = lower_32_bits(address);
+       cmd->data[3]  = upper_32_bits(address);
+       CMD_SET_TYPE(cmd, CMD_INV_IOMMU_PAGES);
+       if (s) /* size bit - we flush more than one 4kb page */
+               cmd->data[2] |= CMD_INV_IOMMU_PAGES_SIZE_MASK;
+       if (pde) /* PDE bit - we wan't flush everything not only the PTEs */
+               cmd->data[2] |= CMD_INV_IOMMU_PAGES_PDE_MASK;
+}
+
+static void build_inv_iotlb_pages(struct iommu_cmd *cmd, u16 devid, int qdep,
+                                 u64 address, size_t size)
+{
+       u64 pages;
+       int s;
+
+       pages = iommu_num_pages(address, size, PAGE_SIZE);
+       s     = 0;
+
+       if (pages > 1) {
+               /*
+                * If we have to flush more than one page, flush all
+                * TLB entries for this domain
+                */
+               address = CMD_INV_IOMMU_ALL_PAGES_ADDRESS;
+               s = 1;
+       }
+
+       address &= PAGE_MASK;
+
+       memset(cmd, 0, sizeof(*cmd));
+       cmd->data[0]  = devid;
+       cmd->data[0] |= (qdep & 0xff) << 24;
+       cmd->data[1]  = devid;
+       cmd->data[2]  = lower_32_bits(address);
+       cmd->data[3]  = upper_32_bits(address);
+       CMD_SET_TYPE(cmd, CMD_INV_IOTLB_PAGES);
+       if (s)
+               cmd->data[2] |= CMD_INV_IOMMU_PAGES_SIZE_MASK;
+}
+
+static void build_inv_all(struct iommu_cmd *cmd)
+{
+       memset(cmd, 0, sizeof(*cmd));
+       CMD_SET_TYPE(cmd, CMD_INV_ALL);
 }
 
 /*
- * General queuing function for commands. Takes iommu->lock and calls
- * __iommu_queue_command().
+ * Writes the command to the IOMMUs command buffer and informs the
+ * hardware about the new command.
  */
 static int iommu_queue_command(struct amd_iommu *iommu, struct iommu_cmd *cmd)
 {
+       u32 left, tail, head, next_tail;
        unsigned long flags;
-       int ret;
 
+       WARN_ON(iommu->cmd_buf_size & CMD_BUFFER_UNINITIALIZED);
+
+again:
        spin_lock_irqsave(&iommu->lock, flags);
-       ret = __iommu_queue_command(iommu, cmd);
-       if (!ret)
-               iommu->need_sync = true;
-       spin_unlock_irqrestore(&iommu->lock, flags);
 
-       return ret;
-}
+       head      = readl(iommu->mmio_base + MMIO_CMD_HEAD_OFFSET);
+       tail      = readl(iommu->mmio_base + MMIO_CMD_TAIL_OFFSET);
+       next_tail = (tail + sizeof(*cmd)) % iommu->cmd_buf_size;
+       left      = (head - next_tail) % iommu->cmd_buf_size;
 
-/*
- * This function waits until an IOMMU has completed a completion
- * wait command
- */
-static void __iommu_wait_for_completion(struct amd_iommu *iommu)
-{
-       int ready = 0;
-       unsigned status = 0;
-       unsigned long i = 0;
+       if (left <= 2) {
+               struct iommu_cmd sync_cmd;
+               volatile u64 sem = 0;
+               int ret;
 
-       INC_STATS_COUNTER(compl_wait);
+               build_completion_wait(&sync_cmd, (u64)&sem);
+               copy_cmd_to_buffer(iommu, &sync_cmd, tail);
 
-       while (!ready && (i < EXIT_LOOP_COUNT)) {
-               ++i;
-               /* wait for the bit to become one */
-               status = readl(iommu->mmio_base + MMIO_STATUS_OFFSET);
-               ready = status & MMIO_STATUS_COM_WAIT_INT_MASK;
+               spin_unlock_irqrestore(&iommu->lock, flags);
+
+               if ((ret = wait_on_sem(&sem)) != 0)
+                       return ret;
+
+               goto again;
        }
 
-       /* set bit back to zero */
-       status &= ~MMIO_STATUS_COM_WAIT_INT_MASK;
-       writel(status, iommu->mmio_base + MMIO_STATUS_OFFSET);
+       copy_cmd_to_buffer(iommu, cmd, tail);
+
+       /* We need to sync now to make sure all commands are processed */
+       iommu->need_sync = true;
+
+       spin_unlock_irqrestore(&iommu->lock, flags);
 
-       if (unlikely(i == EXIT_LOOP_COUNT))
-               iommu->reset_in_progress = true;
+       return 0;
 }
 
 /*
  * This function queues a completion wait command into the command
  * buffer of an IOMMU
  */
-static int __iommu_completion_wait(struct amd_iommu *iommu)
+static int iommu_completion_wait(struct amd_iommu *iommu)
 {
        struct iommu_cmd cmd;
+       volatile u64 sem = 0;
+       int ret;
 
-        memset(&cmd, 0, sizeof(cmd));
-        cmd.data[0] = CMD_COMPL_WAIT_INT_MASK;
-        CMD_SET_TYPE(&cmd, CMD_COMPL_WAIT);
+       if (!iommu->need_sync)
+               return 0;
 
-        return __iommu_queue_command(iommu, &cmd);
+       build_completion_wait(&cmd, (u64)&sem);
+
+       ret = iommu_queue_command(iommu, &cmd);
+       if (ret)
+               return ret;
+
+       return wait_on_sem(&sem);
 }
 
-/*
- * This function is called whenever we need to ensure that the IOMMU has
- * completed execution of all commands we sent. It sends a
- * COMPLETION_WAIT command and waits for it to finish. The IOMMU informs
- * us about that by writing a value to a physical address we pass with
- * the command.
- */
-static int iommu_completion_wait(struct amd_iommu *iommu)
+static int iommu_flush_dte(struct amd_iommu *iommu, u16 devid)
 {
-       int ret = 0;
-       unsigned long flags;
+       struct iommu_cmd cmd;
 
-       spin_lock_irqsave(&iommu->lock, flags);
+       build_inv_dte(&cmd, devid);
 
-       if (!iommu->need_sync)
-               goto out;
+       return iommu_queue_command(iommu, &cmd);
+}
 
-       ret = __iommu_completion_wait(iommu);
+static void iommu_flush_dte_all(struct amd_iommu *iommu)
+{
+       u32 devid;
 
-       iommu->need_sync = false;
+       for (devid = 0; devid <= 0xffff; ++devid)
+               iommu_flush_dte(iommu, devid);
 
-       if (ret)
-               goto out;
-
-       __iommu_wait_for_completion(iommu);
+       iommu_completion_wait(iommu);
+}
 
-out:
-       spin_unlock_irqrestore(&iommu->lock, flags);
+/*
+ * This function uses heavy locking and may disable irqs for some time. But
+ * this is no issue because it is only called during resume.
+ */
+static void iommu_flush_tlb_all(struct amd_iommu *iommu)
+{
+       u32 dom_id;
 
-       if (iommu->reset_in_progress)
-               reset_iommu_command_buffer(iommu);
+       for (dom_id = 0; dom_id <= 0xffff; ++dom_id) {
+               struct iommu_cmd cmd;
+               build_inv_iommu_pages(&cmd, 0, CMD_INV_IOMMU_ALL_PAGES_ADDRESS,
+                                     dom_id, 1);
+               iommu_queue_command(iommu, &cmd);
+       }
 
-       return 0;
+       iommu_completion_wait(iommu);
 }
 
-static void iommu_flush_complete(struct protection_domain *domain)
+static void iommu_flush_all(struct amd_iommu *iommu)
 {
-       int i;
+       struct iommu_cmd cmd;
 
-       for (i = 0; i < amd_iommus_present; ++i) {
-               if (!domain->dev_iommu[i])
-                       continue;
+       build_inv_all(&cmd);
 
-               /*
-                * Devices of this domain are behind this IOMMU
-                * We need to wait for completion of all commands.
-                */
-               iommu_completion_wait(amd_iommus[i]);
+       iommu_queue_command(iommu, &cmd);
+       iommu_completion_wait(iommu);
+}
+
+void iommu_flush_all_caches(struct amd_iommu *iommu)
+{
+       if (iommu_feature(iommu, FEATURE_IA)) {
+               iommu_flush_all(iommu);
+       } else {
+               iommu_flush_dte_all(iommu);
+               iommu_flush_tlb_all(iommu);
        }
 }
 
 /*
- * Command send function for invalidating a device table entry
+ * Command send function for flushing on-device TLB
  */
-static int iommu_flush_device(struct device *dev)
+static int device_flush_iotlb(struct device *dev, u64 address, size_t size)
 {
+       struct pci_dev *pdev = to_pci_dev(dev);
        struct amd_iommu *iommu;
        struct iommu_cmd cmd;
        u16 devid;
+       int qdep;
 
+       qdep  = pci_ats_queue_depth(pdev);
        devid = get_device_id(dev);
        iommu = amd_iommu_rlookup_table[devid];
 
-       /* Build command */
-       memset(&cmd, 0, sizeof(cmd));
-       CMD_SET_TYPE(&cmd, CMD_INV_DEV_ENTRY);
-       cmd.data[0] = devid;
+       build_inv_iotlb_pages(&cmd, devid, qdep, address, size);
 
        return iommu_queue_command(iommu, &cmd);
 }
 
-static void __iommu_build_inv_iommu_pages(struct iommu_cmd *cmd, u64 address,
-                                         u16 domid, int pde, int s)
-{
-       memset(cmd, 0, sizeof(*cmd));
-       address &= PAGE_MASK;
-       CMD_SET_TYPE(cmd, CMD_INV_IOMMU_PAGES);
-       cmd->data[1] |= domid;
-       cmd->data[2] = lower_32_bits(address);
-       cmd->data[3] = upper_32_bits(address);
-       if (s) /* size bit - we flush more than one 4kb page */
-               cmd->data[2] |= CMD_INV_IOMMU_PAGES_SIZE_MASK;
-       if (pde) /* PDE bit - we wan't flush everything not only the PTEs */
-               cmd->data[2] |= CMD_INV_IOMMU_PAGES_PDE_MASK;
-}
-
 /*
- * Generic command send function for invalidaing TLB entries
+ * Command send function for invalidating a device table entry
  */
-static int iommu_queue_inv_iommu_pages(struct amd_iommu *iommu,
-               u64 address, u16 domid, int pde, int s)
+static int device_flush_dte(struct device *dev)
 {
-       struct iommu_cmd cmd;
+       struct amd_iommu *iommu;
+       struct pci_dev *pdev;
+       u16 devid;
        int ret;
 
-       __iommu_build_inv_iommu_pages(&cmd, address, domid, pde, s);
+       pdev  = to_pci_dev(dev);
+       devid = get_device_id(dev);
+       iommu = amd_iommu_rlookup_table[devid];
 
-       ret = iommu_queue_command(iommu, &cmd);
+       ret = iommu_flush_dte(iommu, devid);
+       if (ret)
+               return ret;
+
+       if (pci_ats_enabled(pdev))
+               ret = device_flush_iotlb(dev, 0, ~0UL);
 
        return ret;
 }
@@ -572,23 +679,14 @@ static int iommu_queue_inv_iommu_pages(struct amd_iommu *iommu,
  * It invalidates a single PTE if the range to flush is within a single
  * page. Otherwise it flushes the whole TLB of the IOMMU.
  */
-static void __iommu_flush_pages(struct protection_domain *domain,
-                               u64 address, size_t size, int pde)
+static void __domain_flush_pages(struct protection_domain *domain,
+                                u64 address, size_t size, int pde)
 {
-       int s = 0, i;
-       unsigned long pages = iommu_num_pages(address, size, PAGE_SIZE);
-
-       address &= PAGE_MASK;
-
-       if (pages > 1) {
-               /*
-                * If we have to flush more than one page, flush all
-                * TLB entries for this domain
-                */
-               address = CMD_INV_IOMMU_ALL_PAGES_ADDRESS;
-               s = 1;
-       }
+       struct iommu_dev_data *dev_data;
+       struct iommu_cmd cmd;
+       int ret = 0, i;
 
+       build_inv_iommu_pages(&cmd, address, size, domain->id, pde);
 
        for (i = 0; i < amd_iommus_present; ++i) {
                if (!domain->dev_iommu[i])
@@ -598,101 +696,70 @@ static void __iommu_flush_pages(struct protection_domain *domain,
                 * Devices of this domain are behind this IOMMU
                 * We need a TLB flush
                 */
-               iommu_queue_inv_iommu_pages(amd_iommus[i], address,
-                                           domain->id, pde, s);
+               ret |= iommu_queue_command(amd_iommus[i], &cmd);
+       }
+
+       list_for_each_entry(dev_data, &domain->dev_list, list) {
+               struct pci_dev *pdev = to_pci_dev(dev_data->dev);
+
+               if (!pci_ats_enabled(pdev))
+                       continue;
+
+               ret |= device_flush_iotlb(dev_data->dev, address, size);
        }
 
-       return;
+       WARN_ON(ret);
 }
 
-static void iommu_flush_pages(struct protection_domain *domain,
-                            u64 address, size_t size)
+static void domain_flush_pages(struct protection_domain *domain,
+                              u64 address, size_t size)
 {
-       __iommu_flush_pages(domain, address, size, 0);
+       __domain_flush_pages(domain, address, size, 0);
 }
 
 /* Flush the whole IO/TLB for a given protection domain */
-static void iommu_flush_tlb(struct protection_domain *domain)
+static void domain_flush_tlb(struct protection_domain *domain)
 {
-       __iommu_flush_pages(domain, 0, CMD_INV_IOMMU_ALL_PAGES_ADDRESS, 0);
+       __domain_flush_pages(domain, 0, CMD_INV_IOMMU_ALL_PAGES_ADDRESS, 0);
 }
 
 /* Flush the whole IO/TLB for a given protection domain - including PDE */
-static void iommu_flush_tlb_pde(struct protection_domain *domain)
+static void domain_flush_tlb_pde(struct protection_domain *domain)
 {
-       __iommu_flush_pages(domain, 0, CMD_INV_IOMMU_ALL_PAGES_ADDRESS, 1);
-}
-
-
-/*
- * This function flushes the DTEs for all devices in domain
- */
-static void iommu_flush_domain_devices(struct protection_domain *domain)
-{
-       struct iommu_dev_data *dev_data;
-       unsigned long flags;
-
-       spin_lock_irqsave(&domain->lock, flags);
-
-       list_for_each_entry(dev_data, &domain->dev_list, list)
-               iommu_flush_device(dev_data->dev);
-
-       spin_unlock_irqrestore(&domain->lock, flags);
+       __domain_flush_pages(domain, 0, CMD_INV_IOMMU_ALL_PAGES_ADDRESS, 1);
 }
 
-static void iommu_flush_all_domain_devices(void)
+static void domain_flush_complete(struct protection_domain *domain)
 {
-       struct protection_domain *domain;
-       unsigned long flags;
+       int i;
 
-       spin_lock_irqsave(&amd_iommu_pd_lock, flags);
+       for (i = 0; i < amd_iommus_present; ++i) {
+               if (!domain->dev_iommu[i])
+                       continue;
 
-       list_for_each_entry(domain, &amd_iommu_pd_list, list) {
-               iommu_flush_domain_devices(domain);
-               iommu_flush_complete(domain);
+               /*
+                * Devices of this domain are behind this IOMMU
+                * We need to wait for completion of all commands.
+                */
+               iommu_completion_wait(amd_iommus[i]);
        }
-
-       spin_unlock_irqrestore(&amd_iommu_pd_lock, flags);
 }
 
-void amd_iommu_flush_all_devices(void)
-{
-       iommu_flush_all_domain_devices();
-}
 
 /*
- * This function uses heavy locking and may disable irqs for some time. But
- * this is no issue because it is only called during resume.
+ * This function flushes the DTEs for all devices in domain
  */
-void amd_iommu_flush_all_domains(void)
+static void domain_flush_devices(struct protection_domain *domain)
 {
-       struct protection_domain *domain;
+       struct iommu_dev_data *dev_data;
        unsigned long flags;
 
-       spin_lock_irqsave(&amd_iommu_pd_lock, flags);
-
-       list_for_each_entry(domain, &amd_iommu_pd_list, list) {
-               spin_lock(&domain->lock);
-               iommu_flush_tlb_pde(domain);
-               iommu_flush_complete(domain);
-               spin_unlock(&domain->lock);
-       }
-
-       spin_unlock_irqrestore(&amd_iommu_pd_lock, flags);
-}
-
-static void reset_iommu_command_buffer(struct amd_iommu *iommu)
-{
-       pr_err("AMD-Vi: Resetting IOMMU command buffer\n");
-
-       if (iommu->reset_in_progress)
-               panic("AMD-Vi: ILLEGAL_COMMAND_ERROR while resetting command buffer\n");
+       spin_lock_irqsave(&domain->lock, flags);
 
-       amd_iommu_reset_cmd_buffer(iommu);
-       amd_iommu_flush_all_devices();
-       amd_iommu_flush_all_domains();
+       list_for_each_entry(dev_data, &domain->dev_list, list)
+               device_flush_dte(dev_data->dev);
 
-       iommu->reset_in_progress = false;
+       spin_unlock_irqrestore(&domain->lock, flags);
 }
 
 /****************************************************************************
@@ -1410,17 +1477,22 @@ static bool dma_ops_domain(struct protection_domain *domain)
        return domain->flags & PD_DMA_OPS_MASK;
 }
 
-static void set_dte_entry(u16 devid, struct protection_domain *domain)
+static void set_dte_entry(u16 devid, struct protection_domain *domain, bool ats)
 {
        u64 pte_root = virt_to_phys(domain->pt_root);
+       u32 flags = 0;
 
        pte_root |= (domain->mode & DEV_ENTRY_MODE_MASK)
                    << DEV_ENTRY_MODE_SHIFT;
        pte_root |= IOMMU_PTE_IR | IOMMU_PTE_IW | IOMMU_PTE_P | IOMMU_PTE_TV;
 
-       amd_iommu_dev_table[devid].data[2] = domain->id;
-       amd_iommu_dev_table[devid].data[1] = upper_32_bits(pte_root);
-       amd_iommu_dev_table[devid].data[0] = lower_32_bits(pte_root);
+       if (ats)
+               flags |= DTE_FLAG_IOTLB;
+
+       amd_iommu_dev_table[devid].data[3] |= flags;
+       amd_iommu_dev_table[devid].data[2]  = domain->id;
+       amd_iommu_dev_table[devid].data[1]  = upper_32_bits(pte_root);
+       amd_iommu_dev_table[devid].data[0]  = lower_32_bits(pte_root);
 }
 
 static void clear_dte_entry(u16 devid)
@@ -1437,34 +1509,42 @@ static void do_attach(struct device *dev, struct protection_domain *domain)
 {
        struct iommu_dev_data *dev_data;
        struct amd_iommu *iommu;
+       struct pci_dev *pdev;
+       bool ats = false;
        u16 devid;
 
        devid    = get_device_id(dev);
        iommu    = amd_iommu_rlookup_table[devid];
        dev_data = get_dev_data(dev);
+       pdev     = to_pci_dev(dev);
+
+       if (amd_iommu_iotlb_sup)
+               ats = pci_ats_enabled(pdev);
 
        /* Update data structures */
        dev_data->domain = domain;
        list_add(&dev_data->list, &domain->dev_list);
-       set_dte_entry(devid, domain);
+       set_dte_entry(devid, domain, ats);
 
        /* Do reference counting */
        domain->dev_iommu[iommu->index] += 1;
        domain->dev_cnt                 += 1;
 
        /* Flush the DTE entry */
-       iommu_flush_device(dev);
+       device_flush_dte(dev);
 }
 
 static void do_detach(struct device *dev)
 {
        struct iommu_dev_data *dev_data;
        struct amd_iommu *iommu;
+       struct pci_dev *pdev;
        u16 devid;
 
        devid    = get_device_id(dev);
        iommu    = amd_iommu_rlookup_table[devid];
        dev_data = get_dev_data(dev);
+       pdev     = to_pci_dev(dev);
 
        /* decrease reference counters */
        dev_data->domain->dev_iommu[iommu->index] -= 1;
@@ -1476,7 +1556,7 @@ static void do_detach(struct device *dev)
        clear_dte_entry(devid);
 
        /* Flush the DTE entry */
-       iommu_flush_device(dev);
+       device_flush_dte(dev);
 }
 
 /*
@@ -1539,9 +1619,13 @@ out_unlock:
 static int attach_device(struct device *dev,
                         struct protection_domain *domain)
 {
+       struct pci_dev *pdev = to_pci_dev(dev);
        unsigned long flags;
        int ret;
 
+       if (amd_iommu_iotlb_sup)
+               pci_enable_ats(pdev, PAGE_SHIFT);
+
        write_lock_irqsave(&amd_iommu_devtable_lock, flags);
        ret = __attach_device(dev, domain);
        write_unlock_irqrestore(&amd_iommu_devtable_lock, flags);
@@ -1551,7 +1635,7 @@ static int attach_device(struct device *dev,
         * left the caches in the IOMMU dirty. So we have to flush
         * here to evict all dirty stuff.
         */
-       iommu_flush_tlb_pde(domain);
+       domain_flush_tlb_pde(domain);
 
        return ret;
 }
@@ -1598,12 +1682,16 @@ static void __detach_device(struct device *dev)
  */
 static void detach_device(struct device *dev)
 {
+       struct pci_dev *pdev = to_pci_dev(dev);
        unsigned long flags;
 
        /* lock device table */
        write_lock_irqsave(&amd_iommu_devtable_lock, flags);
        __detach_device(dev);
        write_unlock_irqrestore(&amd_iommu_devtable_lock, flags);
+
+       if (amd_iommu_iotlb_sup && pci_ats_enabled(pdev))
+               pci_disable_ats(pdev);
 }
 
 /*
@@ -1692,7 +1780,7 @@ static int device_change_notifier(struct notifier_block *nb,
                goto out;
        }
 
-       iommu_flush_device(dev);
+       device_flush_dte(dev);
        iommu_completion_wait(iommu);
 
 out:
@@ -1753,8 +1841,9 @@ static void update_device_table(struct protection_domain *domain)
        struct iommu_dev_data *dev_data;
 
        list_for_each_entry(dev_data, &domain->dev_list, list) {
+               struct pci_dev *pdev = to_pci_dev(dev_data->dev);
                u16 devid = get_device_id(dev_data->dev);
-               set_dte_entry(devid, domain);
+               set_dte_entry(devid, domain, pci_ats_enabled(pdev));
        }
 }
 
@@ -1764,8 +1853,9 @@ static void update_domain(struct protection_domain *domain)
                return;
 
        update_device_table(domain);
-       iommu_flush_domain_devices(domain);
-       iommu_flush_tlb_pde(domain);
+
+       domain_flush_devices(domain);
+       domain_flush_tlb_pde(domain);
 
        domain->updated = false;
 }
@@ -1924,10 +2014,10 @@ retry:
        ADD_STATS_COUNTER(alloced_io_mem, size);
 
        if (unlikely(dma_dom->need_flush && !amd_iommu_unmap_flush)) {
-               iommu_flush_tlb(&dma_dom->domain);
+               domain_flush_tlb(&dma_dom->domain);
                dma_dom->need_flush = false;
        } else if (unlikely(amd_iommu_np_cache))
-               iommu_flush_pages(&dma_dom->domain, address, size);
+               domain_flush_pages(&dma_dom->domain, address, size);
 
 out:
        return address;
@@ -1976,7 +2066,7 @@ static void __unmap_single(struct dma_ops_domain *dma_dom,
        dma_ops_free_addresses(dma_dom, dma_addr, pages);
 
        if (amd_iommu_unmap_flush || dma_dom->need_flush) {
-               iommu_flush_pages(&dma_dom->domain, flush_addr, size);
+               domain_flush_pages(&dma_dom->domain, flush_addr, size);
                dma_dom->need_flush = false;
        }
 }
@@ -2012,7 +2102,7 @@ static dma_addr_t map_page(struct device *dev, struct page *page,
        if (addr == DMA_ERROR_CODE)
                goto out;
 
-       iommu_flush_complete(domain);
+       domain_flush_complete(domain);
 
 out:
        spin_unlock_irqrestore(&domain->lock, flags);
@@ -2039,7 +2129,7 @@ static void unmap_page(struct device *dev, dma_addr_t dma_addr, size_t size,
 
        __unmap_single(domain->priv, dma_addr, size, dir);
 
-       iommu_flush_complete(domain);
+       domain_flush_complete(domain);
 
        spin_unlock_irqrestore(&domain->lock, flags);
 }
@@ -2104,7 +2194,7 @@ static int map_sg(struct device *dev, struct scatterlist *sglist,
                        goto unmap;
        }
 
-       iommu_flush_complete(domain);
+       domain_flush_complete(domain);
 
 out:
        spin_unlock_irqrestore(&domain->lock, flags);
@@ -2150,7 +2240,7 @@ static void unmap_sg(struct device *dev, struct scatterlist *sglist,
                s->dma_address = s->dma_length = 0;
        }
 
-       iommu_flush_complete(domain);
+       domain_flush_complete(domain);
 
        spin_unlock_irqrestore(&domain->lock, flags);
 }
@@ -2200,7 +2290,7 @@ static void *alloc_coherent(struct device *dev, size_t size,
                goto out_free;
        }
 
-       iommu_flush_complete(domain);
+       domain_flush_complete(domain);
 
        spin_unlock_irqrestore(&domain->lock, flags);
 
@@ -2232,7 +2322,7 @@ static void free_coherent(struct device *dev, size_t size,
 
        __unmap_single(domain->priv, dma_addr, size, DMA_BIDIRECTIONAL);
 
-       iommu_flush_complete(domain);
+       domain_flush_complete(domain);
 
        spin_unlock_irqrestore(&domain->lock, flags);
 
@@ -2476,7 +2566,7 @@ static void amd_iommu_detach_device(struct iommu_domain *dom,
        if (!iommu)
                return;
 
-       iommu_flush_device(dev);
+       device_flush_dte(dev);
        iommu_completion_wait(iommu);
 }
 
@@ -2542,7 +2632,7 @@ static int amd_iommu_unmap(struct iommu_domain *dom, unsigned long iova,
        unmap_size = iommu_unmap_page(domain, iova, page_size);
        mutex_unlock(&domain->api_lock);
 
-       iommu_flush_tlb_pde(domain);
+       domain_flush_tlb_pde(domain);
 
        return get_order(unmap_size);
 }
index 246d727..9179c21 100644 (file)
@@ -137,6 +137,7 @@ int amd_iommus_present;
 
 /* IOMMUs have a non-present cache? */
 bool amd_iommu_np_cache __read_mostly;
+bool amd_iommu_iotlb_sup __read_mostly = true;
 
 /*
  * The ACPI table parsing functions set this variable on an error
@@ -180,6 +181,12 @@ static u32 dev_table_size; /* size of the device table */
 static u32 alias_table_size;   /* size of the alias table */
 static u32 rlookup_table_size; /* size if the rlookup table */
 
+/*
+ * This function flushes all internal caches of
+ * the IOMMU used by this driver.
+ */
+extern void iommu_flush_all_caches(struct amd_iommu *iommu);
+
 static inline void update_last_devid(u16 devid)
 {
        if (devid > amd_iommu_last_bdf)
@@ -293,9 +300,23 @@ static void iommu_feature_disable(struct amd_iommu *iommu, u8 bit)
 /* Function to enable the hardware */
 static void iommu_enable(struct amd_iommu *iommu)
 {
-       printk(KERN_INFO "AMD-Vi: Enabling IOMMU at %s cap 0x%hx\n",
+       static const char * const feat_str[] = {
+               "PreF", "PPR", "X2APIC", "NX", "GT", "[5]",
+               "IA", "GA", "HE", "PC", NULL
+       };
+       int i;
+
+       printk(KERN_INFO "AMD-Vi: Enabling IOMMU at %s cap 0x%hx",
               dev_name(&iommu->dev->dev), iommu->cap_ptr);
 
+       if (iommu->cap & (1 << IOMMU_CAP_EFR)) {
+               printk(KERN_CONT " extended features: ");
+               for (i = 0; feat_str[i]; ++i)
+                       if (iommu_feature(iommu, (1ULL << i)))
+                               printk(KERN_CONT " %s", feat_str[i]);
+       }
+       printk(KERN_CONT "\n");
+
        iommu_feature_enable(iommu, CONTROL_IOMMU_EN);
 }
 
@@ -651,7 +672,7 @@ static void __init set_device_exclusion_range(u16 devid, struct ivmd_header *m)
 static void __init init_iommu_from_pci(struct amd_iommu *iommu)
 {
        int cap_ptr = iommu->cap_ptr;
-       u32 range, misc;
+       u32 range, misc, low, high;
        int i, j;
 
        pci_read_config_dword(iommu->dev, cap_ptr + MMIO_CAP_HDR_OFFSET,
@@ -667,6 +688,15 @@ static void __init init_iommu_from_pci(struct amd_iommu *iommu)
                                        MMIO_GET_LD(range));
        iommu->evt_msi_num = MMIO_MSI_NUM(misc);
 
+       if (!(iommu->cap & (1 << IOMMU_CAP_IOTLB)))
+               amd_iommu_iotlb_sup = false;
+
+       /* read extended feature bits */
+       low  = readl(iommu->mmio_base + MMIO_EXT_FEATURES);
+       high = readl(iommu->mmio_base + MMIO_EXT_FEATURES + 4);
+
+       iommu->features = ((u64)high << 32) | low;
+
        if (!is_rd890_iommu(iommu->dev))
                return;
 
@@ -1004,10 +1034,11 @@ static int iommu_setup_msi(struct amd_iommu *iommu)
        if (pci_enable_msi(iommu->dev))
                return 1;
 
-       r = request_irq(iommu->dev->irq, amd_iommu_int_handler,
-                       IRQF_SAMPLE_RANDOM,
-                       "AMD-Vi",
-                       NULL);
+       r = request_threaded_irq(iommu->dev->irq,
+                                amd_iommu_int_handler,
+                                amd_iommu_int_thread,
+                                0, "AMD-Vi",
+                                iommu->dev);
 
        if (r) {
                pci_disable_msi(iommu->dev);
@@ -1244,6 +1275,7 @@ static void enable_iommus(void)
                iommu_set_exclusion_range(iommu);
                iommu_init_msi(iommu);
                iommu_enable(iommu);
+               iommu_flush_all_caches(iommu);
        }
 }
 
@@ -1274,8 +1306,8 @@ static void amd_iommu_resume(void)
         * we have to flush after the IOMMUs are enabled because a
         * disabled IOMMU will never execute the commands we send
         */
-       amd_iommu_flush_all_devices();
-       amd_iommu_flush_all_domains();
+       for_each_iommu(iommu)
+               iommu_flush_all_caches(iommu);
 }
 
 static int amd_iommu_suspend(void)
index cd1ffed..289e928 100644 (file)
@@ -177,7 +177,6 @@ static struct clocksource clocksource_apbt = {
        .rating         = APBT_CLOCKSOURCE_RATING,
        .read           = apbt_read_clocksource,
        .mask           = APBT_MASK,
-       .shift          = APBT_SHIFT,
        .flags          = CLOCK_SOURCE_IS_CONTINUOUS,
        .resume         = apbt_restart_clocksource,
 };
@@ -543,14 +542,7 @@ static int apbt_clocksource_register(void)
        if (t1 == apbt_read_clocksource(&clocksource_apbt))
                panic("APBT counter not counting. APBT disabled\n");
 
-       /*
-        * initialize and register APBT clocksource
-        * convert that to ns/clock cycle
-        * mult = (ns/c) * 2^APBT_SHIFT
-        */
-       clocksource_apbt.mult = div_sc(MSEC_PER_SEC,
-                                      (unsigned long) apbt_freq, APBT_SHIFT);
-       clocksource_register(&clocksource_apbt);
+       clocksource_register_khz(&clocksource_apbt, (u32)apbt_freq*1000);
 
        return 0;
 }
index 73fb469..3d2661c 100644 (file)
 #include <asm/amd_nb.h>
 #include <asm/x86_init.h>
 
+/*
+ * Using 512M as goal, in case kexec will load kernel_big
+ * that will do the on-position decompress, and could overlap with
+ * with the gart aperture that is used.
+ * Sequence:
+ * kernel_small
+ * ==> kexec (with kdump trigger path or gart still enabled)
+ * ==> kernel_small (gart area become e820_reserved)
+ * ==> kexec (with kdump trigger path or gart still enabled)
+ * ==> kerne_big (uncompressed size will be big than 64M or 128M)
+ * So don't use 512M below as gart iommu, leave the space for kernel
+ * code for safe.
+ */
+#define GART_MIN_ADDR  (512ULL << 20)
+#define GART_MAX_ADDR  (1ULL   << 32)
+
 int gart_iommu_aperture;
 int gart_iommu_aperture_disabled __initdata;
 int gart_iommu_aperture_allowed __initdata;
@@ -70,21 +86,9 @@ static u32 __init allocate_aperture(void)
         * memory. Unfortunately we cannot move it up because that would
         * make the IOMMU useless.
         */
-       /*
-        * using 512M as goal, in case kexec will load kernel_big
-        * that will do the on position decompress, and  could overlap with
-        * that position with gart that is used.
-        * sequende:
-        * kernel_small
-        * ==> kexec (with kdump trigger path or previous doesn't shutdown gart)
-        * ==> kernel_small(gart area become e820_reserved)
-        * ==> kexec (with kdump trigger path or previous doesn't shutdown gart)
-        * ==> kerne_big (uncompressed size will be big than 64M or 128M)
-        * so don't use 512M below as gart iommu, leave the space for kernel
-        * code for safe
-        */
-       addr = memblock_find_in_range(0, 1ULL<<32, aper_size, 512ULL<<20);
-       if (addr == MEMBLOCK_ERROR || addr + aper_size > 0xffffffff) {
+       addr = memblock_find_in_range(GART_MIN_ADDR, GART_MAX_ADDR,
+                                     aper_size, aper_size);
+       if (addr == MEMBLOCK_ERROR || addr + aper_size > GART_MAX_ADDR) {
                printk(KERN_ERR
                        "Cannot allocate aperture memory hole (%lx,%uK)\n",
                                addr, aper_size>>10);
index fabf01e..f92a8e5 100644 (file)
@@ -505,7 +505,7 @@ static void __cpuinit setup_APIC_timer(void)
 {
        struct clock_event_device *levt = &__get_cpu_var(lapic_events);
 
-       if (cpu_has(__this_cpu_ptr(&cpu_info), X86_FEATURE_ARAT)) {
+       if (this_cpu_has(X86_FEATURE_ARAT)) {
                lapic_clockevent.features &= ~CLOCK_EVT_FEAT_C3STOP;
                /* Make LAPIC timer preferrable over percpu HPET */
                lapic_clockevent.rating = 150;
@@ -1237,6 +1237,17 @@ void __cpuinit setup_local_APIC(void)
        /* always use the value from LDR */
        early_per_cpu(x86_cpu_to_logical_apicid, cpu) =
                logical_smp_processor_id();
+
+       /*
+        * Some NUMA implementations (NUMAQ) don't initialize apicid to
+        * node mapping during NUMA init.  Now that logical apicid is
+        * guaranteed to be known, give it another chance.  This is already
+        * a bit too late - percpu allocation has already happened without
+        * proper NUMA affinity.
+        */
+       if (apic->x86_32_numa_cpu_node)
+               set_apicid_to_node(early_per_cpu(x86_cpu_to_apicid, cpu),
+                                  apic->x86_32_numa_cpu_node(cpu));
 #endif
 
        /*
@@ -1812,30 +1823,41 @@ void smp_spurious_interrupt(struct pt_regs *regs)
  */
 void smp_error_interrupt(struct pt_regs *regs)
 {
-       u32 v, v1;
+       u32 v0, v1;
+       u32 i = 0;
+       static const char * const error_interrupt_reason[] = {
+               "Send CS error",                /* APIC Error Bit 0 */
+               "Receive CS error",             /* APIC Error Bit 1 */
+               "Send accept error",            /* APIC Error Bit 2 */
+               "Receive accept error",         /* APIC Error Bit 3 */
+               "Redirectable IPI",             /* APIC Error Bit 4 */
+               "Send illegal vector",          /* APIC Error Bit 5 */
+               "Received illegal vector",      /* APIC Error Bit 6 */
+               "Illegal register address",     /* APIC Error Bit 7 */
+       };
 
        exit_idle();
        irq_enter();
        /* First tickle the hardware, only then report what went on. -- REW */
-       v = apic_read(APIC_ESR);
+       v0 = apic_read(APIC_ESR);
        apic_write(APIC_ESR, 0);
        v1 = apic_read(APIC_ESR);
        ack_APIC_irq();
        atomic_inc(&irq_err_count);
 
-       /*
-        * Here is what the APIC error bits mean:
-        * 0: Send CS error
-        * 1: Receive CS error
-        * 2: Send accept error
-        * 3: Receive accept error
-        * 4: Reserved
-        * 5: Send illegal vector
-        * 6: Received illegal vector
-        * 7: Illegal register address
-        */
-       pr_debug("APIC error on CPU%d: %02x(%02x)\n",
-               smp_processor_id(), v , v1);
+       apic_printk(APIC_DEBUG, KERN_DEBUG "APIC error on CPU%d: %02x(%02x)",
+                   smp_processor_id(), v0 , v1);
+
+       v1 = v1 & 0xff;
+       while (v1) {
+               if (v1 & 0x1)
+                       apic_printk(APIC_DEBUG, KERN_CONT " : %s", error_interrupt_reason[i]);
+               i++;
+               v1 >>= 1;
+       };
+
+       apic_printk(APIC_DEBUG, KERN_CONT "\n");
+
        irq_exit();
 }
 
@@ -2003,21 +2025,6 @@ void default_init_apic_ldr(void)
        apic_write(APIC_LDR, val);
 }
 
-#ifdef CONFIG_X86_32
-int default_x86_32_numa_cpu_node(int cpu)
-{
-#ifdef CONFIG_NUMA
-       int apicid = early_per_cpu(x86_cpu_to_apicid, cpu);
-
-       if (apicid != BAD_APICID)
-               return __apicid_to_node[apicid];
-       return NUMA_NO_NODE;
-#else
-       return 0;
-#endif
-}
-#endif
-
 /*
  * Power management
  */
index f1baa2d..775b82b 100644 (file)
@@ -119,14 +119,6 @@ static void noop_apic_write(u32 reg, u32 v)
        WARN_ON_ONCE(cpu_has_apic && !disable_apic);
 }
 
-#ifdef CONFIG_X86_32
-static int noop_x86_32_numa_cpu_node(int cpu)
-{
-       /* we're always on node 0 */
-       return 0;
-}
-#endif
-
 struct apic apic_noop = {
        .name                           = "noop",
        .probe                          = noop_probe,
@@ -195,6 +187,5 @@ struct apic apic_noop = {
 
 #ifdef CONFIG_X86_32
        .x86_32_early_logical_apicid    = noop_x86_32_early_logical_apicid,
-       .x86_32_numa_cpu_node           = noop_x86_32_numa_cpu_node,
 #endif
 };
index 541a2e4..d84ac5a 100644 (file)
@@ -253,5 +253,4 @@ struct apic apic_bigsmp = {
        .safe_wait_icr_idle             = native_safe_apic_wait_icr_idle,
 
        .x86_32_early_logical_apicid    = bigsmp_early_logical_apicid,
-       .x86_32_numa_cpu_node           = default_x86_32_numa_cpu_node,
 };
index 3e9de48..70533de 100644 (file)
@@ -510,11 +510,6 @@ static void es7000_setup_apic_routing(void)
                nr_ioapics, cpumask_bits(es7000_target_cpus())[0]);
 }
 
-static int es7000_numa_cpu_node(int cpu)
-{
-       return 0;
-}
-
 static int es7000_cpu_present_to_apicid(int mps_cpu)
 {
        if (!mps_cpu)
@@ -688,7 +683,6 @@ struct apic __refdata apic_es7000_cluster = {
        .safe_wait_icr_idle             = native_safe_apic_wait_icr_idle,
 
        .x86_32_early_logical_apicid    = es7000_early_logical_apicid,
-       .x86_32_numa_cpu_node           = es7000_numa_cpu_node,
 };
 
 struct apic __refdata apic_es7000 = {
@@ -752,5 +746,4 @@ struct apic __refdata apic_es7000 = {
        .safe_wait_icr_idle             = native_safe_apic_wait_icr_idle,
 
        .x86_32_early_logical_apicid    = es7000_early_logical_apicid,
-       .x86_32_numa_cpu_node           = es7000_numa_cpu_node,
 };
index 6273eee..30f1331 100644 (file)
@@ -48,8 +48,6 @@
 #include <asm/e820.h>
 #include <asm/ipi.h>
 
-#define        MB_TO_PAGES(addr)               ((addr) << (20 - PAGE_SHIFT))
-
 int found_numaq;
 
 /*
@@ -79,31 +77,20 @@ int                                 quad_local_to_mp_bus_id[NR_CPUS/4][4];
 static inline void numaq_register_node(int node, struct sys_cfg_data *scd)
 {
        struct eachquadmem *eq = scd->eq + node;
+       u64 start = (u64)(eq->hi_shrd_mem_start - eq->priv_mem_size) << 20;
+       u64 end = (u64)(eq->hi_shrd_mem_start + eq->hi_shrd_mem_size) << 20;
+       int ret;
 
-       node_set_online(node);
-
-       /* Convert to pages */
-       node_start_pfn[node] =
-                MB_TO_PAGES(eq->hi_shrd_mem_start - eq->priv_mem_size);
-
-       node_end_pfn[node] =
-                MB_TO_PAGES(eq->hi_shrd_mem_start + eq->hi_shrd_mem_size);
-
-       memblock_x86_register_active_regions(node, node_start_pfn[node],
-                                               node_end_pfn[node]);
-
-       memory_present(node, node_start_pfn[node], node_end_pfn[node]);
-
-       node_remap_size[node] = node_memmap_size_bytes(node,
-                                       node_start_pfn[node],
-                                       node_end_pfn[node]);
+       node_set(node, numa_nodes_parsed);
+       ret = numa_add_memblk(node, start, end);
+       BUG_ON(ret < 0);
 }
 
 /*
  * Function: smp_dump_qct()
  *
  * Description: gets memory layout from the quad config table.  This
- * function also updates node_online_map with the nodes (quads) present.
+ * function also updates numa_nodes_parsed with the nodes (quads) present.
  */
 static void __init smp_dump_qct(void)
 {
@@ -112,7 +99,6 @@ static void __init smp_dump_qct(void)
 
        scd = (void *)__va(SYS_CFG_DATA_PRIV_ADDR);
 
-       nodes_clear(node_online_map);
        for_each_node(node) {
                if (scd->quads_present31_0 & (1 << node))
                        numaq_register_node(node, scd);
@@ -282,14 +268,14 @@ static __init void early_check_numaq(void)
        }
 }
 
-int __init get_memcfg_numaq(void)
+int __init numaq_numa_init(void)
 {
        early_check_numaq();
        if (!found_numaq)
-               return 0;
+               return -ENOENT;
        smp_dump_qct();
 
-       return 1;
+       return 0;
 }
 
 #define NUMAQ_APIC_DFR_VALUE   (APIC_DFR_CLUSTER)
index fc84c7b..6541e47 100644 (file)
@@ -172,7 +172,6 @@ struct apic apic_default = {
        .safe_wait_icr_idle             = native_safe_apic_wait_icr_idle,
 
        .x86_32_early_logical_apicid    = default_x86_32_early_logical_apicid,
-       .x86_32_numa_cpu_node           = default_x86_32_numa_cpu_node,
 };
 
 extern struct apic apic_numaq;
index e4b8059..35bcd7d 100644 (file)
@@ -551,5 +551,4 @@ struct apic apic_summit = {
        .safe_wait_icr_idle             = native_safe_apic_wait_icr_idle,
 
        .x86_32_early_logical_apicid    = summit_early_logical_apicid,
-       .x86_32_numa_cpu_node           = default_x86_32_numa_cpu_node,
 };
index 33b10a0..7acd2d2 100644 (file)
 #include <asm/smp.h>
 #include <asm/x86_init.h>
 #include <asm/emergency-restart.h>
+#include <asm/nmi.h>
+
+/* BMC sets a bit this MMR non-zero before sending an NMI */
+#define UVH_NMI_MMR                            UVH_SCRATCH5
+#define UVH_NMI_MMR_CLEAR                      (UVH_NMI_MMR + 8)
+#define UV_NMI_PENDING_MASK                    (1UL << 63)
+DEFINE_PER_CPU(unsigned long, cpu_last_nmi_count);
 
 DEFINE_PER_CPU(int, x2apic_extra_bits);
 
@@ -642,18 +649,46 @@ void __cpuinit uv_cpu_init(void)
  */
 int uv_handle_nmi(struct notifier_block *self, unsigned long reason, void *data)
 {
+       unsigned long real_uv_nmi;
+       int bid;
+
        if (reason != DIE_NMIUNKNOWN)
                return NOTIFY_OK;
 
        if (in_crash_kexec)
                /* do nothing if entering the crash kernel */
                return NOTIFY_OK;
+
        /*
-        * Use a lock so only one cpu prints at a time
-        * to prevent intermixed output.
+        * Each blade has an MMR that indicates when an NMI has been sent
+        * to cpus on the blade. If an NMI is detected, atomically
+        * clear the MMR and update a per-blade NMI count used to
+        * cause each cpu on the blade to notice a new NMI.
+        */
+       bid = uv_numa_blade_id();
+       real_uv_nmi = (uv_read_local_mmr(UVH_NMI_MMR) & UV_NMI_PENDING_MASK);
+
+       if (unlikely(real_uv_nmi)) {
+               spin_lock(&uv_blade_info[bid].nmi_lock);
+               real_uv_nmi = (uv_read_local_mmr(UVH_NMI_MMR) & UV_NMI_PENDING_MASK);
+               if (real_uv_nmi) {
+                       uv_blade_info[bid].nmi_count++;
+                       uv_write_local_mmr(UVH_NMI_MMR_CLEAR, UV_NMI_PENDING_MASK);
+               }
+               spin_unlock(&uv_blade_info[bid].nmi_lock);
+       }
+
+       if (likely(__get_cpu_var(cpu_last_nmi_count) == uv_blade_info[bid].nmi_count))
+               return NOTIFY_DONE;
+
+       __get_cpu_var(cpu_last_nmi_count) = uv_blade_info[bid].nmi_count;
+
+       /*
+        * Use a lock so only one cpu prints at a time.
+        * This prevents intermixed output.
         */
        spin_lock(&uv_nmi_lock);
-       pr_info("NMI stack dump cpu %u:\n", smp_processor_id());
+       pr_info("UV NMI stack dump cpu %u:\n", smp_processor_id());
        dump_stack();
        spin_unlock(&uv_nmi_lock);
 
@@ -661,7 +696,8 @@ int uv_handle_nmi(struct notifier_block *self, unsigned long reason, void *data)
 }
 
 static struct notifier_block uv_dump_stack_nmi_nb = {
-       .notifier_call  = uv_handle_nmi
+       .notifier_call  = uv_handle_nmi,
+       .priority = NMI_LOCAL_LOW_PRIOR - 1,
 };
 
 void uv_register_nmi_notifier(void)
@@ -720,8 +756,9 @@ void __init uv_system_init(void)
        printk(KERN_DEBUG "UV: Found %d blades\n", uv_num_possible_blades());
 
        bytes = sizeof(struct uv_blade_info) * uv_num_possible_blades();
-       uv_blade_info = kmalloc(bytes, GFP_KERNEL);
+       uv_blade_info = kzalloc(bytes, GFP_KERNEL);
        BUG_ON(!uv_blade_info);
+
        for (blade = 0; blade < uv_num_possible_blades(); blade++)
                uv_blade_info[blade].memory_nid = -1;
 
@@ -747,6 +784,7 @@ void __init uv_system_init(void)
                        uv_blade_info[blade].pnode = pnode;
                        uv_blade_info[blade].nr_possible_cpus = 0;
                        uv_blade_info[blade].nr_online_cpus = 0;
+                       spin_lock_init(&uv_blade_info[blade].nmi_lock);
                        max_pnode = max(pnode, max_pnode);
                        blade++;
                }
index adee12e..3bfa022 100644 (file)
@@ -1238,7 +1238,6 @@ static int suspend(int vetoable)
        dpm_suspend_noirq(PMSG_SUSPEND);
 
        local_irq_disable();
-       sysdev_suspend(PMSG_SUSPEND);
        syscore_suspend();
 
        local_irq_enable();
@@ -1258,7 +1257,6 @@ static int suspend(int vetoable)
        err = (err == APM_SUCCESS) ? 0 : -EIO;
 
        syscore_resume();
-       sysdev_resume();
        local_irq_enable();
 
        dpm_resume_noirq(PMSG_RESUME);
@@ -1282,7 +1280,6 @@ static void standby(void)
        dpm_suspend_noirq(PMSG_SUSPEND);
 
        local_irq_disable();
-       sysdev_suspend(PMSG_SUSPEND);
        syscore_suspend();
        local_irq_enable();
 
@@ -1292,7 +1289,6 @@ static void standby(void)
 
        local_irq_disable();
        syscore_resume();
-       sysdev_resume();
        local_irq_enable();
 
        dpm_resume_noirq(PMSG_RESUME);
index 3f0ebe4..6042981 100644 (file)
@@ -30,7 +30,6 @@ obj-$(CONFIG_PERF_EVENTS)             += perf_event.o
 
 obj-$(CONFIG_X86_MCE)                  += mcheck/
 obj-$(CONFIG_MTRR)                     += mtrr/
-obj-$(CONFIG_CPU_FREQ)                 += cpufreq/
 
 obj-$(CONFIG_X86_LOCAL_APIC)           += perfctr-watchdog.o
 
index bb9eb29..6f9d1f6 100644 (file)
@@ -613,7 +613,7 @@ static void __cpuinit init_amd(struct cpuinfo_x86 *c)
 #endif
 
        /* As a rule processors have APIC timer running in deep C states */
-       if (c->x86 >= 0xf && !cpu_has_amd_erratum(amd_erratum_400))
+       if (c->x86 > 0xf && !cpu_has_amd_erratum(amd_erratum_400))
                set_cpu_cap(c, X86_FEATURE_ARAT);
 
        /*
@@ -698,7 +698,7 @@ cpu_dev_register(amd_cpu_dev);
  */
 
 const int amd_erratum_400[] =
-       AMD_OSVW_ERRATUM(1, AMD_MODEL_RANGE(0x0f, 0x4, 0x2, 0xff, 0xf),
+       AMD_OSVW_ERRATUM(1, AMD_MODEL_RANGE(0xf, 0x41, 0x2, 0xff, 0xf),
                            AMD_MODEL_RANGE(0x10, 0x2, 0x1, 0xff, 0xf));
 EXPORT_SYMBOL_GPL(amd_erratum_400);
 
index 173f3a3..cbc70a2 100644 (file)
@@ -254,6 +254,25 @@ static inline void squash_the_stupid_serial_number(struct cpuinfo_x86 *c)
 }
 #endif
 
+static int disable_smep __initdata;
+static __init int setup_disable_smep(char *arg)
+{
+       disable_smep = 1;
+       return 1;
+}
+__setup("nosmep", setup_disable_smep);
+
+static __init void setup_smep(struct cpuinfo_x86 *c)
+{
+       if (cpu_has(c, X86_FEATURE_SMEP)) {
+               if (unlikely(disable_smep)) {
+                       setup_clear_cpu_cap(X86_FEATURE_SMEP);
+                       clear_in_cr4(X86_CR4_SMEP);
+               } else
+                       set_in_cr4(X86_CR4_SMEP);
+       }
+}
+
 /*
  * Some CPU features depend on higher CPUID levels, which may not always
  * be available due to CPUID level capping or broken virtualization
@@ -667,6 +686,8 @@ static void __init early_identify_cpu(struct cpuinfo_x86 *c)
        c->cpu_index = 0;
 #endif
        filter_cpuid_features(c, false);
+
+       setup_smep(c);
 }
 
 void __init early_cpu_init(void)
@@ -752,6 +773,8 @@ static void __cpuinit generic_identify(struct cpuinfo_x86 *c)
 #endif
        }
 
+       setup_smep(c);
+
        get_model_name(c); /* Default name */
 
        detect_nopl(c);
diff --git a/arch/x86/kernel/cpu/cpufreq/Makefile b/arch/x86/kernel/cpu/cpufreq/Makefile
deleted file mode 100644 (file)
index bd54bf6..0000000
+++ /dev/null
@@ -1,21 +0,0 @@
-# Link order matters. K8 is preferred to ACPI because of firmware bugs in early
-# K8 systems. ACPI is preferred to all other hardware-specific drivers.
-# speedstep-* is preferred over p4-clockmod.
-
-obj-$(CONFIG_X86_POWERNOW_K8)          += powernow-k8.o mperf.o
-obj-$(CONFIG_X86_ACPI_CPUFREQ)         += acpi-cpufreq.o mperf.o
-obj-$(CONFIG_X86_PCC_CPUFREQ)          += pcc-cpufreq.o
-obj-$(CONFIG_X86_POWERNOW_K6)          += powernow-k6.o
-obj-$(CONFIG_X86_POWERNOW_K7)          += powernow-k7.o
-obj-$(CONFIG_X86_LONGHAUL)             += longhaul.o
-obj-$(CONFIG_X86_E_POWERSAVER)         += e_powersaver.o
-obj-$(CONFIG_ELAN_CPUFREQ)             += elanfreq.o
-obj-$(CONFIG_SC520_CPUFREQ)            += sc520_freq.o
-obj-$(CONFIG_X86_LONGRUN)              += longrun.o  
-obj-$(CONFIG_X86_GX_SUSPMOD)           += gx-suspmod.o
-obj-$(CONFIG_X86_SPEEDSTEP_ICH)                += speedstep-ich.o
-obj-$(CONFIG_X86_SPEEDSTEP_LIB)                += speedstep-lib.o
-obj-$(CONFIG_X86_SPEEDSTEP_SMI)                += speedstep-smi.o
-obj-$(CONFIG_X86_SPEEDSTEP_CENTRINO)   += speedstep-centrino.o
-obj-$(CONFIG_X86_P4_CLOCKMOD)          += p4-clockmod.o
-obj-$(CONFIG_X86_CPUFREQ_NFORCE2)      += cpufreq-nforce2.o
index fc73a34..1edf5ba 100644 (file)
@@ -411,12 +411,10 @@ static void __cpuinit init_intel(struct cpuinfo_x86 *c)
 
                switch (c->x86_model) {
                case 5:
-                       if (c->x86_mask == 0) {
-                               if (l2 == 0)
-                                       p = "Celeron (Covington)";
-                               else if (l2 == 256)
-                                       p = "Mobile Pentium II (Dixon)";
-                       }
+                       if (l2 == 0)
+                               p = "Celeron (Covington)";
+                       else if (l2 == 256)
+                               p = "Mobile Pentium II (Dixon)";
                        break;
 
                case 6:
index 1ce1af2..c105c53 100644 (file)
@@ -327,7 +327,6 @@ static void __cpuinit amd_calc_l3_indices(struct amd_l3_cache *l3)
        l3->subcaches[2] = sc2 = !(val & BIT(8))  + !(val & BIT(9));
        l3->subcaches[3] = sc3 = !(val & BIT(12)) + !(val & BIT(13));
 
-       l3->indices = (max(max(max(sc0, sc1), sc2), sc3) << 10) - 1;
        l3->indices = (max(max3(sc0, sc1, sc2), sc3) << 10) - 1;
 }
 
@@ -454,27 +453,16 @@ int amd_set_l3_disable_slot(struct amd_l3_cache *l3, int cpu, unsigned slot,
 {
        int ret = 0;
 
-#define SUBCACHE_MASK  (3UL << 20)
-#define SUBCACHE_INDEX 0xfff
-
-       /*
-        * check whether this slot is already used or
-        * the index is already disabled
-        */
+       /*  check if @slot is already used or the index is already disabled */
        ret = amd_get_l3_disable_slot(l3, slot);
        if (ret >= 0)
                return -EINVAL;
 
-       /*
-        * check whether the other slot has disabled the
-        * same index already
-        */
-       if (index == amd_get_l3_disable_slot(l3, !slot))
+       if (index > l3->indices)
                return -EINVAL;
 
-       /* do not allow writes outside of allowed bits */
-       if ((index & ~(SUBCACHE_MASK | SUBCACHE_INDEX)) ||
-           ((index & SUBCACHE_INDEX) > l3->indices))
+       /* check whether the other slot has disabled the same index already */
+       if (index == amd_get_l3_disable_slot(l3, !slot))
                return -EINVAL;
 
        amd_l3_disable_index(l3, cpu, slot, index);
index 3385ea2..ff1ae9b 100644 (file)
@@ -105,20 +105,6 @@ static int                 cpu_missing;
 ATOMIC_NOTIFIER_HEAD(x86_mce_decoder_chain);
 EXPORT_SYMBOL_GPL(x86_mce_decoder_chain);
 
-static int default_decode_mce(struct notifier_block *nb, unsigned long val,
-                              void *data)
-{
-       pr_emerg(HW_ERR "No human readable MCE decoding support on this CPU type.\n");
-       pr_emerg(HW_ERR "Run the message through 'mcelog --ascii' to decode.\n");
-
-       return NOTIFY_STOP;
-}
-
-static struct notifier_block mce_dec_nb = {
-       .notifier_call = default_decode_mce,
-       .priority      = -1,
-};
-
 /* MCA banks polled by the period polling timer for corrected events */
 DEFINE_PER_CPU(mce_banks_t, mce_poll_banks) = {
        [0 ... BITS_TO_LONGS(MAX_NR_BANKS)-1] = ~0UL
@@ -212,6 +198,8 @@ void mce_log(struct mce *mce)
 
 static void print_mce(struct mce *m)
 {
+       int ret = 0;
+
        pr_emerg(HW_ERR "CPU %d: Machine Check Exception: %Lx Bank %d: %016Lx\n",
               m->extcpu, m->mcgstatus, m->bank, m->status);
 
@@ -239,7 +227,11 @@ static void print_mce(struct mce *m)
         * Print out human-readable details about the MCE error,
         * (if the CPU has an implementation for that)
         */
-       atomic_notifier_call_chain(&x86_mce_decoder_chain, 0, m);
+       ret = atomic_notifier_call_chain(&x86_mce_decoder_chain, 0, m);
+       if (ret == NOTIFY_STOP)
+               return;
+
+       pr_emerg_ratelimited(HW_ERR "Run the above through 'mcelog --ascii'\n");
 }
 
 #define PANIC_TIMEOUT 5 /* 5 seconds */
@@ -590,7 +582,6 @@ void machine_check_poll(enum mcp_flags flags, mce_banks_t *b)
                if (!(flags & MCP_DONTLOG) && !mce_dont_log_ce) {
                        mce_log(&m);
                        atomic_notifier_call_chain(&x86_mce_decoder_chain, 0, &m);
-                       add_taint(TAINT_MACHINE_CHECK);
                }
 
                /*
@@ -1722,8 +1713,6 @@ __setup("mce", mcheck_enable);
 
 int __init mcheck_init(void)
 {
-       atomic_notifier_chain_register(&x86_mce_decoder_chain, &mce_dec_nb);
-
        mcheck_intel_therm_init();
 
        return 0;
index 167f97b..bb0adad 100644 (file)
@@ -509,6 +509,7 @@ recurse:
 out_free:
        if (b) {
                kobject_put(&b->kobj);
+               list_del(&b->miscj);
                kfree(b);
        }
        return err;
index 6f8c5e9..27c6251 100644 (file)
@@ -187,8 +187,6 @@ static int therm_throt_process(bool new_event, int event, int level)
                                this_cpu,
                                level == CORE_LEVEL ? "Core" : "Package",
                                state->count);
-
-               add_taint(TAINT_MACHINE_CHECK);
                return 1;
        }
        if (old_event) {
@@ -355,7 +353,6 @@ static void notify_thresholds(__u64 msr_val)
 static void intel_thermal_interrupt(void)
 {
        __u64 msr_val;
-       struct cpuinfo_x86 *c = &cpu_data(smp_processor_id());
 
        rdmsrl(MSR_IA32_THERM_STATUS, msr_val);
 
@@ -367,19 +364,19 @@ static void intel_thermal_interrupt(void)
                                CORE_LEVEL) != 0)
                mce_log_therm_throt_event(CORE_THROTTLED | msr_val);
 
-       if (cpu_has(c, X86_FEATURE_PLN))
+       if (this_cpu_has(X86_FEATURE_PLN))
                if (therm_throt_process(msr_val & THERM_STATUS_POWER_LIMIT,
                                        POWER_LIMIT_EVENT,
                                        CORE_LEVEL) != 0)
                        mce_log_therm_throt_event(CORE_POWER_LIMIT | msr_val);
 
-       if (cpu_has(c, X86_FEATURE_PTS)) {
+       if (this_cpu_has(X86_FEATURE_PTS)) {
                rdmsrl(MSR_IA32_PACKAGE_THERM_STATUS, msr_val);
                if (therm_throt_process(msr_val & PACKAGE_THERM_STATUS_PROCHOT,
                                        THERMAL_THROTTLING_EVENT,
                                        PACKAGE_LEVEL) != 0)
                        mce_log_therm_throt_event(PACKAGE_THROTTLED | msr_val);
-               if (cpu_has(c, X86_FEATURE_PLN))
+               if (this_cpu_has(X86_FEATURE_PLN))
                        if (therm_throt_process(msr_val &
                                        PACKAGE_THERM_STATUS_POWER_LIMIT,
                                        POWER_LIMIT_EVENT,
@@ -393,7 +390,6 @@ static void unexpected_thermal_interrupt(void)
 {
        printk(KERN_ERR "CPU%d: Unexpected LVT thermal interrupt!\n",
                        smp_processor_id());
-       add_taint(TAINT_MACHINE_CHECK);
 }
 
 static void (*smp_thermal_vector)(void) = unexpected_thermal_interrupt;
@@ -446,18 +442,20 @@ void intel_init_thermal(struct cpuinfo_x86 *c)
         */
        rdmsr(MSR_IA32_MISC_ENABLE, l, h);
 
+       h = lvtthmr_init;
        /*
         * The initial value of thermal LVT entries on all APs always reads
         * 0x10000 because APs are woken up by BSP issuing INIT-SIPI-SIPI
         * sequence to them and LVT registers are reset to 0s except for
         * the mask bits which are set to 1s when APs receive INIT IPI.
-        * Always restore the value that BIOS has programmed on AP based on
-        * BSP's info we saved since BIOS is always setting the same value
-        * for all threads/cores
+        * If BIOS takes over the thermal interrupt and sets its interrupt
+        * delivery mode to SMI (not fixed), it restores the value that the
+        * BIOS has programmed on AP based on BSP's info we saved since BIOS
+        * is always setting the same value for all threads/cores.
         */
-       apic_write(APIC_LVTTHMR, lvtthmr_init);
+       if ((h & APIC_DM_FIXED_MASK) != APIC_DM_FIXED)
+               apic_write(APIC_LVTTHMR, lvtthmr_init);
 
-       h = lvtthmr_init;
 
        if ((l & MSR_IA32_MISC_ENABLE_TM1) && (h & APIC_DM_SMI)) {
                printk(KERN_DEBUG
index f478ff6..1aae78f 100644 (file)
@@ -263,7 +263,6 @@ int __kprobes __die(const char *str, struct pt_regs *regs, long err)
        printk("DEBUG_PAGEALLOC");
 #endif
        printk("\n");
-       sysfs_printk_last_file();
        if (notify_die(DIE_OOPS, str, regs, err,
                        current->thread.trap_no, SIGSEGV) == NOTIFY_STOP)
                return 1;
index a93742a..0ba15a6 100644 (file)
@@ -260,9 +260,9 @@ do_ftrace_mod_code(unsigned long ip, void *new_code)
        return mod_code_status;
 }
 
-static unsigned char *ftrace_nop_replace(void)
+static const unsigned char *ftrace_nop_replace(void)
 {
-       return ideal_nop5;
+       return ideal_nops[NOP_ATOMIC5];
 }
 
 static int
index d6d6bb3..3bb0850 100644 (file)
@@ -23,7 +23,6 @@
 static void __init i386_default_early_setup(void)
 {
        /* Initialize 32bit specific setup functions */
-       x86_init.resources.probe_roms = probe_roms;
        x86_init.resources.reserve_resources = i386_reserve_resources;
        x86_init.mpparse.setup_ioapic_ids = setup_ioapic_ids_from_mpc;
 
index bfe8f72..6781765 100644 (file)
@@ -217,7 +217,7 @@ static void hpet_reserve_platform_timers(unsigned int id) { }
 /*
  * Common hpet info
  */
-static unsigned long hpet_period;
+static unsigned long hpet_freq;
 
 static void hpet_legacy_set_mode(enum clock_event_mode mode,
                          struct clock_event_device *evt);
@@ -232,7 +232,6 @@ static struct clock_event_device hpet_clockevent = {
        .features       = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT,
        .set_mode       = hpet_legacy_set_mode,
        .set_next_event = hpet_legacy_next_event,
-       .shift          = 32,
        .irq            = 0,
        .rating         = 50,
 };
@@ -290,28 +289,12 @@ static void hpet_legacy_clockevent_register(void)
        hpet_enable_legacy_int();
 
        /*
-        * The mult factor is defined as (include/linux/clockchips.h)
-        *  mult/2^shift = cyc/ns (in contrast to ns/cyc in clocksource.h)
-        * hpet_period is in units of femtoseconds (per cycle), so
-        *  mult/2^shift = cyc/ns = 10^6/hpet_period
-        *  mult = (10^6 * 2^shift)/hpet_period
-        *  mult = (FSEC_PER_NSEC << hpet_clockevent.shift)/hpet_period
-        */
-       hpet_clockevent.mult = div_sc((unsigned long) FSEC_PER_NSEC,
-                                     hpet_period, hpet_clockevent.shift);
-       /* Calculate the min / max delta */
-       hpet_clockevent.max_delta_ns = clockevent_delta2ns(0x7FFFFFFF,
-                                                          &hpet_clockevent);
-       /* Setup minimum reprogramming delta. */
-       hpet_clockevent.min_delta_ns = clockevent_delta2ns(HPET_MIN_PROG_DELTA,
-                                                          &hpet_clockevent);
-
-       /*
         * Start hpet with the boot cpu mask and make it
         * global after the IO_APIC has been initialized.
         */
        hpet_clockevent.cpumask = cpumask_of(smp_processor_id());
-       clockevents_register_device(&hpet_clockevent);
+       clockevents_config_and_register(&hpet_clockevent, hpet_freq,
+                                       HPET_MIN_PROG_DELTA, 0x7FFFFFFF);
        global_clock_event = &hpet_clockevent;
        printk(KERN_DEBUG "hpet clockevent registered\n");
 }
@@ -549,7 +532,6 @@ static int hpet_setup_irq(struct hpet_dev *dev)
 static void init_one_hpet_msi_clockevent(struct hpet_dev *hdev, int cpu)
 {
        struct clock_event_device *evt = &hdev->evt;
-       uint64_t hpet_freq;
 
        WARN_ON(cpu != smp_processor_id());
        if (!(hdev->flags & HPET_DEV_VALID))
@@ -571,24 +553,10 @@ static void init_one_hpet_msi_clockevent(struct hpet_dev *hdev, int cpu)
 
        evt->set_mode = hpet_msi_set_mode;
        evt->set_next_event = hpet_msi_next_event;
-       evt->shift = 32;
-
-       /*
-        * The period is a femto seconds value. We need to calculate the
-        * scaled math multiplication factor for nanosecond to hpet tick
-        * conversion.
-        */
-       hpet_freq = FSEC_PER_SEC;
-       do_div(hpet_freq, hpet_period);
-       evt->mult = div_sc((unsigned long) hpet_freq,
-                                     NSEC_PER_SEC, evt->shift);
-       /* Calculate the max delta */
-       evt->max_delta_ns = clockevent_delta2ns(0x7FFFFFFF, evt);
-       /* 5 usec minimum reprogramming delta. */
-       evt->min_delta_ns = 5000;
-
        evt->cpumask = cpumask_of(hdev->cpu);
-       clockevents_register_device(evt);
+
+       clockevents_config_and_register(evt, hpet_freq, HPET_MIN_PROG_DELTA,
+                                       0x7FFFFFFF);
 }
 
 #ifdef CONFIG_HPET
@@ -792,7 +760,6 @@ static struct clocksource clocksource_hpet = {
 static int hpet_clocksource_register(void)
 {
        u64 start, now;
-       u64 hpet_freq;
        cycle_t t1;
 
        /* Start the counter */
@@ -819,24 +786,7 @@ static int hpet_clocksource_register(void)
                return -ENODEV;
        }
 
-       /*
-        * The definition of mult is (include/linux/clocksource.h)
-        * mult/2^shift = ns/cyc and hpet_period is in units of fsec/cyc
-        * so we first need to convert hpet_period to ns/cyc units:
-        *  mult/2^shift = ns/cyc = hpet_period/10^6
-        *  mult = (hpet_period * 2^shift)/10^6
-        *  mult = (hpet_period << shift)/FSEC_PER_NSEC
-        */
-
-       /* Need to convert hpet_period (fsec/cyc) to cyc/sec:
-        *
-        * cyc/sec = FSEC_PER_SEC/hpet_period(fsec/cyc)
-        * cyc/sec = (FSEC_PER_NSEC * NSEC_PER_SEC)/hpet_period
-        */
-       hpet_freq = FSEC_PER_SEC;
-       do_div(hpet_freq, hpet_period);
        clocksource_register_hz(&clocksource_hpet, (u32)hpet_freq);
-
        return 0;
 }
 
@@ -845,7 +795,9 @@ static int hpet_clocksource_register(void)
  */
 int __init hpet_enable(void)
 {
+       unsigned long hpet_period;
        unsigned int id;
+       u64 freq;
        int i;
 
        if (!is_hpet_capable())
@@ -884,6 +836,14 @@ int __init hpet_enable(void)
                goto out_nohpet;
 
        /*
+        * The period is a femto seconds value. Convert it to a
+        * frequency.
+        */
+       freq = FSEC_PER_SEC;
+       do_div(freq, hpet_period);
+       hpet_freq = freq;
+
+       /*
         * Read the HPET ID register to retrieve the IRQ routing
         * information and the number of channels
         */
index 2dfd315..fb66dc9 100644 (file)
@@ -93,7 +93,6 @@ static struct clock_event_device pit_ce = {
        .features       = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT,
        .set_mode       = init_pit_timer,
        .set_next_event = pit_next_event,
-       .shift          = 32,
        .irq            = 0,
 };
 
@@ -108,90 +107,12 @@ void __init setup_pit_timer(void)
         * IO_APIC has been initialized.
         */
        pit_ce.cpumask = cpumask_of(smp_processor_id());
-       pit_ce.mult = div_sc(CLOCK_TICK_RATE, NSEC_PER_SEC, pit_ce.shift);
-       pit_ce.max_delta_ns = clockevent_delta2ns(0x7FFF, &pit_ce);
-       pit_ce.min_delta_ns = clockevent_delta2ns(0xF, &pit_ce);
 
-       clockevents_register_device(&pit_ce);
+       clockevents_config_and_register(&pit_ce, CLOCK_TICK_RATE, 0xF, 0x7FFF);
        global_clock_event = &pit_ce;
 }
 
 #ifndef CONFIG_X86_64
-/*
- * Since the PIT overflows every tick, its not very useful
- * to just read by itself. So use jiffies to emulate a free
- * running counter:
- */
-static cycle_t pit_read(struct clocksource *cs)
-{
-       static int old_count;
-       static u32 old_jifs;
-       unsigned long flags;
-       int count;
-       u32 jifs;
-
-       raw_spin_lock_irqsave(&i8253_lock, flags);
-       /*
-        * Although our caller may have the read side of xtime_lock,
-        * this is now a seqlock, and we are cheating in this routine
-        * by having side effects on state that we cannot undo if
-        * there is a collision on the seqlock and our caller has to
-        * retry.  (Namely, old_jifs and old_count.)  So we must treat
-        * jiffies as volatile despite the lock.  We read jiffies
-        * before latching the timer count to guarantee that although
-        * the jiffies value might be older than the count (that is,
-        * the counter may underflow between the last point where
-        * jiffies was incremented and the point where we latch the
-        * count), it cannot be newer.
-        */
-       jifs = jiffies;
-       outb_pit(0x00, PIT_MODE);       /* latch the count ASAP */
-       count = inb_pit(PIT_CH0);       /* read the latched count */
-       count |= inb_pit(PIT_CH0) << 8;
-
-       /* VIA686a test code... reset the latch if count > max + 1 */
-       if (count > LATCH) {
-               outb_pit(0x34, PIT_MODE);
-               outb_pit(LATCH & 0xff, PIT_CH0);
-               outb_pit(LATCH >> 8, PIT_CH0);
-               count = LATCH - 1;
-       }
-
-       /*
-        * It's possible for count to appear to go the wrong way for a
-        * couple of reasons:
-        *
-        *  1. The timer counter underflows, but we haven't handled the
-        *     resulting interrupt and incremented jiffies yet.
-        *  2. Hardware problem with the timer, not giving us continuous time,
-        *     the counter does small "jumps" upwards on some Pentium systems,
-        *     (see c't 95/10 page 335 for Neptun bug.)
-        *
-        * Previous attempts to handle these cases intelligently were
-        * buggy, so we just do the simple thing now.
-        */
-       if (count > old_count && jifs == old_jifs)
-               count = old_count;
-
-       old_count = count;
-       old_jifs = jifs;
-
-       raw_spin_unlock_irqrestore(&i8253_lock, flags);
-
-       count = (LATCH - 1) - count;
-
-       return (cycle_t)(jifs * LATCH) + count;
-}
-
-static struct clocksource pit_cs = {
-       .name           = "pit",
-       .rating         = 110,
-       .read           = pit_read,
-       .mask           = CLOCKSOURCE_MASK(32),
-       .mult           = 0,
-       .shift          = 20,
-};
-
 static int __init init_pit_clocksource(void)
 {
         /*
@@ -205,10 +126,7 @@ static int __init init_pit_clocksource(void)
            pit_ce.mode != CLOCK_EVT_MODE_PERIODIC)
                return 0;
 
-       pit_cs.mult = clocksource_hz2mult(CLOCK_TICK_RATE, pit_cs.shift);
-
-       return clocksource_register(&pit_cs);
+       return clocksource_i8253_init();
 }
 arch_initcall(init_pit_clocksource);
-
 #endif /* !CONFIG_X86_64 */
index 1cb0b9f..6c0802e 100644 (file)
@@ -249,7 +249,7 @@ void fixup_irqs(void)
 
                data = irq_desc_get_irq_data(desc);
                affinity = data->affinity;
-               if (!irq_has_action(irq) ||
+               if (!irq_has_action(irq) || irqd_is_per_cpu(data) ||
                    cpumask_subset(affinity, cpu_online_mask)) {
                        raw_spin_unlock(&desc->lock);
                        continue;
@@ -276,7 +276,8 @@ void fixup_irqs(void)
                else if (!(warned++))
                        set_affinity = 0;
 
-               if (!irqd_can_move_in_process_context(data) && chip->irq_unmask)
+               if (!irqd_can_move_in_process_context(data) &&
+                   !irqd_irq_disabled(data) && chip->irq_unmask)
                        chip->irq_unmask(data);
 
                raw_spin_unlock(&desc->lock);
index 961b6b3..3fee346 100644 (file)
@@ -34,7 +34,7 @@ void arch_jump_label_transform(struct jump_entry *entry,
                code.offset = entry->target -
                                (entry->code + JUMP_LABEL_NOP_SIZE);
        } else
-               memcpy(&code, ideal_nop5, JUMP_LABEL_NOP_SIZE);
+               memcpy(&code, ideal_nops[NOP_ATOMIC5], JUMP_LABEL_NOP_SIZE);
        get_online_cpus();
        mutex_lock(&text_mutex);
        text_poke_smp((void *)entry->code, &code, JUMP_LABEL_NOP_SIZE);
@@ -44,7 +44,8 @@ void arch_jump_label_transform(struct jump_entry *entry,
 
 void arch_jump_label_text_poke_early(jump_label_t addr)
 {
-       text_poke_early((void *)addr, ideal_nop5, JUMP_LABEL_NOP_SIZE);
+       text_poke_early((void *)addr, ideal_nops[NOP_ATOMIC5],
+                       JUMP_LABEL_NOP_SIZE);
 }
 
 #endif
index c969fd9..f1a6244 100644 (file)
@@ -1183,12 +1183,13 @@ static void __kprobes optimized_callback(struct optimized_kprobe *op,
                                         struct pt_regs *regs)
 {
        struct kprobe_ctlblk *kcb = get_kprobe_ctlblk();
+       unsigned long flags;
 
        /* This is possible if op is under delayed unoptimizing */
        if (kprobe_disabled(&op->kp))
                return;
 
-       preempt_disable();
+       local_irq_save(flags);
        if (kprobe_running()) {
                kprobes_inc_nmissed_count(&op->kp);
        } else {
@@ -1207,7 +1208,7 @@ static void __kprobes optimized_callback(struct optimized_kprobe *op,
                opt_pre_handler(&op->kp, regs);
                __this_cpu_write(current_kprobe, NULL);
        }
-       preempt_enable_no_resched();
+       local_irq_restore(flags);
 }
 
 static int __kprobes copy_optimized_instructions(u8 *dest, u8 *src)
index f98d3ea..6389a6b 100644 (file)
@@ -26,8 +26,6 @@
 #include <asm/x86_init.h>
 #include <asm/reboot.h>
 
-#define KVM_SCALE 22
-
 static int kvmclock = 1;
 static int msr_kvm_system_time = MSR_KVM_SYSTEM_TIME;
 static int msr_kvm_wall_clock = MSR_KVM_WALL_CLOCK;
@@ -120,8 +118,6 @@ static struct clocksource kvm_clock = {
        .read = kvm_clock_get_cycles,
        .rating = 400,
        .mask = CLOCKSOURCE_MASK(64),
-       .mult = 1 << KVM_SCALE,
-       .shift = KVM_SCALE,
        .flags = CLOCK_SOURCE_IS_CONTINUOUS,
 };
 
@@ -203,7 +199,7 @@ void __init kvmclock_init(void)
        machine_ops.crash_shutdown  = kvm_crash_shutdown;
 #endif
        kvm_get_preset_lpj();
-       clocksource_register(&kvm_clock);
+       clocksource_register_hz(&kvm_clock, NSEC_PER_SEC);
        pv_info.paravirt_enabled = 1;
        pv_info.name = "KVM";
 
index 5a532ce..6f9bfff 100644 (file)
@@ -715,17 +715,15 @@ static void __init check_irq_src(struct mpc_intsrc *m, int *nr_m_spare)
        }
 }
 
-static int
+static int __init
 check_slot(unsigned long mpc_new_phys, unsigned long mpc_new_length, int count)
 {
-       int ret = 0;
-
        if (!mpc_new_phys || count <= mpc_new_length) {
                WARN(1, "update_mptable: No spare slots (length: %x)\n", count);
                return -1;
        }
 
-       return ret;
+       return 0;
 }
 #else /* CONFIG_X86_IO_APIC */
 static
index 55d745e..35ccf75 100644 (file)
@@ -50,20 +50,14 @@ void __init check_iommu_entries(struct iommu_table_entry *start,
                                struct iommu_table_entry *finish)
 {
        struct iommu_table_entry *p, *q, *x;
-       char sym_p[KSYM_SYMBOL_LEN];
-       char sym_q[KSYM_SYMBOL_LEN];
 
        /* Simple cyclic dependency checker. */
        for (p = start; p < finish; p++) {
                q = find_dependents_of(start, finish, p);
                x = find_dependents_of(start, finish, q);
                if (p == x) {
-                       sprint_symbol(sym_p, (unsigned long)p->detect);
-                       sprint_symbol(sym_q, (unsigned long)q->detect);
-
-                       printk(KERN_ERR "CYCLIC DEPENDENCY FOUND! %s depends" \
-                                       " on %s and vice-versa. BREAKING IT.\n",
-                                       sym_p, sym_q);
+                       printk(KERN_ERR "CYCLIC DEPENDENCY FOUND! %pS depends on %pS and vice-versa. BREAKING IT.\n",
+                              p->detect, q->detect);
                        /* Heavy handed way..*/
                        x->depend = 0;
                }
@@ -72,12 +66,8 @@ void __init check_iommu_entries(struct iommu_table_entry *start,
        for (p = start; p < finish; p++) {
                q = find_dependents_of(p, finish, p);
                if (q && q > p) {
-                       sprint_symbol(sym_p, (unsigned long)p->detect);
-                       sprint_symbol(sym_q, (unsigned long)q->detect);
-
-                       printk(KERN_ERR "EXECUTION ORDER INVALID! %s "\
-                                       "should be called before %s!\n",
-                                       sym_p, sym_q);
+                       printk(KERN_ERR "EXECUTION ORDER INVALID! %pS should be called before %pS!\n",
+                              p->detect, q->detect);
                }
        }
 }
similarity index 65%
rename from arch/x86/kernel/probe_roms_32.c
rename to arch/x86/kernel/probe_roms.c
index 071e7fe..ba0a4cc 100644 (file)
@@ -73,6 +73,107 @@ static struct resource video_rom_resource = {
        .flags  = IORESOURCE_BUSY | IORESOURCE_READONLY | IORESOURCE_MEM
 };
 
+/* does this oprom support the given pci device, or any of the devices
+ * that the driver supports?
+ */
+static bool match_id(struct pci_dev *pdev, unsigned short vendor, unsigned short device)
+{
+       struct pci_driver *drv = pdev->driver;
+       const struct pci_device_id *id;
+
+       if (pdev->vendor == vendor && pdev->device == device)
+               return true;
+
+       for (id = drv ? drv->id_table : NULL; id && id->vendor; id++)
+               if (id->vendor == vendor && id->device == device)
+                       break;
+
+       return id && id->vendor;
+}
+
+static bool probe_list(struct pci_dev *pdev, unsigned short vendor,
+                      const unsigned char *rom_list)
+{
+       unsigned short device;
+
+       do {
+               if (probe_kernel_address(rom_list, device) != 0)
+                       device = 0;
+
+               if (device && match_id(pdev, vendor, device))
+                       break;
+
+               rom_list += 2;
+       } while (device);
+
+       return !!device;
+}
+
+static struct resource *find_oprom(struct pci_dev *pdev)
+{
+       struct resource *oprom = NULL;
+       int i;
+
+       for (i = 0; i < ARRAY_SIZE(adapter_rom_resources); i++) {
+               struct resource *res = &adapter_rom_resources[i];
+               unsigned short offset, vendor, device, list, rev;
+               const unsigned char *rom;
+
+               if (res->end == 0)
+                       break;
+
+               rom = isa_bus_to_virt(res->start);
+               if (probe_kernel_address(rom + 0x18, offset) != 0)
+                       continue;
+
+               if (probe_kernel_address(rom + offset + 0x4, vendor) != 0)
+                       continue;
+
+               if (probe_kernel_address(rom + offset + 0x6, device) != 0)
+                       continue;
+
+               if (match_id(pdev, vendor, device)) {
+                       oprom = res;
+                       break;
+               }
+
+               if (probe_kernel_address(rom + offset + 0x8, list) == 0 &&
+                   probe_kernel_address(rom + offset + 0xc, rev) == 0 &&
+                   rev >= 3 && list &&
+                   probe_list(pdev, vendor, rom + offset + list)) {
+                       oprom = res;
+                       break;
+               }
+       }
+
+       return oprom;
+}
+
+void *pci_map_biosrom(struct pci_dev *pdev)
+{
+       struct resource *oprom = find_oprom(pdev);
+
+       if (!oprom)
+               return NULL;
+
+       return ioremap(oprom->start, resource_size(oprom));
+}
+EXPORT_SYMBOL(pci_map_biosrom);
+
+void pci_unmap_biosrom(void __iomem *image)
+{
+       iounmap(image);
+}
+EXPORT_SYMBOL(pci_unmap_biosrom);
+
+size_t pci_biosrom_size(struct pci_dev *pdev)
+{
+       struct resource *oprom = find_oprom(pdev);
+
+       return oprom ? resource_size(oprom) : 0;
+}
+EXPORT_SYMBOL(pci_biosrom_size);
+
 #define ROMSIGNATURE 0xaa55
 
 static int __init romsignature(const unsigned char *rom)
index d46cbe4..88a90a9 100644 (file)
@@ -449,7 +449,7 @@ EXPORT_SYMBOL_GPL(cpu_idle_wait);
 void mwait_idle_with_hints(unsigned long ax, unsigned long cx)
 {
        if (!need_resched()) {
-               if (cpu_has(__this_cpu_ptr(&cpu_info), X86_FEATURE_CLFLUSH_MONITOR))
+               if (this_cpu_has(X86_FEATURE_CLFLUSH_MONITOR))
                        clflush((void *)&current_thread_info()->flags);
 
                __monitor((void *)&current_thread_info()->flags, 0, 0);
@@ -465,7 +465,7 @@ static void mwait_idle(void)
        if (!need_resched()) {
                trace_power_start(POWER_CSTATE, 1, smp_processor_id());
                trace_cpu_idle(1, smp_processor_id());
-               if (cpu_has(__this_cpu_ptr(&cpu_info), X86_FEATURE_CLFLUSH_MONITOR))
+               if (this_cpu_has(X86_FEATURE_CLFLUSH_MONITOR))
                        clflush((void *)&current_thread_info()->flags);
 
                __monitor((void *)&current_thread_info()->flags, 0, 0);
index 08c44b0..0c016f7 100644 (file)
@@ -36,7 +36,7 @@ EXPORT_SYMBOL(pm_power_off);
 
 static const struct desc_ptr no_idt = {};
 static int reboot_mode;
-enum reboot_type reboot_type = BOOT_KBD;
+enum reboot_type reboot_type = BOOT_ACPI;
 int reboot_force;
 
 #if defined(CONFIG_X86_32) && defined(CONFIG_SMP)
@@ -478,9 +478,24 @@ void __attribute__((weak)) mach_reboot_fixups(void)
 {
 }
 
+/*
+ * Windows compatible x86 hardware expects the following on reboot:
+ *
+ * 1) If the FADT has the ACPI reboot register flag set, try it
+ * 2) If still alive, write to the keyboard controller
+ * 3) If still alive, write to the ACPI reboot register again
+ * 4) If still alive, write to the keyboard controller again
+ *
+ * If the machine is still alive at this stage, it gives up. We default to
+ * following the same pattern, except that if we're still alive after (4) we'll
+ * try to force a triple fault and then cycle between hitting the keyboard
+ * controller and doing that
+ */
 static void native_machine_emergency_restart(void)
 {
        int i;
+       int attempt = 0;
+       int orig_reboot_type = reboot_type;
 
        if (reboot_emergency)
                emergency_vmx_disable_all();
@@ -502,6 +517,13 @@ static void native_machine_emergency_restart(void)
                                outb(0xfe, 0x64); /* pulse reset low */
                                udelay(50);
                        }
+                       if (attempt == 0 && orig_reboot_type == BOOT_ACPI) {
+                               attempt = 1;
+                               reboot_type = BOOT_ACPI;
+                       } else {
+                               reboot_type = BOOT_TRIPLE;
+                       }
+                       break;
 
                case BOOT_TRIPLE:
                        load_idt(&no_idt);
index 4be9b39..c3050af 100644 (file)
@@ -691,8 +691,6 @@ early_param("reservelow", parse_reservelow);
 
 void __init setup_arch(char **cmdline_p)
 {
-       unsigned long flags;
-
 #ifdef CONFIG_X86_32
        memcpy(&boot_cpu_data, &new_cpu_data, sizeof(new_cpu_data));
        visws_early_detect();
@@ -1041,9 +1039,7 @@ void __init setup_arch(char **cmdline_p)
 
        mcheck_init();
 
-       local_irq_save(flags);
-       arch_init_ideal_nop5();
-       local_irq_restore(flags);
+       arch_init_ideal_nops();
 }
 
 #ifdef CONFIG_X86_32
index 513deac..013e7eb 100644 (file)
@@ -194,14 +194,13 @@ static void native_stop_other_cpus(int wait)
 }
 
 /*
- * Reschedule call back. Nothing to do,
- * all the work is done automatically when
- * we return from the interrupt.
+ * Reschedule call back.
  */
 void smp_reschedule_interrupt(struct pt_regs *regs)
 {
        ack_APIC_irq();
        inc_irq_stat(irq_resched_count);
+       scheduler_ipi();
        /*
         * KVM uses this interrupt to force a cpu out of guest mode
         */
index c2871d3..a3c430b 100644 (file)
@@ -1332,9 +1332,9 @@ static inline void mwait_play_dead(void)
        void *mwait_ptr;
        struct cpuinfo_x86 *c = __this_cpu_ptr(&cpu_info);
 
-       if (!(cpu_has(c, X86_FEATURE_MWAIT) && mwait_usable(c)))
+       if (!this_cpu_has(X86_FEATURE_MWAIT) && mwait_usable(c))
                return;
-       if (!cpu_has(__this_cpu_ptr(&cpu_info), X86_FEATURE_CLFLSH))
+       if (!this_cpu_has(X86_FEATURE_CLFLSH))
                return;
        if (__this_cpu_read(cpu_info.cpuid_level) < CPUID_MWAIT_LEAF)
                return;
index c11514e..6f164bd 100644 (file)
@@ -35,7 +35,7 @@ void iommu_shutdown_noop(void) { }
 struct x86_init_ops x86_init __initdata = {
 
        .resources = {
-               .probe_roms             = x86_init_noop,
+               .probe_roms             = probe_roms,
                .reserve_resources      = reserve_standard_io_resources,
                .memory_setup           = default_machine_specific_memory_setup,
        },
@@ -61,6 +61,10 @@ struct x86_init_ops x86_init __initdata = {
                .banner                 = default_banner,
        },
 
+       .mapping = {
+               .pagetable_reserve              = native_pagetable_reserve,
+       },
+
        .paging = {
                .pagetable_setup_start  = native_pagetable_setup_start,
                .pagetable_setup_done   = native_pagetable_setup_done,
index 1cd6089..e191c09 100644 (file)
@@ -7,7 +7,7 @@
  * kernel and insert a module (lg.ko) which allows us to run other Linux
  * kernels the same way we'd run processes.  We call the first kernel the Host,
  * and the others the Guests.  The program which sets up and configures Guests
- * (such as the example in Documentation/lguest/lguest.c) is called the
+ * (such as the example in Documentation/virtual/lguest/lguest.c) is called the
  * Launcher.
  *
  * Secondly, we only run specially modified Guests, not normal kernels: setting
@@ -913,8 +913,6 @@ static struct clocksource lguest_clock = {
        .rating         = 200,
        .read           = lguest_clock_read,
        .mask           = CLOCKSOURCE_MASK(64),
-       .mult           = 1 << 22,
-       .shift          = 22,
        .flags          = CLOCK_SOURCE_IS_CONTINUOUS,
 };
 
@@ -997,7 +995,7 @@ static void lguest_time_init(void)
        /* Set up the timer interrupt (0) to go to our simple timer routine */
        irq_set_handler(0, lguest_time_irq);
 
-       clocksource_register(&lguest_clock);
+       clocksource_register_hz(&lguest_clock, NSEC_PER_SEC);
 
        /* We can't set cpumask in the initializer: damn C limitations!  Set it
         * here and register our timer device. */
index daab21d..efbf2a0 100644 (file)
@@ -67,7 +67,7 @@ ENTRY(memcpy)
        jb .Lhandle_tail
 
        /*
-        * We check whether memory false dependece could occur,
+        * We check whether memory false dependence could occur,
         * then jump to corresponding copy mode.
         */
        cmp  %dil, %sil
index 3e608ed..3d11327 100644 (file)
@@ -23,8 +23,8 @@ mmiotrace-y                   := kmmio.o pf_in.o mmio-mod.o
 obj-$(CONFIG_MMIOTRACE_TEST)   += testmmiotrace.o
 
 obj-$(CONFIG_NUMA)             += numa.o numa_$(BITS).o
-obj-$(CONFIG_AMD_NUMA)         += amdtopology_64.o
-obj-$(CONFIG_ACPI_NUMA)                += srat_$(BITS).o
+obj-$(CONFIG_AMD_NUMA)         += amdtopology.o
+obj-$(CONFIG_ACPI_NUMA)                += srat.o
 obj-$(CONFIG_NUMA_EMU)         += numa_emulation.o
 
 obj-$(CONFIG_HAVE_MEMBLOCK)            += memblock.o
similarity index 90%
rename from arch/x86/mm/amdtopology_64.c
rename to arch/x86/mm/amdtopology.c
index 0919c26..5247d01 100644 (file)
@@ -12,6 +12,7 @@
 #include <linux/module.h>
 #include <linux/nodemask.h>
 #include <linux/memblock.h>
+#include <linux/bootmem.h>
 
 #include <asm/io.h>
 #include <linux/pci_ids.h>
@@ -69,10 +70,10 @@ static __init void early_get_boot_cpu_id(void)
 
 int __init amd_numa_init(void)
 {
-       unsigned long start = PFN_PHYS(0);
-       unsigned long end = PFN_PHYS(max_pfn);
+       u64 start = PFN_PHYS(0);
+       u64 end = PFN_PHYS(max_pfn);
        unsigned numnodes;
-       unsigned long prevbase;
+       u64 prevbase;
        int i, j, nb;
        u32 nodeid, reg;
        unsigned int bits, cores, apicid_base;
@@ -95,7 +96,7 @@ int __init amd_numa_init(void)
 
        prevbase = 0;
        for (i = 0; i < 8; i++) {
-               unsigned long base, limit;
+               u64 base, limit;
 
                base = read_pci_config(0, nb, 1, 0x40 + i*8);
                limit = read_pci_config(0, nb, 1, 0x44 + i*8);
@@ -107,18 +108,18 @@ int __init amd_numa_init(void)
                        continue;
                }
                if (nodeid >= numnodes) {
-                       pr_info("Ignoring excess node %d (%lx:%lx)\n", nodeid,
+                       pr_info("Ignoring excess node %d (%Lx:%Lx)\n", nodeid,
                                base, limit);
                        continue;
                }
 
                if (!limit) {
-                       pr_info("Skipping node entry %d (base %lx)\n",
+                       pr_info("Skipping node entry %d (base %Lx)\n",
                                i, base);
                        continue;
                }
                if ((base >> 8) & 3 || (limit >> 8) & 3) {
-                       pr_err("Node %d using interleaving mode %lx/%lx\n",
+                       pr_err("Node %d using interleaving mode %Lx/%Lx\n",
                               nodeid, (base >> 8) & 3, (limit >> 8) & 3);
                        return -EINVAL;
                }
@@ -150,19 +151,19 @@ int __init amd_numa_init(void)
                        continue;
                }
                if (limit < base) {
-                       pr_err("Node %d bogus settings %lx-%lx.\n",
+                       pr_err("Node %d bogus settings %Lx-%Lx.\n",
                               nodeid, base, limit);
                        continue;
                }
 
                /* Could sort here, but pun for now. Should not happen anyroads. */
                if (prevbase > base) {
-                       pr_err("Node map not sorted %lx,%lx\n",
+                       pr_err("Node map not sorted %Lx,%Lx\n",
                               prevbase, base);
                        return -EINVAL;
                }
 
-               pr_info("Node %d MemBase %016lx Limit %016lx\n",
+               pr_info("Node %d MemBase %016Lx Limit %016Lx\n",
                        nodeid, base, limit);
 
                prevbase = base;
index 286d289..37b8b0f 100644 (file)
@@ -81,6 +81,11 @@ static void __init find_early_table_space(unsigned long end, int use_pse,
                end, pgt_buf_start << PAGE_SHIFT, pgt_buf_top << PAGE_SHIFT);
 }
 
+void __init native_pagetable_reserve(u64 start, u64 end)
+{
+       memblock_x86_reserve_range(start, end, "PGTABLE");
+}
+
 struct map_range {
        unsigned long start;
        unsigned long end;
@@ -272,9 +277,24 @@ unsigned long __init_refok init_memory_mapping(unsigned long start,
 
        __flush_tlb_all();
 
+       /*
+        * Reserve the kernel pagetable pages we used (pgt_buf_start -
+        * pgt_buf_end) and free the other ones (pgt_buf_end - pgt_buf_top)
+        * so that they can be reused for other purposes.
+        *
+        * On native it just means calling memblock_x86_reserve_range, on Xen it
+        * also means marking RW the pagetable pages that we allocated before
+        * but that haven't been used.
+        *
+        * In fact on xen we mark RO the whole range pgt_buf_start -
+        * pgt_buf_top, because we have to make sure that when
+        * init_memory_mapping reaches the pagetable pages area, it maps
+        * RO all the pagetable pages, including the ones that are beyond
+        * pgt_buf_end at that time.
+        */
        if (!after_bootmem && pgt_buf_end > pgt_buf_start)
-               memblock_x86_reserve_range(pgt_buf_start << PAGE_SHIFT,
-                                pgt_buf_end << PAGE_SHIFT, "PGTABLE");
+               x86_init.mapping.pagetable_reserve(PFN_PHYS(pgt_buf_start),
+                               PFN_PHYS(pgt_buf_end));
 
        if (!after_bootmem)
                early_memtest(start, end);
index 80088f9..29f7c6d 100644 (file)
@@ -678,8 +678,10 @@ static void __init zone_sizes_init(void)
 {
        unsigned long max_zone_pfns[MAX_NR_ZONES];
        memset(max_zone_pfns, 0, sizeof(max_zone_pfns));
+#ifdef CONFIG_ZONE_DMA
        max_zone_pfns[ZONE_DMA] =
                virt_to_phys((char *)MAX_DMA_ADDRESS) >> PAGE_SHIFT;
+#endif
        max_zone_pfns[ZONE_NORMAL] = max_low_pfn;
 #ifdef CONFIG_HIGHMEM
        max_zone_pfns[ZONE_HIGHMEM] = highend_pfn;
@@ -716,6 +718,7 @@ void __init paging_init(void)
         * NOTE: at this point the bootmem allocator is fully available.
         */
        olpc_dt_build_devicetree();
+       sparse_memory_present_with_active_regions(MAX_NUMNODES);
        sparse_init();
        zone_sizes_init();
 }
index 7942335..d865c4a 100644 (file)
@@ -616,7 +616,9 @@ void __init paging_init(void)
        unsigned long max_zone_pfns[MAX_NR_ZONES];
 
        memset(max_zone_pfns, 0, sizeof(max_zone_pfns));
+#ifdef CONFIG_ZONE_DMA
        max_zone_pfns[ZONE_DMA] = MAX_DMA_PFN;
+#endif
        max_zone_pfns[ZONE_DMA32] = MAX_DMA32_PFN;
        max_zone_pfns[ZONE_NORMAL] = max_pfn;
 
@@ -679,14 +681,6 @@ int arch_add_memory(int nid, u64 start, u64 size)
 }
 EXPORT_SYMBOL_GPL(arch_add_memory);
 
-#if !defined(CONFIG_ACPI_NUMA) && defined(CONFIG_NUMA)
-int memory_add_physaddr_to_nid(u64 start)
-{
-       return 0;
-}
-EXPORT_SYMBOL_GPL(memory_add_physaddr_to_nid);
-#endif
-
 #endif /* CONFIG_MEMORY_HOTPLUG */
 
 static struct kcore_list kcore_vsyscall;
index 0369843..be1ef57 100644 (file)
@@ -91,13 +91,6 @@ static void __iomem *__ioremap_caller(resource_size_t phys_addr,
                return (__force void __iomem *)phys_to_virt(phys_addr);
 
        /*
-        * Check if the request spans more than any BAR in the iomem resource
-        * tree.
-        */
-       WARN_ONCE(iomem_map_sanity_check(phys_addr, size),
-                 KERN_INFO "Info: mapping multiple BARs. Your kernel is fine.");
-
-       /*
         * Don't allow anybody to remap normal RAM that we're using..
         */
        last_pfn = last_addr >> PAGE_SHIFT;
@@ -170,6 +163,13 @@ static void __iomem *__ioremap_caller(resource_size_t phys_addr,
        ret_addr = (void __iomem *) (vaddr + offset);
        mmiotrace_ioremap(unaligned_phys_addr, unaligned_size, ret_addr);
 
+       /*
+        * Check if the request spans more than any BAR in the iomem resource
+        * tree.
+        */
+       WARN_ONCE(iomem_map_sanity_check(unaligned_phys_addr, unaligned_size),
+                 KERN_INFO "Info: mapping multiple BARs. Your kernel is fine.");
+
        return ret_addr;
 err_free_area:
        free_vm_area(area);
index 745258d..f5510d8 100644 (file)
@@ -1,11 +1,39 @@
 /* Common code for 32 and 64-bit NUMA */
-#include <linux/topology.h>
-#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <linux/string.h>
+#include <linux/init.h>
 #include <linux/bootmem.h>
-#include <asm/numa.h>
+#include <linux/memblock.h>
+#include <linux/mmzone.h>
+#include <linux/ctype.h>
+#include <linux/module.h>
+#include <linux/nodemask.h>
+#include <linux/sched.h>
+#include <linux/topology.h>
+
+#include <asm/e820.h>
+#include <asm/proto.h>
+#include <asm/dma.h>
 #include <asm/acpi.h>
+#include <asm/amd_nb.h>
+
+#include "numa_internal.h"
 
 int __initdata numa_off;
+nodemask_t numa_nodes_parsed __initdata;
+
+struct pglist_data *node_data[MAX_NUMNODES] __read_mostly;
+EXPORT_SYMBOL(node_data);
+
+static struct numa_meminfo numa_meminfo
+#ifndef CONFIG_MEMORY_HOTPLUG
+__initdata
+#endif
+;
+
+static int numa_distance_cnt;
+static u8 *numa_distance;
 
 static __init int numa_setup(char *opt)
 {
@@ -32,6 +60,15 @@ s16 __apicid_to_node[MAX_LOCAL_APIC] __cpuinitdata = {
        [0 ... MAX_LOCAL_APIC-1] = NUMA_NO_NODE
 };
 
+int __cpuinit numa_cpu_node(int cpu)
+{
+       int apicid = early_per_cpu(x86_cpu_to_apicid, cpu);
+
+       if (apicid != BAD_APICID)
+               return __apicid_to_node[apicid];
+       return NUMA_NO_NODE;
+}
+
 cpumask_var_t node_to_cpumask_map[MAX_NUMNODES];
 EXPORT_SYMBOL(node_to_cpumask_map);
 
@@ -95,6 +132,407 @@ void __init setup_node_to_cpumask_map(void)
        pr_debug("Node to cpumask map for %d nodes\n", nr_node_ids);
 }
 
+static int __init numa_add_memblk_to(int nid, u64 start, u64 end,
+                                    struct numa_meminfo *mi)
+{
+       /* ignore zero length blks */
+       if (start == end)
+               return 0;
+
+       /* whine about and ignore invalid blks */
+       if (start > end || nid < 0 || nid >= MAX_NUMNODES) {
+               pr_warning("NUMA: Warning: invalid memblk node %d (%Lx-%Lx)\n",
+                          nid, start, end);
+               return 0;
+       }
+
+       if (mi->nr_blks >= NR_NODE_MEMBLKS) {
+               pr_err("NUMA: too many memblk ranges\n");
+               return -EINVAL;
+       }
+
+       mi->blk[mi->nr_blks].start = start;
+       mi->blk[mi->nr_blks].end = end;
+       mi->blk[mi->nr_blks].nid = nid;
+       mi->nr_blks++;
+       return 0;
+}
+
+/**
+ * numa_remove_memblk_from - Remove one numa_memblk from a numa_meminfo
+ * @idx: Index of memblk to remove
+ * @mi: numa_meminfo to remove memblk from
+ *
+ * Remove @idx'th numa_memblk from @mi by shifting @mi->blk[] and
+ * decrementing @mi->nr_blks.
+ */
+void __init numa_remove_memblk_from(int idx, struct numa_meminfo *mi)
+{
+       mi->nr_blks--;
+       memmove(&mi->blk[idx], &mi->blk[idx + 1],
+               (mi->nr_blks - idx) * sizeof(mi->blk[0]));
+}
+
+/**
+ * numa_add_memblk - Add one numa_memblk to numa_meminfo
+ * @nid: NUMA node ID of the new memblk
+ * @start: Start address of the new memblk
+ * @end: End address of the new memblk
+ *
+ * Add a new memblk to the default numa_meminfo.
+ *
+ * RETURNS:
+ * 0 on success, -errno on failure.
+ */
+int __init numa_add_memblk(int nid, u64 start, u64 end)
+{
+       return numa_add_memblk_to(nid, start, end, &numa_meminfo);
+}
+
+/* Initialize NODE_DATA for a node on the local memory */
+static void __init setup_node_data(int nid, u64 start, u64 end)
+{
+       const u64 nd_low = PFN_PHYS(MAX_DMA_PFN);
+       const u64 nd_high = PFN_PHYS(max_pfn_mapped);
+       const size_t nd_size = roundup(sizeof(pg_data_t), PAGE_SIZE);
+       bool remapped = false;
+       u64 nd_pa;
+       void *nd;
+       int tnid;
+
+       /*
+        * Don't confuse VM with a node that doesn't have the
+        * minimum amount of memory:
+        */
+       if (end && (end - start) < NODE_MIN_SIZE)
+               return;
+
+       /* initialize remap allocator before aligning to ZONE_ALIGN */
+       init_alloc_remap(nid, start, end);
+
+       start = roundup(start, ZONE_ALIGN);
+
+       printk(KERN_INFO "Initmem setup node %d %016Lx-%016Lx\n",
+              nid, start, end);
+
+       /*
+        * Allocate node data.  Try remap allocator first, node-local
+        * memory and then any node.  Never allocate in DMA zone.
+        */
+       nd = alloc_remap(nid, nd_size);
+       if (nd) {
+               nd_pa = __pa(nd);
+               remapped = true;
+       } else {
+               nd_pa = memblock_x86_find_in_range_node(nid, nd_low, nd_high,
+                                               nd_size, SMP_CACHE_BYTES);
+               if (nd_pa == MEMBLOCK_ERROR)
+                       nd_pa = memblock_find_in_range(nd_low, nd_high,
+                                               nd_size, SMP_CACHE_BYTES);
+               if (nd_pa == MEMBLOCK_ERROR) {
+                       pr_err("Cannot find %zu bytes in node %d\n",
+                              nd_size, nid);
+                       return;
+               }
+               memblock_x86_reserve_range(nd_pa, nd_pa + nd_size, "NODE_DATA");
+               nd = __va(nd_pa);
+       }
+
+       /* report and initialize */
+       printk(KERN_INFO "  NODE_DATA [%016Lx - %016Lx]%s\n",
+              nd_pa, nd_pa + nd_size - 1, remapped ? " (remapped)" : "");
+       tnid = early_pfn_to_nid(nd_pa >> PAGE_SHIFT);
+       if (!remapped && tnid != nid)
+               printk(KERN_INFO "    NODE_DATA(%d) on node %d\n", nid, tnid);
+
+       node_data[nid] = nd;
+       memset(NODE_DATA(nid), 0, sizeof(pg_data_t));
+       NODE_DATA(nid)->node_id = nid;
+       NODE_DATA(nid)->node_start_pfn = start >> PAGE_SHIFT;
+       NODE_DATA(nid)->node_spanned_pages = (end - start) >> PAGE_SHIFT;
+
+       node_set_online(nid);
+}
+
+/**
+ * numa_cleanup_meminfo - Cleanup a numa_meminfo
+ * @mi: numa_meminfo to clean up
+ *
+ * Sanitize @mi by merging and removing unncessary memblks.  Also check for
+ * conflicts and clear unused memblks.
+ *
+ * RETURNS:
+ * 0 on success, -errno on failure.
+ */
+int __init numa_cleanup_meminfo(struct numa_meminfo *mi)
+{
+       const u64 low = 0;
+       const u64 high = PFN_PHYS(max_pfn);
+       int i, j, k;
+
+       /* first, trim all entries */
+       for (i = 0; i < mi->nr_blks; i++) {
+               struct numa_memblk *bi = &mi->blk[i];
+
+               /* make sure all blocks are inside the limits */
+               bi->start = max(bi->start, low);
+               bi->end = min(bi->end, high);
+
+               /* and there's no empty block */
+               if (bi->start >= bi->end)
+                       numa_remove_memblk_from(i--, mi);
+       }
+
+       /* merge neighboring / overlapping entries */
+       for (i = 0; i < mi->nr_blks; i++) {
+               struct numa_memblk *bi = &mi->blk[i];
+
+               for (j = i + 1; j < mi->nr_blks; j++) {
+                       struct numa_memblk *bj = &mi->blk[j];
+                       u64 start, end;
+
+                       /*
+                        * See whether there are overlapping blocks.  Whine
+                        * about but allow overlaps of the same nid.  They
+                        * will be merged below.
+                        */
+                       if (bi->end > bj->start && bi->start < bj->end) {
+                               if (bi->nid != bj->nid) {
+                                       pr_err("NUMA: node %d (%Lx-%Lx) overlaps with node %d (%Lx-%Lx)\n",
+                                              bi->nid, bi->start, bi->end,
+                                              bj->nid, bj->start, bj->end);
+                                       return -EINVAL;
+                               }
+                               pr_warning("NUMA: Warning: node %d (%Lx-%Lx) overlaps with itself (%Lx-%Lx)\n",
+                                          bi->nid, bi->start, bi->end,
+                                          bj->start, bj->end);
+                       }
+
+                       /*
+                        * Join together blocks on the same node, holes
+                        * between which don't overlap with memory on other
+                        * nodes.
+                        */
+                       if (bi->nid != bj->nid)
+                               continue;
+                       start = min(bi->start, bj->start);
+                       end = max(bi->end, bj->end);
+                       for (k = 0; k < mi->nr_blks; k++) {
+                               struct numa_memblk *bk = &mi->blk[k];
+
+                               if (bi->nid == bk->nid)
+                                       continue;
+                               if (start < bk->end && end > bk->start)
+                                       break;
+                       }
+                       if (k < mi->nr_blks)
+                               continue;
+                       printk(KERN_INFO "NUMA: Node %d [%Lx,%Lx) + [%Lx,%Lx) -> [%Lx,%Lx)\n",
+                              bi->nid, bi->start, bi->end, bj->start, bj->end,
+                              start, end);
+                       bi->start = start;
+                       bi->end = end;
+                       numa_remove_memblk_from(j--, mi);
+               }
+       }
+
+       /* clear unused ones */
+       for (i = mi->nr_blks; i < ARRAY_SIZE(mi->blk); i++) {
+               mi->blk[i].start = mi->blk[i].end = 0;
+               mi->blk[i].nid = NUMA_NO_NODE;
+       }
+
+       return 0;
+}
+
+/*
+ * Set nodes, which have memory in @mi, in *@nodemask.
+ */
+static void __init numa_nodemask_from_meminfo(nodemask_t *nodemask,
+                                             const struct numa_meminfo *mi)
+{
+       int i;
+
+       for (i = 0; i < ARRAY_SIZE(mi->blk); i++)
+               if (mi->blk[i].start != mi->blk[i].end &&
+                   mi->blk[i].nid != NUMA_NO_NODE)
+                       node_set(mi->blk[i].nid, *nodemask);
+}
+
+/**
+ * numa_reset_distance - Reset NUMA distance table
+ *
+ * The current table is freed.  The next numa_set_distance() call will
+ * create a new one.
+ */
+void __init numa_reset_distance(void)
+{
+       size_t size = numa_distance_cnt * numa_distance_cnt * sizeof(numa_distance[0]);
+
+       /* numa_distance could be 1LU marking allocation failure, test cnt */
+       if (numa_distance_cnt)
+               memblock_x86_free_range(__pa(numa_distance),
+                                       __pa(numa_distance) + size);
+       numa_distance_cnt = 0;
+       numa_distance = NULL;   /* enable table creation */
+}
+
+static int __init numa_alloc_distance(void)
+{
+       nodemask_t nodes_parsed;
+       size_t size;
+       int i, j, cnt = 0;
+       u64 phys;
+
+       /* size the new table and allocate it */
+       nodes_parsed = numa_nodes_parsed;
+       numa_nodemask_from_meminfo(&nodes_parsed, &numa_meminfo);
+
+       for_each_node_mask(i, nodes_parsed)
+               cnt = i;
+       cnt++;
+       size = cnt * cnt * sizeof(numa_distance[0]);
+
+       phys = memblock_find_in_range(0, PFN_PHYS(max_pfn_mapped),
+                                     size, PAGE_SIZE);
+       if (phys == MEMBLOCK_ERROR) {
+               pr_warning("NUMA: Warning: can't allocate distance table!\n");
+               /* don't retry until explicitly reset */
+               numa_distance = (void *)1LU;
+               return -ENOMEM;
+       }
+       memblock_x86_reserve_range(phys, phys + size, "NUMA DIST");
+
+       numa_distance = __va(phys);
+       numa_distance_cnt = cnt;
+
+       /* fill with the default distances */
+       for (i = 0; i < cnt; i++)
+               for (j = 0; j < cnt; j++)
+                       numa_distance[i * cnt + j] = i == j ?
+                               LOCAL_DISTANCE : REMOTE_DISTANCE;
+       printk(KERN_DEBUG "NUMA: Initialized distance table, cnt=%d\n", cnt);
+
+       return 0;
+}
+
+/**
+ * numa_set_distance - Set NUMA distance from one NUMA to another
+ * @from: the 'from' node to set distance
+ * @to: the 'to'  node to set distance
+ * @distance: NUMA distance
+ *
+ * Set the distance from node @from to @to to @distance.  If distance table
+ * doesn't exist, one which is large enough to accommodate all the currently
+ * known nodes will be created.
+ *
+ * If such table cannot be allocated, a warning is printed and further
+ * calls are ignored until the distance table is reset with
+ * numa_reset_distance().
+ *
+ * If @from or @to is higher than the highest known node at the time of
+ * table creation or @distance doesn't make sense, the call is ignored.
+ * This is to allow simplification of specific NUMA config implementations.
+ */
+void __init numa_set_distance(int from, int to, int distance)
+{
+       if (!numa_distance && numa_alloc_distance() < 0)
+               return;
+
+       if (from >= numa_distance_cnt || to >= numa_distance_cnt) {
+               printk_once(KERN_DEBUG "NUMA: Debug: distance out of bound, from=%d to=%d distance=%d\n",
+                           from, to, distance);
+               return;
+       }
+
+       if ((u8)distance != distance ||
+           (from == to && distance != LOCAL_DISTANCE)) {
+               pr_warn_once("NUMA: Warning: invalid distance parameter, from=%d to=%d distance=%d\n",
+                            from, to, distance);
+               return;
+       }
+
+       numa_distance[from * numa_distance_cnt + to] = distance;
+}
+
+int __node_distance(int from, int to)
+{
+       if (from >= numa_distance_cnt || to >= numa_distance_cnt)
+               return from == to ? LOCAL_DISTANCE : REMOTE_DISTANCE;
+       return numa_distance[from * numa_distance_cnt + to];
+}
+EXPORT_SYMBOL(__node_distance);
+
+/*
+ * Sanity check to catch more bad NUMA configurations (they are amazingly
+ * common).  Make sure the nodes cover all memory.
+ */
+static bool __init numa_meminfo_cover_memory(const struct numa_meminfo *mi)
+{
+       u64 numaram, e820ram;
+       int i;
+
+       numaram = 0;
+       for (i = 0; i < mi->nr_blks; i++) {
+               u64 s = mi->blk[i].start >> PAGE_SHIFT;
+               u64 e = mi->blk[i].end >> PAGE_SHIFT;
+               numaram += e - s;
+               numaram -= __absent_pages_in_range(mi->blk[i].nid, s, e);
+               if ((s64)numaram < 0)
+                       numaram = 0;
+       }
+
+       e820ram = max_pfn - (memblock_x86_hole_size(0,
+                                       PFN_PHYS(max_pfn)) >> PAGE_SHIFT);
+       /* We seem to lose 3 pages somewhere. Allow 1M of slack. */
+       if ((s64)(e820ram - numaram) >= (1 << (20 - PAGE_SHIFT))) {
+               printk(KERN_ERR "NUMA: nodes only cover %LuMB of your %LuMB e820 RAM. Not used.\n",
+                      (numaram << PAGE_SHIFT) >> 20,
+                      (e820ram << PAGE_SHIFT) >> 20);
+               return false;
+       }
+       return true;
+}
+
+static int __init numa_register_memblks(struct numa_meminfo *mi)
+{
+       int i, nid;
+
+       /* Account for nodes with cpus and no memory */
+       node_possible_map = numa_nodes_parsed;
+       numa_nodemask_from_meminfo(&node_possible_map, mi);
+       if (WARN_ON(nodes_empty(node_possible_map)))
+               return -EINVAL;
+
+       for (i = 0; i < mi->nr_blks; i++)
+               memblock_x86_register_active_regions(mi->blk[i].nid,
+                                       mi->blk[i].start >> PAGE_SHIFT,
+                                       mi->blk[i].end >> PAGE_SHIFT);
+
+       /* for out of order entries */
+       sort_node_map();
+       if (!numa_meminfo_cover_memory(mi))
+               return -EINVAL;
+
+       /* Finally register nodes. */
+       for_each_node_mask(nid, node_possible_map) {
+               u64 start = PFN_PHYS(max_pfn);
+               u64 end = 0;
+
+               for (i = 0; i < mi->nr_blks; i++) {
+                       if (nid != mi->blk[i].nid)
+                               continue;
+                       start = min(mi->blk[i].start, start);
+                       end = max(mi->blk[i].end, end);
+               }
+
+               if (start < end)
+                       setup_node_data(nid, start, end);
+       }
+
+       return 0;
+}
+
 /*
  * There are unfortunately some poorly designed mainboards around that
  * only connect memory to a single CPU. This breaks the 1:1 cpu->node
@@ -102,7 +540,7 @@ void __init setup_node_to_cpumask_map(void)
  * as the number of CPUs is not known yet. We round robin the existing
  * nodes.
  */
-void __init numa_init_array(void)
+static void __init numa_init_array(void)
 {
        int rr, i;
 
@@ -117,6 +555,95 @@ void __init numa_init_array(void)
        }
 }
 
+static int __init numa_init(int (*init_func)(void))
+{
+       int i;
+       int ret;
+
+       for (i = 0; i < MAX_LOCAL_APIC; i++)
+               set_apicid_to_node(i, NUMA_NO_NODE);
+
+       nodes_clear(numa_nodes_parsed);
+       nodes_clear(node_possible_map);
+       nodes_clear(node_online_map);
+       memset(&numa_meminfo, 0, sizeof(numa_meminfo));
+       remove_all_active_ranges();
+       numa_reset_distance();
+
+       ret = init_func();
+       if (ret < 0)
+               return ret;
+       ret = numa_cleanup_meminfo(&numa_meminfo);
+       if (ret < 0)
+               return ret;
+
+       numa_emulation(&numa_meminfo, numa_distance_cnt);
+
+       ret = numa_register_memblks(&numa_meminfo);
+       if (ret < 0)
+               return ret;
+
+       for (i = 0; i < nr_cpu_ids; i++) {
+               int nid = early_cpu_to_node(i);
+
+               if (nid == NUMA_NO_NODE)
+                       continue;
+               if (!node_online(nid))
+                       numa_clear_node(i);
+       }
+       numa_init_array();
+       return 0;
+}
+
+/**
+ * dummy_numa_init - Fallback dummy NUMA init
+ *
+ * Used if there's no underlying NUMA architecture, NUMA initialization
+ * fails, or NUMA is disabled on the command line.
+ *
+ * Must online at least one node and add memory blocks that cover all
+ * allowed memory.  This function must not fail.
+ */
+static int __init dummy_numa_init(void)
+{
+       printk(KERN_INFO "%s\n",
+              numa_off ? "NUMA turned off" : "No NUMA configuration found");
+       printk(KERN_INFO "Faking a node at %016Lx-%016Lx\n",
+              0LLU, PFN_PHYS(max_pfn));
+
+       node_set(0, numa_nodes_parsed);
+       numa_add_memblk(0, 0, PFN_PHYS(max_pfn));
+
+       return 0;
+}
+
+/**
+ * x86_numa_init - Initialize NUMA
+ *
+ * Try each configured NUMA initialization method until one succeeds.  The
+ * last fallback is dummy single node config encomapssing whole memory and
+ * never fails.
+ */
+void __init x86_numa_init(void)
+{
+       if (!numa_off) {
+#ifdef CONFIG_X86_NUMAQ
+               if (!numa_init(numaq_numa_init))
+                       return;
+#endif
+#ifdef CONFIG_ACPI_NUMA
+               if (!numa_init(x86_acpi_numa_init))
+                       return;
+#endif
+#ifdef CONFIG_AMD_NUMA
+               if (!numa_init(amd_numa_init))
+                       return;
+#endif
+       }
+
+       numa_init(dummy_numa_init);
+}
+
 static __init int find_near_online_node(int node)
 {
        int n, val;
@@ -282,3 +809,18 @@ const struct cpumask *cpumask_of_node(int node)
 EXPORT_SYMBOL(cpumask_of_node);
 
 #endif /* !CONFIG_DEBUG_PER_CPU_MAPS */
+
+#ifdef CONFIG_MEMORY_HOTPLUG
+int memory_add_physaddr_to_nid(u64 start)
+{
+       struct numa_meminfo *mi = &numa_meminfo;
+       int nid = mi->blk[0].nid;
+       int i;
+
+       for (i = 0; i < mi->nr_blks; i++)
+               if (mi->blk[i].start <= start && mi->blk[i].end > start)
+                       nid = mi->blk[i].nid;
+       return nid;
+}
+EXPORT_SYMBOL_GPL(memory_add_physaddr_to_nid);
+#endif
index bde3906..849a975 100644 (file)
  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  */
 
-#include <linux/mm.h>
 #include <linux/bootmem.h>
 #include <linux/memblock.h>
-#include <linux/mmzone.h>
-#include <linux/highmem.h>
-#include <linux/initrd.h>
-#include <linux/nodemask.h>
 #include <linux/module.h>
-#include <linux/kexec.h>
-#include <linux/pfn.h>
-#include <linux/swap.h>
-#include <linux/acpi.h>
-
-#include <asm/e820.h>
-#include <asm/setup.h>
-#include <asm/mmzone.h>
-#include <asm/bios_ebda.h>
-#include <asm/proto.h>
-
-struct pglist_data *node_data[MAX_NUMNODES] __read_mostly;
-EXPORT_SYMBOL(node_data);
-
-/*
- * numa interface - we expect the numa architecture specific code to have
- *                  populated the following initialisation.
- *
- * 1) node_online_map  - the map of all nodes configured (online) in the system
- * 2) node_start_pfn   - the starting page frame number for a node
- * 3) node_end_pfn     - the ending page fram number for a node
- */
-unsigned long node_start_pfn[MAX_NUMNODES] __read_mostly;
-unsigned long node_end_pfn[MAX_NUMNODES] __read_mostly;
 
+#include "numa_internal.h"
 
 #ifdef CONFIG_DISCONTIGMEM
 /*
@@ -99,108 +71,46 @@ unsigned long node_memmap_size_bytes(int nid, unsigned long start_pfn,
 }
 #endif
 
-extern unsigned long find_max_low_pfn(void);
 extern unsigned long highend_pfn, highstart_pfn;
 
 #define LARGE_PAGE_BYTES (PTRS_PER_PTE * PAGE_SIZE)
 
-unsigned long node_remap_size[MAX_NUMNODES];
 static void *node_remap_start_vaddr[MAX_NUMNODES];
 void set_pmd_pfn(unsigned long vaddr, unsigned long pfn, pgprot_t flags);
 
-static unsigned long kva_start_pfn;
-static unsigned long kva_pages;
-
-int __cpuinit numa_cpu_node(int cpu)
-{
-       return apic->x86_32_numa_cpu_node(cpu);
-}
-
-/*
- * FLAT - support for basic PC memory model with discontig enabled, essentially
- *        a single node with all available processors in it with a flat
- *        memory map.
- */
-int __init get_memcfg_numa_flat(void)
-{
-       printk(KERN_DEBUG "NUMA - single node, flat memory mode\n");
-
-       node_start_pfn[0] = 0;
-       node_end_pfn[0] = max_pfn;
-       memblock_x86_register_active_regions(0, 0, max_pfn);
-       memory_present(0, 0, max_pfn);
-       node_remap_size[0] = node_memmap_size_bytes(0, 0, max_pfn);
-
-        /* Indicate there is one node available. */
-       nodes_clear(node_online_map);
-       node_set_online(0);
-       return 1;
-}
-
-/*
- * Find the highest page frame number we have available for the node
- */
-static void __init propagate_e820_map_node(int nid)
-{
-       if (node_end_pfn[nid] > max_pfn)
-               node_end_pfn[nid] = max_pfn;
-       /*
-        * if a user has given mem=XXXX, then we need to make sure 
-        * that the node _starts_ before that, too, not just ends
-        */
-       if (node_start_pfn[nid] > max_pfn)
-               node_start_pfn[nid] = max_pfn;
-       BUG_ON(node_start_pfn[nid] > node_end_pfn[nid]);
-}
-
-/* 
- * Allocate memory for the pg_data_t for this node via a crude pre-bootmem
- * method.  For node zero take this from the bottom of memory, for
- * subsequent nodes place them at node_remap_start_vaddr which contains
- * node local data in physically node local memory.  See setup_memory()
- * for details.
- */
-static void __init allocate_pgdat(int nid)
-{
-       char buf[16];
-
-       if (node_has_online_mem(nid) && node_remap_start_vaddr[nid])
-               NODE_DATA(nid) = (pg_data_t *)node_remap_start_vaddr[nid];
-       else {
-               unsigned long pgdat_phys;
-               pgdat_phys = memblock_find_in_range(min_low_pfn<<PAGE_SHIFT,
-                                max_pfn_mapped<<PAGE_SHIFT,
-                                sizeof(pg_data_t),
-                                PAGE_SIZE);
-               NODE_DATA(nid) = (pg_data_t *)(pfn_to_kaddr(pgdat_phys>>PAGE_SHIFT));
-               memset(buf, 0, sizeof(buf));
-               sprintf(buf, "NODE_DATA %d",  nid);
-               memblock_x86_reserve_range(pgdat_phys, pgdat_phys + sizeof(pg_data_t), buf);
-       }
-       printk(KERN_DEBUG "allocate_pgdat: node %d NODE_DATA %08lx\n",
-               nid, (unsigned long)NODE_DATA(nid));
-}
-
 /*
- * In the DISCONTIGMEM and SPARSEMEM memory model, a portion of the kernel
- * virtual address space (KVA) is reserved and portions of nodes are mapped
- * using it. This is to allow node-local memory to be allocated for
- * structures that would normally require ZONE_NORMAL. The memory is
- * allocated with alloc_remap() and callers should be prepared to allocate
- * from the bootmem allocator instead.
+ * Remap memory allocator
  */
 static unsigned long node_remap_start_pfn[MAX_NUMNODES];
 static void *node_remap_end_vaddr[MAX_NUMNODES];
 static void *node_remap_alloc_vaddr[MAX_NUMNODES];
-static unsigned long node_remap_offset[MAX_NUMNODES];
 
+/**
+ * alloc_remap - Allocate remapped memory
+ * @nid: NUMA node to allocate memory from
+ * @size: The size of allocation
+ *
+ * Allocate @size bytes from the remap area of NUMA node @nid.  The
+ * size of the remap area is predetermined by init_alloc_remap() and
+ * only the callers considered there should call this function.  For
+ * more info, please read the comment on top of init_alloc_remap().
+ *
+ * The caller must be ready to handle allocation failure from this
+ * function and fall back to regular memory allocator in such cases.
+ *
+ * CONTEXT:
+ * Single CPU early boot context.
+ *
+ * RETURNS:
+ * Pointer to the allocated memory on success, %NULL on failure.
+ */
 void *alloc_remap(int nid, unsigned long size)
 {
        void *allocation = node_remap_alloc_vaddr[nid];
 
        size = ALIGN(size, L1_CACHE_BYTES);
 
-       if (!allocation || (allocation + size) >= node_remap_end_vaddr[nid])
+       if (!allocation || (allocation + size) > node_remap_end_vaddr[nid])
                return NULL;
 
        node_remap_alloc_vaddr[nid] += size;
@@ -209,26 +119,6 @@ void *alloc_remap(int nid, unsigned long size)
        return allocation;
 }
 
-static void __init remap_numa_kva(void)
-{
-       void *vaddr;
-       unsigned long pfn;
-       int node;
-
-       for_each_online_node(node) {
-               printk(KERN_DEBUG "remap_numa_kva: node %d\n", node);
-               for (pfn=0; pfn < node_remap_size[node]; pfn += PTRS_PER_PTE) {
-                       vaddr = node_remap_start_vaddr[node]+(pfn<<PAGE_SHIFT);
-                       printk(KERN_DEBUG "remap_numa_kva: %08lx to pfn %08lx\n",
-                               (unsigned long)vaddr,
-                               node_remap_start_pfn[node] + pfn);
-                       set_pmd_pfn((ulong) vaddr, 
-                               node_remap_start_pfn[node] + pfn, 
-                               PAGE_KERNEL_LARGE);
-               }
-       }
-}
-
 #ifdef CONFIG_HIBERNATION
 /**
  * resume_map_numa_kva - add KVA mapping to the temporary page tables created
@@ -240,15 +130,16 @@ void resume_map_numa_kva(pgd_t *pgd_base)
        int node;
 
        for_each_online_node(node) {
-               unsigned long start_va, start_pfn, size, pfn;
+               unsigned long start_va, start_pfn, nr_pages, pfn;
 
                start_va = (unsigned long)node_remap_start_vaddr[node];
                start_pfn = node_remap_start_pfn[node];
-               size = node_remap_size[node];
+               nr_pages = (node_remap_end_vaddr[node] -
+                           node_remap_start_vaddr[node]) >> PAGE_SHIFT;
 
                printk(KERN_DEBUG "%s: node %d\n", __func__, node);
 
-               for (pfn = 0; pfn < size; pfn += PTRS_PER_PTE) {
+               for (pfn = 0; pfn < nr_pages; pfn += PTRS_PER_PTE) {
                        unsigned long vaddr = start_va + (pfn << PAGE_SHIFT);
                        pgd_t *pgd = pgd_base + pgd_index(vaddr);
                        pud_t *pud = pud_offset(pgd, vaddr);
@@ -264,132 +155,89 @@ void resume_map_numa_kva(pgd_t *pgd_base)
 }
 #endif
 
-static __init unsigned long calculate_numa_remap_pages(void)
+/**
+ * init_alloc_remap - Initialize remap allocator for a NUMA node
+ * @nid: NUMA node to initizlie remap allocator for
+ *
+ * NUMA nodes may end up without any lowmem.  As allocating pgdat and
+ * memmap on a different node with lowmem is inefficient, a special
+ * remap allocator is implemented which can be used by alloc_remap().
+ *
+ * For each node, the amount of memory which will be necessary for
+ * pgdat and memmap is calculated and two memory areas of the size are
+ * allocated - one in the node and the other in lowmem; then, the area
+ * in the node is remapped to the lowmem area.
+ *
+ * As pgdat and memmap must be allocated in lowmem anyway, this
+ * doesn't waste lowmem address space; however, the actual lowmem
+ * which gets remapped over is wasted.  The amount shouldn't be
+ * problematic on machines this feature will be used.
+ *
+ * Initialization failure isn't fatal.  alloc_remap() is used
+ * opportunistically and the callers will fall back to other memory
+ * allocation mechanisms on failure.
+ */
+void __init init_alloc_remap(int nid, u64 start, u64 end)
 {
-       int nid;
-       unsigned long size, reserve_pages = 0;
-
-       for_each_online_node(nid) {
-               u64 node_kva_target;
-               u64 node_kva_final;
-
-               /*
-                * The acpi/srat node info can show hot-add memroy zones
-                * where memory could be added but not currently present.
-                */
-               printk(KERN_DEBUG "node %d pfn: [%lx - %lx]\n",
-                       nid, node_start_pfn[nid], node_end_pfn[nid]);
-               if (node_start_pfn[nid] > max_pfn)
-                       continue;
-               if (!node_end_pfn[nid])
-                       continue;
-               if (node_end_pfn[nid] > max_pfn)
-                       node_end_pfn[nid] = max_pfn;
-
-               /* ensure the remap includes space for the pgdat. */
-               size = node_remap_size[nid] + sizeof(pg_data_t);
-
-               /* convert size to large (pmd size) pages, rounding up */
-               size = (size + LARGE_PAGE_BYTES - 1) / LARGE_PAGE_BYTES;
-               /* now the roundup is correct, convert to PAGE_SIZE pages */
-               size = size * PTRS_PER_PTE;
-
-               node_kva_target = round_down(node_end_pfn[nid] - size,
-                                                PTRS_PER_PTE);
-               node_kva_target <<= PAGE_SHIFT;
-               do {
-                       node_kva_final = memblock_find_in_range(node_kva_target,
-                                       ((u64)node_end_pfn[nid])<<PAGE_SHIFT,
-                                               ((u64)size)<<PAGE_SHIFT,
-                                               LARGE_PAGE_BYTES);
-                       node_kva_target -= LARGE_PAGE_BYTES;
-               } while (node_kva_final == MEMBLOCK_ERROR &&
-                        (node_kva_target>>PAGE_SHIFT) > (node_start_pfn[nid]));
-
-               if (node_kva_final == MEMBLOCK_ERROR)
-                       panic("Can not get kva ram\n");
-
-               node_remap_size[nid] = size;
-               node_remap_offset[nid] = reserve_pages;
-               reserve_pages += size;
-               printk(KERN_DEBUG "Reserving %ld pages of KVA for lmem_map of"
-                                 " node %d at %llx\n",
-                               size, nid, node_kva_final>>PAGE_SHIFT);
-
-               /*
-                *  prevent kva address below max_low_pfn want it on system
-                *  with less memory later.
-                *  layout will be: KVA address , KVA RAM
-                *
-                *  we are supposed to only record the one less then max_low_pfn
-                *  but we could have some hole in high memory, and it will only
-                *  check page_is_ram(pfn) && !page_is_reserved_early(pfn) to decide
-                *  to use it as free.
-                *  So memblock_x86_reserve_range here, hope we don't run out of that array
-                */
-               memblock_x86_reserve_range(node_kva_final,
-                             node_kva_final+(((u64)size)<<PAGE_SHIFT),
-                             "KVA RAM");
-
-               node_remap_start_pfn[nid] = node_kva_final>>PAGE_SHIFT;
-       }
-       printk(KERN_INFO "Reserving total of %lx pages for numa KVA remap\n",
-                       reserve_pages);
-       return reserve_pages;
-}
+       unsigned long start_pfn = start >> PAGE_SHIFT;
+       unsigned long end_pfn = end >> PAGE_SHIFT;
+       unsigned long size, pfn;
+       u64 node_pa, remap_pa;
+       void *remap_va;
 
-static void init_remap_allocator(int nid)
-{
-       node_remap_start_vaddr[nid] = pfn_to_kaddr(
-                       kva_start_pfn + node_remap_offset[nid]);
-       node_remap_end_vaddr[nid] = node_remap_start_vaddr[nid] +
-               (node_remap_size[nid] * PAGE_SIZE);
-       node_remap_alloc_vaddr[nid] = node_remap_start_vaddr[nid] +
-               ALIGN(sizeof(pg_data_t), PAGE_SIZE);
-
-       printk(KERN_DEBUG "node %d will remap to vaddr %08lx - %08lx\n", nid,
-               (ulong) node_remap_start_vaddr[nid],
-               (ulong) node_remap_end_vaddr[nid]);
+       /*
+        * The acpi/srat node info can show hot-add memroy zones where
+        * memory could be added but not currently present.
+        */
+       printk(KERN_DEBUG "node %d pfn: [%lx - %lx]\n",
+              nid, start_pfn, end_pfn);
+
+       /* calculate the necessary space aligned to large page size */
+       size = node_memmap_size_bytes(nid, start_pfn, end_pfn);
+       size += ALIGN(sizeof(pg_data_t), PAGE_SIZE);
+       size = ALIGN(size, LARGE_PAGE_BYTES);
+
+       /* allocate node memory and the lowmem remap area */
+       node_pa = memblock_find_in_range(start, end, size, LARGE_PAGE_BYTES);
+       if (node_pa == MEMBLOCK_ERROR) {
+               pr_warning("remap_alloc: failed to allocate %lu bytes for node %d\n",
+                          size, nid);
+               return;
+       }
+       memblock_x86_reserve_range(node_pa, node_pa + size, "KVA RAM");
+
+       remap_pa = memblock_find_in_range(min_low_pfn << PAGE_SHIFT,
+                                         max_low_pfn << PAGE_SHIFT,
+                                         size, LARGE_PAGE_BYTES);
+       if (remap_pa == MEMBLOCK_ERROR) {
+               pr_warning("remap_alloc: failed to allocate %lu bytes remap area for node %d\n",
+                          size, nid);
+               memblock_x86_free_range(node_pa, node_pa + size);
+               return;
+       }
+       memblock_x86_reserve_range(remap_pa, remap_pa + size, "KVA PG");
+       remap_va = phys_to_virt(remap_pa);
+
+       /* perform actual remap */
+       for (pfn = 0; pfn < size >> PAGE_SHIFT; pfn += PTRS_PER_PTE)
+               set_pmd_pfn((unsigned long)remap_va + (pfn << PAGE_SHIFT),
+                           (node_pa >> PAGE_SHIFT) + pfn,
+                           PAGE_KERNEL_LARGE);
+
+       /* initialize remap allocator parameters */
+       node_remap_start_pfn[nid] = node_pa >> PAGE_SHIFT;
+       node_remap_start_vaddr[nid] = remap_va;
+       node_remap_end_vaddr[nid] = remap_va + size;
+       node_remap_alloc_vaddr[nid] = remap_va;
+
+       printk(KERN_DEBUG "remap_alloc: node %d [%08llx-%08llx) -> [%p-%p)\n",
+              nid, node_pa, node_pa + size, remap_va, remap_va + size);
 }
 
 void __init initmem_init(void)
 {
-       int nid;
-       long kva_target_pfn;
-
-       /*
-        * When mapping a NUMA machine we allocate the node_mem_map arrays
-        * from node local memory.  They are then mapped directly into KVA
-        * between zone normal and vmalloc space.  Calculate the size of
-        * this space and use it to adjust the boundary between ZONE_NORMAL
-        * and ZONE_HIGHMEM.
-        */
-
-       get_memcfg_numa();
-       numa_init_array();
-
-       kva_pages = roundup(calculate_numa_remap_pages(), PTRS_PER_PTE);
+       x86_numa_init();
 
-       kva_target_pfn = round_down(max_low_pfn - kva_pages, PTRS_PER_PTE);
-       do {
-               kva_start_pfn = memblock_find_in_range(kva_target_pfn<<PAGE_SHIFT,
-                                       max_low_pfn<<PAGE_SHIFT,
-                                       kva_pages<<PAGE_SHIFT,
-                                       PTRS_PER_PTE<<PAGE_SHIFT) >> PAGE_SHIFT;
-               kva_target_pfn -= PTRS_PER_PTE;
-       } while (kva_start_pfn == MEMBLOCK_ERROR && kva_target_pfn > min_low_pfn);
-
-       if (kva_start_pfn == MEMBLOCK_ERROR)
-               panic("Can not get kva space\n");
-
-       printk(KERN_INFO "kva_start_pfn ~ %lx max_low_pfn ~ %lx\n",
-               kva_start_pfn, max_low_pfn);
-       printk(KERN_INFO "max_pfn = %lx\n", max_pfn);
-
-       /* avoid clash with initrd */
-       memblock_x86_reserve_range(kva_start_pfn<<PAGE_SHIFT,
-                     (kva_start_pfn + kva_pages)<<PAGE_SHIFT,
-                    "KVA PG");
 #ifdef CONFIG_HIGHMEM
        highstart_pfn = highend_pfn = max_pfn;
        if (max_pfn > max_low_pfn)
@@ -409,51 +257,9 @@ void __init initmem_init(void)
 
        printk(KERN_DEBUG "Low memory ends at vaddr %08lx\n",
                        (ulong) pfn_to_kaddr(max_low_pfn));
-       for_each_online_node(nid) {
-               init_remap_allocator(nid);
-
-               allocate_pgdat(nid);
-       }
-       remap_numa_kva();
 
        printk(KERN_DEBUG "High memory starts at vaddr %08lx\n",
                        (ulong) pfn_to_kaddr(highstart_pfn));
-       for_each_online_node(nid)
-               propagate_e820_map_node(nid);
-
-       for_each_online_node(nid) {
-               memset(NODE_DATA(nid), 0, sizeof(struct pglist_data));
-               NODE_DATA(nid)->node_id = nid;
-       }
 
        setup_bootmem_allocator();
 }
-
-#ifdef CONFIG_MEMORY_HOTPLUG
-static int paddr_to_nid(u64 addr)
-{
-       int nid;
-       unsigned long pfn = PFN_DOWN(addr);
-
-       for_each_node(nid)
-               if (node_start_pfn[nid] <= pfn &&
-                   pfn < node_end_pfn[nid])
-                       return nid;
-
-       return -1;
-}
-
-/*
- * This function is used to ask node id BEFORE memmap and mem_section's
- * initialization (pfn_to_nid() can't be used yet).
- * If _PXM is not defined on ACPI's DSDT, node id must be found by this.
- */
-int memory_add_physaddr_to_nid(u64 addr)
-{
-       int nid = paddr_to_nid(addr);
-       return (nid >= 0) ? nid : 0;
-}
-
-EXPORT_SYMBOL_GPL(memory_add_physaddr_to_nid);
-#endif
-
index 85b52fc..dd27f40 100644 (file)
  * Generic VM initialization for x86-64 NUMA setups.
  * Copyright 2002,2003 Andi Kleen, SuSE Labs.
  */
-#include <linux/kernel.h>
-#include <linux/mm.h>
-#include <linux/string.h>
-#include <linux/init.h>
 #include <linux/bootmem.h>
-#include <linux/memblock.h>
-#include <linux/mmzone.h>
-#include <linux/ctype.h>
-#include <linux/module.h>
-#include <linux/nodemask.h>
-#include <linux/sched.h>
-#include <linux/acpi.h>
-
-#include <asm/e820.h>
-#include <asm/proto.h>
-#include <asm/dma.h>
-#include <asm/acpi.h>
-#include <asm/amd_nb.h>
 
 #include "numa_internal.h"
 
-struct pglist_data *node_data[MAX_NUMNODES] __read_mostly;
-EXPORT_SYMBOL(node_data);
-
-nodemask_t numa_nodes_parsed __initdata;
-
-struct memnode memnode;
-
-static unsigned long __initdata nodemap_addr;
-static unsigned long __initdata nodemap_size;
-
-static struct numa_meminfo numa_meminfo __initdata;
-
-static int numa_distance_cnt;
-static u8 *numa_distance;
-
-/*
- * Given a shift value, try to populate memnodemap[]
- * Returns :
- * 1 if OK
- * 0 if memnodmap[] too small (of shift too small)
- * -1 if node overlap or lost ram (shift too big)
- */
-static int __init populate_memnodemap(const struct numa_meminfo *mi, int shift)
-{
-       unsigned long addr, end;
-       int i, res = -1;
-
-       memset(memnodemap, 0xff, sizeof(s16)*memnodemapsize);
-       for (i = 0; i < mi->nr_blks; i++) {
-               addr = mi->blk[i].start;
-               end = mi->blk[i].end;
-               if (addr >= end)
-                       continue;
-               if ((end >> shift) >= memnodemapsize)
-                       return 0;
-               do {
-                       if (memnodemap[addr >> shift] != NUMA_NO_NODE)
-                               return -1;
-                       memnodemap[addr >> shift] = mi->blk[i].nid;
-                       addr += (1UL << shift);
-               } while (addr < end);
-               res = 1;
-       }
-       return res;
-}
-
-static int __init allocate_cachealigned_memnodemap(void)
-{
-       unsigned long addr;
-
-       memnodemap = memnode.embedded_map;
-       if (memnodemapsize <= ARRAY_SIZE(memnode.embedded_map))
-               return 0;
-
-       addr = 0x8000;
-       nodemap_size = roundup(sizeof(s16) * memnodemapsize, L1_CACHE_BYTES);
-       nodemap_addr = memblock_find_in_range(addr, get_max_mapped(),
-                                     nodemap_size, L1_CACHE_BYTES);
-       if (nodemap_addr == MEMBLOCK_ERROR) {
-               printk(KERN_ERR
-                      "NUMA: Unable to allocate Memory to Node hash map\n");
-               nodemap_addr = nodemap_size = 0;
-               return -1;
-       }
-       memnodemap = phys_to_virt(nodemap_addr);
-       memblock_x86_reserve_range(nodemap_addr, nodemap_addr + nodemap_size, "MEMNODEMAP");
-
-       printk(KERN_DEBUG "NUMA: Allocated memnodemap from %lx - %lx\n",
-              nodemap_addr, nodemap_addr + nodemap_size);
-       return 0;
-}
-
-/*
- * The LSB of all start and end addresses in the node map is the value of the
- * maximum possible shift.
- */
-static int __init extract_lsb_from_nodes(const struct numa_meminfo *mi)
-{
-       int i, nodes_used = 0;
-       unsigned long start, end;
-       unsigned long bitfield = 0, memtop = 0;
-
-       for (i = 0; i < mi->nr_blks; i++) {
-               start = mi->blk[i].start;
-               end = mi->blk[i].end;
-               if (start >= end)
-                       continue;
-               bitfield |= start;
-               nodes_used++;
-               if (end > memtop)
-                       memtop = end;
-       }
-       if (nodes_used <= 1)
-               i = 63;
-       else
-               i = find_first_bit(&bitfield, sizeof(unsigned long)*8);
-       memnodemapsize = (memtop >> i)+1;
-       return i;
-}
-
-static int __init compute_hash_shift(const struct numa_meminfo *mi)
-{
-       int shift;
-
-       shift = extract_lsb_from_nodes(mi);
-       if (allocate_cachealigned_memnodemap())
-               return -1;
-       printk(KERN_DEBUG "NUMA: Using %d for the hash shift.\n",
-               shift);
-
-       if (populate_memnodemap(mi, shift) != 1) {
-               printk(KERN_INFO "Your memory is not aligned you need to "
-                      "rebuild your kernel with a bigger NODEMAPSIZE "
-                      "shift=%d\n", shift);
-               return -1;
-       }
-       return shift;
-}
-
-int __meminit  __early_pfn_to_nid(unsigned long pfn)
-{
-       return phys_to_nid(pfn << PAGE_SHIFT);
-}
-
-static void * __init early_node_mem(int nodeid, unsigned long start,
-                                   unsigned long end, unsigned long size,
-                                   unsigned long align)
-{
-       unsigned long mem;
-
-       /*
-        * put it on high as possible
-        * something will go with NODE_DATA
-        */
-       if (start < (MAX_DMA_PFN<<PAGE_SHIFT))
-               start = MAX_DMA_PFN<<PAGE_SHIFT;
-       if (start < (MAX_DMA32_PFN<<PAGE_SHIFT) &&
-           end > (MAX_DMA32_PFN<<PAGE_SHIFT))
-               start = MAX_DMA32_PFN<<PAGE_SHIFT;
-       mem = memblock_x86_find_in_range_node(nodeid, start, end, size, align);
-       if (mem != MEMBLOCK_ERROR)
-               return __va(mem);
-
-       /* extend the search scope */
-       end = max_pfn_mapped << PAGE_SHIFT;
-       start = MAX_DMA_PFN << PAGE_SHIFT;
-       mem = memblock_find_in_range(start, end, size, align);
-       if (mem != MEMBLOCK_ERROR)
-               return __va(mem);
-
-       printk(KERN_ERR "Cannot find %lu bytes in node %d\n",
-                      size, nodeid);
-
-       return NULL;
-}
-
-static int __init numa_add_memblk_to(int nid, u64 start, u64 end,
-                                    struct numa_meminfo *mi)
-{
-       /* ignore zero length blks */
-       if (start == end)
-               return 0;
-
-       /* whine about and ignore invalid blks */
-       if (start > end || nid < 0 || nid >= MAX_NUMNODES) {
-               pr_warning("NUMA: Warning: invalid memblk node %d (%Lx-%Lx)\n",
-                          nid, start, end);
-               return 0;
-       }
-
-       if (mi->nr_blks >= NR_NODE_MEMBLKS) {
-               pr_err("NUMA: too many memblk ranges\n");
-               return -EINVAL;
-       }
-
-       mi->blk[mi->nr_blks].start = start;
-       mi->blk[mi->nr_blks].end = end;
-       mi->blk[mi->nr_blks].nid = nid;
-       mi->nr_blks++;
-       return 0;
-}
-
-/**
- * numa_remove_memblk_from - Remove one numa_memblk from a numa_meminfo
- * @idx: Index of memblk to remove
- * @mi: numa_meminfo to remove memblk from
- *
- * Remove @idx'th numa_memblk from @mi by shifting @mi->blk[] and
- * decrementing @mi->nr_blks.
- */
-void __init numa_remove_memblk_from(int idx, struct numa_meminfo *mi)
-{
-       mi->nr_blks--;
-       memmove(&mi->blk[idx], &mi->blk[idx + 1],
-               (mi->nr_blks - idx) * sizeof(mi->blk[0]));
-}
-
-/**
- * numa_add_memblk - Add one numa_memblk to numa_meminfo
- * @nid: NUMA node ID of the new memblk
- * @start: Start address of the new memblk
- * @end: End address of the new memblk
- *
- * Add a new memblk to the default numa_meminfo.
- *
- * RETURNS:
- * 0 on success, -errno on failure.
- */
-int __init numa_add_memblk(int nid, u64 start, u64 end)
-{
-       return numa_add_memblk_to(nid, start, end, &numa_meminfo);
-}
-
-/* Initialize bootmem allocator for a node */
-void __init
-setup_node_bootmem(int nodeid, unsigned long start, unsigned long end)
-{
-       unsigned long start_pfn, last_pfn, nodedata_phys;
-       const int pgdat_size = roundup(sizeof(pg_data_t), PAGE_SIZE);
-       int nid;
-
-       if (!end)
-               return;
-
-       /*
-        * Don't confuse VM with a node that doesn't have the
-        * minimum amount of memory:
-        */
-       if (end && (end - start) < NODE_MIN_SIZE)
-               return;
-
-       start = roundup(start, ZONE_ALIGN);
-
-       printk(KERN_INFO "Initmem setup node %d %016lx-%016lx\n", nodeid,
-              start, end);
-
-       start_pfn = start >> PAGE_SHIFT;
-       last_pfn = end >> PAGE_SHIFT;
-
-       node_data[nodeid] = early_node_mem(nodeid, start, end, pgdat_size,
-                                          SMP_CACHE_BYTES);
-       if (node_data[nodeid] == NULL)
-               return;
-       nodedata_phys = __pa(node_data[nodeid]);
-       memblock_x86_reserve_range(nodedata_phys, nodedata_phys + pgdat_size, "NODE_DATA");
-       printk(KERN_INFO "  NODE_DATA [%016lx - %016lx]\n", nodedata_phys,
-               nodedata_phys + pgdat_size - 1);
-       nid = phys_to_nid(nodedata_phys);
-       if (nid != nodeid)
-               printk(KERN_INFO "    NODE_DATA(%d) on node %d\n", nodeid, nid);
-
-       memset(NODE_DATA(nodeid), 0, sizeof(pg_data_t));
-       NODE_DATA(nodeid)->node_id = nodeid;
-       NODE_DATA(nodeid)->node_start_pfn = start_pfn;
-       NODE_DATA(nodeid)->node_spanned_pages = last_pfn - start_pfn;
-
-       node_set_online(nodeid);
-}
-
-/**
- * numa_cleanup_meminfo - Cleanup a numa_meminfo
- * @mi: numa_meminfo to clean up
- *
- * Sanitize @mi by merging and removing unncessary memblks.  Also check for
- * conflicts and clear unused memblks.
- *
- * RETURNS:
- * 0 on success, -errno on failure.
- */
-int __init numa_cleanup_meminfo(struct numa_meminfo *mi)
-{
-       const u64 low = 0;
-       const u64 high = (u64)max_pfn << PAGE_SHIFT;
-       int i, j, k;
-
-       for (i = 0; i < mi->nr_blks; i++) {
-               struct numa_memblk *bi = &mi->blk[i];
-
-               /* make sure all blocks are inside the limits */
-               bi->start = max(bi->start, low);
-               bi->end = min(bi->end, high);
-
-               /* and there's no empty block */
-               if (bi->start >= bi->end) {
-                       numa_remove_memblk_from(i--, mi);
-                       continue;
-               }
-
-               for (j = i + 1; j < mi->nr_blks; j++) {
-                       struct numa_memblk *bj = &mi->blk[j];
-                       unsigned long start, end;
-
-                       /*
-                        * See whether there are overlapping blocks.  Whine
-                        * about but allow overlaps of the same nid.  They
-                        * will be merged below.
-                        */
-                       if (bi->end > bj->start && bi->start < bj->end) {
-                               if (bi->nid != bj->nid) {
-                                       pr_err("NUMA: node %d (%Lx-%Lx) overlaps with node %d (%Lx-%Lx)\n",
-                                              bi->nid, bi->start, bi->end,
-                                              bj->nid, bj->start, bj->end);
-                                       return -EINVAL;
-                               }
-                               pr_warning("NUMA: Warning: node %d (%Lx-%Lx) overlaps with itself (%Lx-%Lx)\n",
-                                          bi->nid, bi->start, bi->end,
-                                          bj->start, bj->end);
-                       }
-
-                       /*
-                        * Join together blocks on the same node, holes
-                        * between which don't overlap with memory on other
-                        * nodes.
-                        */
-                       if (bi->nid != bj->nid)
-                               continue;
-                       start = max(min(bi->start, bj->start), low);
-                       end = min(max(bi->end, bj->end), high);
-                       for (k = 0; k < mi->nr_blks; k++) {
-                               struct numa_memblk *bk = &mi->blk[k];
-
-                               if (bi->nid == bk->nid)
-                                       continue;
-                               if (start < bk->end && end > bk->start)
-                                       break;
-                       }
-                       if (k < mi->nr_blks)
-                               continue;
-                       printk(KERN_INFO "NUMA: Node %d [%Lx,%Lx) + [%Lx,%Lx) -> [%lx,%lx)\n",
-                              bi->nid, bi->start, bi->end, bj->start, bj->end,
-                              start, end);
-                       bi->start = start;
-                       bi->end = end;
-                       numa_remove_memblk_from(j--, mi);
-               }
-       }
-
-       for (i = mi->nr_blks; i < ARRAY_SIZE(mi->blk); i++) {
-               mi->blk[i].start = mi->blk[i].end = 0;
-               mi->blk[i].nid = NUMA_NO_NODE;
-       }
-
-       return 0;
-}
-
-/*
- * Set nodes, which have memory in @mi, in *@nodemask.
- */
-static void __init numa_nodemask_from_meminfo(nodemask_t *nodemask,
-                                             const struct numa_meminfo *mi)
-{
-       int i;
-
-       for (i = 0; i < ARRAY_SIZE(mi->blk); i++)
-               if (mi->blk[i].start != mi->blk[i].end &&
-                   mi->blk[i].nid != NUMA_NO_NODE)
-                       node_set(mi->blk[i].nid, *nodemask);
-}
-
-/**
- * numa_reset_distance - Reset NUMA distance table
- *
- * The current table is freed.  The next numa_set_distance() call will
- * create a new one.
- */
-void __init numa_reset_distance(void)
-{
-       size_t size = numa_distance_cnt * numa_distance_cnt * sizeof(numa_distance[0]);
-
-       /* numa_distance could be 1LU marking allocation failure, test cnt */
-       if (numa_distance_cnt)
-               memblock_x86_free_range(__pa(numa_distance),
-                                       __pa(numa_distance) + size);
-       numa_distance_cnt = 0;
-       numa_distance = NULL;   /* enable table creation */
-}
-
-static int __init numa_alloc_distance(void)
-{
-       nodemask_t nodes_parsed;
-       size_t size;
-       int i, j, cnt = 0;
-       u64 phys;
-
-       /* size the new table and allocate it */
-       nodes_parsed = numa_nodes_parsed;
-       numa_nodemask_from_meminfo(&nodes_parsed, &numa_meminfo);
-
-       for_each_node_mask(i, nodes_parsed)
-               cnt = i;
-       cnt++;
-       size = cnt * cnt * sizeof(numa_distance[0]);
-
-       phys = memblock_find_in_range(0, (u64)max_pfn_mapped << PAGE_SHIFT,
-                                     size, PAGE_SIZE);
-       if (phys == MEMBLOCK_ERROR) {
-               pr_warning("NUMA: Warning: can't allocate distance table!\n");
-               /* don't retry until explicitly reset */
-               numa_distance = (void *)1LU;
-               return -ENOMEM;
-       }
-       memblock_x86_reserve_range(phys, phys + size, "NUMA DIST");
-
-       numa_distance = __va(phys);
-       numa_distance_cnt = cnt;
-
-       /* fill with the default distances */
-       for (i = 0; i < cnt; i++)
-               for (j = 0; j < cnt; j++)
-                       numa_distance[i * cnt + j] = i == j ?
-                               LOCAL_DISTANCE : REMOTE_DISTANCE;
-       printk(KERN_DEBUG "NUMA: Initialized distance table, cnt=%d\n", cnt);
-
-       return 0;
-}
-
-/**
- * numa_set_distance - Set NUMA distance from one NUMA to another
- * @from: the 'from' node to set distance
- * @to: the 'to'  node to set distance
- * @distance: NUMA distance
- *
- * Set the distance from node @from to @to to @distance.  If distance table
- * doesn't exist, one which is large enough to accommodate all the currently
- * known nodes will be created.
- *
- * If such table cannot be allocated, a warning is printed and further
- * calls are ignored until the distance table is reset with
- * numa_reset_distance().
- *
- * If @from or @to is higher than the highest known node at the time of
- * table creation or @distance doesn't make sense, the call is ignored.
- * This is to allow simplification of specific NUMA config implementations.
- */
-void __init numa_set_distance(int from, int to, int distance)
-{
-       if (!numa_distance && numa_alloc_distance() < 0)
-               return;
-
-       if (from >= numa_distance_cnt || to >= numa_distance_cnt) {
-               printk_once(KERN_DEBUG "NUMA: Debug: distance out of bound, from=%d to=%d distance=%d\n",
-                           from, to, distance);
-               return;
-       }
-
-       if ((u8)distance != distance ||
-           (from == to && distance != LOCAL_DISTANCE)) {
-               pr_warn_once("NUMA: Warning: invalid distance parameter, from=%d to=%d distance=%d\n",
-                            from, to, distance);
-               return;
-       }
-
-       numa_distance[from * numa_distance_cnt + to] = distance;
-}
-
-int __node_distance(int from, int to)
-{
-       if (from >= numa_distance_cnt || to >= numa_distance_cnt)
-               return from == to ? LOCAL_DISTANCE : REMOTE_DISTANCE;
-       return numa_distance[from * numa_distance_cnt + to];
-}
-EXPORT_SYMBOL(__node_distance);
-
-/*
- * Sanity check to catch more bad NUMA configurations (they are amazingly
- * common).  Make sure the nodes cover all memory.
- */
-static bool __init numa_meminfo_cover_memory(const struct numa_meminfo *mi)
-{
-       unsigned long numaram, e820ram;
-       int i;
-
-       numaram = 0;
-       for (i = 0; i < mi->nr_blks; i++) {
-               unsigned long s = mi->blk[i].start >> PAGE_SHIFT;
-               unsigned long e = mi->blk[i].end >> PAGE_SHIFT;
-               numaram += e - s;
-               numaram -= __absent_pages_in_range(mi->blk[i].nid, s, e);
-               if ((long)numaram < 0)
-                       numaram = 0;
-       }
-
-       e820ram = max_pfn - (memblock_x86_hole_size(0,
-                                       max_pfn << PAGE_SHIFT) >> PAGE_SHIFT);
-       /* We seem to lose 3 pages somewhere. Allow 1M of slack. */
-       if ((long)(e820ram - numaram) >= (1 << (20 - PAGE_SHIFT))) {
-               printk(KERN_ERR "NUMA: nodes only cover %luMB of your %luMB e820 RAM. Not used.\n",
-                      (numaram << PAGE_SHIFT) >> 20,
-                      (e820ram << PAGE_SHIFT) >> 20);
-               return false;
-       }
-       return true;
-}
-
-static int __init numa_register_memblks(struct numa_meminfo *mi)
-{
-       int i, nid;
-
-       /* Account for nodes with cpus and no memory */
-       node_possible_map = numa_nodes_parsed;
-       numa_nodemask_from_meminfo(&node_possible_map, mi);
-       if (WARN_ON(nodes_empty(node_possible_map)))
-               return -EINVAL;
-
-       memnode_shift = compute_hash_shift(mi);
-       if (memnode_shift < 0) {
-               printk(KERN_ERR "NUMA: No NUMA node hash function found. Contact maintainer\n");
-               return -EINVAL;
-       }
-
-       for (i = 0; i < mi->nr_blks; i++)
-               memblock_x86_register_active_regions(mi->blk[i].nid,
-                                       mi->blk[i].start >> PAGE_SHIFT,
-                                       mi->blk[i].end >> PAGE_SHIFT);
-
-       /* for out of order entries */
-       sort_node_map();
-       if (!numa_meminfo_cover_memory(mi))
-               return -EINVAL;
-
-       /* Finally register nodes. */
-       for_each_node_mask(nid, node_possible_map) {
-               u64 start = (u64)max_pfn << PAGE_SHIFT;
-               u64 end = 0;
-
-               for (i = 0; i < mi->nr_blks; i++) {
-                       if (nid != mi->blk[i].nid)
-                               continue;
-                       start = min(mi->blk[i].start, start);
-                       end = max(mi->blk[i].end, end);
-               }
-
-               if (start < end)
-                       setup_node_bootmem(nid, start, end);
-       }
-
-       return 0;
-}
-
-/**
- * dummy_numma_init - Fallback dummy NUMA init
- *
- * Used if there's no underlying NUMA architecture, NUMA initialization
- * fails, or NUMA is disabled on the command line.
- *
- * Must online at least one node and add memory blocks that cover all
- * allowed memory.  This function must not fail.
- */
-static int __init dummy_numa_init(void)
-{
-       printk(KERN_INFO "%s\n",
-              numa_off ? "NUMA turned off" : "No NUMA configuration found");
-       printk(KERN_INFO "Faking a node at %016lx-%016lx\n",
-              0LU, max_pfn << PAGE_SHIFT);
-
-       node_set(0, numa_nodes_parsed);
-       numa_add_memblk(0, 0, (u64)max_pfn << PAGE_SHIFT);
-
-       return 0;
-}
-
-static int __init numa_init(int (*init_func)(void))
-{
-       int i;
-       int ret;
-
-       for (i = 0; i < MAX_LOCAL_APIC; i++)
-               set_apicid_to_node(i, NUMA_NO_NODE);
-
-       nodes_clear(numa_nodes_parsed);
-       nodes_clear(node_possible_map);
-       nodes_clear(node_online_map);
-       memset(&numa_meminfo, 0, sizeof(numa_meminfo));
-       remove_all_active_ranges();
-       numa_reset_distance();
-
-       ret = init_func();
-       if (ret < 0)
-               return ret;
-       ret = numa_cleanup_meminfo(&numa_meminfo);
-       if (ret < 0)
-               return ret;
-
-       numa_emulation(&numa_meminfo, numa_distance_cnt);
-
-       ret = numa_register_memblks(&numa_meminfo);
-       if (ret < 0)
-               return ret;
-
-       for (i = 0; i < nr_cpu_ids; i++) {
-               int nid = early_cpu_to_node(i);
-
-               if (nid == NUMA_NO_NODE)
-                       continue;
-               if (!node_online(nid))
-                       numa_clear_node(i);
-       }
-       numa_init_array();
-       return 0;
-}
-
 void __init initmem_init(void)
 {
-       int ret;
-
-       if (!numa_off) {
-#ifdef CONFIG_ACPI_NUMA
-               ret = numa_init(x86_acpi_numa_init);
-               if (!ret)
-                       return;
-#endif
-#ifdef CONFIG_AMD_NUMA
-               ret = numa_init(amd_numa_init);
-               if (!ret)
-                       return;
-#endif
-       }
-
-       numa_init(dummy_numa_init);
+       x86_numa_init();
 }
 
 unsigned long __init numa_free_all_bootmem(void)
@@ -656,12 +23,3 @@ unsigned long __init numa_free_all_bootmem(void)
 
        return pages;
 }
-
-int __cpuinit numa_cpu_node(int cpu)
-{
-       int apicid = early_per_cpu(x86_cpu_to_apicid, cpu);
-
-       if (apicid != BAD_APICID)
-               return __apicid_to_node[apicid];
-       return NUMA_NO_NODE;
-}
index de84cc1..d0ed086 100644 (file)
@@ -5,6 +5,7 @@
 #include <linux/errno.h>
 #include <linux/topology.h>
 #include <linux/memblock.h>
+#include <linux/bootmem.h>
 #include <asm/dma.h>
 
 #include "numa_internal.h"
@@ -84,7 +85,13 @@ static int __init split_nodes_interleave(struct numa_meminfo *ei,
                nr_nodes = MAX_NUMNODES;
        }
 
-       size = (max_addr - addr - memblock_x86_hole_size(addr, max_addr)) / nr_nodes;
+       /*
+        * Calculate target node size.  x86_32 freaks on __udivdi3() so do
+        * the division in ulong number of pages and convert back.
+        */
+       size = max_addr - addr - memblock_x86_hole_size(addr, max_addr);
+       size = PFN_PHYS((unsigned long)(size >> PAGE_SHIFT) / nr_nodes);
+
        /*
         * Calculate the number of big nodes that can be allocated as a result
         * of consolidating the remainder.
@@ -226,7 +233,7 @@ static int __init split_nodes_size_interleave(struct numa_meminfo *ei,
         */
        while (nodes_weight(physnode_mask)) {
                for_each_node_mask(i, physnode_mask) {
-                       u64 dma32_end = MAX_DMA32_PFN << PAGE_SHIFT;
+                       u64 dma32_end = PFN_PHYS(MAX_DMA32_PFN);
                        u64 start, limit, end;
                        int phys_blk;
 
@@ -298,7 +305,7 @@ void __init numa_emulation(struct numa_meminfo *numa_meminfo, int numa_dist_cnt)
 {
        static struct numa_meminfo ei __initdata;
        static struct numa_meminfo pi __initdata;
-       const u64 max_addr = max_pfn << PAGE_SHIFT;
+       const u64 max_addr = PFN_PHYS(max_pfn);
        u8 *phys_dist = NULL;
        size_t phys_size = numa_dist_cnt * numa_dist_cnt * sizeof(phys_dist[0]);
        int max_emu_nid, dfl_phys_nid;
@@ -342,8 +349,7 @@ void __init numa_emulation(struct numa_meminfo *numa_meminfo, int numa_dist_cnt)
        if (numa_dist_cnt) {
                u64 phys;
 
-               phys = memblock_find_in_range(0,
-                                             (u64)max_pfn_mapped << PAGE_SHIFT,
+               phys = memblock_find_in_range(0, PFN_PHYS(max_pfn_mapped),
                                              phys_size, PAGE_SIZE);
                if (phys == MEMBLOCK_ERROR) {
                        pr_warning("NUMA: Warning: can't allocate copy of distance table, disabling emulation\n");
index ef2d973..7178c3a 100644 (file)
@@ -19,6 +19,14 @@ void __init numa_remove_memblk_from(int idx, struct numa_meminfo *mi);
 int __init numa_cleanup_meminfo(struct numa_meminfo *mi);
 void __init numa_reset_distance(void);
 
+void __init x86_numa_init(void);
+
+#ifdef CONFIG_X86_64
+static inline void init_alloc_remap(int nid, u64 start, u64 end)       { }
+#else
+void __init init_alloc_remap(int nid, u64 start, u64 end);
+#endif
+
 #ifdef CONFIG_NUMA_EMU
 void __init numa_emulation(struct numa_meminfo *numa_meminfo,
                           int numa_dist_cnt);
similarity index 67%
rename from arch/x86/mm/srat_64.c
rename to arch/x86/mm/srat.c
index 8e9d339..81dbfde 100644 (file)
@@ -26,8 +26,6 @@
 
 int acpi_numa __initdata;
 
-static struct bootnode nodes_add[MAX_NUMNODES];
-
 static __init int setup_node(int pxm)
 {
        return acpi_map_pxm_to_node(pxm);
@@ -37,7 +35,6 @@ static __init void bad_srat(void)
 {
        printk(KERN_ERR "SRAT: SRAT not used.\n");
        acpi_numa = -1;
-       memset(nodes_add, 0, sizeof(nodes_add));
 }
 
 static __init inline int srat_disabled(void)
@@ -131,73 +128,17 @@ acpi_numa_processor_affinity_init(struct acpi_srat_cpu_affinity *pa)
               pxm, apic_id, node);
 }
 
-#ifdef CONFIG_MEMORY_HOTPLUG_SPARSE
+#ifdef CONFIG_MEMORY_HOTPLUG
 static inline int save_add_info(void) {return 1;}
 #else
 static inline int save_add_info(void) {return 0;}
 #endif
-/*
- * Update nodes_add[]
- * This code supports one contiguous hot add area per node
- */
-static void __init
-update_nodes_add(int node, unsigned long start, unsigned long end)
-{
-       unsigned long s_pfn = start >> PAGE_SHIFT;
-       unsigned long e_pfn = end >> PAGE_SHIFT;
-       int changed = 0;
-       struct bootnode *nd = &nodes_add[node];
-
-       /* I had some trouble with strange memory hotadd regions breaking
-          the boot. Be very strict here and reject anything unexpected.
-          If you want working memory hotadd write correct SRATs.
-
-          The node size check is a basic sanity check to guard against
-          mistakes */
-       if ((signed long)(end - start) < NODE_MIN_SIZE) {
-               printk(KERN_ERR "SRAT: Hotplug area too small\n");
-               return;
-       }
-
-       /* This check might be a bit too strict, but I'm keeping it for now. */
-       if (absent_pages_in_range(s_pfn, e_pfn) != e_pfn - s_pfn) {
-               printk(KERN_ERR
-                       "SRAT: Hotplug area %lu -> %lu has existing memory\n",
-                       s_pfn, e_pfn);
-               return;
-       }
-
-       /* Looks good */
-
-       if (nd->start == nd->end) {
-               nd->start = start;
-               nd->end = end;
-               changed = 1;
-       } else {
-               if (nd->start == end) {
-                       nd->start = start;
-                       changed = 1;
-               }
-               if (nd->end == start) {
-                       nd->end = end;
-                       changed = 1;
-               }
-               if (!changed)
-                       printk(KERN_ERR "SRAT: Hotplug zone not continuous. Partly ignored\n");
-       }
-
-       if (changed) {
-               node_set(node, numa_nodes_parsed);
-               printk(KERN_INFO "SRAT: hot plug zone found %Lx - %Lx\n",
-                                nd->start, nd->end);
-       }
-}
 
 /* Callback for parsing of the Proximity Domain <-> Memory Area mappings */
 void __init
 acpi_numa_memory_affinity_init(struct acpi_srat_mem_affinity *ma)
 {
-       unsigned long start, end;
+       u64 start, end;
        int node, pxm;
 
        if (srat_disabled())
@@ -226,11 +167,8 @@ acpi_numa_memory_affinity_init(struct acpi_srat_mem_affinity *ma)
                return;
        }
 
-       printk(KERN_INFO "SRAT: Node %u PXM %u %lx-%lx\n", node, pxm,
+       printk(KERN_INFO "SRAT: Node %u PXM %u %Lx-%Lx\n", node, pxm,
               start, end);
-
-       if (ma->flags & ACPI_SRAT_MEM_HOT_PLUGGABLE)
-               update_nodes_add(node, start, end);
 }
 
 void __init acpi_numa_arch_fixup(void) {}
@@ -244,17 +182,3 @@ int __init x86_acpi_numa_init(void)
                return ret;
        return srat_disabled() ? -EINVAL : 0;
 }
-
-#if defined(CONFIG_MEMORY_HOTPLUG_SPARSE) || defined(CONFIG_ACPI_HOTPLUG_MEMORY)
-int memory_add_physaddr_to_nid(u64 start)
-{
-       int i, ret = 0;
-
-       for_each_node(i)
-               if (nodes_add[i].start <= start && nodes_add[i].end > start)
-                       ret = i;
-
-       return ret;
-}
-EXPORT_SYMBOL_GPL(memory_add_physaddr_to_nid);
-#endif
diff --git a/arch/x86/mm/srat_32.c b/arch/x86/mm/srat_32.c
deleted file mode 100644 (file)
index 364f36b..0000000
+++ /dev/null
@@ -1,288 +0,0 @@
-/*
- * Some of the code in this file has been gleaned from the 64 bit 
- * discontigmem support code base.
- *
- * Copyright (C) 2002, IBM Corp.
- *
- * All rights reserved.          
- *
- * 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, GOOD TITLE or
- * NON INFRINGEMENT.  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.
- *
- * Send feedback to Pat Gaughen <gone@us.ibm.com>
- */
-#include <linux/mm.h>
-#include <linux/bootmem.h>
-#include <linux/memblock.h>
-#include <linux/mmzone.h>
-#include <linux/acpi.h>
-#include <linux/nodemask.h>
-#include <asm/srat.h>
-#include <asm/topology.h>
-#include <asm/smp.h>
-#include <asm/e820.h>
-
-/*
- * proximity macros and definitions
- */
-#define NODE_ARRAY_INDEX(x)    ((x) / 8)       /* 8 bits/char */
-#define NODE_ARRAY_OFFSET(x)   ((x) % 8)       /* 8 bits/char */
-#define BMAP_SET(bmap, bit)    ((bmap)[NODE_ARRAY_INDEX(bit)] |= 1 << NODE_ARRAY_OFFSET(bit))
-#define BMAP_TEST(bmap, bit)   ((bmap)[NODE_ARRAY_INDEX(bit)] & (1 << NODE_ARRAY_OFFSET(bit)))
-/* bitmap length; _PXM is at most 255 */
-#define PXM_BITMAP_LEN (MAX_PXM_DOMAINS / 8) 
-static u8 __initdata pxm_bitmap[PXM_BITMAP_LEN];       /* bitmap of proximity domains */
-
-#define MAX_CHUNKS_PER_NODE    3
-#define MAXCHUNKS              (MAX_CHUNKS_PER_NODE * MAX_NUMNODES)
-struct node_memory_chunk_s {
-       unsigned long   start_pfn;
-       unsigned long   end_pfn;
-       u8      pxm;            // proximity domain of node
-       u8      nid;            // which cnode contains this chunk?
-       u8      bank;           // which mem bank on this node
-};
-static struct node_memory_chunk_s __initdata node_memory_chunk[MAXCHUNKS];
-
-static int __initdata num_memory_chunks; /* total number of memory chunks */
-static u8 __initdata apicid_to_pxm[MAX_LOCAL_APIC];
-
-int acpi_numa __initdata;
-
-static __init void bad_srat(void)
-{
-        printk(KERN_ERR "SRAT: SRAT not used.\n");
-        acpi_numa = -1;
-       num_memory_chunks = 0;
-}
-
-static __init inline int srat_disabled(void)
-{
-       return numa_off || acpi_numa < 0;
-}
-
-/* Identify CPU proximity domains */
-void __init
-acpi_numa_processor_affinity_init(struct acpi_srat_cpu_affinity *cpu_affinity)
-{
-       if (srat_disabled())
-               return;
-       if (cpu_affinity->header.length !=
-            sizeof(struct acpi_srat_cpu_affinity)) {
-               bad_srat();
-               return;
-       }
-
-       if ((cpu_affinity->flags & ACPI_SRAT_CPU_ENABLED) == 0)
-               return;         /* empty entry */
-
-       /* mark this node as "seen" in node bitmap */
-       BMAP_SET(pxm_bitmap, cpu_affinity->proximity_domain_lo);
-
-       /* don't need to check apic_id here, because it is always 8 bits */
-       apicid_to_pxm[cpu_affinity->apic_id] = cpu_affinity->proximity_domain_lo;
-
-       printk(KERN_DEBUG "CPU %02x in proximity domain %02x\n",
-               cpu_affinity->apic_id, cpu_affinity->proximity_domain_lo);
-}
-
-/*
- * Identify memory proximity domains and hot-remove capabilities.
- * Fill node memory chunk list structure.
- */
-void __init
-acpi_numa_memory_affinity_init(struct acpi_srat_mem_affinity *memory_affinity)
-{
-       unsigned long long paddr, size;
-       unsigned long start_pfn, end_pfn;
-       u8 pxm;
-       struct node_memory_chunk_s *p, *q, *pend;
-
-       if (srat_disabled())
-               return;
-       if (memory_affinity->header.length !=
-            sizeof(struct acpi_srat_mem_affinity)) {
-               bad_srat();
-               return;
-       }
-
-       if ((memory_affinity->flags & ACPI_SRAT_MEM_ENABLED) == 0)
-               return;         /* empty entry */
-
-       pxm = memory_affinity->proximity_domain & 0xff;
-
-       /* mark this node as "seen" in node bitmap */
-       BMAP_SET(pxm_bitmap, pxm);
-
-       /* calculate info for memory chunk structure */
-       paddr = memory_affinity->base_address;
-       size = memory_affinity->length;
-
-       start_pfn = paddr >> PAGE_SHIFT;
-       end_pfn = (paddr + size) >> PAGE_SHIFT;
-
-
-       if (num_memory_chunks >= MAXCHUNKS) {
-               printk(KERN_WARNING "Too many mem chunks in SRAT."
-                       " Ignoring %lld MBytes at %llx\n",
-                       size/(1024*1024), paddr);
-               return;
-       }
-
-       /* Insertion sort based on base address */
-       pend = &node_memory_chunk[num_memory_chunks];
-       for (p = &node_memory_chunk[0]; p < pend; p++) {
-               if (start_pfn < p->start_pfn)
-                       break;
-       }
-       if (p < pend) {
-               for (q = pend; q >= p; q--)
-                       *(q + 1) = *q;
-       }
-       p->start_pfn = start_pfn;
-       p->end_pfn = end_pfn;
-       p->pxm = pxm;
-
-       num_memory_chunks++;
-
-       printk(KERN_DEBUG "Memory range %08lx to %08lx"
-                         " in proximity domain %02x %s\n",
-               start_pfn, end_pfn,
-               pxm,
-               ((memory_affinity->flags & ACPI_SRAT_MEM_HOT_PLUGGABLE) ?
-                "enabled and removable" : "enabled" ) );
-}
-
-/* Callback for SLIT parsing */
-void __init acpi_numa_slit_init(struct acpi_table_slit *slit)
-{
-}
-
-void acpi_numa_arch_fixup(void)
-{
-}
-/*
- * The SRAT table always lists ascending addresses, so can always
- * assume that the first "start" address that you see is the real
- * start of the node, and that the current "end" address is after
- * the previous one.
- */
-static __init int node_read_chunk(int nid, struct node_memory_chunk_s *memory_chunk)
-{
-       /*
-        * Only add present memory as told by the e820.
-        * There is no guarantee from the SRAT that the memory it
-        * enumerates is present at boot time because it represents
-        * *possible* memory hotplug areas the same as normal RAM.
-        */
-       if (memory_chunk->start_pfn >= max_pfn) {
-               printk(KERN_INFO "Ignoring SRAT pfns: %08lx - %08lx\n",
-                       memory_chunk->start_pfn, memory_chunk->end_pfn);
-               return -1;
-       }
-       if (memory_chunk->nid != nid)
-               return -1;
-
-       if (!node_has_online_mem(nid))
-               node_start_pfn[nid] = memory_chunk->start_pfn;
-
-       if (node_start_pfn[nid] > memory_chunk->start_pfn)
-               node_start_pfn[nid] = memory_chunk->start_pfn;
-
-       if (node_end_pfn[nid] < memory_chunk->end_pfn)
-               node_end_pfn[nid] = memory_chunk->end_pfn;
-
-       return 0;
-}
-
-int __init get_memcfg_from_srat(void)
-{
-       int i, j, nid;
-
-       if (srat_disabled())
-               goto out_fail;
-
-       if (acpi_numa_init() < 0)
-               goto out_fail;
-
-       if (num_memory_chunks == 0) {
-               printk(KERN_DEBUG
-                        "could not find any ACPI SRAT memory areas.\n");
-               goto out_fail;
-       }
-
-       /* Calculate total number of nodes in system from PXM bitmap and create
-        * a set of sequential node IDs starting at zero.  (ACPI doesn't seem
-        * to specify the range of _PXM values.)
-        */
-       /*
-        * MCD - we no longer HAVE to number nodes sequentially.  PXM domain
-        * numbers could go as high as 256, and MAX_NUMNODES for i386 is typically
-        * 32, so we will continue numbering them in this manner until MAX_NUMNODES
-        * approaches MAX_PXM_DOMAINS for i386.
-        */
-       nodes_clear(node_online_map);
-       for (i = 0; i < MAX_PXM_DOMAINS; i++) {
-               if (BMAP_TEST(pxm_bitmap, i)) {
-                       int nid = acpi_map_pxm_to_node(i);
-                       node_set_online(nid);
-               }
-       }
-       BUG_ON(num_online_nodes() == 0);
-
-       /* set cnode id in memory chunk structure */
-       for (i = 0; i < num_memory_chunks; i++)
-               node_memory_chunk[i].nid = pxm_to_node(node_memory_chunk[i].pxm);
-
-       printk(KERN_DEBUG "pxm bitmap: ");
-       for (i = 0; i < sizeof(pxm_bitmap); i++) {
-               printk(KERN_CONT "%02x ", pxm_bitmap[i]);
-       }
-       printk(KERN_CONT "\n");
-       printk(KERN_DEBUG "Number of logical nodes in system = %d\n",
-                        num_online_nodes());
-       printk(KERN_DEBUG "Number of memory chunks in system = %d\n",
-                        num_memory_chunks);
-
-       for (i = 0; i < MAX_LOCAL_APIC; i++)
-               set_apicid_to_node(i, pxm_to_node(apicid_to_pxm[i]));
-
-       for (j = 0; j < num_memory_chunks; j++){
-               struct node_memory_chunk_s * chunk = &node_memory_chunk[j];
-               printk(KERN_DEBUG
-                       "chunk %d nid %d start_pfn %08lx end_pfn %08lx\n",
-                      j, chunk->nid, chunk->start_pfn, chunk->end_pfn);
-               if (node_read_chunk(chunk->nid, chunk))
-                       continue;
-
-               memblock_x86_register_active_regions(chunk->nid, chunk->start_pfn,
-                                            min(chunk->end_pfn, max_pfn));
-       }
-       /* for out of order entries in SRAT */
-       sort_node_map();
-
-       for_each_online_node(nid) {
-               unsigned long start = node_start_pfn[nid];
-               unsigned long end = min(node_end_pfn[nid], max_pfn);
-
-               memory_present(nid, start, end);
-               node_remap_size[nid] = node_memmap_size_bytes(nid, start, end);
-       }
-       return 1;
-out_fail:
-       printk(KERN_DEBUG "failed to get NUMA memory information from SRAT"
-                       " table\n");
-       return 0;
-}
index e37b407..8214724 100644 (file)
@@ -108,7 +108,8 @@ static int xen_hvm_setup_msi_irqs(struct pci_dev *dev, int nvec, int type)
                }
                irq = xen_bind_pirq_msi_to_irq(dev, msidesc, pirq, 0,
                                               (type == PCI_CAP_ID_MSIX) ?
-                                              "msi-x" : "msi");
+                                              "msi-x" : "msi",
+                                              DOMID_SELF);
                if (irq < 0)
                        goto error;
                dev_dbg(&dev->dev,
@@ -148,7 +149,8 @@ static int xen_setup_msi_irqs(struct pci_dev *dev, int nvec, int type)
                irq = xen_bind_pirq_msi_to_irq(dev, msidesc, v[i], 0,
                                               (type == PCI_CAP_ID_MSIX) ?
                                               "pcifront-msi-x" :
-                                              "pcifront-msi");
+                                              "pcifront-msi",
+                                               DOMID_SELF);
                if (irq < 0)
                        goto free;
                i++;
@@ -190,9 +192,16 @@ static int xen_initdom_setup_msi_irqs(struct pci_dev *dev, int nvec, int type)
 
        list_for_each_entry(msidesc, &dev->msi_list, list) {
                struct physdev_map_pirq map_irq;
+               domid_t domid;
+
+               domid = ret = xen_find_device_domain_owner(dev);
+               /* N.B. Casting int's -ENODEV to uint16_t results in 0xFFED,
+                * hence check ret value for < 0. */
+               if (ret < 0)
+                       domid = DOMID_SELF;
 
                memset(&map_irq, 0, sizeof(map_irq));
-               map_irq.domid = DOMID_SELF;
+               map_irq.domid = domid;
                map_irq.type = MAP_PIRQ_TYPE_MSI;
                map_irq.index = -1;
                map_irq.pirq = -1;
@@ -215,14 +224,16 @@ static int xen_initdom_setup_msi_irqs(struct pci_dev *dev, int nvec, int type)
 
                ret = HYPERVISOR_physdev_op(PHYSDEVOP_map_pirq, &map_irq);
                if (ret) {
-                       dev_warn(&dev->dev, "xen map irq failed %d\n", ret);
+                       dev_warn(&dev->dev, "xen map irq failed %d for %d domain\n",
+                                ret, domid);
                        goto out;
                }
 
                ret = xen_bind_pirq_msi_to_irq(dev, msidesc,
                                               map_irq.pirq, map_irq.index,
                                               (type == PCI_CAP_ID_MSIX) ?
-                                              "msi-x" : "msi");
+                                              "msi-x" : "msi",
+                                               domid);
                if (ret < 0)
                        goto out;
        }
@@ -461,3 +472,78 @@ void __init xen_setup_pirqs(void)
        }
 }
 #endif
+
+#ifdef CONFIG_XEN_DOM0
+struct xen_device_domain_owner {
+       domid_t domain;
+       struct pci_dev *dev;
+       struct list_head list;
+};
+
+static DEFINE_SPINLOCK(dev_domain_list_spinlock);
+static struct list_head dev_domain_list = LIST_HEAD_INIT(dev_domain_list);
+
+static struct xen_device_domain_owner *find_device(struct pci_dev *dev)
+{
+       struct xen_device_domain_owner *owner;
+
+       list_for_each_entry(owner, &dev_domain_list, list) {
+               if (owner->dev == dev)
+                       return owner;
+       }
+       return NULL;
+}
+
+int xen_find_device_domain_owner(struct pci_dev *dev)
+{
+       struct xen_device_domain_owner *owner;
+       int domain = -ENODEV;
+
+       spin_lock(&dev_domain_list_spinlock);
+       owner = find_device(dev);
+       if (owner)
+               domain = owner->domain;
+       spin_unlock(&dev_domain_list_spinlock);
+       return domain;
+}
+EXPORT_SYMBOL_GPL(xen_find_device_domain_owner);
+
+int xen_register_device_domain_owner(struct pci_dev *dev, uint16_t domain)
+{
+       struct xen_device_domain_owner *owner;
+
+       owner = kzalloc(sizeof(struct xen_device_domain_owner), GFP_KERNEL);
+       if (!owner)
+               return -ENODEV;
+
+       spin_lock(&dev_domain_list_spinlock);
+       if (find_device(dev)) {
+               spin_unlock(&dev_domain_list_spinlock);
+               kfree(owner);
+               return -EEXIST;
+       }
+       owner->domain = domain;
+       owner->dev = dev;
+       list_add_tail(&owner->list, &dev_domain_list);
+       spin_unlock(&dev_domain_list_spinlock);
+       return 0;
+}
+EXPORT_SYMBOL_GPL(xen_register_device_domain_owner);
+
+int xen_unregister_device_domain_owner(struct pci_dev *dev)
+{
+       struct xen_device_domain_owner *owner;
+
+       spin_lock(&dev_domain_list_spinlock);
+       owner = find_device(dev);
+       if (!owner) {
+               spin_unlock(&dev_domain_list_spinlock);
+               return -ENODEV;
+       }
+       list_del(&owner->list);
+       spin_unlock(&dev_domain_list_spinlock);
+       kfree(owner);
+       return 0;
+}
+EXPORT_SYMBOL_GPL(xen_unregister_device_domain_owner);
+#endif
index 0fe27d7..b30aa26 100644 (file)
@@ -145,17 +145,6 @@ static void virt_efi_reset_system(int reset_type,
                       data_size, data);
 }
 
-static efi_status_t virt_efi_set_virtual_address_map(
-       unsigned long memory_map_size,
-       unsigned long descriptor_size,
-       u32 descriptor_version,
-       efi_memory_desc_t *virtual_map)
-{
-       return efi_call_virt4(set_virtual_address_map,
-                             memory_map_size, descriptor_size,
-                             descriptor_version, virtual_map);
-}
-
 static efi_status_t __init phys_efi_set_virtual_address_map(
        unsigned long memory_map_size,
        unsigned long descriptor_size,
@@ -468,11 +457,25 @@ void __init efi_init(void)
 #endif
 }
 
+void __init efi_set_executable(efi_memory_desc_t *md, bool executable)
+{
+       u64 addr, npages;
+
+       addr = md->virt_addr;
+       npages = md->num_pages;
+
+       memrange_efi_to_native(&addr, &npages);
+
+       if (executable)
+               set_memory_x(addr, npages);
+       else
+               set_memory_nx(addr, npages);
+}
+
 static void __init runtime_code_page_mkexec(void)
 {
        efi_memory_desc_t *md;
        void *p;
-       u64 addr, npages;
 
        /* Make EFI runtime service code area executable */
        for (p = memmap.map; p < memmap.map_end; p += memmap.desc_size) {
@@ -481,10 +484,7 @@ static void __init runtime_code_page_mkexec(void)
                if (md->type != EFI_RUNTIME_SERVICES_CODE)
                        continue;
 
-               addr = md->virt_addr;
-               npages = md->num_pages;
-               memrange_efi_to_native(&addr, &npages);
-               set_memory_x(addr, npages);
+               efi_set_executable(md, true);
        }
 }
 
@@ -498,13 +498,42 @@ static void __init runtime_code_page_mkexec(void)
  */
 void __init efi_enter_virtual_mode(void)
 {
-       efi_memory_desc_t *md;
+       efi_memory_desc_t *md, *prev_md = NULL;
        efi_status_t status;
        unsigned long size;
        u64 end, systab, addr, npages, end_pfn;
-       void *p, *va;
+       void *p, *va, *new_memmap = NULL;
+       int count = 0;
 
        efi.systab = NULL;
+
+       /* Merge contiguous regions of the same type and attribute */
+       for (p = memmap.map; p < memmap.map_end; p += memmap.desc_size) {
+               u64 prev_size;
+               md = p;
+
+               if (!prev_md) {
+                       prev_md = md;
+                       continue;
+               }
+
+               if (prev_md->type != md->type ||
+                   prev_md->attribute != md->attribute) {
+                       prev_md = md;
+                       continue;
+               }
+
+               prev_size = prev_md->num_pages << EFI_PAGE_SHIFT;
+
+               if (md->phys_addr == (prev_md->phys_addr + prev_size)) {
+                       prev_md->num_pages += md->num_pages;
+                       md->type = EFI_RESERVED_TYPE;
+                       md->attribute = 0;
+                       continue;
+               }
+               prev_md = md;
+       }
+
        for (p = memmap.map; p < memmap.map_end; p += memmap.desc_size) {
                md = p;
                if (!(md->attribute & EFI_MEMORY_RUNTIME))
@@ -541,15 +570,21 @@ void __init efi_enter_virtual_mode(void)
                        systab += md->virt_addr - md->phys_addr;
                        efi.systab = (efi_system_table_t *) (unsigned long) systab;
                }
+               new_memmap = krealloc(new_memmap,
+                                     (count + 1) * memmap.desc_size,
+                                     GFP_KERNEL);
+               memcpy(new_memmap + (count * memmap.desc_size), md,
+                      memmap.desc_size);
+               count++;
        }
 
        BUG_ON(!efi.systab);
 
        status = phys_efi_set_virtual_address_map(
-               memmap.desc_size * memmap.nr_map,
+               memmap.desc_size * count,
                memmap.desc_size,
                memmap.desc_version,
-               memmap.phys_map);
+               (efi_memory_desc_t *)__pa(new_memmap));
 
        if (status != EFI_SUCCESS) {
                printk(KERN_ALERT "Unable to switch EFI into virtual mode "
@@ -572,11 +607,12 @@ void __init efi_enter_virtual_mode(void)
        efi.set_variable = virt_efi_set_variable;
        efi.get_next_high_mono_count = virt_efi_get_next_high_mono_count;
        efi.reset_system = virt_efi_reset_system;
-       efi.set_virtual_address_map = virt_efi_set_virtual_address_map;
+       efi.set_virtual_address_map = NULL;
        if (__supported_pte_mask & _PAGE_NX)
                runtime_code_page_mkexec();
        early_iounmap(memmap.map, memmap.nr_map * memmap.desc_size);
        memmap.map = NULL;
+       kfree(new_memmap);
 }
 
 /*
index ac0621a..2649426 100644 (file)
 static pgd_t save_pgd __initdata;
 static unsigned long efi_flags __initdata;
 
-static void __init early_mapping_set_exec(unsigned long start,
-                                         unsigned long end,
-                                         int executable)
-{
-       unsigned long num_pages;
-
-       start &= PMD_MASK;
-       end = (end + PMD_SIZE - 1) & PMD_MASK;
-       num_pages = (end - start) >> PAGE_SHIFT;
-       if (executable)
-               set_memory_x((unsigned long)__va(start), num_pages);
-       else
-               set_memory_nx((unsigned long)__va(start), num_pages);
-}
-
-static void __init early_runtime_code_mapping_set_exec(int executable)
+static void __init early_code_mapping_set_exec(int executable)
 {
        efi_memory_desc_t *md;
        void *p;
@@ -67,11 +52,8 @@ static void __init early_runtime_code_mapping_set_exec(int executable)
        /* Make EFI runtime service code area executable */
        for (p = memmap.map; p < memmap.map_end; p += memmap.desc_size) {
                md = p;
-               if (md->type == EFI_RUNTIME_SERVICES_CODE) {
-                       unsigned long end;
-                       end = md->phys_addr + (md->num_pages << EFI_PAGE_SHIFT);
-                       early_mapping_set_exec(md->phys_addr, end, executable);
-               }
+               if (md->type == EFI_RUNTIME_SERVICES_CODE)
+                       efi_set_executable(md, executable);
        }
 }
 
@@ -79,7 +61,7 @@ void __init efi_call_phys_prelog(void)
 {
        unsigned long vaddress;
 
-       early_runtime_code_mapping_set_exec(1);
+       early_code_mapping_set_exec(1);
        local_irq_save(efi_flags);
        vaddress = (unsigned long)__va(0x0UL);
        save_pgd = *pgd_offset_k(0x0UL);
@@ -95,7 +77,7 @@ void __init efi_call_phys_epilog(void)
        set_pgd(pgd_offset_k(0x0UL), save_pgd);
        __flush_tlb_all();
        local_irq_restore(efi_flags);
-       early_runtime_code_mapping_set_exec(0);
+       early_code_mapping_set_exec(0);
 }
 
 void __iomem *__init efi_ioremap(unsigned long phys_addr, unsigned long size,
@@ -107,8 +89,10 @@ void __iomem *__init efi_ioremap(unsigned long phys_addr, unsigned long size,
                return ioremap(phys_addr, size);
 
        last_map_pfn = init_memory_mapping(phys_addr, phys_addr + size);
-       if ((last_map_pfn << PAGE_SHIFT) < phys_addr + size)
-               return NULL;
+       if ((last_map_pfn << PAGE_SHIFT) < phys_addr + size) {
+               unsigned long top = last_map_pfn << PAGE_SHIFT;
+               efi_ioremap(top, size - (top - phys_addr), type);
+       }
 
        return (void __iomem *)__va(phys_addr);
 }
index 275dbc1..7000e74 100644 (file)
@@ -194,7 +194,7 @@ static unsigned long __init mrst_calibrate_tsc(void)
        return 0;
 }
 
-void __init mrst_time_init(void)
+static void __init mrst_time_init(void)
 {
        sfi_table_parse(SFI_SIG_MTMR, NULL, NULL, sfi_parse_mtmr);
        switch (mrst_timer_options) {
@@ -216,7 +216,7 @@ void __init mrst_time_init(void)
        apbt_time_init();
 }
 
-void __cpuinit mrst_arch_setup(void)
+static void __cpuinit mrst_arch_setup(void)
 {
        if (boot_cpu_data.x86 == 6 && boot_cpu_data.x86_model == 0x27)
                __mrst_cpu_chip = MRST_CPU_CHIP_PENWELL;
index c2a8cab..81c5e21 100644 (file)
@@ -1,4 +1,2 @@
-obj-$(CONFIG_OLPC)             += olpc.o
+obj-$(CONFIG_OLPC)             += olpc.o olpc_ofw.o olpc_dt.o
 obj-$(CONFIG_OLPC_XO1)         += olpc-xo1.o
-obj-$(CONFIG_OLPC)             += olpc_ofw.o
-obj-$(CONFIG_OF_PROMTREE)      += olpc_dt.o
index edaf3fe..0060fd5 100644 (file)
@@ -18,6 +18,7 @@
 #include <linux/io.h>
 #include <linux/string.h>
 #include <linux/platform_device.h>
+#include <linux/of.h>
 
 #include <asm/geode.h>
 #include <asm/setup.h>
@@ -187,41 +188,43 @@ err:
 }
 EXPORT_SYMBOL_GPL(olpc_ec_cmd);
 
-static bool __init check_ofw_architecture(void)
+static bool __init check_ofw_architecture(struct device_node *root)
 {
-       size_t propsize;
-       char olpc_arch[5];
-       const void *args[] = { NULL, "architecture", olpc_arch, (void *)5 };
-       void *res[] = { &propsize };
+       const char *olpc_arch;
+       int propsize;
 
-       if (olpc_ofw("getprop", args, res)) {
-               printk(KERN_ERR "ofw: getprop call failed!\n");
-               return false;
-       }
+       olpc_arch = of_get_property(root, "architecture", &propsize);
        return propsize == 5 && strncmp("OLPC", olpc_arch, 5) == 0;
 }
 
-static u32 __init get_board_revision(void)
+static u32 __init get_board_revision(struct device_node *root)
 {
-       size_t propsize;
-       __be32 rev;
-       const void *args[] = { NULL, "board-revision-int", &rev, (void *)4 };
-       void *res[] = { &propsize };
-
-       if (olpc_ofw("getprop", args, res) || propsize != 4) {
-               printk(KERN_ERR "ofw: getprop call failed!\n");
-               return cpu_to_be32(0);
-       }
-       return be32_to_cpu(rev);
+       int propsize;
+       const __be32 *rev;
+
+       rev = of_get_property(root, "board-revision-int", &propsize);
+       if (propsize != 4)
+               return 0;
+
+       return be32_to_cpu(*rev);
 }
 
 static bool __init platform_detect(void)
 {
-       if (!check_ofw_architecture())
+       struct device_node *root = of_find_node_by_path("/");
+       bool success;
+
+       if (!root)
                return false;
-       olpc_platform_info.flags |= OLPC_F_PRESENT;
-       olpc_platform_info.boardrev = get_board_revision();
-       return true;
+
+       success = check_ofw_architecture(root);
+       if (success) {
+               olpc_platform_info.boardrev = get_board_revision(root);
+               olpc_platform_info.flags |= OLPC_F_PRESENT;
+       }
+
+       of_node_put(root);
+       return success;
 }
 
 static int __init add_xo1_platform_devices(void)
index 044bda5..d39f63d 100644 (file)
@@ -19,7 +19,9 @@
 #include <linux/kernel.h>
 #include <linux/bootmem.h>
 #include <linux/of.h>
+#include <linux/of_platform.h>
 #include <linux/of_pdt.h>
+#include <asm/olpc.h>
 #include <asm/olpc_ofw.h>
 
 static phandle __init olpc_dt_getsibling(phandle node)
@@ -180,3 +182,20 @@ void __init olpc_dt_build_devicetree(void)
        pr_info("PROM DT: Built device tree with %u bytes of memory.\n",
                        prom_early_allocated);
 }
+
+/* A list of DT node/bus matches that we want to expose as platform devices */
+static struct of_device_id __initdata of_ids[] = {
+       { .compatible = "olpc,xo1-battery" },
+       { .compatible = "olpc,xo1-dcon" },
+       { .compatible = "olpc,xo1-rtc" },
+       {},
+};
+
+static int __init olpc_create_platform_devices(void)
+{
+       if (machine_is_olpc())
+               return of_platform_bus_probe(NULL, of_ids, NULL);
+       else
+               return 0;
+}
+device_initcall(olpc_create_platform_devices);
index 7cb6424..c58e0ea 100644 (file)
@@ -699,16 +699,17 @@ const struct cpumask *uv_flush_tlb_others(const struct cpumask *cpumask,
                                          struct mm_struct *mm,
                                          unsigned long va, unsigned int cpu)
 {
-       int tcpu;
-       int uvhub;
        int locals = 0;
        int remotes = 0;
        int hubs = 0;
+       int tcpu;
+       int tpnode;
        struct bau_desc *bau_desc;
        struct cpumask *flush_mask;
        struct ptc_stats *stat;
        struct bau_control *bcp;
        struct bau_control *tbcp;
+       struct hub_and_pnode *hpp;
 
        /* kernel was booted 'nobau' */
        if (nobau)
@@ -750,11 +751,18 @@ const struct cpumask *uv_flush_tlb_others(const struct cpumask *cpumask,
        bau_desc += UV_ITEMS_PER_DESCRIPTOR * bcp->uvhub_cpu;
        bau_uvhubs_clear(&bau_desc->distribution, UV_DISTRIBUTION_SIZE);
 
-       /* cpu statistics */
        for_each_cpu(tcpu, flush_mask) {
-               uvhub = uv_cpu_to_blade_id(tcpu);
-               bau_uvhub_set(uvhub, &bau_desc->distribution);
-               if (uvhub == bcp->uvhub)
+               /*
+                * The distribution vector is a bit map of pnodes, relative
+                * to the partition base pnode (and the partition base nasid
+                * in the header).
+                * Translate cpu to pnode and hub using an array stored
+                * in local memory.
+                */
+               hpp = &bcp->socket_master->target_hub_and_pnode[tcpu];
+               tpnode = hpp->pnode - bcp->partition_base_pnode;
+               bau_uvhub_set(tpnode, &bau_desc->distribution);
+               if (hpp->uvhub == bcp->uvhub)
                        locals++;
                else
                        remotes++;
@@ -855,7 +863,7 @@ void uv_bau_message_interrupt(struct pt_regs *regs)
  * an interrupt, but causes an error message to be returned to
  * the sender.
  */
-static void uv_enable_timeouts(void)
+static void __init uv_enable_timeouts(void)
 {
        int uvhub;
        int nuvhubs;
@@ -1326,10 +1334,10 @@ static int __init uv_ptc_init(void)
 }
 
 /*
- * initialize the sending side's sending buffers
+ * Initialize the sending side's sending buffers.
  */
 static void
-uv_activation_descriptor_init(int node, int pnode)
+uv_activation_descriptor_init(int node, int pnode, int base_pnode)
 {
        int i;
        int cpu;
@@ -1352,11 +1360,11 @@ uv_activation_descriptor_init(int node, int pnode)
        n = pa >> uv_nshift;
        m = pa & uv_mmask;
 
+       /* the 14-bit pnode */
        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
+        * Initializing all 8 (UV_ITEMS_PER_DESCRIPTOR) descriptors for each
         * cpu even though we only use the first one; one descriptor can
         * describe a broadcast to 256 uv hubs.
         */
@@ -1365,12 +1373,13 @@ uv_activation_descriptor_init(int node, int pnode)
                memset(bd2, 0, sizeof(struct bau_desc));
                bd2->header.sw_ack_flag = 1;
                /*
-                * base_dest_nodeid is the nasid of the first uvhub
-                * in the partition. The bit map will indicate uvhub numbers,
-                * which are 0-N in a partition. Pnodes are unique system-wide.
+                * The base_dest_nasid set in the message header is the nasid
+                * of the first uvhub in the partition. The bit map will
+                * indicate destination pnode numbers relative to that base.
+                * They may not be consecutive if nasid striding is being used.
                 */
-               bd2->header.base_dest_nodeid = UV_PNODE_TO_NASID(uv_partition_base_pnode);
-               bd2->header.dest_subnodeid = 0x10; /* the LB */
+               bd2->header.base_dest_nasid = UV_PNODE_TO_NASID(base_pnode);
+               bd2->header.dest_subnodeid = UV_LB_SUBNODEID;
                bd2->header.command = UV_NET_ENDPOINT_INTD;
                bd2->header.int_both = 1;
                /*
@@ -1442,7 +1451,7 @@ uv_payload_queue_init(int node, int pnode)
 /*
  * Initialization of each UV hub's structures
  */
-static void __init uv_init_uvhub(int uvhub, int vector)
+static void __init uv_init_uvhub(int uvhub, int vector, int base_pnode)
 {
        int node;
        int pnode;
@@ -1450,11 +1459,11 @@ static void __init uv_init_uvhub(int uvhub, int vector)
 
        node = uvhub_to_first_node(uvhub);
        pnode = uv_blade_to_pnode(uvhub);
-       uv_activation_descriptor_init(node, pnode);
+       uv_activation_descriptor_init(node, pnode, base_pnode);
        uv_payload_queue_init(node, pnode);
        /*
-        * the below initialization can't be in firmware because the
-        * messaging IRQ will be determined by the OS
+        * The below initialization can't be in firmware because the
+        * messaging IRQ will be determined by the OS.
         */
        apicid = uvhub_to_first_apicid(uvhub) | uv_apicid_hibits;
        uv_write_global_mmr64(pnode, UVH_BAU_DATA_CONFIG,
@@ -1491,10 +1500,11 @@ calculate_destination_timeout(void)
 /*
  * initialize the bau_control structure for each cpu
  */
-static int __init uv_init_per_cpu(int nuvhubs)
+static int __init uv_init_per_cpu(int nuvhubs, int base_part_pnode)
 {
        int i;
        int cpu;
+       int tcpu;
        int pnode;
        int uvhub;
        int have_hmaster;
@@ -1528,6 +1538,15 @@ static int __init uv_init_per_cpu(int nuvhubs)
                bcp = &per_cpu(bau_control, cpu);
                memset(bcp, 0, sizeof(struct bau_control));
                pnode = uv_cpu_hub_info(cpu)->pnode;
+               if ((pnode - base_part_pnode) >= UV_DISTRIBUTION_SIZE) {
+                       printk(KERN_EMERG
+                               "cpu %d pnode %d-%d beyond %d; BAU disabled\n",
+                               cpu, pnode, base_part_pnode,
+                               UV_DISTRIBUTION_SIZE);
+                       return 1;
+               }
+               bcp->osnode = cpu_to_node(cpu);
+               bcp->partition_base_pnode = uv_partition_base_pnode;
                uvhub = uv_cpu_hub_info(cpu)->numa_blade_id;
                *(uvhub_mask + (uvhub/8)) |= (1 << (uvhub%8));
                bdp = &uvhub_descs[uvhub];
@@ -1536,7 +1555,7 @@ static int __init uv_init_per_cpu(int nuvhubs)
                bdp->pnode = pnode;
                /* kludge: 'assuming' one node per socket, and assuming that
                   disabling a socket just leaves a gap in node numbers */
-               socket = (cpu_to_node(cpu) & 1);
+               socket = bcp->osnode & 1;
                bdp->socket_mask |= (1 << socket);
                sdp = &bdp->socket[socket];
                sdp->cpu_number[sdp->num_cpus] = cpu;
@@ -1585,6 +1604,20 @@ static int __init uv_init_per_cpu(int nuvhubs)
 nextsocket:
                        socket++;
                        socket_mask = (socket_mask >> 1);
+                       /* each socket gets a local array of pnodes/hubs */
+                       bcp = smaster;
+                       bcp->target_hub_and_pnode = kmalloc_node(
+                               sizeof(struct hub_and_pnode) *
+                               num_possible_cpus(), GFP_KERNEL, bcp->osnode);
+                       memset(bcp->target_hub_and_pnode, 0,
+                               sizeof(struct hub_and_pnode) *
+                               num_possible_cpus());
+                       for_each_present_cpu(tcpu) {
+                               bcp->target_hub_and_pnode[tcpu].pnode =
+                                       uv_cpu_hub_info(tcpu)->pnode;
+                               bcp->target_hub_and_pnode[tcpu].uvhub =
+                                       uv_cpu_hub_info(tcpu)->numa_blade_id;
+                       }
                }
        }
        kfree(uvhub_descs);
@@ -1637,21 +1670,22 @@ static int __init uv_bau_init(void)
        spin_lock_init(&disable_lock);
        congested_cycles = microsec_2_cycles(congested_response_us);
 
-       if (uv_init_per_cpu(nuvhubs)) {
-               nobau = 1;
-               return 0;
-       }
-
        uv_partition_base_pnode = 0x7fffffff;
-       for (uvhub = 0; uvhub < nuvhubs; uvhub++)
+       for (uvhub = 0; uvhub < nuvhubs; uvhub++) {
                if (uv_blade_nr_possible_cpus(uvhub) &&
                        (uv_blade_to_pnode(uvhub) < uv_partition_base_pnode))
                        uv_partition_base_pnode = uv_blade_to_pnode(uvhub);
+       }
+
+       if (uv_init_per_cpu(nuvhubs, uv_partition_base_pnode)) {
+               nobau = 1;
+               return 0;
+       }
 
        vector = UV_BAU_MESSAGE;
        for_each_possible_blade(uvhub)
                if (uv_blade_nr_possible_cpus(uvhub))
-                       uv_init_uvhub(uvhub, vector);
+                       uv_init_uvhub(uvhub, vector, uv_partition_base_pnode);
 
        uv_enable_timeouts();
        alloc_intr_gate(vector, uv_bau_message_intr1);
index 9daf5d1..0eb9018 100644 (file)
@@ -40,7 +40,6 @@ static struct clocksource clocksource_uv = {
        .rating         = 400,
        .read           = uv_read_rtc,
        .mask           = (cycle_t)UVH_RTC_REAL_TIME_CLOCK_MASK,
-       .shift          = 10,
        .flags          = CLOCK_SOURCE_IS_CONTINUOUS,
 };
 
@@ -372,14 +371,11 @@ static __init int uv_rtc_setup_clock(void)
        if (!is_uv_system())
                return -ENODEV;
 
-       clocksource_uv.mult = clocksource_hz2mult(sn_rtc_cycles_per_second,
-                               clocksource_uv.shift);
-
        /* If single blade, prefer tsc */
        if (uv_num_possible_blades() == 1)
                clocksource_uv.rating = 250;
 
-       rc = clocksource_register(&clocksource_uv);
+       rc = clocksource_register_hz(&clocksource_uv, sn_rtc_cycles_per_second);
        if (rc)
                printk(KERN_INFO "UV RTC clocksource failed rc %d\n", rc);
        else
index e3c6a06..dd7b88f 100644 (file)
@@ -235,7 +235,7 @@ static void xen_cpuid(unsigned int *ax, unsigned int *bx,
        *dx &= maskedx;
 }
 
-static __init void xen_init_cpuid_mask(void)
+static void __init xen_init_cpuid_mask(void)
 {
        unsigned int ax, bx, cx, dx;
        unsigned int xsave_mask;
@@ -400,7 +400,7 @@ static void xen_load_gdt(const struct desc_ptr *dtr)
 /*
  * load_gdt for early boot, when the gdt is only mapped once
  */
-static __init void xen_load_gdt_boot(const struct desc_ptr *dtr)
+static void __init xen_load_gdt_boot(const struct desc_ptr *dtr)
 {
        unsigned long va = dtr->address;
        unsigned int size = dtr->size + 1;
@@ -662,7 +662,7 @@ static void xen_write_gdt_entry(struct desc_struct *dt, int entry,
  * Version of write_gdt_entry for use at early boot-time needed to
  * update an entry as simply as possible.
  */
-static __init void xen_write_gdt_entry_boot(struct desc_struct *dt, int entry,
+static void __init xen_write_gdt_entry_boot(struct desc_struct *dt, int entry,
                                            const void *desc, int type)
 {
        switch (type) {
@@ -933,18 +933,18 @@ static unsigned xen_patch(u8 type, u16 clobbers, void *insnbuf,
        return ret;
 }
 
-static const struct pv_info xen_info __initdata = {
+static const struct pv_info xen_info __initconst = {
        .paravirt_enabled = 1,
        .shared_kernel_pmd = 0,
 
        .name = "Xen",
 };
 
-static const struct pv_init_ops xen_init_ops __initdata = {
+static const struct pv_init_ops xen_init_ops __initconst = {
        .patch = xen_patch,
 };
 
-static const struct pv_cpu_ops xen_cpu_ops __initdata = {
+static const struct pv_cpu_ops xen_cpu_ops __initconst = {
        .cpuid = xen_cpuid,
 
        .set_debugreg = xen_set_debugreg,
@@ -1004,7 +1004,7 @@ static const struct pv_cpu_ops xen_cpu_ops __initdata = {
        .end_context_switch = xen_end_context_switch,
 };
 
-static const struct pv_apic_ops xen_apic_ops __initdata = {
+static const struct pv_apic_ops xen_apic_ops __initconst = {
 #ifdef CONFIG_X86_LOCAL_APIC
        .startup_ipi_hook = paravirt_nop,
 #endif
@@ -1055,7 +1055,7 @@ int xen_panic_handler_init(void)
        return 0;
 }
 
-static const struct machine_ops __initdata xen_machine_ops = {
+static const struct machine_ops xen_machine_ops __initconst = {
        .restart = xen_restart,
        .halt = xen_machine_halt,
        .power_off = xen_machine_halt,
@@ -1332,7 +1332,7 @@ static int __cpuinit xen_hvm_cpu_notify(struct notifier_block *self,
        return NOTIFY_OK;
 }
 
-static struct notifier_block __cpuinitdata xen_hvm_cpu_notifier = {
+static struct notifier_block xen_hvm_cpu_notifier __cpuinitdata = {
        .notifier_call  = xen_hvm_cpu_notify,
 };
 
@@ -1381,7 +1381,7 @@ bool xen_hvm_need_lapic(void)
 }
 EXPORT_SYMBOL_GPL(xen_hvm_need_lapic);
 
-const __refconst struct hypervisor_x86 x86_hyper_xen_hvm = {
+const struct hypervisor_x86 x86_hyper_xen_hvm __refconst = {
        .name                   = "Xen HVM",
        .detect                 = xen_hvm_platform,
        .init_platform          = xen_hvm_guest_init,
index 6a6fe89..8bbb465 100644 (file)
@@ -113,7 +113,7 @@ static void xen_halt(void)
                xen_safe_halt();
 }
 
-static const struct pv_irq_ops xen_irq_ops __initdata = {
+static const struct pv_irq_ops xen_irq_ops __initconst = {
        .save_fl = PV_CALLEE_SAVE(xen_save_fl),
        .restore_fl = PV_CALLEE_SAVE(xen_restore_fl),
        .irq_disable = PV_CALLEE_SAVE(xen_irq_disable),
index 55c965b..02d7524 100644 (file)
@@ -1054,7 +1054,7 @@ void xen_mm_pin_all(void)
  * that's before we have page structures to store the bits.  So do all
  * the book-keeping now.
  */
-static __init int xen_mark_pinned(struct mm_struct *mm, struct page *page,
+static int __init xen_mark_pinned(struct mm_struct *mm, struct page *page,
                                  enum pt_level level)
 {
        SetPagePinned(page);
@@ -1187,7 +1187,7 @@ static void drop_other_mm_ref(void *info)
 
        active_mm = percpu_read(cpu_tlbstate.active_mm);
 
-       if (active_mm == mm)
+       if (active_mm == mm && percpu_read(cpu_tlbstate.state) != TLBSTATE_OK)
                leave_mm(smp_processor_id());
 
        /* If this cpu still has a stale cr3 reference, then make sure
@@ -1271,13 +1271,27 @@ void xen_exit_mmap(struct mm_struct *mm)
        spin_unlock(&mm->page_table_lock);
 }
 
-static __init void xen_pagetable_setup_start(pgd_t *base)
+static void __init xen_pagetable_setup_start(pgd_t *base)
 {
 }
 
+static __init void xen_mapping_pagetable_reserve(u64 start, u64 end)
+{
+       /* reserve the range used */
+       native_pagetable_reserve(start, end);
+
+       /* set as RW the rest */
+       printk(KERN_DEBUG "xen: setting RW the range %llx - %llx\n", end,
+                       PFN_PHYS(pgt_buf_top));
+       while (end < PFN_PHYS(pgt_buf_top)) {
+               make_lowmem_page_readwrite(__va(end));
+               end += PAGE_SIZE;
+       }
+}
+
 static void xen_post_allocator_init(void);
 
-static __init void xen_pagetable_setup_done(pgd_t *base)
+static void __init xen_pagetable_setup_done(pgd_t *base)
 {
        xen_setup_shared_info();
        xen_post_allocator_init();
@@ -1463,119 +1477,6 @@ static int xen_pgd_alloc(struct mm_struct *mm)
        return ret;
 }
 
-#ifdef CONFIG_X86_64
-static __initdata u64 __last_pgt_set_rw = 0;
-static __initdata u64 __pgt_buf_start = 0;
-static __initdata u64 __pgt_buf_end = 0;
-static __initdata u64 __pgt_buf_top = 0;
-/*
- * As a consequence of the commit:
- * 
- * commit 4b239f458c229de044d6905c2b0f9fe16ed9e01e
- * Author: Yinghai Lu <yinghai@kernel.org>
- * Date:   Fri Dec 17 16:58:28 2010 -0800
- * 
- *     x86-64, mm: Put early page table high
- * 
- * at some point init_memory_mapping is going to reach the pagetable pages
- * area and map those pages too (mapping them as normal memory that falls
- * in the range of addresses passed to init_memory_mapping as argument).
- * Some of those pages are already pagetable pages (they are in the range
- * pgt_buf_start-pgt_buf_end) therefore they are going to be mapped RO and
- * everything is fine.
- * Some of these pages are not pagetable pages yet (they fall in the range
- * pgt_buf_end-pgt_buf_top; for example the page at pgt_buf_end) so they
- * are going to be mapped RW.  When these pages become pagetable pages and
- * are hooked into the pagetable, xen will find that the guest has already
- * a RW mapping of them somewhere and fail the operation.
- * The reason Xen requires pagetables to be RO is that the hypervisor needs
- * to verify that the pagetables are valid before using them. The validation
- * operations are called "pinning".
- * 
- * In order to fix the issue we mark all the pages in the entire range
- * pgt_buf_start-pgt_buf_top as RO, however when the pagetable allocation
- * is completed only the range pgt_buf_start-pgt_buf_end is reserved by
- * init_memory_mapping. Hence the kernel is going to crash as soon as one
- * of the pages in the range pgt_buf_end-pgt_buf_top is reused (b/c those
- * ranges are RO).
- * 
- * For this reason, 'mark_rw_past_pgt' is introduced which is called _after_
- * the init_memory_mapping has completed (in a perfect world we would
- * call this function from init_memory_mapping, but lets ignore that).
- * 
- * Because we are called _after_ init_memory_mapping the pgt_buf_[start,
- * end,top] have all changed to new values (b/c init_memory_mapping
- * is called and setting up another new page-table). Hence, the first time
- * we enter this function, we save away the pgt_buf_start value and update
- * the pgt_buf_[end,top].
- * 
- * When we detect that the "old" pgt_buf_start through pgt_buf_end
- * PFNs have been reserved (so memblock_x86_reserve_range has been called),
- * we immediately set out to RW the "old" pgt_buf_end through pgt_buf_top.
- * 
- * And then we update those "old" pgt_buf_[end|top] with the new ones
- * so that we can redo this on the next pagetable.
- */
-static __init void mark_rw_past_pgt(void) {
-
-       if (pgt_buf_end > pgt_buf_start) {
-               u64 addr, size;
-
-               /* Save it away. */
-               if (!__pgt_buf_start) {
-                       __pgt_buf_start = pgt_buf_start;
-                       __pgt_buf_end = pgt_buf_end;
-                       __pgt_buf_top = pgt_buf_top;
-                       return;
-               }
-               /* If we get the range that starts at __pgt_buf_end that means
-                * the range is reserved, and that in 'init_memory_mapping'
-                * the 'memblock_x86_reserve_range' has been called with the
-                * outdated __pgt_buf_start, __pgt_buf_end (the "new"
-                * pgt_buf_[start|end|top] refer now to a new pagetable.
-                * Note: we are called _after_ the pgt_buf_[..] have been
-                * updated.*/
-
-               addr = memblock_x86_find_in_range_size(PFN_PHYS(__pgt_buf_start),
-                                                      &size, PAGE_SIZE);
-
-               /* Still not reserved, meaning 'memblock_x86_reserve_range'
-                * hasn't been called yet. Update the _end and _top.*/
-               if (addr == PFN_PHYS(__pgt_buf_start)) {
-                       __pgt_buf_end = pgt_buf_end;
-                       __pgt_buf_top = pgt_buf_top;
-                       return;
-               }
-
-               /* OK, the area is reserved, meaning it is time for us to
-                * set RW for the old end->top PFNs. */
-
-               /* ..unless we had already done this. */
-               if (__pgt_buf_end == __last_pgt_set_rw)
-                       return;
-
-               addr = PFN_PHYS(__pgt_buf_end);
-               
-               /* set as RW the rest */
-               printk(KERN_DEBUG "xen: setting RW the range %llx - %llx\n",
-                       PFN_PHYS(__pgt_buf_end), PFN_PHYS(__pgt_buf_top));
-               
-               while (addr < PFN_PHYS(__pgt_buf_top)) {
-                       make_lowmem_page_readwrite(__va(addr));
-                       addr += PAGE_SIZE;
-               }
-               /* And update everything so that we are ready for the next
-                * pagetable (the one created for regions past 4GB) */
-               __last_pgt_set_rw = __pgt_buf_end;
-               __pgt_buf_start = pgt_buf_start;
-               __pgt_buf_end = pgt_buf_end;
-               __pgt_buf_top = pgt_buf_top;
-       }
-       return;
-}
-#else
-static __init void mark_rw_past_pgt(void) { }
-#endif
 static void xen_pgd_free(struct mm_struct *mm, pgd_t *pgd)
 {
 #ifdef CONFIG_X86_64
@@ -1587,7 +1488,7 @@ static void xen_pgd_free(struct mm_struct *mm, pgd_t *pgd)
 }
 
 #ifdef CONFIG_X86_32
-static __init pte_t mask_rw_pte(pte_t *ptep, pte_t pte)
+static pte_t __init mask_rw_pte(pte_t *ptep, pte_t pte)
 {
        /* If there's an existing pte, then don't allow _PAGE_RW to be set */
        if (pte_val_ma(*ptep) & _PAGE_PRESENT)
@@ -1597,19 +1498,11 @@ static __init pte_t mask_rw_pte(pte_t *ptep, pte_t pte)
        return pte;
 }
 #else /* CONFIG_X86_64 */
-static __init pte_t mask_rw_pte(pte_t *ptep, pte_t pte)
+static pte_t __init mask_rw_pte(pte_t *ptep, pte_t pte)
 {
        unsigned long pfn = pte_pfn(pte);
 
        /*
-        * A bit of optimization. We do not need to call the workaround
-        * when xen_set_pte_init is called with a PTE with 0 as PFN.
-        * That is b/c the pagetable at that point are just being populated
-        * with empty values and we can save some cycles by not calling
-        * the 'memblock' code.*/
-       if (pfn)
-               mark_rw_past_pgt();
-       /*
         * If the new pfn is within the range of the newly allocated
         * kernel pagetable, and it isn't being mapped into an
         * early_ioremap fixmap slot as a freshly allocated page, make sure
@@ -1626,7 +1519,7 @@ static __init pte_t mask_rw_pte(pte_t *ptep, pte_t pte)
 
 /* Init-time set_pte while constructing initial pagetables, which
    doesn't allow RO pagetable pages to be remapped RW */
-static __init void xen_set_pte_init(pte_t *ptep, pte_t pte)
+static void __init xen_set_pte_init(pte_t *ptep, pte_t pte)
 {
        pte = mask_rw_pte(ptep, pte);
 
@@ -1644,7 +1537,7 @@ static void pin_pagetable_pfn(unsigned cmd, unsigned long pfn)
 
 /* Early in boot, while setting up the initial pagetable, assume
    everything is pinned. */
-static __init void xen_alloc_pte_init(struct mm_struct *mm, unsigned long pfn)
+static void __init xen_alloc_pte_init(struct mm_struct *mm, unsigned long pfn)
 {
 #ifdef CONFIG_FLATMEM
        BUG_ON(mem_map);        /* should only be used early */
@@ -1654,7 +1547,7 @@ static __init void xen_alloc_pte_init(struct mm_struct *mm, unsigned long pfn)
 }
 
 /* Used for pmd and pud */
-static __init void xen_alloc_pmd_init(struct mm_struct *mm, unsigned long pfn)
+static void __init xen_alloc_pmd_init(struct mm_struct *mm, unsigned long pfn)
 {
 #ifdef CONFIG_FLATMEM
        BUG_ON(mem_map);        /* should only be used early */
@@ -1664,13 +1557,13 @@ static __init void xen_alloc_pmd_init(struct mm_struct *mm, unsigned long pfn)
 
 /* Early release_pte assumes that all pts are pinned, since there's
    only init_mm and anything attached to that is pinned. */
-static __init void xen_release_pte_init(unsigned long pfn)
+static void __init xen_release_pte_init(unsigned long pfn)
 {
        pin_pagetable_pfn(MMUEXT_UNPIN_TABLE, pfn);
        make_lowmem_page_readwrite(__va(PFN_PHYS(pfn)));
 }
 
-static __init void xen_release_pmd_init(unsigned long pfn)
+static void __init xen_release_pmd_init(unsigned long pfn)
 {
        make_lowmem_page_readwrite(__va(PFN_PHYS(pfn)));
 }
@@ -1796,7 +1689,7 @@ static void set_page_prot(void *addr, pgprot_t prot)
                BUG();
 }
 
-static __init void xen_map_identity_early(pmd_t *pmd, unsigned long max_pfn)
+static void __init xen_map_identity_early(pmd_t *pmd, unsigned long max_pfn)
 {
        unsigned pmdidx, pteidx;
        unsigned ident_pte;
@@ -1879,7 +1772,7 @@ static void convert_pfn_mfn(void *v)
  * of the physical mapping once some sort of allocator has been set
  * up.
  */
-__init pgd_t *xen_setup_kernel_pagetable(pgd_t *pgd,
+pgd_t * __init xen_setup_kernel_pagetable(pgd_t *pgd,
                                         unsigned long max_pfn)
 {
        pud_t *l3;
@@ -1950,7 +1843,7 @@ __init pgd_t *xen_setup_kernel_pagetable(pgd_t *pgd,
 static RESERVE_BRK_ARRAY(pmd_t, initial_kernel_pmd, PTRS_PER_PMD);
 static RESERVE_BRK_ARRAY(pmd_t, swapper_kernel_pmd, PTRS_PER_PMD);
 
-static __init void xen_write_cr3_init(unsigned long cr3)
+static void __init xen_write_cr3_init(unsigned long cr3)
 {
        unsigned long pfn = PFN_DOWN(__pa(swapper_pg_dir));
 
@@ -1987,7 +1880,7 @@ static __init void xen_write_cr3_init(unsigned long cr3)
        pv_mmu_ops.write_cr3 = &xen_write_cr3;
 }
 
-__init pgd_t *xen_setup_kernel_pagetable(pgd_t *pgd,
+pgd_t * __init xen_setup_kernel_pagetable(pgd_t *pgd,
                                         unsigned long max_pfn)
 {
        pmd_t *kernel_pmd;
@@ -2093,7 +1986,7 @@ static void xen_set_fixmap(unsigned idx, phys_addr_t phys, pgprot_t prot)
 #endif
 }
 
-__init void xen_ident_map_ISA(void)
+void __init xen_ident_map_ISA(void)
 {
        unsigned long pa;
 
@@ -2116,10 +2009,8 @@ __init void xen_ident_map_ISA(void)
        xen_flush_tlb();
 }
 
-static __init void xen_post_allocator_init(void)
+static void __init xen_post_allocator_init(void)
 {
-       mark_rw_past_pgt();
-
 #ifdef CONFIG_XEN_DEBUG
        pv_mmu_ops.make_pte = PV_CALLEE_SAVE(xen_make_pte_debug);
 #endif
@@ -2155,7 +2046,7 @@ static void xen_leave_lazy_mmu(void)
        preempt_enable();
 }
 
-static const struct pv_mmu_ops xen_mmu_ops __initdata = {
+static const struct pv_mmu_ops xen_mmu_ops __initconst = {
        .read_cr2 = xen_read_cr2,
        .write_cr2 = xen_write_cr2,
 
@@ -2228,6 +2119,7 @@ static const struct pv_mmu_ops xen_mmu_ops __initdata = {
 
 void __init xen_init_mmu_ops(void)
 {
+       x86_init.mapping.pagetable_reserve = xen_mapping_pagetable_reserve;
        x86_init.paging.pagetable_setup_start = xen_pagetable_setup_start;
        x86_init.paging.pagetable_setup_done = xen_pagetable_setup_done;
        pv_mmu_ops = xen_mmu_ops;
index 141eb0d..58efeb9 100644 (file)
@@ -522,11 +522,20 @@ static bool __init __early_alloc_p2m(unsigned long pfn)
        /* Boundary cross-over for the edges: */
        if (idx) {
                unsigned long *p2m = extend_brk(PAGE_SIZE, PAGE_SIZE);
+               unsigned long *mid_mfn_p;
 
                p2m_init(p2m);
 
                p2m_top[topidx][mididx] = p2m;
 
+               /* For save/restore we need to MFN of the P2M saved */
+               
+               mid_mfn_p = p2m_top_mfn_p[topidx];
+               WARN(mid_mfn_p[mididx] != virt_to_mfn(p2m_missing),
+                       "P2M_TOP_P[%d][%d] != MFN of p2m_missing!\n",
+                       topidx, mididx);
+               mid_mfn_p[mididx] = virt_to_mfn(p2m);
+
        }
        return idx != 0;
 }
@@ -549,12 +558,29 @@ unsigned long __init set_phys_range_identity(unsigned long pfn_s,
                pfn += P2M_MID_PER_PAGE * P2M_PER_PAGE)
        {
                unsigned topidx = p2m_top_index(pfn);
-               if (p2m_top[topidx] == p2m_mid_missing) {
-                       unsigned long **mid = extend_brk(PAGE_SIZE, PAGE_SIZE);
+               unsigned long *mid_mfn_p;
+               unsigned long **mid;
+
+               mid = p2m_top[topidx];
+               mid_mfn_p = p2m_top_mfn_p[topidx];
+               if (mid == p2m_mid_missing) {
+                       mid = extend_brk(PAGE_SIZE, PAGE_SIZE);
 
                        p2m_mid_init(mid);
 
                        p2m_top[topidx] = mid;
+
+                       BUG_ON(mid_mfn_p != p2m_mid_missing_mfn);
+               }
+               /* And the save/restore P2M tables.. */
+               if (mid_mfn_p == p2m_mid_missing_mfn) {
+                       mid_mfn_p = extend_brk(PAGE_SIZE, PAGE_SIZE);
+                       p2m_mid_mfn_init(mid_mfn_p);
+
+                       p2m_top_mfn_p[topidx] = mid_mfn_p;
+                       p2m_top_mfn[topidx] = virt_to_mfn(mid_mfn_p);
+                       /* Note: we don't set mid_mfn_p[midix] here,
+                        * look in __early_alloc_p2m */
                }
        }
 
@@ -650,7 +676,7 @@ static unsigned long mfn_hash(unsigned long mfn)
 }
 
 /* Add an MFN override for a particular page */
-int m2p_add_override(unsigned long mfn, struct page *page)
+int m2p_add_override(unsigned long mfn, struct page *page, bool clear_pte)
 {
        unsigned long flags;
        unsigned long pfn;
@@ -662,7 +688,6 @@ int m2p_add_override(unsigned long mfn, struct page *page)
        if (!PageHighMem(page)) {
                address = (unsigned long)__va(pfn << PAGE_SHIFT);
                ptep = lookup_address(address, &level);
-
                if (WARN(ptep == NULL || level != PG_LEVEL_4K,
                                        "m2p_add_override: pfn %lx not mapped", pfn))
                        return -EINVAL;
@@ -674,18 +699,17 @@ int m2p_add_override(unsigned long mfn, struct page *page)
        if (unlikely(!set_phys_to_machine(pfn, FOREIGN_FRAME(mfn))))
                return -ENOMEM;
 
-       if (!PageHighMem(page))
+       if (clear_pte && !PageHighMem(page))
                /* Just zap old mapping for now */
                pte_clear(&init_mm, address, ptep);
-
        spin_lock_irqsave(&m2p_override_lock, flags);
        list_add(&page->lru,  &m2p_overrides[mfn_hash(mfn)]);
        spin_unlock_irqrestore(&m2p_override_lock, flags);
 
        return 0;
 }
-
-int m2p_remove_override(struct page *page)
+EXPORT_SYMBOL_GPL(m2p_add_override);
+int m2p_remove_override(struct page *page, bool clear_pte)
 {
        unsigned long flags;
        unsigned long mfn;
@@ -713,7 +737,7 @@ int m2p_remove_override(struct page *page)
        spin_unlock_irqrestore(&m2p_override_lock, flags);
        set_phys_to_machine(pfn, page->index);
 
-       if (!PageHighMem(page))
+       if (clear_pte && !PageHighMem(page))
                set_pte_at(&init_mm, address, ptep,
                                pfn_pte(pfn, PAGE_KERNEL));
                /* No tlb flush necessary because the caller already
@@ -721,6 +745,7 @@ int m2p_remove_override(struct page *page)
 
        return 0;
 }
+EXPORT_SYMBOL_GPL(m2p_remove_override);
 
 struct page *m2p_find_override(unsigned long mfn)
 {
index 90bac0a..be1a464 100644 (file)
@@ -50,7 +50,7 @@ phys_addr_t xen_extra_mem_start, xen_extra_mem_size;
  */
 #define EXTRA_MEM_RATIO                (10)
 
-static __init void xen_add_extra_mem(unsigned long pages)
+static void __init xen_add_extra_mem(unsigned long pages)
 {
        unsigned long pfn;
 
@@ -166,7 +166,7 @@ static unsigned long __init xen_set_identity(const struct e820entry *list,
                if (last > end)
                        continue;
 
-               if (entry->type == E820_RAM) {
+               if ((entry->type == E820_RAM) || (entry->type == E820_UNUSABLE)) {
                        if (start > start_pci)
                                identity += set_phys_range_identity(
                                                PFN_UP(start_pci), PFN_DOWN(start));
@@ -227,7 +227,11 @@ char * __init xen_memory_setup(void)
 
        memcpy(map_raw, map, sizeof(map));
        e820.nr_map = 0;
+#ifdef CONFIG_X86_32
+       xen_extra_mem_start = mem_end;
+#else
        xen_extra_mem_start = max((1ULL << 32), mem_end);
+#endif
        for (i = 0; i < memmap.nr_entries; i++) {
                unsigned long long end;
 
@@ -336,7 +340,7 @@ static void __init fiddle_vdso(void)
 #endif
 }
 
-static __cpuinit int register_callback(unsigned type, const void *func)
+static int __cpuinit register_callback(unsigned type, const void *func)
 {
        struct callback_register callback = {
                .type = type,
index 3061244..41038c0 100644 (file)
@@ -46,18 +46,17 @@ static irqreturn_t xen_call_function_interrupt(int irq, void *dev_id);
 static irqreturn_t xen_call_function_single_interrupt(int irq, void *dev_id);
 
 /*
- * Reschedule call back. Nothing to do,
- * all the work is done automatically when
- * we return from the interrupt.
+ * Reschedule call back.
  */
 static irqreturn_t xen_reschedule_interrupt(int irq, void *dev_id)
 {
        inc_irq_stat(irq_resched_count);
+       scheduler_ipi();
 
        return IRQ_HANDLED;
 }
 
-static __cpuinit void cpu_bringup(void)
+static void __cpuinit cpu_bringup(void)
 {
        int cpu = smp_processor_id();
 
@@ -85,7 +84,7 @@ static __cpuinit void cpu_bringup(void)
        wmb();                  /* make sure everything is out */
 }
 
-static __cpuinit void cpu_bringup_and_idle(void)
+static void __cpuinit cpu_bringup_and_idle(void)
 {
        cpu_bringup();
        cpu_idle();
@@ -242,7 +241,7 @@ static void __init xen_smp_prepare_cpus(unsigned int max_cpus)
        }
 }
 
-static __cpuinit int
+static int __cpuinit
 cpu_initialize_context(unsigned int cpu, struct task_struct *idle)
 {
        struct vcpu_guest_context *ctxt;
@@ -486,7 +485,7 @@ static irqreturn_t xen_call_function_single_interrupt(int irq, void *dev_id)
        return IRQ_HANDLED;
 }
 
-static const struct smp_ops xen_smp_ops __initdata = {
+static const struct smp_ops xen_smp_ops __initconst = {
        .smp_prepare_boot_cpu = xen_smp_prepare_boot_cpu,
        .smp_prepare_cpus = xen_smp_prepare_cpus,
        .smp_cpus_done = xen_smp_cpus_done,
index 2e2d370..5158c50 100644 (file)
@@ -26,8 +26,6 @@
 
 #include "xen-ops.h"
 
-#define XEN_SHIFT 22
-
 /* Xen may fire a timer up to this many ns early */
 #define TIMER_SLOP     100000
 #define NS_PER_TICK    (1000000000LL / HZ)
@@ -211,8 +209,6 @@ static struct clocksource xen_clocksource __read_mostly = {
        .rating = 400,
        .read = xen_clocksource_get_cycles,
        .mask = ~0,
-       .mult = 1<<XEN_SHIFT,           /* time directly in nanoseconds */
-       .shift = XEN_SHIFT,
        .flags = CLOCK_SOURCE_IS_CONTINUOUS,
 };
 
@@ -439,16 +435,16 @@ void xen_timer_resume(void)
        }
 }
 
-static const struct pv_time_ops xen_time_ops __initdata = {
+static const struct pv_time_ops xen_time_ops __initconst = {
        .sched_clock = xen_clocksource_read,
 };
 
-static __init void xen_time_init(void)
+static void __init xen_time_init(void)
 {
        int cpu = smp_processor_id();
        struct timespec tp;
 
-       clocksource_register(&xen_clocksource);
+       clocksource_register_hz(&xen_clocksource, NSEC_PER_SEC);
 
        if (HYPERVISOR_vcpu_op(VCPUOP_stop_periodic_timer, cpu, NULL) == 0) {
                /* Successfully turned off 100Hz tick, so we have the
@@ -468,7 +464,7 @@ static __init void xen_time_init(void)
        xen_setup_cpu_clockevents();
 }
 
-__init void xen_init_time_ops(void)
+void __init xen_init_time_ops(void)
 {
        pv_time_ops = xen_time_ops;
 
@@ -490,7 +486,7 @@ static void xen_hvm_setup_cpu_clockevents(void)
        xen_setup_cpu_clockevents();
 }
 
-__init void xen_hvm_init_time_ops(void)
+void __init xen_hvm_init_time_ops(void)
 {
        /* vector callback is needed otherwise we cannot receive interrupts
         * on cpu > 0 and at this point we don't know how many cpus are
index 3112f55..97dfdc8 100644 (file)
@@ -74,7 +74,7 @@ static inline void xen_hvm_smp_init(void) {}
 
 #ifdef CONFIG_PARAVIRT_SPINLOCKS
 void __init xen_init_spinlocks(void);
-__cpuinit void xen_init_lock_cpu(int cpu);
+void __cpuinit xen_init_lock_cpu(int cpu);
 void xen_uninit_lock_cpu(int cpu);
 #else
 static inline void xen_init_spinlocks(void)
index f0605ab..471fdcc 100644 (file)
@@ -114,6 +114,13 @@ struct blkio_cgroup *cgroup_to_blkio_cgroup(struct cgroup *cgroup)
 }
 EXPORT_SYMBOL_GPL(cgroup_to_blkio_cgroup);
 
+struct blkio_cgroup *task_blkio_cgroup(struct task_struct *tsk)
+{
+       return container_of(task_subsys_state(tsk, blkio_subsys_id),
+                           struct blkio_cgroup, css);
+}
+EXPORT_SYMBOL_GPL(task_blkio_cgroup);
+
 static inline void
 blkio_update_group_weight(struct blkio_group *blkg, unsigned int weight)
 {
index 10919fa..c774930 100644 (file)
@@ -291,6 +291,7 @@ static inline void blkiocg_set_start_empty_time(struct blkio_group *blkg) {}
 #if defined(CONFIG_BLK_CGROUP) || defined(CONFIG_BLK_CGROUP_MODULE)
 extern struct blkio_cgroup blkio_root_cgroup;
 extern struct blkio_cgroup *cgroup_to_blkio_cgroup(struct cgroup *cgroup);
+extern struct blkio_cgroup *task_blkio_cgroup(struct task_struct *tsk);
 extern void blkiocg_add_blkio_group(struct blkio_cgroup *blkcg,
        struct blkio_group *blkg, void *key, dev_t dev,
        enum blkio_policy_id plid);
@@ -314,6 +315,8 @@ void blkiocg_update_io_remove_stats(struct blkio_group *blkg,
 struct cgroup;
 static inline struct blkio_cgroup *
 cgroup_to_blkio_cgroup(struct cgroup *cgroup) { return NULL; }
+static inline struct blkio_cgroup *
+task_blkio_cgroup(struct task_struct *tsk) { return NULL; }
 
 static inline void blkiocg_add_blkio_group(struct blkio_cgroup *blkcg,
                struct blkio_group *blkg, void *key, dev_t dev,
index a2e58ee..3fe00a1 100644 (file)
@@ -316,8 +316,10 @@ EXPORT_SYMBOL(__blk_run_queue);
  */
 void blk_run_queue_async(struct request_queue *q)
 {
-       if (likely(!blk_queue_stopped(q)))
+       if (likely(!blk_queue_stopped(q))) {
+               __cancel_delayed_work(&q->delay_work);
                queue_delayed_work(kblockd_workqueue, &q->delay_work, 0);
+       }
 }
 EXPORT_SYMBOL(blk_run_queue_async);
 
index 0475a22..252a81a 100644 (file)
@@ -160,9 +160,8 @@ static void throtl_put_tg(struct throtl_grp *tg)
 }
 
 static struct throtl_grp * throtl_find_alloc_tg(struct throtl_data *td,
-                       struct cgroup *cgroup)
+                       struct blkio_cgroup *blkcg)
 {
-       struct blkio_cgroup *blkcg = cgroup_to_blkio_cgroup(cgroup);
        struct throtl_grp *tg = NULL;
        void *key = td;
        struct backing_dev_info *bdi = &td->queue->backing_dev_info;
@@ -229,12 +228,12 @@ done:
 
 static struct throtl_grp * throtl_get_tg(struct throtl_data *td)
 {
-       struct cgroup *cgroup;
        struct throtl_grp *tg = NULL;
+       struct blkio_cgroup *blkcg;
 
        rcu_read_lock();
-       cgroup = task_cgroup(current, blkio_subsys_id);
-       tg = throtl_find_alloc_tg(td, cgroup);
+       blkcg = task_blkio_cgroup(current);
+       tg = throtl_find_alloc_tg(td, blkcg);
        if (!tg)
                tg = &td->root_tg;
        rcu_read_unlock();
index 5b52011..ab7a9e6 100644 (file)
@@ -1014,10 +1014,9 @@ void cfq_update_blkio_group_weight(void *key, struct blkio_group *blkg,
        cfqg->needs_update = true;
 }
 
-static struct cfq_group *
-cfq_find_alloc_cfqg(struct cfq_data *cfqd, struct cgroup *cgroup, int create)
+static struct cfq_group * cfq_find_alloc_cfqg(struct cfq_data *cfqd,
+               struct blkio_cgroup *blkcg, int create)
 {
-       struct blkio_cgroup *blkcg = cgroup_to_blkio_cgroup(cgroup);
        struct cfq_group *cfqg = NULL;
        void *key = cfqd;
        int i, j;
@@ -1079,12 +1078,12 @@ done:
  */
 static struct cfq_group *cfq_get_cfqg(struct cfq_data *cfqd, int create)
 {
-       struct cgroup *cgroup;
+       struct blkio_cgroup *blkcg;
        struct cfq_group *cfqg = NULL;
 
        rcu_read_lock();
-       cgroup = task_cgroup(current, blkio_subsys_id);
-       cfqg = cfq_find_alloc_cfqg(cfqd, cgroup, create);
+       blkcg = task_blkio_cgroup(current);
+       cfqg = cfq_find_alloc_cfqg(cfqd, blkcg, create);
        if (!cfqg && create)
                cfqg = &cfqd->root_group;
        rcu_read_unlock();
index 177c7d1..557a469 100644 (file)
@@ -119,4 +119,7 @@ source "drivers/platform/Kconfig"
 source "drivers/clk/Kconfig"
 
 source "drivers/hwspinlock/Kconfig"
+
+source "drivers/clocksource/Kconfig"
+
 endmenu
index 3a73a93..85b3237 100644 (file)
@@ -49,10 +49,6 @@ ACPI_MODULE_NAME("processor_perflib");
 
 static DEFINE_MUTEX(performance_mutex);
 
-/* Use cpufreq debug layer for _PPC changes. */
-#define cpufreq_printk(msg...) cpufreq_debug_printk(CPUFREQ_DEBUG_CORE, \
-                                               "cpufreq-core", msg)
-
 /*
  * _PPC support is implemented as a CPUfreq policy notifier:
  * This means each time a CPUfreq driver registered also with
@@ -145,7 +141,7 @@ static int acpi_processor_get_platform_limit(struct acpi_processor *pr)
                return -ENODEV;
        }
 
-       cpufreq_printk("CPU %d: _PPC is %d - frequency %s limited\n", pr->id,
+       pr_debug("CPU %d: _PPC is %d - frequency %s limited\n", pr->id,
                       (int)ppc, ppc ? "" : "not");
 
        pr->performance_platform_limit = (int)ppc;
index ad35017..605a295 100644 (file)
@@ -710,20 +710,14 @@ static int acpi_processor_get_throttling_fadt(struct acpi_processor *pr)
 }
 
 #ifdef CONFIG_X86
-static int acpi_throttling_rdmsr(struct acpi_processor *pr,
-                                       u64 *value)
+static int acpi_throttling_rdmsr(u64 *value)
 {
-       struct cpuinfo_x86 *c;
        u64 msr_high, msr_low;
-       unsigned int cpu;
        u64 msr = 0;
        int ret = -1;
 
-       cpu = pr->id;
-       c = &cpu_data(cpu);
-
-       if ((c->x86_vendor != X86_VENDOR_INTEL) ||
-               !cpu_has(c, X86_FEATURE_ACPI)) {
+       if ((this_cpu_read(cpu_info.x86_vendor) != X86_VENDOR_INTEL) ||
+               !this_cpu_has(X86_FEATURE_ACPI)) {
                printk(KERN_ERR PREFIX
                        "HARDWARE addr space,NOT supported yet\n");
        } else {
@@ -738,18 +732,13 @@ static int acpi_throttling_rdmsr(struct acpi_processor *pr,
        return ret;
 }
 
-static int acpi_throttling_wrmsr(struct acpi_processor *pr, u64 value)
+static int acpi_throttling_wrmsr(u64 value)
 {
-       struct cpuinfo_x86 *c;
-       unsigned int cpu;
        int ret = -1;
        u64 msr;
 
-       cpu = pr->id;
-       c = &cpu_data(cpu);
-
-       if ((c->x86_vendor != X86_VENDOR_INTEL) ||
-               !cpu_has(c, X86_FEATURE_ACPI)) {
+       if ((this_cpu_read(cpu_info.x86_vendor) != X86_VENDOR_INTEL) ||
+               !this_cpu_has(X86_FEATURE_ACPI)) {
                printk(KERN_ERR PREFIX
                        "HARDWARE addr space,NOT supported yet\n");
        } else {
@@ -761,15 +750,14 @@ static int acpi_throttling_wrmsr(struct acpi_processor *pr, u64 value)
        return ret;
 }
 #else
-static int acpi_throttling_rdmsr(struct acpi_processor *pr,
-                               u64 *value)
+static int acpi_throttling_rdmsr(u64 *value)
 {
        printk(KERN_ERR PREFIX
                "HARDWARE addr space,NOT supported yet\n");
        return -1;
 }
 
-static int acpi_throttling_wrmsr(struct acpi_processor *pr, u64 value)
+static int acpi_throttling_wrmsr(u64 value)
 {
        printk(KERN_ERR PREFIX
                "HARDWARE addr space,NOT supported yet\n");
@@ -801,7 +789,7 @@ static int acpi_read_throttling_status(struct acpi_processor *pr,
                ret = 0;
                break;
        case ACPI_ADR_SPACE_FIXED_HARDWARE:
-               ret = acpi_throttling_rdmsr(pr, value);
+               ret = acpi_throttling_rdmsr(value);
                break;
        default:
                printk(KERN_ERR PREFIX "Unknown addr space %d\n",
@@ -834,7 +822,7 @@ static int acpi_write_throttling_state(struct acpi_processor *pr,
                ret = 0;
                break;
        case ACPI_ADR_SPACE_FIXED_HARDWARE:
-               ret = acpi_throttling_wrmsr(pr, value);
+               ret = acpi_throttling_wrmsr(value);
                break;
        default:
                printk(KERN_ERR PREFIX "Unknown addr space %d\n",
index ff9d832..d38c40f 100644 (file)
@@ -561,27 +561,6 @@ void ahci_start_engine(struct ata_port *ap)
 {
        void __iomem *port_mmio = ahci_port_base(ap);
        u32 tmp;
-       u8 status;
-
-       status = readl(port_mmio + PORT_TFDATA) & 0xFF;
-
-       /*
-        * At end of section 10.1 of AHCI spec (rev 1.3), it states
-        * Software shall not set PxCMD.ST to 1 until it is determined
-        * that a functoinal device is present on the port as determined by
-        * PxTFD.STS.BSY=0, PxTFD.STS.DRQ=0 and PxSSTS.DET=3h
-        *
-        * Even though most AHCI host controllers work without this check,
-        * specific controller will fail under this condition
-        */
-       if (status & (ATA_BUSY | ATA_DRQ))
-               return;
-       else {
-               ahci_scr_read(&ap->link, SCR_STATUS, &tmp);
-
-               if ((tmp & 0xf) != 0x3)
-                       return;
-       }
 
        /* start DMA */
        tmp = readl(port_mmio + PORT_CMD);
index f26f2fe..dad9fd6 100644 (file)
@@ -3316,7 +3316,7 @@ static int ata_eh_set_lpm(struct ata_link *link, enum ata_lpm_policy policy,
        struct ata_eh_context *ehc = &link->eh_context;
        struct ata_device *dev, *link_dev = NULL, *lpm_dev = NULL;
        enum ata_lpm_policy old_policy = link->lpm_policy;
-       bool no_dipm = ap->flags & ATA_FLAG_NO_DIPM;
+       bool no_dipm = link->ap->flags & ATA_FLAG_NO_DIPM;
        unsigned int hints = ATA_LPM_EMPTY | ATA_LPM_HIPM;
        unsigned int err_mask;
        int rc;
index bdd2719..bc9e702 100644 (file)
@@ -2643,16 +2643,19 @@ fore200e_init(struct fore200e* fore200e, struct device *parent)
 }
 
 #ifdef CONFIG_SBUS
+static const struct of_device_id fore200e_sba_match[];
 static int __devinit fore200e_sba_probe(struct platform_device *op)
 {
+       const struct of_device_id *match;
        const struct fore200e_bus *bus;
        struct fore200e *fore200e;
        static int index = 0;
        int err;
 
-       if (!op->dev.of_match)
+       match = of_match_device(fore200e_sba_match, &op->dev);
+       if (!match)
                return -EINVAL;
-       bus = op->dev.of_match->data;
+       bus = match->data;
 
        fore200e = kzalloc(sizeof(struct fore200e), GFP_KERNEL);
        if (!fore200e)
index e9e5238..d57e8d0 100644 (file)
@@ -168,11 +168,4 @@ config SYS_HYPERVISOR
        bool
        default n
 
-config ARCH_NO_SYSDEV_OPS
-       bool
-       ---help---
-         To be selected by architectures that don't use sysdev class or
-         sysdev driver power management (suspend/resume) and shutdown
-         operations.
-
 endmenu
index 19f49e4..a34dca0 100644 (file)
@@ -111,8 +111,6 @@ static inline int driver_match_device(struct device_driver *drv,
        return drv->bus->match ? drv->bus->match(dev, drv) : 1;
 }
 
-extern void sysdev_shutdown(void);
-
 extern char *make_class_name(const char *name, struct kobject *kobj);
 
 extern int devres_release_all(struct device *dev);
index 81b78ed..bc8729d 100644 (file)
@@ -400,7 +400,7 @@ static void device_remove_groups(struct device *dev,
 static int device_add_attrs(struct device *dev)
 {
        struct class *class = dev->class;
-       struct device_type *type = dev->type;
+       const struct device_type *type = dev->type;
        int error;
 
        if (class) {
@@ -440,7 +440,7 @@ static int device_add_attrs(struct device *dev)
 static void device_remove_attrs(struct device *dev)
 {
        struct class *class = dev->class;
-       struct device_type *type = dev->type;
+       const struct device_type *type = dev->type;
 
        device_remove_groups(dev, dev->groups);
 
@@ -1314,8 +1314,7 @@ EXPORT_SYMBOL_GPL(put_device);
 EXPORT_SYMBOL_GPL(device_create_file);
 EXPORT_SYMBOL_GPL(device_remove_file);
 
-struct root_device
-{
+struct root_device {
        struct device dev;
        struct module *owner;
 };
index da57ee9..6658da7 100644 (file)
@@ -245,6 +245,10 @@ int device_attach(struct device *dev)
 
        device_lock(dev);
        if (dev->driver) {
+               if (klist_node_attached(&dev->p->knode_driver)) {
+                       ret = 1;
+                       goto out_unlock;
+               }
                ret = device_bind_driver(dev);
                if (ret == 0)
                        ret = 1;
@@ -257,6 +261,7 @@ int device_attach(struct device *dev)
                ret = bus_for_each_drv(dev->bus, NULL, dev, __device_attach);
                pm_runtime_put_sync(dev);
        }
+out_unlock:
        device_unlock(dev);
        return ret;
 }
@@ -316,8 +321,7 @@ static void __device_release_driver(struct device *dev)
 
        drv = dev->driver;
        if (drv) {
-               pm_runtime_get_noresume(dev);
-               pm_runtime_barrier(dev);
+               pm_runtime_get_sync(dev);
 
                driver_sysfs_remove(dev);
 
@@ -326,6 +330,8 @@ static void __device_release_driver(struct device *dev)
                                                     BUS_NOTIFY_UNBIND_DRIVER,
                                                     dev);
 
+               pm_runtime_put_sync(dev);
+
                if (dev->bus && dev->bus->remove)
                        dev->bus->remove(dev);
                else if (drv->remove)
@@ -338,7 +344,6 @@ static void __device_release_driver(struct device *dev)
                                                     BUS_NOTIFY_UNBOUND_DRIVER,
                                                     dev);
 
-               pm_runtime_put_sync(dev);
        }
 }
 
@@ -408,17 +413,16 @@ void *dev_get_drvdata(const struct device *dev)
 }
 EXPORT_SYMBOL(dev_get_drvdata);
 
-void dev_set_drvdata(struct device *dev, void *data)
+int dev_set_drvdata(struct device *dev, void *data)
 {
        int error;
 
-       if (!dev)
-               return;
        if (!dev->p) {
                error = device_private_init(dev);
                if (error)
-                       return;
+                       return error;
        }
        dev->p->driver_data = data;
+       return 0;
 }
 EXPORT_SYMBOL(dev_set_drvdata);
index 8c798ef..bbb03e6 100644 (file)
@@ -521,6 +521,11 @@ static int _request_firmware(const struct firmware **firmware_p,
        if (!firmware_p)
                return -EINVAL;
 
+       if (WARN_ON(usermodehelper_is_disabled())) {
+               dev_err(device, "firmware: %s will not be loaded\n", name);
+               return -EBUSY;
+       }
+
        *firmware_p = firmware = kzalloc(sizeof(*firmware), GFP_KERNEL);
        if (!firmware) {
                dev_err(device, "%s: kmalloc(struct firmware) failed\n",
index 3da6a43..0a134a4 100644 (file)
@@ -48,7 +48,8 @@ static const char *memory_uevent_name(struct kset *kset, struct kobject *kobj)
        return MEMORY_CLASS_NAME;
 }
 
-static int memory_uevent(struct kset *kset, struct kobject *obj, struct kobj_uevent_env *env)
+static int memory_uevent(struct kset *kset, struct kobject *obj,
+                       struct kobj_uevent_env *env)
 {
        int retval = 0;
 
@@ -228,10 +229,11 @@ int memory_isolate_notify(unsigned long val, void *v)
  * OK to have direct references to sparsemem variables in here.
  */
 static int
-memory_section_action(unsigned long phys_index, unsigned long action)
+memory_block_action(unsigned long phys_index, unsigned long action)
 {
        int i;
        unsigned long start_pfn, start_paddr;
+       unsigned long nr_pages = PAGES_PER_SECTION * sections_per_block;
        struct page *first_page;
        int ret;
 
@@ -243,7 +245,7 @@ memory_section_action(unsigned long phys_index, unsigned long action)
         * that way.
         */
        if (action == MEM_ONLINE) {
-               for (i = 0; i < PAGES_PER_SECTION; i++) {
+               for (i = 0; i < nr_pages; i++) {
                        if (PageReserved(first_page+i))
                                continue;
 
@@ -257,12 +259,12 @@ memory_section_action(unsigned long phys_index, unsigned long action)
        switch (action) {
                case MEM_ONLINE:
                        start_pfn = page_to_pfn(first_page);
-                       ret = online_pages(start_pfn, PAGES_PER_SECTION);
+                       ret = online_pages(start_pfn, nr_pages);
                        break;
                case MEM_OFFLINE:
                        start_paddr = page_to_pfn(first_page) << PAGE_SHIFT;
                        ret = remove_memory(start_paddr,
-                                           PAGES_PER_SECTION << PAGE_SHIFT);
+                                           nr_pages << PAGE_SHIFT);
                        break;
                default:
                        WARN(1, KERN_WARNING "%s(%ld, %ld) unknown action: "
@@ -276,7 +278,7 @@ memory_section_action(unsigned long phys_index, unsigned long action)
 static int memory_block_change_state(struct memory_block *mem,
                unsigned long to_state, unsigned long from_state_req)
 {
-       int i, ret = 0;
+       int ret = 0;
 
        mutex_lock(&mem->state_mutex);
 
@@ -288,20 +290,11 @@ static int memory_block_change_state(struct memory_block *mem,
        if (to_state == MEM_OFFLINE)
                mem->state = MEM_GOING_OFFLINE;
 
-       for (i = 0; i < sections_per_block; i++) {
-               ret = memory_section_action(mem->start_section_nr + i,
-                                           to_state);
-               if (ret)
-                       break;
-       }
-
-       if (ret) {
-               for (i = 0; i < sections_per_block; i++)
-                       memory_section_action(mem->start_section_nr + i,
-                                             from_state_req);
+       ret = memory_block_action(mem->start_section_nr, to_state);
 
+       if (ret)
                mem->state = from_state_req;
-       else
+       else
                mem->state = to_state;
 
 out:
index 9e0e4fc..1c291af 100644 (file)
@@ -192,18 +192,18 @@ EXPORT_SYMBOL_GPL(platform_device_alloc);
 int platform_device_add_resources(struct platform_device *pdev,
                                  const struct resource *res, unsigned int num)
 {
-       struct resource *r;
+       struct resource *r = NULL;
 
-       if (!res)
-               return 0;
-
-       r = kmemdup(res, sizeof(struct resource) * num, GFP_KERNEL);
-       if (r) {
-               pdev->resource = r;
-               pdev->num_resources = num;
-               return 0;
+       if (res) {
+               r = kmemdup(res, sizeof(struct resource) * num, GFP_KERNEL);
+               if (!r)
+                       return -ENOMEM;
        }
-       return -ENOMEM;
+
+       kfree(pdev->resource);
+       pdev->resource = r;
+       pdev->num_resources = num;
+       return 0;
 }
 EXPORT_SYMBOL_GPL(platform_device_add_resources);
 
@@ -220,17 +220,17 @@ EXPORT_SYMBOL_GPL(platform_device_add_resources);
 int platform_device_add_data(struct platform_device *pdev, const void *data,
                             size_t size)
 {
-       void *d;
+       void *d = NULL;
 
-       if (!data)
-               return 0;
-
-       d = kmemdup(data, size, GFP_KERNEL);
-       if (d) {
-               pdev->dev.platform_data = d;
-               return 0;
+       if (data) {
+               d = kmemdup(data, size, GFP_KERNEL);
+               if (!d)
+                       return -ENOMEM;
        }
-       return -ENOMEM;
+
+       kfree(pdev->dev.platform_data);
+       pdev->dev.platform_data = d;
+       return 0;
 }
 EXPORT_SYMBOL_GPL(platform_device_add_data);
 
@@ -667,7 +667,7 @@ static int platform_legacy_resume(struct device *dev)
        return ret;
 }
 
-static int platform_pm_prepare(struct device *dev)
+int platform_pm_prepare(struct device *dev)
 {
        struct device_driver *drv = dev->driver;
        int ret = 0;
@@ -678,7 +678,7 @@ static int platform_pm_prepare(struct device *dev)
        return ret;
 }
 
-static void platform_pm_complete(struct device *dev)
+void platform_pm_complete(struct device *dev)
 {
        struct device_driver *drv = dev->driver;
 
@@ -686,16 +686,11 @@ static void platform_pm_complete(struct device *dev)
                drv->pm->complete(dev);
 }
 
-#else /* !CONFIG_PM_SLEEP */
-
-#define platform_pm_prepare            NULL
-#define platform_pm_complete           NULL
-
-#endif /* !CONFIG_PM_SLEEP */
+#endif /* CONFIG_PM_SLEEP */
 
 #ifdef CONFIG_SUSPEND
 
-int __weak platform_pm_suspend(struct device *dev)
+int platform_pm_suspend(struct device *dev)
 {
        struct device_driver *drv = dev->driver;
        int ret = 0;
@@ -713,7 +708,7 @@ int __weak platform_pm_suspend(struct device *dev)
        return ret;
 }
 
-int __weak platform_pm_suspend_noirq(struct device *dev)
+int platform_pm_suspend_noirq(struct device *dev)
 {
        struct device_driver *drv = dev->driver;
        int ret = 0;
@@ -729,7 +724,7 @@ int __weak platform_pm_suspend_noirq(struct device *dev)
        return ret;
 }
 
-int __weak platform_pm_resume(struct device *dev)
+int platform_pm_resume(struct device *dev)
 {
        struct device_driver *drv = dev->driver;
        int ret = 0;
@@ -747,7 +742,7 @@ int __weak platform_pm_resume(struct device *dev)
        return ret;
 }
 
-int __weak platform_pm_resume_noirq(struct device *dev)
+int platform_pm_resume_noirq(struct device *dev)
 {
        struct device_driver *drv = dev->driver;
        int ret = 0;
@@ -763,18 +758,11 @@ int __weak platform_pm_resume_noirq(struct device *dev)
        return ret;
 }
 
-#else /* !CONFIG_SUSPEND */
-
-#define platform_pm_suspend            NULL
-#define platform_pm_resume             NULL
-#define platform_pm_suspend_noirq      NULL
-#define platform_pm_resume_noirq       NULL
-
-#endif /* !CONFIG_SUSPEND */
+#endif /* CONFIG_SUSPEND */
 
 #ifdef CONFIG_HIBERNATE_CALLBACKS
 
-static int platform_pm_freeze(struct device *dev)
+int platform_pm_freeze(struct device *dev)
 {
        struct device_driver *drv = dev->driver;
        int ret = 0;
@@ -792,7 +780,7 @@ static int platform_pm_freeze(struct device *dev)
        return ret;
 }
 
-static int platform_pm_freeze_noirq(struct device *dev)
+int platform_pm_freeze_noirq(struct device *dev)
 {
        struct device_driver *drv = dev->driver;
        int ret = 0;
@@ -808,7 +796,7 @@ static int platform_pm_freeze_noirq(struct device *dev)
        return ret;
 }
 
-static int platform_pm_thaw(struct device *dev)
+int platform_pm_thaw(struct device *dev)
 {
        struct device_driver *drv = dev->driver;
        int ret = 0;
@@ -826,7 +814,7 @@ static int platform_pm_thaw(struct device *dev)
        return ret;
 }
 
-static int platform_pm_thaw_noirq(struct device *dev)
+int platform_pm_thaw_noirq(struct device *dev)
 {
        struct device_driver *drv = dev->driver;
        int ret = 0;
@@ -842,7 +830,7 @@ static int platform_pm_thaw_noirq(struct device *dev)
        return ret;
 }
 
-static int platform_pm_poweroff(struct device *dev)
+int platform_pm_poweroff(struct device *dev)
 {
        struct device_driver *drv = dev->driver;
        int ret = 0;
@@ -860,7 +848,7 @@ static int platform_pm_poweroff(struct device *dev)
        return ret;
 }
 
-static int platform_pm_poweroff_noirq(struct device *dev)
+int platform_pm_poweroff_noirq(struct device *dev)
 {
        struct device_driver *drv = dev->driver;
        int ret = 0;
@@ -876,7 +864,7 @@ static int platform_pm_poweroff_noirq(struct device *dev)
        return ret;
 }
 
-static int platform_pm_restore(struct device *dev)
+int platform_pm_restore(struct device *dev)
 {
        struct device_driver *drv = dev->driver;
        int ret = 0;
@@ -894,7 +882,7 @@ static int platform_pm_restore(struct device *dev)
        return ret;
 }
 
-static int platform_pm_restore_noirq(struct device *dev)
+int platform_pm_restore_noirq(struct device *dev)
 {
        struct device_driver *drv = dev->driver;
        int ret = 0;
@@ -910,62 +898,13 @@ static int platform_pm_restore_noirq(struct device *dev)
        return ret;
 }
 
-#else /* !CONFIG_HIBERNATE_CALLBACKS */
-
-#define platform_pm_freeze             NULL
-#define platform_pm_thaw               NULL
-#define platform_pm_poweroff           NULL
-#define platform_pm_restore            NULL
-#define platform_pm_freeze_noirq       NULL
-#define platform_pm_thaw_noirq         NULL
-#define platform_pm_poweroff_noirq     NULL
-#define platform_pm_restore_noirq      NULL
-
-#endif /* !CONFIG_HIBERNATE_CALLBACKS */
-
-#ifdef CONFIG_PM_RUNTIME
-
-int __weak platform_pm_runtime_suspend(struct device *dev)
-{
-       return pm_generic_runtime_suspend(dev);
-};
-
-int __weak platform_pm_runtime_resume(struct device *dev)
-{
-       return pm_generic_runtime_resume(dev);
-};
-
-int __weak platform_pm_runtime_idle(struct device *dev)
-{
-       return pm_generic_runtime_idle(dev);
-};
-
-#else /* !CONFIG_PM_RUNTIME */
-
-#define platform_pm_runtime_suspend NULL
-#define platform_pm_runtime_resume NULL
-#define platform_pm_runtime_idle NULL
-
-#endif /* !CONFIG_PM_RUNTIME */
+#endif /* CONFIG_HIBERNATE_CALLBACKS */
 
 static const struct dev_pm_ops platform_dev_pm_ops = {
-       .prepare = platform_pm_prepare,
-       .complete = platform_pm_complete,
-       .suspend = platform_pm_suspend,
-       .resume = platform_pm_resume,
-       .freeze = platform_pm_freeze,
-       .thaw = platform_pm_thaw,
-       .poweroff = platform_pm_poweroff,
-       .restore = platform_pm_restore,
-       .suspend_noirq = platform_pm_suspend_noirq,
-       .resume_noirq = platform_pm_resume_noirq,
-       .freeze_noirq = platform_pm_freeze_noirq,
-       .thaw_noirq = platform_pm_thaw_noirq,
-       .poweroff_noirq = platform_pm_poweroff_noirq,
-       .restore_noirq = platform_pm_restore_noirq,
-       .runtime_suspend = platform_pm_runtime_suspend,
-       .runtime_resume = platform_pm_runtime_resume,
-       .runtime_idle = platform_pm_runtime_idle,
+       .runtime_suspend = pm_generic_runtime_suspend,
+       .runtime_resume = pm_generic_runtime_resume,
+       .runtime_idle = pm_generic_runtime_idle,
+       USE_PLATFORM_PM_SLEEP_OPS
 };
 
 struct bus_type platform_bus_type = {
@@ -977,41 +916,6 @@ struct bus_type platform_bus_type = {
 };
 EXPORT_SYMBOL_GPL(platform_bus_type);
 
-/**
- * platform_bus_get_pm_ops() - return pointer to busses dev_pm_ops
- *
- * This function can be used by platform code to get the current
- * set of dev_pm_ops functions used by the platform_bus_type.
- */
-const struct dev_pm_ops * __init platform_bus_get_pm_ops(void)
-{
-       return platform_bus_type.pm;
-}
-
-/**
- * platform_bus_set_pm_ops() - update dev_pm_ops for the platform_bus_type
- *
- * @pm: pointer to new dev_pm_ops struct to be used for platform_bus_type
- *
- * Platform code can override the dev_pm_ops methods of
- * platform_bus_type by using this function.  It is expected that
- * platform code will first do a platform_bus_get_pm_ops(), then
- * kmemdup it, then customize selected methods and pass a pointer to
- * the new struct dev_pm_ops to this function.
- *
- * Since platform-specific code is customizing methods for *all*
- * devices (not just platform-specific devices) it is expected that
- * any custom overrides of these functions will keep existing behavior
- * and simply extend it.  For example, any customization of the
- * runtime PM methods should continue to call the pm_generic_*
- * functions as the default ones do in addition to the
- * platform-specific behavior.
- */
-void __init platform_bus_set_pm_ops(const struct dev_pm_ops *pm)
-{
-       platform_bus_type.pm = pm;
-}
-
 int __init platform_bus_init(void)
 {
        int error;
index 118c1b9..3647e11 100644 (file)
@@ -3,6 +3,6 @@ obj-$(CONFIG_PM_SLEEP)  += main.o wakeup.o
 obj-$(CONFIG_PM_RUNTIME)       += runtime.o
 obj-$(CONFIG_PM_TRACE_RTC)     += trace.o
 obj-$(CONFIG_PM_OPP)   += opp.o
+obj-$(CONFIG_HAVE_CLK) += clock_ops.o
 
-ccflags-$(CONFIG_DEBUG_DRIVER) := -DDEBUG
-ccflags-$(CONFIG_PM_VERBOSE)   += -DDEBUG
+ccflags-$(CONFIG_DEBUG_DRIVER) := -DDEBUG
\ No newline at end of file
diff --git a/drivers/base/power/clock_ops.c b/drivers/base/power/clock_ops.c
new file mode 100644 (file)
index 0000000..c0dd09d
--- /dev/null
@@ -0,0 +1,431 @@
+/*
+ * drivers/base/power/clock_ops.c - Generic clock manipulation PM callbacks
+ *
+ * Copyright (c) 2011 Rafael J. Wysocki <rjw@sisk.pl>, Renesas Electronics Corp.
+ *
+ * This file is released under the GPLv2.
+ */
+
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/io.h>
+#include <linux/pm.h>
+#include <linux/pm_runtime.h>
+#include <linux/clk.h>
+#include <linux/slab.h>
+#include <linux/err.h>
+
+#ifdef CONFIG_PM_RUNTIME
+
+struct pm_runtime_clk_data {
+       struct list_head clock_list;
+       struct mutex lock;
+};
+
+enum pce_status {
+       PCE_STATUS_NONE = 0,
+       PCE_STATUS_ACQUIRED,
+       PCE_STATUS_ENABLED,
+       PCE_STATUS_ERROR,
+};
+
+struct pm_clock_entry {
+       struct list_head node;
+       char *con_id;
+       struct clk *clk;
+       enum pce_status status;
+};
+
+static struct pm_runtime_clk_data *__to_prd(struct device *dev)
+{
+       return dev ? dev->power.subsys_data : NULL;
+}
+
+/**
+ * pm_runtime_clk_add - Start using a device clock for runtime PM.
+ * @dev: Device whose clock is going to be used for runtime PM.
+ * @con_id: Connection ID of the clock.
+ *
+ * Add the clock represented by @con_id to the list of clocks used for
+ * the runtime PM of @dev.
+ */
+int pm_runtime_clk_add(struct device *dev, const char *con_id)
+{
+       struct pm_runtime_clk_data *prd = __to_prd(dev);
+       struct pm_clock_entry *ce;
+
+       if (!prd)
+               return -EINVAL;
+
+       ce = kzalloc(sizeof(*ce), GFP_KERNEL);
+       if (!ce) {
+               dev_err(dev, "Not enough memory for clock entry.\n");
+               return -ENOMEM;
+       }
+
+       if (con_id) {
+               ce->con_id = kstrdup(con_id, GFP_KERNEL);
+               if (!ce->con_id) {
+                       dev_err(dev,
+                               "Not enough memory for clock connection ID.\n");
+                       kfree(ce);
+                       return -ENOMEM;
+               }
+       }
+
+       mutex_lock(&prd->lock);
+       list_add_tail(&ce->node, &prd->clock_list);
+       mutex_unlock(&prd->lock);
+       return 0;
+}
+
+/**
+ * __pm_runtime_clk_remove - Destroy runtime PM clock entry.
+ * @ce: Runtime PM clock entry to destroy.
+ *
+ * This routine must be called under the mutex protecting the runtime PM list
+ * of clocks corresponding the the @ce's device.
+ */
+static void __pm_runtime_clk_remove(struct pm_clock_entry *ce)
+{
+       if (!ce)
+               return;
+
+       list_del(&ce->node);
+
+       if (ce->status < PCE_STATUS_ERROR) {
+               if (ce->status == PCE_STATUS_ENABLED)
+                       clk_disable(ce->clk);
+
+               if (ce->status >= PCE_STATUS_ACQUIRED)
+                       clk_put(ce->clk);
+       }
+
+       if (ce->con_id)
+               kfree(ce->con_id);
+
+       kfree(ce);
+}
+
+/**
+ * pm_runtime_clk_remove - Stop using a device clock for runtime PM.
+ * @dev: Device whose clock should not be used for runtime PM any more.
+ * @con_id: Connection ID of the clock.
+ *
+ * Remove the clock represented by @con_id from the list of clocks used for
+ * the runtime PM of @dev.
+ */
+void pm_runtime_clk_remove(struct device *dev, const char *con_id)
+{
+       struct pm_runtime_clk_data *prd = __to_prd(dev);
+       struct pm_clock_entry *ce;
+
+       if (!prd)
+               return;
+
+       mutex_lock(&prd->lock);
+
+       list_for_each_entry(ce, &prd->clock_list, node) {
+               if (!con_id && !ce->con_id) {
+                       __pm_runtime_clk_remove(ce);
+                       break;
+               } else if (!con_id || !ce->con_id) {
+                       continue;
+               } else if (!strcmp(con_id, ce->con_id)) {
+                       __pm_runtime_clk_remove(ce);
+                       break;
+               }
+       }
+
+       mutex_unlock(&prd->lock);
+}
+
+/**
+ * pm_runtime_clk_init - Initialize a device's list of runtime PM clocks.
+ * @dev: Device to initialize the list of runtime PM clocks for.
+ *
+ * Allocate a struct pm_runtime_clk_data object, initialize its lock member and
+ * make the @dev's power.subsys_data field point to it.
+ */
+int pm_runtime_clk_init(struct device *dev)
+{
+       struct pm_runtime_clk_data *prd;
+
+       prd = kzalloc(sizeof(*prd), GFP_KERNEL);
+       if (!prd) {
+               dev_err(dev, "Not enough memory fo runtime PM data.\n");
+               return -ENOMEM;
+       }
+
+       INIT_LIST_HEAD(&prd->clock_list);
+       mutex_init(&prd->lock);
+       dev->power.subsys_data = prd;
+       return 0;
+}
+
+/**
+ * pm_runtime_clk_destroy - Destroy a device's list of runtime PM clocks.
+ * @dev: Device to destroy the list of runtime PM clocks for.
+ *
+ * Clear the @dev's power.subsys_data field, remove the list of clock entries
+ * from the struct pm_runtime_clk_data object pointed to by it before and free
+ * that object.
+ */
+void pm_runtime_clk_destroy(struct device *dev)
+{
+       struct pm_runtime_clk_data *prd = __to_prd(dev);
+       struct pm_clock_entry *ce, *c;
+
+       if (!prd)
+               return;
+
+       dev->power.subsys_data = NULL;
+
+       mutex_lock(&prd->lock);
+
+       list_for_each_entry_safe_reverse(ce, c, &prd->clock_list, node)
+               __pm_runtime_clk_remove(ce);
+
+       mutex_unlock(&prd->lock);
+
+       kfree(prd);
+}
+
+/**
+ * pm_runtime_clk_acquire - Acquire a device clock.
+ * @dev: Device whose clock is to be acquired.
+ * @con_id: Connection ID of the clock.
+ */
+static void pm_runtime_clk_acquire(struct device *dev,
+                                   struct pm_clock_entry *ce)
+{
+       ce->clk = clk_get(dev, ce->con_id);
+       if (IS_ERR(ce->clk)) {
+               ce->status = PCE_STATUS_ERROR;
+       } else {
+               ce->status = PCE_STATUS_ACQUIRED;
+               dev_dbg(dev, "Clock %s managed by runtime PM.\n", ce->con_id);
+       }
+}
+
+/**
+ * pm_runtime_clk_suspend - Disable clocks in a device's runtime PM clock list.
+ * @dev: Device to disable the clocks for.
+ */
+int pm_runtime_clk_suspend(struct device *dev)
+{
+       struct pm_runtime_clk_data *prd = __to_prd(dev);
+       struct pm_clock_entry *ce;
+
+       dev_dbg(dev, "%s()\n", __func__);
+
+       if (!prd)
+               return 0;
+
+       mutex_lock(&prd->lock);
+
+       list_for_each_entry_reverse(ce, &prd->clock_list, node) {
+               if (ce->status == PCE_STATUS_NONE)
+                       pm_runtime_clk_acquire(dev, ce);
+
+               if (ce->status < PCE_STATUS_ERROR) {
+                       clk_disable(ce->clk);
+                       ce->status = PCE_STATUS_ACQUIRED;
+               }
+       }
+
+       mutex_unlock(&prd->lock);
+
+       return 0;
+}
+
+/**
+ * pm_runtime_clk_resume - Enable clocks in a device's runtime PM clock list.
+ * @dev: Device to enable the clocks for.
+ */
+int pm_runtime_clk_resume(struct device *dev)
+{
+       struct pm_runtime_clk_data *prd = __to_prd(dev);
+       struct pm_clock_entry *ce;
+
+       dev_dbg(dev, "%s()\n", __func__);
+
+       if (!prd)
+               return 0;
+
+       mutex_lock(&prd->lock);
+
+       list_for_each_entry(ce, &prd->clock_list, node) {
+               if (ce->status == PCE_STATUS_NONE)
+                       pm_runtime_clk_acquire(dev, ce);
+
+               if (ce->status < PCE_STATUS_ERROR) {
+                       clk_enable(ce->clk);
+                       ce->status = PCE_STATUS_ENABLED;
+               }
+       }
+
+       mutex_unlock(&prd->lock);
+
+       return 0;
+}
+
+/**
+ * pm_runtime_clk_notify - Notify routine for device addition and removal.
+ * @nb: Notifier block object this function is a member of.
+ * @action: Operation being carried out by the caller.
+ * @data: Device the routine is being run for.
+ *
+ * For this function to work, @nb must be a member of an object of type
+ * struct pm_clk_notifier_block containing all of the requisite data.
+ * Specifically, the pwr_domain member of that object is copied to the device's
+ * pwr_domain field and its con_ids member is used to populate the device's list
+ * of runtime PM clocks, depending on @action.
+ *
+ * If the device's pwr_domain field is already populated with a value different
+ * from the one stored in the struct pm_clk_notifier_block object, the function
+ * does nothing.
+ */
+static int pm_runtime_clk_notify(struct notifier_block *nb,
+                                unsigned long action, void *data)
+{
+       struct pm_clk_notifier_block *clknb;
+       struct device *dev = data;
+       char *con_id;
+       int error;
+
+       dev_dbg(dev, "%s() %ld\n", __func__, action);
+
+       clknb = container_of(nb, struct pm_clk_notifier_block, nb);
+
+       switch (action) {
+       case BUS_NOTIFY_ADD_DEVICE:
+               if (dev->pwr_domain)
+                       break;
+
+               error = pm_runtime_clk_init(dev);
+               if (error)
+                       break;
+
+               dev->pwr_domain = clknb->pwr_domain;
+               if (clknb->con_ids[0]) {
+                       for (con_id = clknb->con_ids[0]; *con_id; con_id++)
+                               pm_runtime_clk_add(dev, con_id);
+               } else {
+                       pm_runtime_clk_add(dev, NULL);
+               }
+
+               break;
+       case BUS_NOTIFY_DEL_DEVICE:
+               if (dev->pwr_domain != clknb->pwr_domain)
+                       break;
+
+               dev->pwr_domain = NULL;
+               pm_runtime_clk_destroy(dev);
+               break;
+       }
+
+       return 0;
+}
+
+#else /* !CONFIG_PM_RUNTIME */
+
+/**
+ * enable_clock - Enable a device clock.
+ * @dev: Device whose clock is to be enabled.
+ * @con_id: Connection ID of the clock.
+ */
+static void enable_clock(struct device *dev, const char *con_id)
+{
+       struct clk *clk;
+
+       clk = clk_get(dev, con_id);
+       if (!IS_ERR(clk)) {
+               clk_enable(clk);
+               clk_put(clk);
+               dev_info(dev, "Runtime PM disabled, clock forced on.\n");
+       }
+}
+
+/**
+ * disable_clock - Disable a device clock.
+ * @dev: Device whose clock is to be disabled.
+ * @con_id: Connection ID of the clock.
+ */
+static void disable_clock(struct device *dev, const char *con_id)
+{
+       struct clk *clk;
+
+       clk = clk_get(dev, con_id);
+       if (!IS_ERR(clk)) {
+               clk_disable(clk);
+               clk_put(clk);
+               dev_info(dev, "Runtime PM disabled, clock forced off.\n");
+       }
+}
+
+/**
+ * pm_runtime_clk_notify - Notify routine for device addition and removal.
+ * @nb: Notifier block object this function is a member of.
+ * @action: Operation being carried out by the caller.
+ * @data: Device the routine is being run for.
+ *
+ * For this function to work, @nb must be a member of an object of type
+ * struct pm_clk_notifier_block containing all of the requisite data.
+ * Specifically, the con_ids member of that object is used to enable or disable
+ * the device's clocks, depending on @action.
+ */
+static int pm_runtime_clk_notify(struct notifier_block *nb,
+                                unsigned long action, void *data)
+{
+       struct pm_clk_notifier_block *clknb;
+       struct device *dev = data;
+       char *con_id;
+
+       dev_dbg(dev, "%s() %ld\n", __func__, action);
+
+       clknb = container_of(nb, struct pm_clk_notifier_block, nb);
+
+       switch (action) {
+       case BUS_NOTIFY_ADD_DEVICE:
+               if (clknb->con_ids[0]) {
+                       for (con_id = clknb->con_ids[0]; *con_id; con_id++)
+                               enable_clock(dev, con_id);
+               } else {
+                       enable_clock(dev, NULL);
+               }
+               break;
+       case BUS_NOTIFY_DEL_DEVICE:
+               if (clknb->con_ids[0]) {
+                       for (con_id = clknb->con_ids[0]; *con_id; con_id++)
+                               disable_clock(dev, con_id);
+               } else {
+                       disable_clock(dev, NULL);
+               }
+               break;
+       }
+
+       return 0;
+}
+
+#endif /* !CONFIG_PM_RUNTIME */
+
+/**
+ * pm_runtime_clk_add_notifier - Add bus type notifier for runtime PM clocks.
+ * @bus: Bus type to add the notifier to.
+ * @clknb: Notifier to be added to the given bus type.
+ *
+ * The nb member of @clknb is not expected to be initialized and its
+ * notifier_call member will be replaced with pm_runtime_clk_notify().  However,
+ * the remaining members of @clknb should be populated prior to calling this
+ * routine.
+ */
+void pm_runtime_clk_add_notifier(struct bus_type *bus,
+                                struct pm_clk_notifier_block *clknb)
+{
+       if (!bus || !clknb)
+               return;
+
+       clknb->nb.notifier_call = pm_runtime_clk_notify;
+       bus_register_notifier(bus, &clknb->nb);
+}
index 42f97f9..cb3bb36 100644 (file)
@@ -74,6 +74,23 @@ EXPORT_SYMBOL_GPL(pm_generic_runtime_resume);
 
 #ifdef CONFIG_PM_SLEEP
 /**
+ * pm_generic_prepare - Generic routine preparing a device for power transition.
+ * @dev: Device to prepare.
+ *
+ * Prepare a device for a system-wide power transition.
+ */
+int pm_generic_prepare(struct device *dev)
+{
+       struct device_driver *drv = dev->driver;
+       int ret = 0;
+
+       if (drv && drv->pm && drv->pm->prepare)
+               ret = drv->pm->prepare(dev);
+
+       return ret;
+}
+
+/**
  * __pm_generic_call - Generic suspend/freeze/poweroff/thaw subsystem callback.
  * @dev: Device to handle.
  * @event: PM transition of the system under way.
@@ -213,16 +230,38 @@ int pm_generic_restore(struct device *dev)
        return __pm_generic_resume(dev, PM_EVENT_RESTORE);
 }
 EXPORT_SYMBOL_GPL(pm_generic_restore);
+
+/**
+ * pm_generic_complete - Generic routine competing a device power transition.
+ * @dev: Device to handle.
+ *
+ * Complete a device power transition during a system-wide power transition.
+ */
+void pm_generic_complete(struct device *dev)
+{
+       struct device_driver *drv = dev->driver;
+
+       if (drv && drv->pm && drv->pm->complete)
+               drv->pm->complete(dev);
+
+       /*
+        * Let runtime PM try to suspend devices that haven't been in use before
+        * going into the system-wide sleep state we're resuming from.
+        */
+       pm_runtime_idle(dev);
+}
 #endif /* CONFIG_PM_SLEEP */
 
 struct dev_pm_ops generic_subsys_pm_ops = {
 #ifdef CONFIG_PM_SLEEP
+       .prepare = pm_generic_prepare,
        .suspend = pm_generic_suspend,
        .resume = pm_generic_resume,
        .freeze = pm_generic_freeze,
        .thaw = pm_generic_thaw,
        .poweroff = pm_generic_poweroff,
        .restore = pm_generic_restore,
+       .complete = pm_generic_complete,
 #endif
 #ifdef CONFIG_PM_RUNTIME
        .runtime_suspend = pm_generic_runtime_suspend,
index abe3ab7..aa63202 100644 (file)
@@ -426,10 +426,8 @@ static int device_resume_noirq(struct device *dev, pm_message_t state)
 
        if (dev->pwr_domain) {
                pm_dev_dbg(dev, state, "EARLY power domain ");
-               pm_noirq_op(dev, &dev->pwr_domain->ops, state);
-       }
-
-       if (dev->type && dev->type->pm) {
+               error = pm_noirq_op(dev, &dev->pwr_domain->ops, state);
+       } else if (dev->type && dev->type->pm) {
                pm_dev_dbg(dev, state, "EARLY type ");
                error = pm_noirq_op(dev, dev->type->pm, state);
        } else if (dev->class && dev->class->pm) {
@@ -517,7 +515,8 @@ static int device_resume(struct device *dev, pm_message_t state, bool async)
 
        if (dev->pwr_domain) {
                pm_dev_dbg(dev, state, "power domain ");
-               pm_op(dev, &dev->pwr_domain->ops, state);
+               error = pm_op(dev, &dev->pwr_domain->ops, state);
+               goto End;
        }
 
        if (dev->type && dev->type->pm) {
@@ -580,11 +579,13 @@ static bool is_async(struct device *dev)
  * Execute the appropriate "resume" callback for all devices whose status
  * indicates that they are suspended.
  */
-static void dpm_resume(pm_message_t state)
+void dpm_resume(pm_message_t state)
 {
        struct device *dev;
        ktime_t starttime = ktime_get();
 
+       might_sleep();
+
        mutex_lock(&dpm_list_mtx);
        pm_transition = state;
        async_error = 0;
@@ -629,12 +630,11 @@ static void device_complete(struct device *dev, pm_message_t state)
 {
        device_lock(dev);
 
-       if (dev->pwr_domain && dev->pwr_domain->ops.complete) {
+       if (dev->pwr_domain) {
                pm_dev_dbg(dev, state, "completing power domain ");
-               dev->pwr_domain->ops.complete(dev);
-       }
-
-       if (dev->type && dev->type->pm) {
+               if (dev->pwr_domain->ops.complete)
+                       dev->pwr_domain->ops.complete(dev);
+       } else if (dev->type && dev->type->pm) {
                pm_dev_dbg(dev, state, "completing type ");
                if (dev->type->pm->complete)
                        dev->type->pm->complete(dev);
@@ -658,10 +658,12 @@ static void device_complete(struct device *dev, pm_message_t state)
  * Execute the ->complete() callbacks for all devices whose PM status is not
  * DPM_ON (this allows new devices to be registered).
  */
-static void dpm_complete(pm_message_t state)
+void dpm_complete(pm_message_t state)
 {
        struct list_head list;
 
+       might_sleep();
+
        INIT_LIST_HEAD(&list);
        mutex_lock(&dpm_list_mtx);
        while (!list_empty(&dpm_prepared_list)) {
@@ -690,7 +692,6 @@ static void dpm_complete(pm_message_t state)
  */
 void dpm_resume_end(pm_message_t state)
 {
-       might_sleep();
        dpm_resume(state);
        dpm_complete(state);
 }
@@ -732,7 +733,12 @@ static int device_suspend_noirq(struct device *dev, pm_message_t state)
 {
        int error;
 
-       if (dev->type && dev->type->pm) {
+       if (dev->pwr_domain) {
+               pm_dev_dbg(dev, state, "LATE power domain ");
+               error = pm_noirq_op(dev, &dev->pwr_domain->ops, state);
+               if (error)
+                       return error;
+       } else if (dev->type && dev->type->pm) {
                pm_dev_dbg(dev, state, "LATE type ");
                error = pm_noirq_op(dev, dev->type->pm, state);
                if (error)
@@ -749,11 +755,6 @@ static int device_suspend_noirq(struct device *dev, pm_message_t state)
                        return error;
        }
 
-       if (dev->pwr_domain) {
-               pm_dev_dbg(dev, state, "LATE power domain ");
-               pm_noirq_op(dev, &dev->pwr_domain->ops, state);
-       }
-
        return 0;
 }
 
@@ -841,21 +842,27 @@ static int __device_suspend(struct device *dev, pm_message_t state, bool async)
                goto End;
        }
 
+       if (dev->pwr_domain) {
+               pm_dev_dbg(dev, state, "power domain ");
+               error = pm_op(dev, &dev->pwr_domain->ops, state);
+               goto End;
+       }
+
        if (dev->type && dev->type->pm) {
                pm_dev_dbg(dev, state, "type ");
                error = pm_op(dev, dev->type->pm, state);
-               goto Domain;
+               goto End;
        }
 
        if (dev->class) {
                if (dev->class->pm) {
                        pm_dev_dbg(dev, state, "class ");
                        error = pm_op(dev, dev->class->pm, state);
-                       goto Domain;
+                       goto End;
                } else if (dev->class->suspend) {
                        pm_dev_dbg(dev, state, "legacy class ");
                        error = legacy_suspend(dev, state, dev->class->suspend);
-                       goto Domain;
+                       goto End;
                }
        }
 
@@ -869,12 +876,6 @@ static int __device_suspend(struct device *dev, pm_message_t state, bool async)
                }
        }
 
- Domain:
-       if (!error && dev->pwr_domain) {
-               pm_dev_dbg(dev, state, "power domain ");
-               pm_op(dev, &dev->pwr_domain->ops, state);
-       }
-
  End:
        device_unlock(dev);
        complete_all(&dev->power.completion);
@@ -914,11 +915,13 @@ static int device_suspend(struct device *dev)
  * dpm_suspend - Execute "suspend" callbacks for all non-sysdev devices.
  * @state: PM transition of the system being carried out.
  */
-static int dpm_suspend(pm_message_t state)
+int dpm_suspend(pm_message_t state)
 {
        ktime_t starttime = ktime_get();
        int error = 0;
 
+       might_sleep();
+
        mutex_lock(&dpm_list_mtx);
        pm_transition = state;
        async_error = 0;
@@ -965,7 +968,14 @@ static int device_prepare(struct device *dev, pm_message_t state)
 
        device_lock(dev);
 
-       if (dev->type && dev->type->pm) {
+       if (dev->pwr_domain) {
+               pm_dev_dbg(dev, state, "preparing power domain ");
+               if (dev->pwr_domain->ops.prepare)
+                       error = dev->pwr_domain->ops.prepare(dev);
+               suspend_report_result(dev->pwr_domain->ops.prepare, error);
+               if (error)
+                       goto End;
+       } else if (dev->type && dev->type->pm) {
                pm_dev_dbg(dev, state, "preparing type ");
                if (dev->type->pm->prepare)
                        error = dev->type->pm->prepare(dev);
@@ -984,13 +994,6 @@ static int device_prepare(struct device *dev, pm_message_t state)
                if (dev->bus->pm->prepare)
                        error = dev->bus->pm->prepare(dev);
                suspend_report_result(dev->bus->pm->prepare, error);
-               if (error)
-                       goto End;
-       }
-
-       if (dev->pwr_domain && dev->pwr_domain->ops.prepare) {
-               pm_dev_dbg(dev, state, "preparing power domain ");
-               dev->pwr_domain->ops.prepare(dev);
        }
 
  End:
@@ -1005,10 +1008,12 @@ static int device_prepare(struct device *dev, pm_message_t state)
  *
  * Execute the ->prepare() callback(s) for all devices.
  */
-static int dpm_prepare(pm_message_t state)
+int dpm_prepare(pm_message_t state)
 {
        int error = 0;
 
+       might_sleep();
+
        mutex_lock(&dpm_list_mtx);
        while (!list_empty(&dpm_list)) {
                struct device *dev = to_device(dpm_list.next);
@@ -1057,7 +1062,6 @@ int dpm_suspend_start(pm_message_t state)
 {
        int error;
 
-       might_sleep();
        error = dpm_prepare(state);
        if (!error)
                error = dpm_suspend(state);
index 3172c60..0d4587b 100644 (file)
@@ -168,7 +168,6 @@ static int rpm_check_suspend_allowed(struct device *dev)
 static int rpm_idle(struct device *dev, int rpmflags)
 {
        int (*callback)(struct device *);
-       int (*domain_callback)(struct device *);
        int retval;
 
        retval = rpm_check_suspend_allowed(dev);
@@ -214,7 +213,9 @@ static int rpm_idle(struct device *dev, int rpmflags)
 
        dev->power.idle_notification = true;
 
-       if (dev->type && dev->type->pm)
+       if (dev->pwr_domain)
+               callback = dev->pwr_domain->ops.runtime_idle;
+       else if (dev->type && dev->type->pm)
                callback = dev->type->pm->runtime_idle;
        else if (dev->class && dev->class->pm)
                callback = dev->class->pm->runtime_idle;
@@ -223,19 +224,10 @@ static int rpm_idle(struct device *dev, int rpmflags)
        else
                callback = NULL;
 
-       if (dev->pwr_domain)
-               domain_callback = dev->pwr_domain->ops.runtime_idle;
-       else
-               domain_callback = NULL;
-
-       if (callback || domain_callback) {
+       if (callback) {
                spin_unlock_irq(&dev->power.lock);
 
-               if (domain_callback)
-                       retval = domain_callback(dev);
-
-               if (!retval && callback)
-                       callback(dev);
+               callback(dev);
 
                spin_lock_irq(&dev->power.lock);
        }
@@ -382,7 +374,9 @@ static int rpm_suspend(struct device *dev, int rpmflags)
 
        __update_runtime_status(dev, RPM_SUSPENDING);
 
-       if (dev->type && dev->type->pm)
+       if (dev->pwr_domain)
+               callback = dev->pwr_domain->ops.runtime_suspend;
+       else if (dev->type && dev->type->pm)
                callback = dev->type->pm->runtime_suspend;
        else if (dev->class && dev->class->pm)
                callback = dev->class->pm->runtime_suspend;
@@ -400,8 +394,6 @@ static int rpm_suspend(struct device *dev, int rpmflags)
                else
                        pm_runtime_cancel_pending(dev);
        } else {
-               if (dev->pwr_domain)
-                       rpm_callback(dev->pwr_domain->ops.runtime_suspend, dev);
  no_callback:
                __update_runtime_status(dev, RPM_SUSPENDED);
                pm_runtime_deactivate_timer(dev);
@@ -582,9 +574,8 @@ static int rpm_resume(struct device *dev, int rpmflags)
        __update_runtime_status(dev, RPM_RESUMING);
 
        if (dev->pwr_domain)
-               rpm_callback(dev->pwr_domain->ops.runtime_resume, dev);
-
-       if (dev->type && dev->type->pm)
+               callback = dev->pwr_domain->ops.runtime_resume;
+       else if (dev->type && dev->type->pm)
                callback = dev->type->pm->runtime_resume;
        else if (dev->class && dev->class->pm)
                callback = dev->class->pm->runtime_resume;
index fff49be..a9f5b89 100644 (file)
@@ -212,8 +212,9 @@ static ssize_t autosuspend_delay_ms_store(struct device *dev,
 static DEVICE_ATTR(autosuspend_delay_ms, 0644, autosuspend_delay_ms_show,
                autosuspend_delay_ms_store);
 
-#endif
+#endif /* CONFIG_PM_RUNTIME */
 
+#ifdef CONFIG_PM_SLEEP
 static ssize_t
 wake_show(struct device * dev, struct device_attribute *attr, char * buf)
 {
@@ -248,7 +249,6 @@ wake_store(struct device * dev, struct device_attribute *attr,
 
 static DEVICE_ATTR(wakeup, 0644, wake_show, wake_store);
 
-#ifdef CONFIG_PM_SLEEP
 static ssize_t wakeup_count_show(struct device *dev,
                                struct device_attribute *attr, char *buf)
 {
index abbbd33..84f7c7d 100644 (file)
@@ -110,7 +110,6 @@ void wakeup_source_add(struct wakeup_source *ws)
        spin_lock_irq(&events_lock);
        list_add_rcu(&ws->entry, &wakeup_sources);
        spin_unlock_irq(&events_lock);
-       synchronize_rcu();
 }
 EXPORT_SYMBOL_GPL(wakeup_source_add);
 
index acde9b5..9dff77b 100644 (file)
@@ -328,203 +328,8 @@ void sysdev_unregister(struct sys_device *sysdev)
        kobject_put(&sysdev->kobj);
 }
 
-
-#ifndef CONFIG_ARCH_NO_SYSDEV_OPS
-/**
- *     sysdev_shutdown - Shut down all system devices.
- *
- *     Loop over each class of system devices, and the devices in each
- *     of those classes. For each device, we call the shutdown method for
- *     each driver registered for the device - the auxiliaries,
- *     and the class driver.
- *
- *     Note: The list is iterated in reverse order, so that we shut down
- *     child devices before we shut down their parents. The list ordering
- *     is guaranteed by virtue of the fact that child devices are registered
- *     after their parents.
- */
-void sysdev_shutdown(void)
-{
-       struct sysdev_class *cls;
-
-       pr_debug("Shutting Down System Devices\n");
-
-       mutex_lock(&sysdev_drivers_lock);
-       list_for_each_entry_reverse(cls, &system_kset->list, kset.kobj.entry) {
-               struct sys_device *sysdev;
-
-               pr_debug("Shutting down type '%s':\n",
-                        kobject_name(&cls->kset.kobj));
-
-               list_for_each_entry(sysdev, &cls->kset.list, kobj.entry) {
-                       struct sysdev_driver *drv;
-                       pr_debug(" %s\n", kobject_name(&sysdev->kobj));
-
-                       /* Call auxiliary drivers first */
-                       list_for_each_entry(drv, &cls->drivers, entry) {
-                               if (drv->shutdown)
-                                       drv->shutdown(sysdev);
-                       }
-
-                       /* Now call the generic one */
-                       if (cls->shutdown)
-                               cls->shutdown(sysdev);
-               }
-       }
-       mutex_unlock(&sysdev_drivers_lock);
-}
-
-static void __sysdev_resume(struct sys_device *dev)
-{
-       struct sysdev_class *cls = dev->cls;
-       struct sysdev_driver *drv;
-
-       /* First, call the class-specific one */
-       if (cls->resume)
-               cls->resume(dev);
-       WARN_ONCE(!irqs_disabled(),
-               "Interrupts enabled after %pF\n", cls->resume);
-
-       /* Call auxiliary drivers next. */
-       list_for_each_entry(drv, &cls->drivers, entry) {
-               if (drv->resume)
-                       drv->resume(dev);
-               WARN_ONCE(!irqs_disabled(),
-                       "Interrupts enabled after %pF\n", drv->resume);
-       }
-}
-
-/**
- *     sysdev_suspend - Suspend all system devices.
- *     @state:         Power state to enter.
- *
- *     We perform an almost identical operation as sysdev_shutdown()
- *     above, though calling ->suspend() instead. Interrupts are disabled
- *     when this called. Devices are responsible for both saving state and
- *     quiescing or powering down the device.
- *
- *     This is only called by the device PM core, so we let them handle
- *     all synchronization.
- */
-int sysdev_suspend(pm_message_t state)
-{
-       struct sysdev_class *cls;
-       struct sys_device *sysdev, *err_dev;
-       struct sysdev_driver *drv, *err_drv;
-       int ret;
-
-       pr_debug("Checking wake-up interrupts\n");
-
-       /* Return error code if there are any wake-up interrupts pending */
-       ret = check_wakeup_irqs();
-       if (ret)
-               return ret;
-
-       WARN_ONCE(!irqs_disabled(),
-               "Interrupts enabled while suspending system devices\n");
-
-       pr_debug("Suspending System Devices\n");
-
-       list_for_each_entry_reverse(cls, &system_kset->list, kset.kobj.entry) {
-               pr_debug("Suspending type '%s':\n",
-                        kobject_name(&cls->kset.kobj));
-
-               list_for_each_entry(sysdev, &cls->kset.list, kobj.entry) {
-                       pr_debug(" %s\n", kobject_name(&sysdev->kobj));
-
-                       /* Call auxiliary drivers first */
-                       list_for_each_entry(drv, &cls->drivers, entry) {
-                               if (drv->suspend) {
-                                       ret = drv->suspend(sysdev, state);
-                                       if (ret)
-                                               goto aux_driver;
-                               }
-                               WARN_ONCE(!irqs_disabled(),
-                                       "Interrupts enabled after %pF\n",
-                                       drv->suspend);
-                       }
-
-                       /* Now call the generic one */
-                       if (cls->suspend) {
-                               ret = cls->suspend(sysdev, state);
-                               if (ret)
-                                       goto cls_driver;
-                               WARN_ONCE(!irqs_disabled(),
-                                       "Interrupts enabled after %pF\n",
-                                       cls->suspend);
-                       }
-               }
-       }
-       return 0;
-       /* resume current sysdev */
-cls_driver:
-       drv = NULL;
-       printk(KERN_ERR "Class suspend failed for %s: %d\n",
-               kobject_name(&sysdev->kobj), ret);
-
-aux_driver:
-       if (drv)
-               printk(KERN_ERR "Class driver suspend failed for %s: %d\n",
-                               kobject_name(&sysdev->kobj), ret);
-       list_for_each_entry(err_drv, &cls->drivers, entry) {
-               if (err_drv == drv)
-                       break;
-               if (err_drv->resume)
-                       err_drv->resume(sysdev);
-       }
-
-       /* resume other sysdevs in current class */
-       list_for_each_entry(err_dev, &cls->kset.list, kobj.entry) {
-               if (err_dev == sysdev)
-                       break;
-               pr_debug(" %s\n", kobject_name(&err_dev->kobj));
-               __sysdev_resume(err_dev);
-       }
-
-       /* resume other classes */
-       list_for_each_entry_continue(cls, &system_kset->list, kset.kobj.entry) {
-               list_for_each_entry(err_dev, &cls->kset.list, kobj.entry) {
-                       pr_debug(" %s\n", kobject_name(&err_dev->kobj));
-                       __sysdev_resume(err_dev);
-               }
-       }
-       return ret;
-}
-EXPORT_SYMBOL_GPL(sysdev_suspend);
-
-/**
- *     sysdev_resume - Bring system devices back to life.
- *
- *     Similar to sysdev_suspend(), but we iterate the list forwards
- *     to guarantee that parent devices are resumed before their children.
- *
- *     Note: Interrupts are disabled when called.
- */
-int sysdev_resume(void)
-{
-       struct sysdev_class *cls;
-
-       WARN_ONCE(!irqs_disabled(),
-               "Interrupts enabled while resuming system devices\n");
-
-       pr_debug("Resuming System Devices\n");
-
-       list_for_each_entry(cls, &system_kset->list, kset.kobj.entry) {
-               struct sys_device *sysdev;
-
-               pr_debug("Resuming type '%s':\n",
-                        kobject_name(&cls->kset.kobj));
-
-               list_for_each_entry(sysdev, &cls->kset.list, kobj.entry) {
-                       pr_debug(" %s\n", kobject_name(&sysdev->kobj));
-
-                       __sysdev_resume(sysdev);
-               }
-       }
-       return 0;
-}
-EXPORT_SYMBOL_GPL(sysdev_resume);
-#endif /* CONFIG_ARCH_NO_SYSDEV_OPS */
+EXPORT_SYMBOL_GPL(sysdev_register);
+EXPORT_SYMBOL_GPL(sysdev_unregister);
 
 int __init system_bus_init(void)
 {
@@ -534,9 +339,6 @@ int __init system_bus_init(void)
        return 0;
 }
 
-EXPORT_SYMBOL_GPL(sysdev_register);
-EXPORT_SYMBOL_GPL(sysdev_unregister);
-
 #define to_ext_attr(x) container_of(x, struct sysdev_ext_attribute, attr)
 
 ssize_t sysdev_store_ulong(struct sys_device *sysdev,
index 8066d08..e086fbb 100644 (file)
@@ -2547,7 +2547,6 @@ static bool DAC960_RegisterBlockDevice(DAC960_Controller_T *Controller)
        disk->major = MajorNumber;
        disk->first_minor = n << DAC960_MaxPartitionsBits;
        disk->fops = &DAC960_BlockDeviceOperations;
-       disk->events = DISK_EVENT_MEDIA_CHANGE;
    }
   /*
     Indicate the Block Device Registration completed successfully,
index 456c0cc..8eba86b 100644 (file)
@@ -1736,7 +1736,6 @@ static int __init fd_probe_drives(void)
                disk->major = FLOPPY_MAJOR;
                disk->first_minor = drive;
                disk->fops = &floppy_fops;
-               disk->events = DISK_EVENT_MEDIA_CHANGE;
                sprintf(disk->disk_name, "fd%d", drive);
                disk->private_data = &unit[drive];
                set_capacity(disk, 880*2);
index c871eae..ede16c6 100644 (file)
@@ -1964,7 +1964,6 @@ static int __init atari_floppy_init (void)
                unit[i].disk->first_minor = i;
                sprintf(unit[i].disk->disk_name, "fd%d", i);
                unit[i].disk->fops = &floppy_fops;
-               unit[i].disk->events = DISK_EVENT_MEDIA_CHANGE;
                unit[i].disk->private_data = &unit[i];
                unit[i].disk->queue = blk_init_queue(do_fd_request,
                                        &ataflop_lock);
index 301d7a9..db8f885 100644 (file)
@@ -4205,7 +4205,6 @@ static int __init floppy_init(void)
                disks[dr]->major = FLOPPY_MAJOR;
                disks[dr]->first_minor = TOMINOR(dr);
                disks[dr]->fops = &floppy_fops;
-               disks[dr]->events = DISK_EVENT_MEDIA_CHANGE;
                sprintf(disks[dr]->disk_name, "fd%d", dr);
 
                init_timer(&motor_off_timer[dr]);
index 2f2ccf6..8690e31 100644 (file)
@@ -320,7 +320,6 @@ static void pcd_init_units(void)
                disk->first_minor = unit;
                strcpy(disk->disk_name, cd->name);      /* umm... */
                disk->fops = &pcd_bdops;
-               disk->events = DISK_EVENT_MEDIA_CHANGE;
        }
 }
 
index 21dfdb7..869e767 100644 (file)
@@ -837,7 +837,6 @@ static void pd_probe_drive(struct pd_unit *disk)
        p->fops = &pd_fops;
        p->major = major;
        p->first_minor = (disk - pd) << PD_BITS;
-       p->events = DISK_EVENT_MEDIA_CHANGE;
        disk->gd = p;
        p->private_data = disk;
        p->queue = pd_queue;
index 7adeb1e..f21b520 100644 (file)
@@ -294,7 +294,6 @@ static void __init pf_init_units(void)
                disk->first_minor = unit;
                strcpy(disk->disk_name, pf->name);
                disk->fops = &pf_fops;
-               disk->events = DISK_EVENT_MEDIA_CHANGE;
                if (!(*drives[unit])[D_PRT])
                        pf_drive_count++;
        }
index 3e90471..9712fad 100644 (file)
@@ -92,6 +92,8 @@ struct rbd_client {
        struct list_head        node;
 };
 
+struct rbd_req_coll;
+
 /*
  * a single io request
  */
@@ -100,6 +102,24 @@ struct rbd_request {
        struct bio              *bio;           /* cloned bio */
        struct page             **pages;        /* list of used pages */
        u64                     len;
+       int                     coll_index;
+       struct rbd_req_coll     *coll;
+};
+
+struct rbd_req_status {
+       int done;
+       int rc;
+       u64 bytes;
+};
+
+/*
+ * a collection of requests
+ */
+struct rbd_req_coll {
+       int                     total;
+       int                     num_done;
+       struct kref             kref;
+       struct rbd_req_status   status[0];
 };
 
 struct rbd_snap {
@@ -416,6 +436,17 @@ static void rbd_put_client(struct rbd_device *rbd_dev)
        rbd_dev->client = NULL;
 }
 
+/*
+ * Destroy requests collection
+ */
+static void rbd_coll_release(struct kref *kref)
+{
+       struct rbd_req_coll *coll =
+               container_of(kref, struct rbd_req_coll, kref);
+
+       dout("rbd_coll_release %p\n", coll);
+       kfree(coll);
+}
 
 /*
  * Create a new header structure, translate header format from the on-disk
@@ -590,6 +621,14 @@ static u64 rbd_get_segment(struct rbd_image_header *header,
        return len;
 }
 
+static int rbd_get_num_segments(struct rbd_image_header *header,
+                               u64 ofs, u64 len)
+{
+       u64 start_seg = ofs >> header->obj_order;
+       u64 end_seg = (ofs + len - 1) >> header->obj_order;
+       return end_seg - start_seg + 1;
+}
+
 /*
  * bio helpers
  */
@@ -735,6 +774,50 @@ static void rbd_destroy_ops(struct ceph_osd_req_op *ops)
        kfree(ops);
 }
 
+static void rbd_coll_end_req_index(struct request *rq,
+                                  struct rbd_req_coll *coll,
+                                  int index,
+                                  int ret, u64 len)
+{
+       struct request_queue *q;
+       int min, max, i;
+
+       dout("rbd_coll_end_req_index %p index %d ret %d len %lld\n",
+            coll, index, ret, len);
+
+       if (!rq)
+               return;
+
+       if (!coll) {
+               blk_end_request(rq, ret, len);
+               return;
+       }
+
+       q = rq->q;
+
+       spin_lock_irq(q->queue_lock);
+       coll->status[index].done = 1;
+       coll->status[index].rc = ret;
+       coll->status[index].bytes = len;
+       max = min = coll->num_done;
+       while (max < coll->total && coll->status[max].done)
+               max++;
+
+       for (i = min; i<max; i++) {
+               __blk_end_request(rq, coll->status[i].rc,
+                                 coll->status[i].bytes);
+               coll->num_done++;
+               kref_put(&coll->kref, rbd_coll_release);
+       }
+       spin_unlock_irq(q->queue_lock);
+}
+
+static void rbd_coll_end_req(struct rbd_request *req,
+                            int ret, u64 len)
+{
+       rbd_coll_end_req_index(req->rq, req->coll, req->coll_index, ret, len);
+}
+
 /*
  * Send ceph osd request
  */
@@ -749,6 +832,8 @@ static int rbd_do_request(struct request *rq,
                          int flags,
                          struct ceph_osd_req_op *ops,
                          int num_reply,
+                         struct rbd_req_coll *coll,
+                         int coll_index,
                          void (*rbd_cb)(struct ceph_osd_request *req,
                                         struct ceph_msg *msg),
                          struct ceph_osd_request **linger_req,
@@ -763,12 +848,20 @@ static int rbd_do_request(struct request *rq,
        struct ceph_osd_request_head *reqhead;
        struct rbd_image_header *header = &dev->header;
 
-       ret = -ENOMEM;
        req_data = kzalloc(sizeof(*req_data), GFP_NOIO);
-       if (!req_data)
-               goto done;
+       if (!req_data) {
+               if (coll)
+                       rbd_coll_end_req_index(rq, coll, coll_index,
+                                              -ENOMEM, len);
+               return -ENOMEM;
+       }
 
-       dout("rbd_do_request len=%lld ofs=%lld\n", len, ofs);
+       if (coll) {
+               req_data->coll = coll;
+               req_data->coll_index = coll_index;
+       }
+
+       dout("rbd_do_request obj=%s ofs=%lld len=%lld\n", obj, len, ofs);
 
        down_read(&header->snap_rwsem);
 
@@ -828,7 +921,8 @@ static int rbd_do_request(struct request *rq,
                ret = ceph_osdc_wait_request(&dev->client->osdc, req);
                if (ver)
                        *ver = le64_to_cpu(req->r_reassert_version.version);
-               dout("reassert_ver=%lld\n", le64_to_cpu(req->r_reassert_version.version));
+               dout("reassert_ver=%lld\n",
+                    le64_to_cpu(req->r_reassert_version.version));
                ceph_osdc_put_request(req);
        }
        return ret;
@@ -837,10 +931,8 @@ done_err:
        bio_chain_put(req_data->bio);
        ceph_osdc_put_request(req);
 done_pages:
+       rbd_coll_end_req(req_data, ret, len);
        kfree(req_data);
-done:
-       if (rq)
-               blk_end_request(rq, ret, len);
        return ret;
 }
 
@@ -874,7 +966,7 @@ static void rbd_req_cb(struct ceph_osd_request *req, struct ceph_msg *msg)
                bytes = req_data->len;
        }
 
-       blk_end_request(req_data->rq, rc, bytes);
+       rbd_coll_end_req(req_data, rc, bytes);
 
        if (req_data->bio)
                bio_chain_put(req_data->bio);
@@ -934,6 +1026,7 @@ static int rbd_req_sync_op(struct rbd_device *dev,
                          flags,
                          ops,
                          2,
+                         NULL, 0,
                          NULL,
                          linger_req, ver);
        if (ret < 0)
@@ -959,7 +1052,9 @@ static int rbd_do_op(struct request *rq,
                     u64 snapid,
                     int opcode, int flags, int num_reply,
                     u64 ofs, u64 len,
-                    struct bio *bio)
+                    struct bio *bio,
+                    struct rbd_req_coll *coll,
+                    int coll_index)
 {
        char *seg_name;
        u64 seg_ofs;
@@ -995,7 +1090,10 @@ static int rbd_do_op(struct request *rq,
                             flags,
                             ops,
                             num_reply,
+                            coll, coll_index,
                             rbd_req_cb, 0, NULL);
+
+       rbd_destroy_ops(ops);
 done:
        kfree(seg_name);
        return ret;
@@ -1008,13 +1106,15 @@ static int rbd_req_write(struct request *rq,
                         struct rbd_device *rbd_dev,
                         struct ceph_snap_context *snapc,
                         u64 ofs, u64 len,
-                        struct bio *bio)
+                        struct bio *bio,
+                        struct rbd_req_coll *coll,
+                        int coll_index)
 {
        return rbd_do_op(rq, rbd_dev, snapc, CEPH_NOSNAP,
                         CEPH_OSD_OP_WRITE,
                         CEPH_OSD_FLAG_WRITE | CEPH_OSD_FLAG_ONDISK,
                         2,
-                        ofs, len, bio);
+                        ofs, len, bio, coll, coll_index);
 }
 
 /*
@@ -1024,14 +1124,16 @@ static int rbd_req_read(struct request *rq,
                         struct rbd_device *rbd_dev,
                         u64 snapid,
                         u64 ofs, u64 len,
-                        struct bio *bio)
+                        struct bio *bio,
+                        struct rbd_req_coll *coll,
+                        int coll_index)
 {
        return rbd_do_op(rq, rbd_dev, NULL,
                         (snapid ? snapid : CEPH_NOSNAP),
                         CEPH_OSD_OP_READ,
                         CEPH_OSD_FLAG_READ,
                         2,
-                        ofs, len, bio);
+                        ofs, len, bio, coll, coll_index);
 }
 
 /*
@@ -1063,7 +1165,9 @@ static int rbd_req_sync_notify_ack(struct rbd_device *dev,
 {
        struct ceph_osd_req_op *ops;
        struct page **pages = NULL;
-       int ret = rbd_create_rw_ops(&ops, 1, CEPH_OSD_OP_NOTIFY_ACK, 0);
+       int ret;
+
+       ret = rbd_create_rw_ops(&ops, 1, CEPH_OSD_OP_NOTIFY_ACK, 0);
        if (ret < 0)
                return ret;
 
@@ -1077,6 +1181,7 @@ static int rbd_req_sync_notify_ack(struct rbd_device *dev,
                          CEPH_OSD_FLAG_READ,
                          ops,
                          1,
+                         NULL, 0,
                          rbd_simple_req_cb, 0, NULL);
 
        rbd_destroy_ops(ops);
@@ -1274,6 +1379,20 @@ static int rbd_req_sync_exec(struct rbd_device *dev,
        return ret;
 }
 
+static struct rbd_req_coll *rbd_alloc_coll(int num_reqs)
+{
+       struct rbd_req_coll *coll =
+                       kzalloc(sizeof(struct rbd_req_coll) +
+                               sizeof(struct rbd_req_status) * num_reqs,
+                               GFP_ATOMIC);
+
+       if (!coll)
+               return NULL;
+       coll->total = num_reqs;
+       kref_init(&coll->kref);
+       return coll;
+}
+
 /*
  * block device queue callback
  */
@@ -1291,6 +1410,8 @@ static void rbd_rq_fn(struct request_queue *q)
                bool do_write;
                int size, op_size = 0;
                u64 ofs;
+               int num_segs, cur_seg = 0;
+               struct rbd_req_coll *coll;
 
                /* peek at request from block layer */
                if (!rq)
@@ -1321,6 +1442,14 @@ static void rbd_rq_fn(struct request_queue *q)
                     do_write ? "write" : "read",
                     size, blk_rq_pos(rq) * 512ULL);
 
+               num_segs = rbd_get_num_segments(&rbd_dev->header, ofs, size);
+               coll = rbd_alloc_coll(num_segs);
+               if (!coll) {
+                       spin_lock_irq(q->queue_lock);
+                       __blk_end_request_all(rq, -ENOMEM);
+                       goto next;
+               }
+
                do {
                        /* a bio clone to be passed down to OSD req */
                        dout("rq->bio->bi_vcnt=%d\n", rq->bio->bi_vcnt);
@@ -1328,35 +1457,41 @@ static void rbd_rq_fn(struct request_queue *q)
                                                  rbd_dev->header.block_name,
                                                  ofs, size,
                                                  NULL, NULL);
+                       kref_get(&coll->kref);
                        bio = bio_chain_clone(&rq_bio, &next_bio, &bp,
                                              op_size, GFP_ATOMIC);
                        if (!bio) {
-                               spin_lock_irq(q->queue_lock);
-                               __blk_end_request_all(rq, -ENOMEM);
-                               goto next;
+                               rbd_coll_end_req_index(rq, coll, cur_seg,
+                                                      -ENOMEM, op_size);
+                               goto next_seg;
                        }
 
+
                        /* init OSD command: write or read */
                        if (do_write)
                                rbd_req_write(rq, rbd_dev,
                                              rbd_dev->header.snapc,
                                              ofs,
-                                             op_size, bio);
+                                             op_size, bio,
+                                             coll, cur_seg);
                        else
                                rbd_req_read(rq, rbd_dev,
                                             cur_snap_id(rbd_dev),
                                             ofs,
-                                            op_size, bio);
+                                            op_size, bio,
+                                            coll, cur_seg);
 
+next_seg:
                        size -= op_size;
                        ofs += op_size;
 
+                       cur_seg++;
                        rq_bio = next_bio;
                } while (size > 0);
+               kref_put(&coll->kref, rbd_coll_release);
 
                if (bp)
                        bio_pair_release(bp);
-
                spin_lock_irq(q->queue_lock);
 next:
                rq = blk_fetch_request(q);
index 24a482f..fd5adcd 100644 (file)
@@ -858,7 +858,6 @@ static int __devinit swim_floppy_init(struct swim_priv *swd)
                swd->unit[drive].disk->first_minor = drive;
                sprintf(swd->unit[drive].disk->disk_name, "fd%d", drive);
                swd->unit[drive].disk->fops = &floppy_fops;
-               swd->unit[drive].disk->events = DISK_EVENT_MEDIA_CHANGE;
                swd->unit[drive].disk->private_data = &swd->unit[drive];
                swd->unit[drive].disk->queue = swd->queue;
                set_capacity(swd->unit[drive].disk, 2880);
index 4c10f56..773bfa7 100644 (file)
@@ -1163,7 +1163,6 @@ static int __devinit swim3_attach(struct macio_dev *mdev, const struct of_device
        disk->major = FLOPPY_MAJOR;
        disk->first_minor = i;
        disk->fops = &floppy_fops;
-       disk->events = DISK_EVENT_MEDIA_CHANGE;
        disk->private_data = &floppy_states[i];
        disk->queue = swim3_queue;
        disk->flags |= GENHD_FL_REMOVABLE;
index 68b9430..0e376d4 100644 (file)
@@ -2334,7 +2334,6 @@ static int ub_probe_lun(struct ub_dev *sc, int lnum)
        disk->major = UB_MAJOR;
        disk->first_minor = lun->id * UB_PARTS_PER_LUN;
        disk->fops = &ub_bd_fops;
-       disk->events = DISK_EVENT_MEDIA_CHANGE;
        disk->private_data = lun;
        disk->driverfs_dev = &sc->intf->dev;
 
index 645ff76..6c7fd7d 100644 (file)
@@ -1005,7 +1005,6 @@ static int __devinit ace_setup(struct ace_device *ace)
        ace->gd->major = ace_major;
        ace->gd->first_minor = ace->id * ACE_NUM_MINORS;
        ace->gd->fops = &ace_fops;
-       ace->gd->events = DISK_EVENT_MEDIA_CHANGE;
        ace->gd->queue = ace->queue;
        ace->gd->private_data = ace;
        snprintf(ace->gd->disk_name, 32, "xs%c", ace->id + 'a');
index 514dd8e..75fb965 100644 (file)
@@ -986,6 +986,9 @@ int cdrom_open(struct cdrom_device_info *cdi, struct block_device *bdev, fmode_t
 
        cdinfo(CD_OPEN, "entering cdrom_open\n"); 
 
+       /* open is event synchronization point, check events first */
+       check_disk_change(bdev);
+
        /* if this was a O_NONBLOCK open and we should honor the flags,
         * do a quick open without drive/disc integrity checks. */
        cdi->use_count++;
@@ -1012,9 +1015,6 @@ int cdrom_open(struct cdrom_device_info *cdi, struct block_device *bdev, fmode_t
 
        cdinfo(CD_OPEN, "Use count for \"/dev/%s\" now %d\n",
                        cdi->name, cdi->use_count);
-       /* Do this on open.  Don't wait for mount, because they might
-           not be mounting, but opening with O_NONBLOCK */
-       check_disk_change(bdev);
        return 0;
 err_release:
        if (CDROM_CAN(CDC_LOCK) && cdi->options & CDO_LOCK) {
index b2b034f..3ceaf00 100644 (file)
@@ -803,7 +803,6 @@ static int __devinit probe_gdrom(struct platform_device *devptr)
                goto probe_fail_cdrom_register;
        }
        gd.disk->fops = &gdrom_bdops;
-       gd.disk->events = DISK_EVENT_MEDIA_CHANGE;
        /* latch on to the interrupt */
        err = gdrom_set_interrupt_handlers();
        if (err)
index 4e874c5..e427fbe 100644 (file)
@@ -626,7 +626,6 @@ static int viocd_probe(struct vio_dev *vdev, const struct vio_device_id *id)
        gendisk->queue = q;
        gendisk->fops = &viocd_fops;
        gendisk->flags = GENHD_FL_CD|GENHD_FL_REMOVABLE;
-       gendisk->events = DISK_EVENT_MEDIA_CHANGE;
        set_capacity(gendisk, 0);
        gendisk->private_data = d;
        d->viocd_disk = gendisk;
index ad59b4e..49502bc 100644 (file)
@@ -523,7 +523,7 @@ config RAW_DRIVER
           with the O_DIRECT flag.
 
 config MAX_RAW_DEVS
-       int "Maximum number of RAW devices to support (1-8192)"
+       int "Maximum number of RAW devices to support (1-65536)"
        depends on RAW_DRIVER
        default "256"
        help
index 7066e80..051474c 100644 (file)
@@ -84,8 +84,6 @@ static struct clocksource clocksource_hpet = {
        .rating         = 250,
        .read           = read_hpet,
        .mask           = CLOCKSOURCE_MASK(64),
-       .mult           = 0,            /* to be calculated */
-       .shift          = 10,
        .flags          = CLOCK_SOURCE_IS_CONTINUOUS,
 };
 static struct clocksource *hpet_clocksource;
@@ -934,9 +932,7 @@ int hpet_alloc(struct hpet_data *hdp)
        if (!hpet_clocksource) {
                hpet_mctr = (void __iomem *)&hpetp->hp_hpet->hpet_mc;
                CLKSRC_FSYS_MMIO_SET(clocksource_hpet.fsys_mmio, hpet_mctr);
-               clocksource_hpet.mult = clocksource_hz2mult(hpetp->hp_tick_freq,
-                                               clocksource_hpet.shift);
-               clocksource_register(&clocksource_hpet);
+               clocksource_register_hz(&clocksource_hpet, hpetp->hp_tick_freq);
                hpetp->hp_clocksource = &clocksource_hpet;
                hpet_clocksource = &clocksource_hpet;
        }
index 43ac619..ac6739e 100644 (file)
@@ -619,15 +619,18 @@ static void __devinit n2rng_driver_version(void)
                pr_info("%s", version);
 }
 
+static const struct of_device_id n2rng_match[];
 static int __devinit n2rng_probe(struct platform_device *op)
 {
+       const struct of_device_id *match;
        int victoria_falls;
        int err = -ENOMEM;
        struct n2rng *np;
 
-       if (!op->dev.of_match)
+       match = of_match_device(n2rng_match, &op->dev);
+       if (!match)
                return -EINVAL;
-       victoria_falls = (op->dev.of_match->data != NULL);
+       victoria_falls = (match->data != NULL);
 
        n2rng_driver_version();
        np = kzalloc(sizeof(*np), GFP_KERNEL);
index cc6c9b2..64c6b85 100644 (file)
@@ -2554,9 +2554,11 @@ static struct pci_driver ipmi_pci_driver = {
 };
 #endif /* CONFIG_PCI */
 
+static struct of_device_id ipmi_match[];
 static int __devinit ipmi_probe(struct platform_device *dev)
 {
 #ifdef CONFIG_OF
+       const struct of_device_id *match;
        struct smi_info *info;
        struct resource resource;
        const __be32 *regsize, *regspacing, *regshift;
@@ -2566,7 +2568,8 @@ static int __devinit ipmi_probe(struct platform_device *dev)
 
        dev_info(&dev->dev, "probing via device tree\n");
 
-       if (!dev->dev.of_match)
+       match = of_match_device(ipmi_match, &dev->dev);
+       if (!match)
                return -EINVAL;
 
        ret = of_address_to_resource(np, 0, &resource);
@@ -2601,7 +2604,7 @@ static int __devinit ipmi_probe(struct platform_device *dev)
                return -ENOMEM;
        }
 
-       info->si_type           = (enum si_type) dev->dev.of_match->data;
+       info->si_type           = (enum si_type) match->data;
        info->addr_source       = SI_DEVICETREE;
        info->irq_setup         = std_irq_setup;
 
index 436a990..8fc04b4 100644 (file)
@@ -806,29 +806,41 @@ static const struct file_operations oldmem_fops = {
 };
 #endif
 
-static ssize_t kmsg_write(struct file *file, const char __user *buf,
-                         size_t count, loff_t *ppos)
+static ssize_t kmsg_writev(struct kiocb *iocb, const struct iovec *iv,
+                          unsigned long count, loff_t pos)
 {
-       char *tmp;
-       ssize_t ret;
+       char *line, *p;
+       int i;
+       ssize_t ret = -EFAULT;
+       size_t len = iov_length(iv, count);
 
-       tmp = kmalloc(count + 1, GFP_KERNEL);
-       if (tmp == NULL)
+       line = kmalloc(len + 1, GFP_KERNEL);
+       if (line == NULL)
                return -ENOMEM;
-       ret = -EFAULT;
-       if (!copy_from_user(tmp, buf, count)) {
-               tmp[count] = 0;
-               ret = printk("%s", tmp);
-               if (ret > count)
-                       /* printk can add a prefix */
-                       ret = count;
+
+       /*
+        * copy all vectors into a single string, to ensure we do
+        * not interleave our log line with other printk calls
+        */
+       p = line;
+       for (i = 0; i < count; i++) {
+               if (copy_from_user(p, iv[i].iov_base, iv[i].iov_len))
+                       goto out;
+               p += iv[i].iov_len;
        }
-       kfree(tmp);
+       p[0] = '\0';
+
+       ret = printk("%s", line);
+       /* printk can add a prefix */
+       if (ret > len)
+               ret = len;
+out:
+       kfree(line);
        return ret;
 }
 
 static const struct file_operations kmsg_fops = {
-       .write = kmsg_write,
+       .aio_write = kmsg_writev,
        .llseek = noop_llseek,
 };
 
index b4b9d5a..b33e8ea 100644 (file)
@@ -21,6 +21,7 @@
 #include <linux/mutex.h>
 #include <linux/gfp.h>
 #include <linux/compat.h>
+#include <linux/vmalloc.h>
 
 #include <asm/uaccess.h>
 
@@ -30,10 +31,15 @@ struct raw_device_data {
 };
 
 static struct class *raw_class;
-static struct raw_device_data raw_devices[MAX_RAW_MINORS];
+static struct raw_device_data *raw_devices;
 static DEFINE_MUTEX(raw_mutex);
 static const struct file_operations raw_ctl_fops; /* forward declaration */
 
+static int max_raw_minors = MAX_RAW_MINORS;
+
+module_param(max_raw_minors, int, 0);
+MODULE_PARM_DESC(max_raw_minors, "Maximum number of raw devices (1-65536)");
+
 /*
  * Open/close code for raw IO.
  *
@@ -125,7 +131,7 @@ static int bind_set(int number, u64 major, u64 minor)
        struct raw_device_data *rawdev;
        int err = 0;
 
-       if (number <= 0 || number >= MAX_RAW_MINORS)
+       if (number <= 0 || number >= max_raw_minors)
                return -EINVAL;
 
        if (MAJOR(dev) != major || MINOR(dev) != minor)
@@ -312,14 +318,27 @@ static int __init raw_init(void)
        dev_t dev = MKDEV(RAW_MAJOR, 0);
        int ret;
 
-       ret = register_chrdev_region(dev, MAX_RAW_MINORS, "raw");
+       if (max_raw_minors < 1 || max_raw_minors > 65536) {
+               printk(KERN_WARNING "raw: invalid max_raw_minors (must be"
+                       " between 1 and 65536), using %d\n", MAX_RAW_MINORS);
+               max_raw_minors = MAX_RAW_MINORS;
+       }
+
+       raw_devices = vmalloc(sizeof(struct raw_device_data) * max_raw_minors);
+       if (!raw_devices) {
+               printk(KERN_ERR "Not enough memory for raw device structures\n");
+               ret = -ENOMEM;
+               goto error;
+       }
+       memset(raw_devices, 0, sizeof(struct raw_device_data) * max_raw_minors);
+
+       ret = register_chrdev_region(dev, max_raw_minors, "raw");
        if (ret)
                goto error;
 
        cdev_init(&raw_cdev, &raw_fops);
-       ret = cdev_add(&raw_cdev, dev, MAX_RAW_MINORS);
+       ret = cdev_add(&raw_cdev, dev, max_raw_minors);
        if (ret) {
-               kobject_put(&raw_cdev.kobj);
                goto error_region;
        }
 
@@ -336,8 +355,9 @@ static int __init raw_init(void)
        return 0;
 
 error_region:
-       unregister_chrdev_region(dev, MAX_RAW_MINORS);
+       unregister_chrdev_region(dev, max_raw_minors);
 error:
+       vfree(raw_devices);
        return ret;
 }
 
@@ -346,7 +366,7 @@ static void __exit raw_exit(void)
        device_destroy(raw_class, MKDEV(RAW_MAJOR, 0));
        class_destroy(raw_class);
        cdev_del(&raw_cdev);
-       unregister_chrdev_region(MKDEV(RAW_MAJOR, 0), MAX_RAW_MINORS);
+       unregister_chrdev_region(MKDEV(RAW_MAJOR, 0), max_raw_minors);
 }
 
 module_init(raw_init);
index d6412c1..39ccdea 100644 (file)
@@ -715,13 +715,13 @@ static int __devexit hwicap_remove(struct device *dev)
 }
 
 #ifdef CONFIG_OF
-static int __devinit hwicap_of_probe(struct platform_device *op)
+static int __devinit hwicap_of_probe(struct platform_device *op,
+                                    const struct hwicap_driver_config *config)
 {
        struct resource res;
        const unsigned int *id;
        const char *family;
        int rc;
-       const struct hwicap_driver_config *config = op->dev.of_match->data;
        const struct config_registers *regs;
 
 
@@ -751,20 +751,24 @@ static int __devinit hwicap_of_probe(struct platform_device *op)
                        regs);
 }
 #else
-static inline int hwicap_of_probe(struct platform_device *op)
+static inline int hwicap_of_probe(struct platform_device *op,
+                                 const struct hwicap_driver_config *config)
 {
        return -EINVAL;
 }
 #endif /* CONFIG_OF */
 
+static const struct of_device_id __devinitconst hwicap_of_match[];
 static int __devinit hwicap_drv_probe(struct platform_device *pdev)
 {
+       const struct of_device_id *match;
        struct resource *res;
        const struct config_registers *regs;
        const char *family;
 
-       if (pdev->dev.of_match)
-               return hwicap_of_probe(pdev);
+       match = of_match_device(hwicap_of_match, &pdev->dev);
+       if (match)
+               return hwicap_of_probe(pdev, match->data);
 
        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
        if (!res)
diff --git a/drivers/clocksource/Kconfig b/drivers/clocksource/Kconfig
new file mode 100644 (file)
index 0000000..110aeeb
--- /dev/null
@@ -0,0 +1,2 @@
+config CLKSRC_I8253
+       bool
index be61ece..cfb6383 100644 (file)
@@ -6,3 +6,4 @@ obj-$(CONFIG_CS5535_CLOCK_EVENT_SRC)    += cs5535-clockevt.o
 obj-$(CONFIG_SH_TIMER_CMT)     += sh_cmt.o
 obj-$(CONFIG_SH_TIMER_MTU2)    += sh_mtu2.o
 obj-$(CONFIG_SH_TIMER_TMU)     += sh_tmu.o
+obj-$(CONFIG_CLKSRC_I8253)     += i8253.o
index 64e528e..72f811f 100644 (file)
@@ -29,8 +29,6 @@ static struct clocksource clocksource_cyclone = {
        .rating         = 250,
        .read           = read_cyclone,
        .mask           = CYCLONE_TIMER_MASK,
-       .mult           = 10,
-       .shift          = 0,
        .flags          = CLOCK_SOURCE_IS_CONTINUOUS,
 };
 
@@ -108,12 +106,8 @@ static int __init init_cyclone_clocksource(void)
        }
        cyclone_ptr = cyclone_timer;
 
-       /* sort out mult/shift values: */
-       clocksource_cyclone.shift = 22;
-       clocksource_cyclone.mult = clocksource_hz2mult(CYCLONE_TIMER_FREQ,
-                                               clocksource_cyclone.shift);
-
-       return clocksource_register(&clocksource_cyclone);
+       return clocksource_register_hz(&clocksource_cyclone,
+                                       CYCLONE_TIMER_FREQ);
 }
 
 arch_initcall(init_cyclone_clocksource);
diff --git a/drivers/clocksource/i8253.c b/drivers/clocksource/i8253.c
new file mode 100644 (file)
index 0000000..225c176
--- /dev/null
@@ -0,0 +1,88 @@
+/*
+ * i8253 PIT clocksource
+ */
+#include <linux/clocksource.h>
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/spinlock.h>
+#include <linux/timex.h>
+
+#include <asm/i8253.h>
+
+/*
+ * Since the PIT overflows every tick, its not very useful
+ * to just read by itself. So use jiffies to emulate a free
+ * running counter:
+ */
+static cycle_t i8253_read(struct clocksource *cs)
+{
+       static int old_count;
+       static u32 old_jifs;
+       unsigned long flags;
+       int count;
+       u32 jifs;
+
+       raw_spin_lock_irqsave(&i8253_lock, flags);
+       /*
+        * Although our caller may have the read side of xtime_lock,
+        * this is now a seqlock, and we are cheating in this routine
+        * by having side effects on state that we cannot undo if
+        * there is a collision on the seqlock and our caller has to
+        * retry.  (Namely, old_jifs and old_count.)  So we must treat
+        * jiffies as volatile despite the lock.  We read jiffies
+        * before latching the timer count to guarantee that although
+        * the jiffies value might be older than the count (that is,
+        * the counter may underflow between the last point where
+        * jiffies was incremented and the point where we latch the
+        * count), it cannot be newer.
+        */
+       jifs = jiffies;
+       outb_pit(0x00, PIT_MODE);       /* latch the count ASAP */
+       count = inb_pit(PIT_CH0);       /* read the latched count */
+       count |= inb_pit(PIT_CH0) << 8;
+
+       /* VIA686a test code... reset the latch if count > max + 1 */
+       if (count > LATCH) {
+               outb_pit(0x34, PIT_MODE);
+               outb_pit(PIT_LATCH & 0xff, PIT_CH0);
+               outb_pit(PIT_LATCH >> 8, PIT_CH0);
+               count = PIT_LATCH - 1;
+       }
+
+       /*
+        * It's possible for count to appear to go the wrong way for a
+        * couple of reasons:
+        *
+        *  1. The timer counter underflows, but we haven't handled the
+        *     resulting interrupt and incremented jiffies yet.
+        *  2. Hardware problem with the timer, not giving us continuous time,
+        *     the counter does small "jumps" upwards on some Pentium systems,
+        *     (see c't 95/10 page 335 for Neptun bug.)
+        *
+        * Previous attempts to handle these cases intelligently were
+        * buggy, so we just do the simple thing now.
+        */
+       if (count > old_count && jifs == old_jifs)
+               count = old_count;
+
+       old_count = count;
+       old_jifs = jifs;
+
+       raw_spin_unlock_irqrestore(&i8253_lock, flags);
+
+       count = (PIT_LATCH - 1) - count;
+
+       return (cycle_t)(jifs * PIT_LATCH) + count;
+}
+
+static struct clocksource i8253_cs = {
+       .name           = "pit",
+       .rating         = 110,
+       .read           = i8253_read,
+       .mask           = CLOCKSOURCE_MASK(32),
+};
+
+int __init clocksource_i8253_init(void)
+{
+       return clocksource_register_hz(&i8253_cs, PIT_TICK_RATE);
+}
index ca8ee80..9fb8485 100644 (file)
@@ -1,3 +1,5 @@
+menu "CPU Frequency scaling"
+
 config CPU_FREQ
        bool "CPU Frequency scaling"
        help
@@ -18,19 +20,6 @@ if CPU_FREQ
 config CPU_FREQ_TABLE
        tristate
 
-config CPU_FREQ_DEBUG
-       bool "Enable CPUfreq debugging"
-       help
-         Say Y here to enable CPUfreq subsystem (including drivers)
-         debugging. You will need to activate it via the kernel
-         command line by passing
-            cpufreq.debug=<value>
-
-         To get <value>, add 
-              1 to activate CPUfreq core debugging,
-              2 to activate CPUfreq drivers debugging, and
-              4 to activate CPUfreq governor debugging
-
 config CPU_FREQ_STAT
        tristate "CPU frequency translation statistics"
        select CPU_FREQ_TABLE
@@ -190,4 +179,10 @@ config CPU_FREQ_GOV_CONSERVATIVE
 
          If in doubt, say N.
 
-endif  # CPU_FREQ
+menu "x86 CPU frequency scaling drivers"
+depends on X86
+source "drivers/cpufreq/Kconfig.x86"
+endmenu
+
+endif
+endmenu
similarity index 97%
rename from arch/x86/kernel/cpu/cpufreq/Kconfig
rename to drivers/cpufreq/Kconfig.x86
index 870e6cc..78ff7ee 100644 (file)
@@ -1,15 +1,7 @@
 #
-# CPU Frequency scaling
+# x86 CPU Frequency scaling drivers
 #
 
-menu "CPU Frequency scaling"
-
-source "drivers/cpufreq/Kconfig"
-
-if CPU_FREQ
-
-comment "CPUFreq processor drivers"
-
 config X86_PCC_CPUFREQ
        tristate "Processor Clocking Control interface driver"
        depends on ACPI && ACPI_PROCESSOR
@@ -43,7 +35,7 @@ config X86_ACPI_CPUFREQ
 config ELAN_CPUFREQ
        tristate "AMD Elan SC400 and SC410"
        select CPU_FREQ_TABLE
-       depends on X86_ELAN
+       depends on MELAN
        ---help---
          This adds the CPUFreq driver for AMD Elan SC400 and SC410
          processors.
@@ -59,7 +51,7 @@ config ELAN_CPUFREQ
 config SC520_CPUFREQ
        tristate "AMD Elan SC520"
        select CPU_FREQ_TABLE
-       depends on X86_ELAN
+       depends on MELAN
        ---help---
          This adds the CPUFreq driver for AMD Elan SC520 processor.
 
@@ -261,6 +253,3 @@ config X86_SPEEDSTEP_RELAXED_CAP_CHECK
          option lets the probing code bypass some of those checks if the
          parameter "relaxed_check=1" is passed to the module.
 
-endif  # CPU_FREQ
-
-endmenu
index 71fc3b4..c7f1a6f 100644 (file)
@@ -13,3 +13,29 @@ obj-$(CONFIG_CPU_FREQ_GOV_CONSERVATIVE)      += cpufreq_conservative.o
 # CPUfreq cross-arch helpers
 obj-$(CONFIG_CPU_FREQ_TABLE)           += freq_table.o
 
+##################################################################################d
+# x86 drivers.
+# Link order matters. K8 is preferred to ACPI because of firmware bugs in early
+# K8 systems. ACPI is preferred to all other hardware-specific drivers.
+# speedstep-* is preferred over p4-clockmod.
+
+obj-$(CONFIG_X86_POWERNOW_K8)          += powernow-k8.o mperf.o
+obj-$(CONFIG_X86_ACPI_CPUFREQ)         += acpi-cpufreq.o mperf.o
+obj-$(CONFIG_X86_PCC_CPUFREQ)          += pcc-cpufreq.o
+obj-$(CONFIG_X86_POWERNOW_K6)          += powernow-k6.o
+obj-$(CONFIG_X86_POWERNOW_K7)          += powernow-k7.o
+obj-$(CONFIG_X86_LONGHAUL)             += longhaul.o
+obj-$(CONFIG_X86_E_POWERSAVER)         += e_powersaver.o
+obj-$(CONFIG_ELAN_CPUFREQ)             += elanfreq.o
+obj-$(CONFIG_SC520_CPUFREQ)            += sc520_freq.o
+obj-$(CONFIG_X86_LONGRUN)              += longrun.o
+obj-$(CONFIG_X86_GX_SUSPMOD)           += gx-suspmod.o
+obj-$(CONFIG_X86_SPEEDSTEP_ICH)                += speedstep-ich.o
+obj-$(CONFIG_X86_SPEEDSTEP_LIB)                += speedstep-lib.o
+obj-$(CONFIG_X86_SPEEDSTEP_SMI)                += speedstep-smi.o
+obj-$(CONFIG_X86_SPEEDSTEP_CENTRINO)   += speedstep-centrino.o
+obj-$(CONFIG_X86_P4_CLOCKMOD)          += p4-clockmod.o
+obj-$(CONFIG_X86_CPUFREQ_NFORCE2)      += cpufreq-nforce2.o
+
+##################################################################################d
+
similarity index 94%
rename from arch/x86/kernel/cpu/cpufreq/acpi-cpufreq.c
rename to drivers/cpufreq/acpi-cpufreq.c
index a2baafb..4e04e12 100644 (file)
@@ -47,9 +47,6 @@
 #include <asm/cpufeature.h>
 #include "mperf.h"
 
-#define dprintk(msg...) cpufreq_debug_printk(CPUFREQ_DEBUG_DRIVER, \
-               "acpi-cpufreq", msg)
-
 MODULE_AUTHOR("Paul Diefenbaugh, Dominik Brodowski");
 MODULE_DESCRIPTION("ACPI Processor P-States Driver");
 MODULE_LICENSE("GPL");
@@ -233,7 +230,7 @@ static u32 get_cur_val(const struct cpumask *mask)
        cmd.mask = mask;
        drv_read(&cmd);
 
-       dprintk("get_cur_val = %u\n", cmd.val);
+       pr_debug("get_cur_val = %u\n", cmd.val);
 
        return cmd.val;
 }
@@ -244,7 +241,7 @@ static unsigned int get_cur_freq_on_cpu(unsigned int cpu)
        unsigned int freq;
        unsigned int cached_freq;
 
-       dprintk("get_cur_freq_on_cpu (%d)\n", cpu);
+       pr_debug("get_cur_freq_on_cpu (%d)\n", cpu);
 
        if (unlikely(data == NULL ||
                     data->acpi_data == NULL || data->freq_table == NULL)) {
@@ -261,7 +258,7 @@ static unsigned int get_cur_freq_on_cpu(unsigned int cpu)
                data->resume = 1;
        }
 
-       dprintk("cur freq = %u\n", freq);
+       pr_debug("cur freq = %u\n", freq);
 
        return freq;
 }
@@ -293,7 +290,7 @@ static int acpi_cpufreq_target(struct cpufreq_policy *policy,
        unsigned int i;
        int result = 0;
 
-       dprintk("acpi_cpufreq_target %d (%d)\n", target_freq, policy->cpu);
+       pr_debug("acpi_cpufreq_target %d (%d)\n", target_freq, policy->cpu);
 
        if (unlikely(data == NULL ||
             data->acpi_data == NULL || data->freq_table == NULL)) {
@@ -313,11 +310,11 @@ static int acpi_cpufreq_target(struct cpufreq_policy *policy,
        next_perf_state = data->freq_table[next_state].index;
        if (perf->state == next_perf_state) {
                if (unlikely(data->resume)) {
-                       dprintk("Called after resume, resetting to P%d\n",
+                       pr_debug("Called after resume, resetting to P%d\n",
                                next_perf_state);
                        data->resume = 0;
                } else {
-                       dprintk("Already at target state (P%d)\n",
+                       pr_debug("Already at target state (P%d)\n",
                                next_perf_state);
                        goto out;
                }
@@ -357,7 +354,7 @@ static int acpi_cpufreq_target(struct cpufreq_policy *policy,
 
        if (acpi_pstate_strict) {
                if (!check_freqs(cmd.mask, freqs.new, data)) {
-                       dprintk("acpi_cpufreq_target failed (%d)\n",
+                       pr_debug("acpi_cpufreq_target failed (%d)\n",
                                policy->cpu);
                        result = -EAGAIN;
                        goto out;
@@ -378,7 +375,7 @@ static int acpi_cpufreq_verify(struct cpufreq_policy *policy)
 {
        struct acpi_cpufreq_data *data = per_cpu(acfreq_data, policy->cpu);
 
-       dprintk("acpi_cpufreq_verify\n");
+       pr_debug("acpi_cpufreq_verify\n");
 
        return cpufreq_frequency_table_verify(policy, data->freq_table);
 }
@@ -433,11 +430,11 @@ static void free_acpi_perf_data(void)
 static int __init acpi_cpufreq_early_init(void)
 {
        unsigned int i;
-       dprintk("acpi_cpufreq_early_init\n");
+       pr_debug("acpi_cpufreq_early_init\n");
 
        acpi_perf_data = alloc_percpu(struct acpi_processor_performance);
        if (!acpi_perf_data) {
-               dprintk("Memory allocation error for acpi_perf_data.\n");
+               pr_debug("Memory allocation error for acpi_perf_data.\n");
                return -ENOMEM;
        }
        for_each_possible_cpu(i) {
@@ -519,7 +516,7 @@ static int acpi_cpufreq_cpu_init(struct cpufreq_policy *policy)
        static int blacklisted;
 #endif
 
-       dprintk("acpi_cpufreq_cpu_init\n");
+       pr_debug("acpi_cpufreq_cpu_init\n");
 
 #ifdef CONFIG_SMP
        if (blacklisted)
@@ -566,7 +563,7 @@ static int acpi_cpufreq_cpu_init(struct cpufreq_policy *policy)
 
        /* capability check */
        if (perf->state_count <= 1) {
-               dprintk("No P-States\n");
+               pr_debug("No P-States\n");
                result = -ENODEV;
                goto err_unreg;
        }
@@ -578,11 +575,11 @@ static int acpi_cpufreq_cpu_init(struct cpufreq_policy *policy)
 
        switch (perf->control_register.space_id) {
        case ACPI_ADR_SPACE_SYSTEM_IO:
-               dprintk("SYSTEM IO addr space\n");
+               pr_debug("SYSTEM IO addr space\n");
                data->cpu_feature = SYSTEM_IO_CAPABLE;
                break;
        case ACPI_ADR_SPACE_FIXED_HARDWARE:
-               dprintk("HARDWARE addr space\n");
+               pr_debug("HARDWARE addr space\n");
                if (!check_est_cpu(cpu)) {
                        result = -ENODEV;
                        goto err_unreg;
@@ -590,7 +587,7 @@ static int acpi_cpufreq_cpu_init(struct cpufreq_policy *policy)
                data->cpu_feature = SYSTEM_INTEL_MSR_CAPABLE;
                break;
        default:
-               dprintk("Unknown addr space %d\n",
+               pr_debug("Unknown addr space %d\n",
                        (u32) (perf->control_register.space_id));
                result = -ENODEV;
                goto err_unreg;
@@ -661,9 +658,9 @@ static int acpi_cpufreq_cpu_init(struct cpufreq_policy *policy)
        if (cpu_has(c, X86_FEATURE_APERFMPERF))
                acpi_cpufreq_driver.getavg = cpufreq_get_measured_perf;
 
-       dprintk("CPU%u - ACPI performance management activated.\n", cpu);
+       pr_debug("CPU%u - ACPI performance management activated.\n", cpu);
        for (i = 0; i < perf->state_count; i++)
-               dprintk("     %cP%d: %d MHz, %d mW, %d uS\n",
+               pr_debug("     %cP%d: %d MHz, %d mW, %d uS\n",
                        (i == perf->state ? '*' : ' '), i,
                        (u32) perf->states[i].core_frequency,
                        (u32) perf->states[i].power,
@@ -694,7 +691,7 @@ static int acpi_cpufreq_cpu_exit(struct cpufreq_policy *policy)
 {
        struct acpi_cpufreq_data *data = per_cpu(acfreq_data, policy->cpu);
 
-       dprintk("acpi_cpufreq_cpu_exit\n");
+       pr_debug("acpi_cpufreq_cpu_exit\n");
 
        if (data) {
                cpufreq_frequency_table_put_attr(policy->cpu);
@@ -712,7 +709,7 @@ static int acpi_cpufreq_resume(struct cpufreq_policy *policy)
 {
        struct acpi_cpufreq_data *data = per_cpu(acfreq_data, policy->cpu);
 
-       dprintk("acpi_cpufreq_resume\n");
+       pr_debug("acpi_cpufreq_resume\n");
 
        data->resume = 1;
 
@@ -743,7 +740,7 @@ static int __init acpi_cpufreq_init(void)
        if (acpi_disabled)
                return 0;
 
-       dprintk("acpi_cpufreq_init\n");
+       pr_debug("acpi_cpufreq_init\n");
 
        ret = acpi_cpufreq_early_init();
        if (ret)
@@ -758,7 +755,7 @@ static int __init acpi_cpufreq_init(void)
 
 static void __exit acpi_cpufreq_exit(void)
 {
-       dprintk("acpi_cpufreq_exit\n");
+       pr_debug("acpi_cpufreq_exit\n");
 
        cpufreq_unregister_driver(&acpi_cpufreq_driver);
 
similarity index 97%
rename from arch/x86/kernel/cpu/cpufreq/cpufreq-nforce2.c
rename to drivers/cpufreq/cpufreq-nforce2.c
index 141abeb..7bac808 100644 (file)
@@ -57,8 +57,6 @@ MODULE_PARM_DESC(min_fsb,
                "Minimum FSB to use, if not defined: current FSB - 50");
 
 #define PFX "cpufreq-nforce2: "
-#define dprintk(msg...) cpufreq_debug_printk(CPUFREQ_DEBUG_DRIVER, \
-               "cpufreq-nforce2", msg)
 
 /**
  * nforce2_calc_fsb - calculate FSB
@@ -270,7 +268,7 @@ static int nforce2_target(struct cpufreq_policy *policy,
        if (freqs.old == freqs.new)
                return 0;
 
-       dprintk("Old CPU frequency %d kHz, new %d kHz\n",
+       pr_debug("Old CPU frequency %d kHz, new %d kHz\n",
               freqs.old, freqs.new);
 
        cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
@@ -282,7 +280,7 @@ static int nforce2_target(struct cpufreq_policy *policy,
                printk(KERN_ERR PFX "Changing FSB to %d failed\n",
                        target_fsb);
        else
-               dprintk("Changed FSB successfully to %d\n",
+               pr_debug("Changed FSB successfully to %d\n",
                        target_fsb);
 
        /* Enable IRQs */
index 2dafc5c..0a5bea9 100644 (file)
@@ -32,9 +32,6 @@
 
 #include <trace/events/power.h>
 
-#define dprintk(msg...) cpufreq_debug_printk(CPUFREQ_DEBUG_CORE, \
-                                               "cpufreq-core", msg)
-
 /**
  * The "cpufreq driver" - the arch- or hardware-dependent low
  * level driver of CPUFreq support, and its spinlock. This lock
@@ -181,93 +178,6 @@ EXPORT_SYMBOL_GPL(cpufreq_cpu_put);
 
 
 /*********************************************************************
- *                     UNIFIED DEBUG HELPERS                         *
- *********************************************************************/
-#ifdef CONFIG_CPU_FREQ_DEBUG
-
-/* what part(s) of the CPUfreq subsystem are debugged? */
-static unsigned int debug;
-
-/* is the debug output ratelimit'ed using printk_ratelimit? User can
- * set or modify this value.
- */
-static unsigned int debug_ratelimit = 1;
-
-/* is the printk_ratelimit'ing enabled? It's enabled after a successful
- * loading of a cpufreq driver, temporarily disabled when a new policy
- * is set, and disabled upon cpufreq driver removal
- */
-static unsigned int disable_ratelimit = 1;
-static DEFINE_SPINLOCK(disable_ratelimit_lock);
-
-static void cpufreq_debug_enable_ratelimit(void)
-{
-       unsigned long flags;
-
-       spin_lock_irqsave(&disable_ratelimit_lock, flags);
-       if (disable_ratelimit)
-               disable_ratelimit--;
-       spin_unlock_irqrestore(&disable_ratelimit_lock, flags);
-}
-
-static void cpufreq_debug_disable_ratelimit(void)
-{
-       unsigned long flags;
-
-       spin_lock_irqsave(&disable_ratelimit_lock, flags);
-       disable_ratelimit++;
-       spin_unlock_irqrestore(&disable_ratelimit_lock, flags);
-}
-
-void cpufreq_debug_printk(unsigned int type, const char *prefix,
-                       const char *fmt, ...)
-{
-       char s[256];
-       va_list args;
-       unsigned int len;
-       unsigned long flags;
-
-       WARN_ON(!prefix);
-       if (type & debug) {
-               spin_lock_irqsave(&disable_ratelimit_lock, flags);
-               if (!disable_ratelimit && debug_ratelimit
-                                       && !printk_ratelimit()) {
-                       spin_unlock_irqrestore(&disable_ratelimit_lock, flags);
-                       return;
-               }
-               spin_unlock_irqrestore(&disable_ratelimit_lock, flags);
-
-               len = snprintf(s, 256, KERN_DEBUG "%s: ", prefix);
-
-               va_start(args, fmt);
-               len += vsnprintf(&s[len], (256 - len), fmt, args);
-               va_end(args);
-
-               printk(s);
-
-               WARN_ON(len < 5);
-       }
-}
-EXPORT_SYMBOL(cpufreq_debug_printk);
-
-
-module_param(debug, uint, 0644);
-MODULE_PARM_DESC(debug, "CPUfreq debugging: add 1 to debug core,"
-                       " 2 to debug drivers, and 4 to debug governors.");
-
-module_param(debug_ratelimit, uint, 0644);
-MODULE_PARM_DESC(debug_ratelimit, "CPUfreq debugging:"
-                                       " set to 0 to disable ratelimiting.");
-
-#else /* !CONFIG_CPU_FREQ_DEBUG */
-
-static inline void cpufreq_debug_enable_ratelimit(void) { return; }
-static inline void cpufreq_debug_disable_ratelimit(void) { return; }
-
-#endif /* CONFIG_CPU_FREQ_DEBUG */
-
-
-/*********************************************************************
  *            EXTERNALLY AFFECTING FREQUENCY CHANGES                 *
  *********************************************************************/
 
@@ -291,7 +201,7 @@ static void adjust_jiffies(unsigned long val, struct cpufreq_freqs *ci)
        if (!l_p_j_ref_freq) {
                l_p_j_ref = loops_per_jiffy;
                l_p_j_ref_freq = ci->old;
-               dprintk("saving %lu as reference value for loops_per_jiffy; "
+               pr_debug("saving %lu as reference value for loops_per_jiffy; "
                        "freq is %u kHz\n", l_p_j_ref, l_p_j_ref_freq);
        }
        if ((val == CPUFREQ_PRECHANGE  && ci->old < ci->new) ||
@@ -299,7 +209,7 @@ static void adjust_jiffies(unsigned long val, struct cpufreq_freqs *ci)
            (val == CPUFREQ_RESUMECHANGE || val == CPUFREQ_SUSPENDCHANGE)) {
                loops_per_jiffy = cpufreq_scale(l_p_j_ref, l_p_j_ref_freq,
                                                                ci->new);
-               dprintk("scaling loops_per_jiffy to %lu "
+               pr_debug("scaling loops_per_jiffy to %lu "
                        "for frequency %u kHz\n", loops_per_jiffy, ci->new);
        }
 }
@@ -326,7 +236,7 @@ void cpufreq_notify_transition(struct cpufreq_freqs *freqs, unsigned int state)
        BUG_ON(irqs_disabled());
 
        freqs->flags = cpufreq_driver->flags;
-       dprintk("notification %u of frequency transition to %u kHz\n",
+       pr_debug("notification %u of frequency transition to %u kHz\n",
                state, freqs->new);
 
        policy = per_cpu(cpufreq_cpu_data, freqs->cpu);
@@ -340,7 +250,7 @@ void cpufreq_notify_transition(struct cpufreq_freqs *freqs, unsigned int state)
                if (!(cpufreq_driver->flags & CPUFREQ_CONST_LOOPS)) {
                        if ((policy) && (policy->cpu == freqs->cpu) &&
                            (policy->cur) && (policy->cur != freqs->old)) {
-                               dprintk("Warning: CPU frequency is"
+                               pr_debug("Warning: CPU frequency is"
                                        " %u, cpufreq assumed %u kHz.\n",
                                        freqs->old, policy->cur);
                                freqs->old = policy->cur;
@@ -353,7 +263,7 @@ void cpufreq_notify_transition(struct cpufreq_freqs *freqs, unsigned int state)
 
        case CPUFREQ_POSTCHANGE:
                adjust_jiffies(CPUFREQ_POSTCHANGE, freqs);
-               dprintk("FREQ: %lu - CPU: %lu", (unsigned long)freqs->new,
+               pr_debug("FREQ: %lu - CPU: %lu", (unsigned long)freqs->new,
                        (unsigned long)freqs->cpu);
                trace_power_frequency(POWER_PSTATE, freqs->new, freqs->cpu);
                trace_cpu_frequency(freqs->new, freqs->cpu);
@@ -411,21 +321,14 @@ static int cpufreq_parse_governor(char *str_governor, unsigned int *policy,
                t = __find_governor(str_governor);
 
                if (t == NULL) {
-                       char *name = kasprintf(GFP_KERNEL, "cpufreq_%s",
-                                                               str_governor);
-
-                       if (name) {
-                               int ret;
+                       int ret;
 
-                               mutex_unlock(&cpufreq_governor_mutex);
-                               ret = request_module("%s", name);
-                               mutex_lock(&cpufreq_governor_mutex);
+                       mutex_unlock(&cpufreq_governor_mutex);
+                       ret = request_module("cpufreq_%s", str_governor);
+                       mutex_lock(&cpufreq_governor_mutex);
 
-                               if (ret == 0)
-                                       t = __find_governor(str_governor);
-                       }
-
-                       kfree(name);
+                       if (ret == 0)
+                               t = __find_governor(str_governor);
                }
 
                if (t != NULL) {
@@ -753,7 +656,7 @@ no_policy:
 static void cpufreq_sysfs_release(struct kobject *kobj)
 {
        struct cpufreq_policy *policy = to_policy(kobj);
-       dprintk("last reference is dropped\n");
+       pr_debug("last reference is dropped\n");
        complete(&policy->kobj_unregister);
 }
 
@@ -788,7 +691,7 @@ static int cpufreq_add_dev_policy(unsigned int cpu,
        gov = __find_governor(per_cpu(cpufreq_cpu_governor, cpu));
        if (gov) {
                policy->governor = gov;
-               dprintk("Restoring governor %s for cpu %d\n",
+               pr_debug("Restoring governor %s for cpu %d\n",
                       policy->governor->name, cpu);
        }
 #endif
@@ -824,7 +727,7 @@ static int cpufreq_add_dev_policy(unsigned int cpu,
                        per_cpu(cpufreq_cpu_data, cpu) = managed_policy;
                        spin_unlock_irqrestore(&cpufreq_driver_lock, flags);
 
-                       dprintk("CPU already managed, adding link\n");
+                       pr_debug("CPU already managed, adding link\n");
                        ret = sysfs_create_link(&sys_dev->kobj,
                                                &managed_policy->kobj,
                                                "cpufreq");
@@ -865,7 +768,7 @@ static int cpufreq_add_dev_symlink(unsigned int cpu,
                if (!cpu_online(j))
                        continue;
 
-               dprintk("CPU %u already managed, adding link\n", j);
+               pr_debug("CPU %u already managed, adding link\n", j);
                managed_policy = cpufreq_cpu_get(cpu);
                cpu_sys_dev = get_cpu_sysdev(j);
                ret = sysfs_create_link(&cpu_sys_dev->kobj, &policy->kobj,
@@ -941,7 +844,7 @@ static int cpufreq_add_dev_interface(unsigned int cpu,
        policy->user_policy.governor = policy->governor;
 
        if (ret) {
-               dprintk("setting policy failed\n");
+               pr_debug("setting policy failed\n");
                if (cpufreq_driver->exit)
                        cpufreq_driver->exit(policy);
        }
@@ -977,8 +880,7 @@ static int cpufreq_add_dev(struct sys_device *sys_dev)
        if (cpu_is_offline(cpu))
                return 0;
 
-       cpufreq_debug_disable_ratelimit();
-       dprintk("adding CPU %u\n", cpu);
+       pr_debug("adding CPU %u\n", cpu);
 
 #ifdef CONFIG_SMP
        /* check whether a different CPU already registered this
@@ -986,7 +888,6 @@ static int cpufreq_add_dev(struct sys_device *sys_dev)
        policy = cpufreq_cpu_get(cpu);
        if (unlikely(policy)) {
                cpufreq_cpu_put(policy);
-               cpufreq_debug_enable_ratelimit();
                return 0;
        }
 #endif
@@ -1037,7 +938,7 @@ static int cpufreq_add_dev(struct sys_device *sys_dev)
         */
        ret = cpufreq_driver->init(policy);
        if (ret) {
-               dprintk("initialization failed\n");
+               pr_debug("initialization failed\n");
                goto err_unlock_policy;
        }
        policy->user_policy.min = policy->min;
@@ -1063,8 +964,7 @@ static int cpufreq_add_dev(struct sys_device *sys_dev)
 
        kobject_uevent(&policy->kobj, KOBJ_ADD);
        module_put(cpufreq_driver->owner);
-       dprintk("initialization complete\n");
-       cpufreq_debug_enable_ratelimit();
+       pr_debug("initialization complete\n");
 
        return 0;
 
@@ -1088,7 +988,6 @@ err_free_policy:
 nomem_out:
        module_put(cpufreq_driver->owner);
 module_out:
-       cpufreq_debug_enable_ratelimit();
        return ret;
 }
 
@@ -1112,15 +1011,13 @@ static int __cpufreq_remove_dev(struct sys_device *sys_dev)
        unsigned int j;
 #endif
 
-       cpufreq_debug_disable_ratelimit();
-       dprintk("unregistering CPU %u\n", cpu);
+       pr_debug("unregistering CPU %u\n", cpu);
 
        spin_lock_irqsave(&cpufreq_driver_lock, flags);
        data = per_cpu(cpufreq_cpu_data, cpu);
 
        if (!data) {
                spin_unlock_irqrestore(&cpufreq_driver_lock, flags);
-               cpufreq_debug_enable_ratelimit();
                unlock_policy_rwsem_write(cpu);
                return -EINVAL;
        }
@@ -1132,12 +1029,11 @@ static int __cpufreq_remove_dev(struct sys_device *sys_dev)
         * only need to unlink, put and exit
         */
        if (unlikely(cpu != data->cpu)) {
-               dprintk("removing link\n");
+               pr_debug("removing link\n");
                cpumask_clear_cpu(cpu, data->cpus);
                spin_unlock_irqrestore(&cpufreq_driver_lock, flags);
                kobj = &sys_dev->kobj;
                cpufreq_cpu_put(data);
-               cpufreq_debug_enable_ratelimit();
                unlock_policy_rwsem_write(cpu);
                sysfs_remove_link(kobj, "cpufreq");
                return 0;
@@ -1170,7 +1066,7 @@ static int __cpufreq_remove_dev(struct sys_device *sys_dev)
                for_each_cpu(j, data->cpus) {
                        if (j == cpu)
                                continue;
-                       dprintk("removing link for cpu %u\n", j);
+                       pr_debug("removing link for cpu %u\n", j);
 #ifdef CONFIG_HOTPLUG_CPU
                        strncpy(per_cpu(cpufreq_cpu_governor, j),
                                data->governor->name, CPUFREQ_NAME_LEN);
@@ -1199,21 +1095,35 @@ static int __cpufreq_remove_dev(struct sys_device *sys_dev)
         * not referenced anymore by anybody before we proceed with
         * unloading.
         */
-       dprintk("waiting for dropping of refcount\n");
+       pr_debug("waiting for dropping of refcount\n");
        wait_for_completion(cmp);
-       dprintk("wait complete\n");
+       pr_debug("wait complete\n");
 
        lock_policy_rwsem_write(cpu);
        if (cpufreq_driver->exit)
                cpufreq_driver->exit(data);
        unlock_policy_rwsem_write(cpu);
 
+#ifdef CONFIG_HOTPLUG_CPU
+       /* when the CPU which is the parent of the kobj is hotplugged
+        * offline, check for siblings, and create cpufreq sysfs interface
+        * and symlinks
+        */
+       if (unlikely(cpumask_weight(data->cpus) > 1)) {
+               /* first sibling now owns the new sysfs dir */
+               cpumask_clear_cpu(cpu, data->cpus);
+               cpufreq_add_dev(get_cpu_sysdev(cpumask_first(data->cpus)));
+
+               /* finally remove our own symlink */
+               lock_policy_rwsem_write(cpu);
+               __cpufreq_remove_dev(sys_dev);
+       }
+#endif
+
        free_cpumask_var(data->related_cpus);
        free_cpumask_var(data->cpus);
        kfree(data);
-       per_cpu(cpufreq_cpu_data, cpu) = NULL;
 
-       cpufreq_debug_enable_ratelimit();
        return 0;
 }
 
@@ -1239,7 +1149,7 @@ static void handle_update(struct work_struct *work)
        struct cpufreq_policy *policy =
                container_of(work, struct cpufreq_policy, update);
        unsigned int cpu = policy->cpu;
-       dprintk("handle_update for cpu %u called\n", cpu);
+       pr_debug("handle_update for cpu %u called\n", cpu);
        cpufreq_update_policy(cpu);
 }
 
@@ -1257,7 +1167,7 @@ static void cpufreq_out_of_sync(unsigned int cpu, unsigned int old_freq,
 {
        struct cpufreq_freqs freqs;
 
-       dprintk("Warning: CPU frequency out of sync: cpufreq and timing "
+       pr_debug("Warning: CPU frequency out of sync: cpufreq and timing "
               "core thinks of %u, is %u kHz.\n", old_freq, new_freq);
 
        freqs.cpu = cpu;
@@ -1360,7 +1270,7 @@ static int cpufreq_bp_suspend(void)
        int cpu = smp_processor_id();
        struct cpufreq_policy *cpu_policy;
 
-       dprintk("suspending cpu %u\n", cpu);
+       pr_debug("suspending cpu %u\n", cpu);
 
        /* If there's no policy for the boot CPU, we have nothing to do. */
        cpu_policy = cpufreq_cpu_get(cpu);
@@ -1398,7 +1308,7 @@ static void cpufreq_bp_resume(void)
        int cpu = smp_processor_id();
        struct cpufreq_policy *cpu_policy;
 
-       dprintk("resuming cpu %u\n", cpu);
+       pr_debug("resuming cpu %u\n", cpu);
 
        /* If there's no policy for the boot CPU, we have nothing to do. */
        cpu_policy = cpufreq_cpu_get(cpu);
@@ -1510,7 +1420,7 @@ int __cpufreq_driver_target(struct cpufreq_policy *policy,
 {
        int retval = -EINVAL;
 
-       dprintk("target for CPU %u: %u kHz, relation %u\n", policy->cpu,
+       pr_debug("target for CPU %u: %u kHz, relation %u\n", policy->cpu,
                target_freq, relation);
        if (cpu_online(policy->cpu) && cpufreq_driver->target)
                retval = cpufreq_driver->target(policy, target_freq, relation);
@@ -1596,7 +1506,7 @@ static int __cpufreq_governor(struct cpufreq_policy *policy,
        if (!try_module_get(policy->governor->owner))
                return -EINVAL;
 
-       dprintk("__cpufreq_governor for CPU %u, event %u\n",
+       pr_debug("__cpufreq_governor for CPU %u, event %u\n",
                                                policy->cpu, event);
        ret = policy->governor->governor(policy, event);
 
@@ -1697,8 +1607,7 @@ static int __cpufreq_set_policy(struct cpufreq_policy *data,
 {
        int ret = 0;
 
-       cpufreq_debug_disable_ratelimit();
-       dprintk("setting new policy for CPU %u: %u - %u kHz\n", policy->cpu,
+       pr_debug("setting new policy for CPU %u: %u - %u kHz\n", policy->cpu,
                policy->min, policy->max);
 
        memcpy(&policy->cpuinfo, &data->cpuinfo,
@@ -1735,19 +1644,19 @@ static int __cpufreq_set_policy(struct cpufreq_policy *data,
        data->min = policy->min;
        data->max = policy->max;
 
-       dprintk("new min and max freqs are %u - %u kHz\n",
+       pr_debug("new min and max freqs are %u - %u kHz\n",
                                        data->min, data->max);
 
        if (cpufreq_driver->setpolicy) {
                data->policy = policy->policy;
-               dprintk("setting range\n");
+               pr_debug("setting range\n");
                ret = cpufreq_driver->setpolicy(policy);
        } else {
                if (policy->governor != data->governor) {
                        /* save old, working values */
                        struct cpufreq_governor *old_gov = data->governor;
 
-                       dprintk("governor switch\n");
+                       pr_debug("governor switch\n");
 
                        /* end old governor */
                        if (data->governor)
@@ -1757,7 +1666,7 @@ static int __cpufreq_set_policy(struct cpufreq_policy *data,
                        data->governor = policy->governor;
                        if (__cpufreq_governor(data, CPUFREQ_GOV_START)) {
                                /* new governor failed, so re-start old one */
-                               dprintk("starting governor %s failed\n",
+                               pr_debug("starting governor %s failed\n",
                                                        data->governor->name);
                                if (old_gov) {
                                        data->governor = old_gov;
@@ -1769,12 +1678,11 @@ static int __cpufreq_set_policy(struct cpufreq_policy *data,
                        }
                        /* might be a policy change, too, so fall through */
                }
-               dprintk("governor: change or update limits\n");
+               pr_debug("governor: change or update limits\n");
                __cpufreq_governor(data, CPUFREQ_GOV_LIMITS);
        }
 
 error_out:
-       cpufreq_debug_enable_ratelimit();
        return ret;
 }
 
@@ -1801,7 +1709,7 @@ int cpufreq_update_policy(unsigned int cpu)
                goto fail;
        }
 
-       dprintk("updating policy for CPU %u\n", cpu);
+       pr_debug("updating policy for CPU %u\n", cpu);
        memcpy(&policy, data, sizeof(struct cpufreq_policy));
        policy.min = data->user_policy.min;
        policy.max = data->user_policy.max;
@@ -1813,7 +1721,7 @@ int cpufreq_update_policy(unsigned int cpu)
        if (cpufreq_driver->get) {
                policy.cur = cpufreq_driver->get(cpu);
                if (!data->cur) {
-                       dprintk("Driver did not initialize current freq");
+                       pr_debug("Driver did not initialize current freq");
                        data->cur = policy.cur;
                } else {
                        if (data->cur != policy.cur)
@@ -1889,7 +1797,7 @@ int cpufreq_register_driver(struct cpufreq_driver *driver_data)
            ((!driver_data->setpolicy) && (!driver_data->target)))
                return -EINVAL;
 
-       dprintk("trying to register driver %s\n", driver_data->name);
+       pr_debug("trying to register driver %s\n", driver_data->name);
 
        if (driver_data->setpolicy)
                driver_data->flags |= CPUFREQ_CONST_LOOPS;
@@ -1920,15 +1828,14 @@ int cpufreq_register_driver(struct cpufreq_driver *driver_data)
 
                /* if all ->init() calls failed, unregister */
                if (ret) {
-                       dprintk("no CPU initialized for driver %s\n",
+                       pr_debug("no CPU initialized for driver %s\n",
                                                        driver_data->name);
                        goto err_sysdev_unreg;
                }
        }
 
        register_hotcpu_notifier(&cpufreq_cpu_notifier);
-       dprintk("driver %s up and running\n", driver_data->name);
-       cpufreq_debug_enable_ratelimit();
+       pr_debug("driver %s up and running\n", driver_data->name);
 
        return 0;
 err_sysdev_unreg:
@@ -1955,14 +1862,10 @@ int cpufreq_unregister_driver(struct cpufreq_driver *driver)
 {
        unsigned long flags;
 
-       cpufreq_debug_disable_ratelimit();
-
-       if (!cpufreq_driver || (driver != cpufreq_driver)) {
-               cpufreq_debug_enable_ratelimit();
+       if (!cpufreq_driver || (driver != cpufreq_driver))
                return -EINVAL;
-       }
 
-       dprintk("unregistering driver %s\n", driver->name);
+       pr_debug("unregistering driver %s\n", driver->name);
 
        sysdev_driver_unregister(&cpu_sysdev_class, &cpufreq_sysdev_driver);
        unregister_hotcpu_notifier(&cpufreq_cpu_notifier);
index 7e2e515..f13a8a9 100644 (file)
@@ -15,9 +15,6 @@
 #include <linux/cpufreq.h>
 #include <linux/init.h>
 
-#define dprintk(msg...) \
-       cpufreq_debug_printk(CPUFREQ_DEBUG_GOVERNOR, "performance", msg)
-
 
 static int cpufreq_governor_performance(struct cpufreq_policy *policy,
                                        unsigned int event)
@@ -25,7 +22,7 @@ static int cpufreq_governor_performance(struct cpufreq_policy *policy,
        switch (event) {
        case CPUFREQ_GOV_START:
        case CPUFREQ_GOV_LIMITS:
-               dprintk("setting to %u kHz because of event %u\n",
+               pr_debug("setting to %u kHz because of event %u\n",
                                                policy->max, event);
                __cpufreq_driver_target(policy, policy->max,
                                                CPUFREQ_RELATION_H);
index e6db5fa..4c2eb51 100644 (file)
 #include <linux/cpufreq.h>
 #include <linux/init.h>
 
-#define dprintk(msg...) \
-       cpufreq_debug_printk(CPUFREQ_DEBUG_GOVERNOR, "powersave", msg)
-
 static int cpufreq_governor_powersave(struct cpufreq_policy *policy,
                                        unsigned int event)
 {
        switch (event) {
        case CPUFREQ_GOV_START:
        case CPUFREQ_GOV_LIMITS:
-               dprintk("setting to %u kHz because of event %u\n",
+               pr_debug("setting to %u kHz because of event %u\n",
                                                        policy->min, event);
                __cpufreq_driver_target(policy, policy->min,
                                                CPUFREQ_RELATION_L);
index 00d73fc..b60a4c2 100644 (file)
@@ -165,17 +165,27 @@ static int freq_table_get_index(struct cpufreq_stats *stat, unsigned int freq)
        return -1;
 }
 
+/* should be called late in the CPU removal sequence so that the stats
+ * memory is still available in case someone tries to use it.
+ */
 static void cpufreq_stats_free_table(unsigned int cpu)
 {
        struct cpufreq_stats *stat = per_cpu(cpufreq_stats_table, cpu);
-       struct cpufreq_policy *policy = cpufreq_cpu_get(cpu);
-       if (policy && policy->cpu == cpu)
-               sysfs_remove_group(&policy->kobj, &stats_attr_group);
        if (stat) {
                kfree(stat->time_in_state);
                kfree(stat);
        }
        per_cpu(cpufreq_stats_table, cpu) = NULL;
+}
+
+/* must be called early in the CPU removal sequence (before
+ * cpufreq_remove_dev) so that policy is still valid.
+ */
+static void cpufreq_stats_free_sysfs(unsigned int cpu)
+{
+       struct cpufreq_policy *policy = cpufreq_cpu_get(cpu);
+       if (policy && policy->cpu == cpu)
+               sysfs_remove_group(&policy->kobj, &stats_attr_group);
        if (policy)
                cpufreq_cpu_put(policy);
 }
@@ -316,6 +326,9 @@ static int __cpuinit cpufreq_stat_cpu_callback(struct notifier_block *nfb,
        case CPU_ONLINE_FROZEN:
                cpufreq_update_policy(cpu);
                break;
+       case CPU_DOWN_PREPARE:
+               cpufreq_stats_free_sysfs(cpu);
+               break;
        case CPU_DEAD:
        case CPU_DEAD_FROZEN:
                cpufreq_stats_free_table(cpu);
@@ -324,9 +337,10 @@ static int __cpuinit cpufreq_stat_cpu_callback(struct notifier_block *nfb,
        return NOTIFY_OK;
 }
 
-static struct notifier_block cpufreq_stat_cpu_notifier __refdata =
-{
+/* priority=1 so this will get called before cpufreq_remove_dev */
+static struct notifier_block cpufreq_stat_cpu_notifier __refdata = {
        .notifier_call = cpufreq_stat_cpu_callback,
+       .priority = 1,
 };
 
 static struct notifier_block notifier_policy_block = {
index 66d2d1d..f231015 100644 (file)
@@ -37,9 +37,6 @@ static DEFINE_PER_CPU(unsigned int, cpu_is_managed);
 static DEFINE_MUTEX(userspace_mutex);
 static int cpus_using_userspace_governor;
 
-#define dprintk(msg...) \
-       cpufreq_debug_printk(CPUFREQ_DEBUG_GOVERNOR, "userspace", msg)
-
 /* keep track of frequency transitions */
 static int
 userspace_cpufreq_notifier(struct notifier_block *nb, unsigned long val,
@@ -50,7 +47,7 @@ userspace_cpufreq_notifier(struct notifier_block *nb, unsigned long val,
        if (!per_cpu(cpu_is_managed, freq->cpu))
                return 0;
 
-       dprintk("saving cpu_cur_freq of cpu %u to be %u kHz\n",
+       pr_debug("saving cpu_cur_freq of cpu %u to be %u kHz\n",
                        freq->cpu, freq->new);
        per_cpu(cpu_cur_freq, freq->cpu) = freq->new;
 
@@ -73,7 +70,7 @@ static int cpufreq_set(struct cpufreq_policy *policy, unsigned int freq)
 {
        int ret = -EINVAL;
 
-       dprintk("cpufreq_set for cpu %u, freq %u kHz\n", policy->cpu, freq);
+       pr_debug("cpufreq_set for cpu %u, freq %u kHz\n", policy->cpu, freq);
 
        mutex_lock(&userspace_mutex);
        if (!per_cpu(cpu_is_managed, policy->cpu))
@@ -134,7 +131,7 @@ static int cpufreq_governor_userspace(struct cpufreq_policy *policy,
                per_cpu(cpu_max_freq, cpu) = policy->max;
                per_cpu(cpu_cur_freq, cpu) = policy->cur;
                per_cpu(cpu_set_freq, cpu) = policy->cur;
-               dprintk("managing cpu %u started "
+               pr_debug("managing cpu %u started "
                        "(%u - %u kHz, currently %u kHz)\n",
                                cpu,
                                per_cpu(cpu_min_freq, cpu),
@@ -156,12 +153,12 @@ static int cpufreq_governor_userspace(struct cpufreq_policy *policy,
                per_cpu(cpu_min_freq, cpu) = 0;
                per_cpu(cpu_max_freq, cpu) = 0;
                per_cpu(cpu_set_freq, cpu) = 0;
-               dprintk("managing cpu %u stopped\n", cpu);
+               pr_debug("managing cpu %u stopped\n", cpu);
                mutex_unlock(&userspace_mutex);
                break;
        case CPUFREQ_GOV_LIMITS:
                mutex_lock(&userspace_mutex);
-               dprintk("limit event for cpu %u: %u - %u kHz, "
+               pr_debug("limit event for cpu %u: %u - %u kHz, "
                        "currently %u kHz, last set to %u kHz\n",
                        cpu, policy->min, policy->max,
                        per_cpu(cpu_cur_freq, cpu),
index 0543221..90431cb 100644 (file)
@@ -14,9 +14,6 @@
 #include <linux/init.h>
 #include <linux/cpufreq.h>
 
-#define dprintk(msg...) \
-       cpufreq_debug_printk(CPUFREQ_DEBUG_CORE, "freq-table", msg)
-
 /*********************************************************************
  *                     FREQUENCY TABLE HELPERS                       *
  *********************************************************************/
@@ -31,11 +28,11 @@ int cpufreq_frequency_table_cpuinfo(struct cpufreq_policy *policy,
        for (i = 0; (table[i].frequency != CPUFREQ_TABLE_END); i++) {
                unsigned int freq = table[i].frequency;
                if (freq == CPUFREQ_ENTRY_INVALID) {
-                       dprintk("table entry %u is invalid, skipping\n", i);
+                       pr_debug("table entry %u is invalid, skipping\n", i);
 
                        continue;
                }
-               dprintk("table entry %u: %u kHz, %u index\n",
+               pr_debug("table entry %u: %u kHz, %u index\n",
                                        i, freq, table[i].index);
                if (freq < min_freq)
                        min_freq = freq;
@@ -61,7 +58,7 @@ int cpufreq_frequency_table_verify(struct cpufreq_policy *policy,
        unsigned int i;
        unsigned int count = 0;
 
-       dprintk("request for verification of policy (%u - %u kHz) for cpu %u\n",
+       pr_debug("request for verification of policy (%u - %u kHz) for cpu %u\n",
                                        policy->min, policy->max, policy->cpu);
 
        if (!cpu_online(policy->cpu))
@@ -86,7 +83,7 @@ int cpufreq_frequency_table_verify(struct cpufreq_policy *policy,
        cpufreq_verify_within_limits(policy, policy->cpuinfo.min_freq,
                                     policy->cpuinfo.max_freq);
 
-       dprintk("verification lead to (%u - %u kHz) for cpu %u\n",
+       pr_debug("verification lead to (%u - %u kHz) for cpu %u\n",
                                policy->min, policy->max, policy->cpu);
 
        return 0;
@@ -110,7 +107,7 @@ int cpufreq_frequency_table_target(struct cpufreq_policy *policy,
        };
        unsigned int i;
 
-       dprintk("request for target %u kHz (relation: %u) for cpu %u\n",
+       pr_debug("request for target %u kHz (relation: %u) for cpu %u\n",
                                        target_freq, relation, policy->cpu);
 
        switch (relation) {
@@ -167,7 +164,7 @@ int cpufreq_frequency_table_target(struct cpufreq_policy *policy,
        } else
                *index = optimal.index;
 
-       dprintk("target is %u (%u kHz, %u)\n", *index, table[*index].frequency,
+       pr_debug("target is %u (%u kHz, %u)\n", *index, table[*index].frequency,
                table[*index].index);
 
        return 0;
@@ -216,14 +213,14 @@ EXPORT_SYMBOL_GPL(cpufreq_freq_attr_scaling_available_freqs);
 void cpufreq_frequency_table_get_attr(struct cpufreq_frequency_table *table,
                                      unsigned int cpu)
 {
-       dprintk("setting show_table for cpu %u to %p\n", cpu, table);
+       pr_debug("setting show_table for cpu %u to %p\n", cpu, table);
        per_cpu(cpufreq_show_table, cpu) = table;
 }
 EXPORT_SYMBOL_GPL(cpufreq_frequency_table_get_attr);
 
 void cpufreq_frequency_table_put_attr(unsigned int cpu)
 {
-       dprintk("clearing show_table for cpu %u\n", cpu);
+       pr_debug("clearing show_table for cpu %u\n", cpu);
        per_cpu(cpufreq_show_table, cpu) = NULL;
 }
 EXPORT_SYMBOL_GPL(cpufreq_frequency_table_put_attr);
similarity index 95%
rename from arch/x86/kernel/cpu/cpufreq/gx-suspmod.c
rename to drivers/cpufreq/gx-suspmod.c
index 32974cf..ffe1f2c 100644 (file)
@@ -142,9 +142,6 @@ module_param(max_duration, int, 0444);
 #define POLICY_MIN_DIV 20
 
 
-#define dprintk(msg...) cpufreq_debug_printk(CPUFREQ_DEBUG_DRIVER, \
-               "gx-suspmod", msg)
-
 /**
  * we can detect a core multipiler from dir0_lsb
  * from GX1 datasheet p.56,
@@ -191,7 +188,7 @@ static __init struct pci_dev *gx_detect_chipset(void)
        /* check if CPU is a MediaGX or a Geode. */
        if ((boot_cpu_data.x86_vendor != X86_VENDOR_NSC) &&
            (boot_cpu_data.x86_vendor != X86_VENDOR_CYRIX)) {
-               dprintk("error: no MediaGX/Geode processor found!\n");
+               pr_debug("error: no MediaGX/Geode processor found!\n");
                return NULL;
        }
 
@@ -201,7 +198,7 @@ static __init struct pci_dev *gx_detect_chipset(void)
                        return gx_pci;
        }
 
-       dprintk("error: no supported chipset found!\n");
+       pr_debug("error: no supported chipset found!\n");
        return NULL;
 }
 
@@ -305,14 +302,14 @@ static void gx_set_cpuspeed(unsigned int khz)
                        break;
                default:
                        local_irq_restore(flags);
-                       dprintk("fatal: try to set unknown chipset.\n");
+                       pr_debug("fatal: try to set unknown chipset.\n");
                        return;
                }
        } else {
                suscfg = gx_params->pci_suscfg & ~(SUSMOD);
                gx_params->off_duration = 0;
                gx_params->on_duration = 0;
-               dprintk("suspend modulation disabled: cpu runs 100%% speed.\n");
+               pr_debug("suspend modulation disabled: cpu runs 100%% speed.\n");
        }
 
        gx_write_byte(PCI_MODOFF, gx_params->off_duration);
@@ -327,9 +324,9 @@ static void gx_set_cpuspeed(unsigned int khz)
 
        cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
 
-       dprintk("suspend modulation w/ duration of ON:%d us, OFF:%d us\n",
+       pr_debug("suspend modulation w/ duration of ON:%d us, OFF:%d us\n",
                gx_params->on_duration * 32, gx_params->off_duration * 32);
-       dprintk("suspend modulation w/ clock speed: %d kHz.\n", freqs.new);
+       pr_debug("suspend modulation w/ clock speed: %d kHz.\n", freqs.new);
 }
 
 /****************************************************************
@@ -428,8 +425,8 @@ static int cpufreq_gx_cpu_init(struct cpufreq_policy *policy)
        stock_freq = maxfreq;
        curfreq = gx_get_cpuspeed(0);
 
-       dprintk("cpu max frequency is %d.\n", maxfreq);
-       dprintk("cpu current frequency is %dkHz.\n", curfreq);
+       pr_debug("cpu max frequency is %d.\n", maxfreq);
+       pr_debug("cpu current frequency is %dkHz.\n", curfreq);
 
        /* setup basic struct for cpufreq API */
        policy->cpu = 0;
@@ -475,7 +472,7 @@ static int __init cpufreq_gx_init(void)
        if (max_duration > 0xff)
                max_duration = 0xff;
 
-       dprintk("geode suspend modulation available.\n");
+       pr_debug("geode suspend modulation available.\n");
 
        params = kzalloc(sizeof(struct gxfreq_params), GFP_KERNEL);
        if (params == NULL)
similarity index 98%
rename from arch/x86/kernel/cpu/cpufreq/longhaul.c
rename to drivers/cpufreq/longhaul.c
index cf48cdd..f47d26e 100644 (file)
@@ -77,9 +77,6 @@ static int scale_voltage;
 static int disable_acpi_c3;
 static int revid_errata;
 
-#define dprintk(msg...) cpufreq_debug_printk(CPUFREQ_DEBUG_DRIVER, \
-               "longhaul", msg)
-
 
 /* Clock ratios multiplied by 10 */
 static int mults[32];
@@ -87,7 +84,6 @@ static int eblcr[32];
 static int longhaul_version;
 static struct cpufreq_frequency_table *longhaul_table;
 
-#ifdef CONFIG_CPU_FREQ_DEBUG
 static char speedbuffer[8];
 
 static char *print_speed(int speed)
@@ -106,7 +102,6 @@ static char *print_speed(int speed)
 
        return speedbuffer;
 }
-#endif
 
 
 static unsigned int calc_speed(int mult)
@@ -275,7 +270,7 @@ static void longhaul_setstate(unsigned int table_index)
 
        cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
 
-       dprintk("Setting to FSB:%dMHz Mult:%d.%dx (%s)\n",
+       pr_debug("Setting to FSB:%dMHz Mult:%d.%dx (%s)\n",
                        fsb, mult/10, mult%10, print_speed(speed/1000));
 retry_loop:
        preempt_disable();
@@ -460,12 +455,12 @@ static int __cpuinit longhaul_get_ranges(void)
                break;
        }
 
-       dprintk("MinMult:%d.%dx MaxMult:%d.%dx\n",
+       pr_debug("MinMult:%d.%dx MaxMult:%d.%dx\n",
                 minmult/10, minmult%10, maxmult/10, maxmult%10);
 
        highest_speed = calc_speed(maxmult);
        lowest_speed = calc_speed(minmult);
-       dprintk("FSB:%dMHz  Lowest speed: %s   Highest speed:%s\n", fsb,
+       pr_debug("FSB:%dMHz  Lowest speed: %s   Highest speed:%s\n", fsb,
                 print_speed(lowest_speed/1000),
                 print_speed(highest_speed/1000));
 
similarity index 94%
rename from arch/x86/kernel/cpu/cpufreq/longrun.c
rename to drivers/cpufreq/longrun.c
index d9f5136..34ea359 100644 (file)
@@ -15,9 +15,6 @@
 #include <asm/msr.h>
 #include <asm/processor.h>
 
-#define dprintk(msg...) cpufreq_debug_printk(CPUFREQ_DEBUG_DRIVER, \
-               "longrun", msg)
-
 static struct cpufreq_driver   longrun_driver;
 
 /**
@@ -40,14 +37,14 @@ static void __cpuinit longrun_get_policy(struct cpufreq_policy *policy)
        u32 msr_lo, msr_hi;
 
        rdmsr(MSR_TMTA_LONGRUN_FLAGS, msr_lo, msr_hi);
-       dprintk("longrun flags are %x - %x\n", msr_lo, msr_hi);
+       pr_debug("longrun flags are %x - %x\n", msr_lo, msr_hi);
        if (msr_lo & 0x01)
                policy->policy = CPUFREQ_POLICY_PERFORMANCE;
        else
                policy->policy = CPUFREQ_POLICY_POWERSAVE;
 
        rdmsr(MSR_TMTA_LONGRUN_CTRL, msr_lo, msr_hi);
-       dprintk("longrun ctrl is %x - %x\n", msr_lo, msr_hi);
+       pr_debug("longrun ctrl is %x - %x\n", msr_lo, msr_hi);
        msr_lo &= 0x0000007F;
        msr_hi &= 0x0000007F;
 
@@ -150,7 +147,7 @@ static unsigned int longrun_get(unsigned int cpu)
                return 0;
 
        cpuid(0x80860007, &eax, &ebx, &ecx, &edx);
-       dprintk("cpuid eax is %u\n", eax);
+       pr_debug("cpuid eax is %u\n", eax);
 
        return eax * 1000;
 }
@@ -196,7 +193,7 @@ static int __cpuinit longrun_determine_freqs(unsigned int *low_freq,
                rdmsr(MSR_TMTA_LRTI_VOLT_MHZ, msr_lo, msr_hi);
                *high_freq = msr_lo * 1000; /* to kHz */
 
-               dprintk("longrun table interface told %u - %u kHz\n",
+               pr_debug("longrun table interface told %u - %u kHz\n",
                                *low_freq, *high_freq);
 
                if (*low_freq > *high_freq)
@@ -207,7 +204,7 @@ static int __cpuinit longrun_determine_freqs(unsigned int *low_freq,
        /* set the upper border to the value determined during TSC init */
        *high_freq = (cpu_khz / 1000);
        *high_freq = *high_freq * 1000;
-       dprintk("high frequency is %u kHz\n", *high_freq);
+       pr_debug("high frequency is %u kHz\n", *high_freq);
 
        /* get current borders */
        rdmsr(MSR_TMTA_LONGRUN_CTRL, msr_lo, msr_hi);
@@ -233,7 +230,7 @@ static int __cpuinit longrun_determine_freqs(unsigned int *low_freq,
                /* restore values */
                wrmsr(MSR_TMTA_LONGRUN_CTRL, save_lo, save_hi);
        }
-       dprintk("percentage is %u %%, freq is %u MHz\n", ecx, eax);
+       pr_debug("percentage is %u %%, freq is %u MHz\n", ecx, eax);
 
        /* performance_pctg = (current_freq - low_freq)/(high_freq - low_freq)
         * eqals
@@ -249,7 +246,7 @@ static int __cpuinit longrun_determine_freqs(unsigned int *low_freq,
        edx = ((eax - ebx) * 100) / (100 - ecx);
        *low_freq = edx * 1000; /* back to kHz */
 
-       dprintk("low frequency is %u kHz\n", *low_freq);
+       pr_debug("low frequency is %u kHz\n", *low_freq);
 
        if (*low_freq > *high_freq)
                *low_freq = *high_freq;
similarity index 96%
rename from arch/x86/kernel/cpu/cpufreq/p4-clockmod.c
rename to drivers/cpufreq/p4-clockmod.c
index 52c9364..6be3e07 100644 (file)
@@ -35,8 +35,6 @@
 #include "speedstep-lib.h"
 
 #define PFX    "p4-clockmod: "
-#define dprintk(msg...) cpufreq_debug_printk(CPUFREQ_DEBUG_DRIVER, \
-               "p4-clockmod", msg)
 
 /*
  * Duty Cycle (3bits), note DC_DISABLE is not specified in
@@ -66,7 +64,7 @@ static int cpufreq_p4_setdc(unsigned int cpu, unsigned int newstate)
        rdmsr_on_cpu(cpu, MSR_IA32_THERM_STATUS, &l, &h);
 
        if (l & 0x01)
-               dprintk("CPU#%d currently thermal throttled\n", cpu);
+               pr_debug("CPU#%d currently thermal throttled\n", cpu);
 
        if (has_N44_O17_errata[cpu] &&
            (newstate == DC_25PT || newstate == DC_DFLT))
@@ -74,10 +72,10 @@ static int cpufreq_p4_setdc(unsigned int cpu, unsigned int newstate)
 
        rdmsr_on_cpu(cpu, MSR_IA32_THERM_CONTROL, &l, &h);
        if (newstate == DC_DISABLE) {
-               dprintk("CPU#%d disabling modulation\n", cpu);
+               pr_debug("CPU#%d disabling modulation\n", cpu);
                wrmsr_on_cpu(cpu, MSR_IA32_THERM_CONTROL, l & ~(1<<4), h);
        } else {
-               dprintk("CPU#%d setting duty cycle to %d%%\n",
+               pr_debug("CPU#%d setting duty cycle to %d%%\n",
                        cpu, ((125 * newstate) / 10));
                /* bits 63 - 5  : reserved
                 * bit  4       : enable/disable
@@ -217,7 +215,7 @@ static int cpufreq_p4_cpu_init(struct cpufreq_policy *policy)
        case 0x0f11:
        case 0x0f12:
                has_N44_O17_errata[policy->cpu] = 1;
-               dprintk("has errata -- disabling low frequencies\n");
+               pr_debug("has errata -- disabling low frequencies\n");
        }
 
        if (speedstep_detect_processor() == SPEEDSTEP_CPU_P4D &&
similarity index 91%
rename from arch/x86/kernel/cpu/cpufreq/pcc-cpufreq.c
rename to drivers/cpufreq/pcc-cpufreq.c
index 755a31e..7b0603e 100644 (file)
@@ -39,7 +39,7 @@
 
 #include <acpi/processor.h>
 
-#define PCC_VERSION    "1.00.00"
+#define PCC_VERSION    "1.10.00"
 #define POLL_LOOPS     300
 
 #define CMD_COMPLETE   0x1
@@ -48,9 +48,6 @@
 
 #define BUF_SZ         4
 
-#define dprintk(msg...) cpufreq_debug_printk(CPUFREQ_DEBUG_DRIVER,     \
-                                            "pcc-cpufreq", msg)
-
 struct pcc_register_resource {
        u8 descriptor;
        u16 length;
@@ -102,7 +99,7 @@ static struct acpi_generic_address doorbell;
 static u64 doorbell_preserve;
 static u64 doorbell_write;
 
-static u8 OSC_UUID[16] = {0x63, 0x9B, 0x2C, 0x9F, 0x70, 0x91, 0x49, 0x1f,
+static u8 OSC_UUID[16] = {0x9F, 0x2C, 0x9B, 0x63, 0x91, 0x70, 0x1f, 0x49,
                          0xBB, 0x4F, 0xA5, 0x98, 0x2F, 0xA1, 0xB5, 0x46};
 
 struct pcc_cpu {
@@ -152,7 +149,7 @@ static unsigned int pcc_get_freq(unsigned int cpu)
 
        spin_lock(&pcc_lock);
 
-       dprintk("get: get_freq for CPU %d\n", cpu);
+       pr_debug("get: get_freq for CPU %d\n", cpu);
        pcc_cpu_data = per_cpu_ptr(pcc_cpu_info, cpu);
 
        input_buffer = 0x1;
@@ -170,7 +167,7 @@ static unsigned int pcc_get_freq(unsigned int cpu)
 
        status = ioread16(&pcch_hdr->status);
        if (status != CMD_COMPLETE) {
-               dprintk("get: FAILED: for CPU %d, status is %d\n",
+               pr_debug("get: FAILED: for CPU %d, status is %d\n",
                        cpu, status);
                goto cmd_incomplete;
        }
@@ -178,14 +175,14 @@ static unsigned int pcc_get_freq(unsigned int cpu)
        curr_freq = (((ioread32(&pcch_hdr->nominal) * (output_buffer & 0xff))
                        / 100) * 1000);
 
-       dprintk("get: SUCCESS: (virtual) output_offset for cpu %d is "
-               "0x%x, contains a value of: 0x%x. Speed is: %d MHz\n",
+       pr_debug("get: SUCCESS: (virtual) output_offset for cpu %d is "
+               "0x%p, contains a value of: 0x%x. Speed is: %d MHz\n",
                cpu, (pcch_virt_addr + pcc_cpu_data->output_offset),
                output_buffer, curr_freq);
 
        freq_limit = (output_buffer >> 8) & 0xff;
        if (freq_limit != 0xff) {
-               dprintk("get: frequency for cpu %d is being temporarily"
+               pr_debug("get: frequency for cpu %d is being temporarily"
                        " capped at %d\n", cpu, curr_freq);
        }
 
@@ -212,8 +209,8 @@ static int pcc_cpufreq_target(struct cpufreq_policy *policy,
        cpu = policy->cpu;
        pcc_cpu_data = per_cpu_ptr(pcc_cpu_info, cpu);
 
-       dprintk("target: CPU %d should go to target freq: %d "
-               "(virtual) input_offset is 0x%x\n",
+       pr_debug("target: CPU %d should go to target freq: %d "
+               "(virtual) input_offset is 0x%p\n",
                cpu, target_freq,
                (pcch_virt_addr + pcc_cpu_data->input_offset));
 
@@ -234,14 +231,14 @@ static int pcc_cpufreq_target(struct cpufreq_policy *policy,
 
        status = ioread16(&pcch_hdr->status);
        if (status != CMD_COMPLETE) {
-               dprintk("target: FAILED for cpu %d, with status: 0x%x\n",
+               pr_debug("target: FAILED for cpu %d, with status: 0x%x\n",
                        cpu, status);
                goto cmd_incomplete;
        }
        iowrite16(0, &pcch_hdr->status);
 
        cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
-       dprintk("target: was SUCCESSFUL for cpu %d\n", cpu);
+       pr_debug("target: was SUCCESSFUL for cpu %d\n", cpu);
        spin_unlock(&pcc_lock);
 
        return 0;
@@ -293,7 +290,7 @@ static int pcc_get_offset(int cpu)
        memset_io((pcch_virt_addr + pcc_cpu_data->input_offset), 0, BUF_SZ);
        memset_io((pcch_virt_addr + pcc_cpu_data->output_offset), 0, BUF_SZ);
 
-       dprintk("pcc_get_offset: for CPU %d: pcc_cpu_data "
+       pr_debug("pcc_get_offset: for CPU %d: pcc_cpu_data "
                "input_offset: 0x%x, pcc_cpu_data output_offset: 0x%x\n",
                cpu, pcc_cpu_data->input_offset, pcc_cpu_data->output_offset);
 out_free:
@@ -410,7 +407,7 @@ static int __init pcc_cpufreq_probe(void)
        if (ACPI_SUCCESS(status)) {
                ret = pcc_cpufreq_do_osc(&osc_handle);
                if (ret)
-                       dprintk("probe: _OSC evaluation did not succeed\n");
+                       pr_debug("probe: _OSC evaluation did not succeed\n");
                /* Firmware's use of _OSC is optional */
                ret = 0;
        }
@@ -433,7 +430,7 @@ static int __init pcc_cpufreq_probe(void)
 
        mem_resource = (struct pcc_memory_resource *)member->buffer.pointer;
 
-       dprintk("probe: mem_resource descriptor: 0x%x,"
+       pr_debug("probe: mem_resource descriptor: 0x%x,"
                " length: %d, space_id: %d, resource_usage: %d,"
                " type_specific: %d, granularity: 0x%llx,"
                " minimum: 0x%llx, maximum: 0x%llx,"
@@ -453,13 +450,13 @@ static int __init pcc_cpufreq_probe(void)
        pcch_virt_addr = ioremap_nocache(mem_resource->minimum,
                                        mem_resource->address_length);
        if (pcch_virt_addr == NULL) {
-               dprintk("probe: could not map shared mem region\n");
+               pr_debug("probe: could not map shared mem region\n");
                goto out_free;
        }
        pcch_hdr = pcch_virt_addr;
 
-       dprintk("probe: PCCH header (virtual) addr: 0x%p\n", pcch_hdr);
-       dprintk("probe: PCCH header is at physical address: 0x%llx,"
+       pr_debug("probe: PCCH header (virtual) addr: 0x%p\n", pcch_hdr);
+       pr_debug("probe: PCCH header is at physical address: 0x%llx,"
                " signature: 0x%x, length: %d bytes, major: %d, minor: %d,"
                " supported features: 0x%x, command field: 0x%x,"
                " status field: 0x%x, nominal latency: %d us\n",
@@ -469,7 +466,7 @@ static int __init pcc_cpufreq_probe(void)
                ioread16(&pcch_hdr->command), ioread16(&pcch_hdr->status),
                ioread32(&pcch_hdr->latency));
 
-       dprintk("probe: min time between commands: %d us,"
+       pr_debug("probe: min time between commands: %d us,"
                " max time between commands: %d us,"
                " nominal CPU frequency: %d MHz,"
                " minimum CPU frequency: %d MHz,"
@@ -494,7 +491,7 @@ static int __init pcc_cpufreq_probe(void)
        doorbell.access_width = 64;
        doorbell.address = reg_resource->address;
 
-       dprintk("probe: doorbell: space_id is %d, bit_width is %d, "
+       pr_debug("probe: doorbell: space_id is %d, bit_width is %d, "
                "bit_offset is %d, access_width is %d, address is 0x%llx\n",
                doorbell.space_id, doorbell.bit_width, doorbell.bit_offset,
                doorbell.access_width, reg_resource->address);
@@ -515,7 +512,7 @@ static int __init pcc_cpufreq_probe(void)
 
        doorbell_write = member->integer.value;
 
-       dprintk("probe: doorbell_preserve: 0x%llx,"
+       pr_debug("probe: doorbell_preserve: 0x%llx,"
                " doorbell_write: 0x%llx\n",
                doorbell_preserve, doorbell_write);
 
@@ -550,7 +547,7 @@ static int pcc_cpufreq_cpu_init(struct cpufreq_policy *policy)
 
        result = pcc_get_offset(cpu);
        if (result) {
-               dprintk("init: PCCP evaluation failed\n");
+               pr_debug("init: PCCP evaluation failed\n");
                goto out;
        }
 
@@ -561,12 +558,12 @@ static int pcc_cpufreq_cpu_init(struct cpufreq_policy *policy)
        policy->cur = pcc_get_freq(cpu);
 
        if (!policy->cur) {
-               dprintk("init: Unable to get current CPU frequency\n");
+               pr_debug("init: Unable to get current CPU frequency\n");
                result = -EINVAL;
                goto out;
        }
 
-       dprintk("init: policy->max is %d, policy->min is %d\n",
+       pr_debug("init: policy->max is %d, policy->min is %d\n",
                policy->max, policy->min);
 out:
        return result;
@@ -597,7 +594,7 @@ static int __init pcc_cpufreq_init(void)
 
        ret = pcc_cpufreq_probe();
        if (ret) {
-               dprintk("pcc_cpufreq_init: PCCH evaluation failed\n");
+               pr_debug("pcc_cpufreq_init: PCCH evaluation failed\n");
                return ret;
        }
 
similarity index 95%
rename from arch/x86/kernel/cpu/cpufreq/powernow-k7.c
rename to drivers/cpufreq/powernow-k7.c
index 4a45fd6..d71d9f3 100644 (file)
@@ -68,7 +68,6 @@ union powernow_acpi_control_t {
 };
 #endif
 
-#ifdef CONFIG_CPU_FREQ_DEBUG
 /* divide by 1000 to get VCore voltage in V. */
 static const int mobile_vid_table[32] = {
     2000, 1950, 1900, 1850, 1800, 1750, 1700, 1650,
@@ -76,7 +75,6 @@ static const int mobile_vid_table[32] = {
     1275, 1250, 1225, 1200, 1175, 1150, 1125, 1100,
     1075, 1050, 1025, 1000, 975, 950, 925, 0,
 };
-#endif
 
 /* divide by 10 to get FID. */
 static const int fid_codes[32] = {
@@ -103,9 +101,6 @@ static unsigned int fsb;
 static unsigned int latency;
 static char have_a0;
 
-#define dprintk(msg...) cpufreq_debug_printk(CPUFREQ_DEBUG_DRIVER, \
-               "powernow-k7", msg)
-
 static int check_fsb(unsigned int fsbspeed)
 {
        int delta;
@@ -209,7 +204,7 @@ static int get_ranges(unsigned char *pst)
                vid = *pst++;
                powernow_table[j].index |= (vid << 8); /* upper 8 bits */
 
-               dprintk("   FID: 0x%x (%d.%dx [%dMHz])  "
+               pr_debug("   FID: 0x%x (%d.%dx [%dMHz])  "
                         "VID: 0x%x (%d.%03dV)\n", fid, fid_codes[fid] / 10,
                         fid_codes[fid] % 10, speed/1000, vid,
                         mobile_vid_table[vid]/1000,
@@ -367,7 +362,7 @@ static int powernow_acpi_init(void)
                unsigned int speed, speed_mhz;
 
                pc.val = (unsigned long) state->control;
-               dprintk("acpi:  P%d: %d MHz %d mW %d uS control %08x SGTC %d\n",
+               pr_debug("acpi:  P%d: %d MHz %d mW %d uS control %08x SGTC %d\n",
                         i,
                         (u32) state->core_frequency,
                         (u32) state->power,
@@ -401,7 +396,7 @@ static int powernow_acpi_init(void)
                                invalidate_entry(i);
                }
 
-               dprintk("   FID: 0x%x (%d.%dx [%dMHz])  "
+               pr_debug("   FID: 0x%x (%d.%dx [%dMHz])  "
                         "VID: 0x%x (%d.%03dV)\n", fid, fid_codes[fid] / 10,
                         fid_codes[fid] % 10, speed_mhz, vid,
                         mobile_vid_table[vid]/1000,
@@ -409,7 +404,7 @@ static int powernow_acpi_init(void)
 
                if (state->core_frequency != speed_mhz) {
                        state->core_frequency = speed_mhz;
-                       dprintk("   Corrected ACPI frequency to %d\n",
+                       pr_debug("   Corrected ACPI frequency to %d\n",
                                speed_mhz);
                }
 
@@ -453,8 +448,8 @@ static int powernow_acpi_init(void)
 
 static void print_pst_entry(struct pst_s *pst, unsigned int j)
 {
-       dprintk("PST:%d (@%p)\n", j, pst);
-       dprintk(" cpuid: 0x%x  fsb: %d  maxFID: 0x%x  startvid: 0x%x\n",
+       pr_debug("PST:%d (@%p)\n", j, pst);
+       pr_debug(" cpuid: 0x%x  fsb: %d  maxFID: 0x%x  startvid: 0x%x\n",
                pst->cpuid, pst->fsbspeed, pst->maxfid, pst->startvid);
 }
 
@@ -474,20 +469,20 @@ static int powernow_decode_bios(int maxfid, int startvid)
                p = phys_to_virt(i);
 
                if (memcmp(p, "AMDK7PNOW!",  10) == 0) {
-                       dprintk("Found PSB header at %p\n", p);
+                       pr_debug("Found PSB header at %p\n", p);
                        psb = (struct psb_s *) p;
-                       dprintk("Table version: 0x%x\n", psb->tableversion);
+                       pr_debug("Table version: 0x%x\n", psb->tableversion);
                        if (psb->tableversion != 0x12) {
                                printk(KERN_INFO PFX "Sorry, only v1.2 tables"
                                                " supported right now\n");
                                return -ENODEV;
                        }
 
-                       dprintk("Flags: 0x%x\n", psb->flags);
+                       pr_debug("Flags: 0x%x\n", psb->flags);
                        if ((psb->flags & 1) == 0)
-                               dprintk("Mobile voltage regulator\n");
+                               pr_debug("Mobile voltage regulator\n");
                        else
-                               dprintk("Desktop voltage regulator\n");
+                               pr_debug("Desktop voltage regulator\n");
 
                        latency = psb->settlingtime;
                        if (latency < 100) {
@@ -497,9 +492,9 @@ static int powernow_decode_bios(int maxfid, int startvid)
                                                "Correcting.\n", latency);
                                latency = 100;
                        }
-                       dprintk("Settling Time: %d microseconds.\n",
+                       pr_debug("Settling Time: %d microseconds.\n",
                                        psb->settlingtime);
-                       dprintk("Has %d PST tables. (Only dumping ones "
+                       pr_debug("Has %d PST tables. (Only dumping ones "
                                        "relevant to this CPU).\n",
                                        psb->numpst);
 
@@ -650,7 +645,7 @@ static int __cpuinit powernow_cpu_init(struct cpufreq_policy *policy)
                printk(KERN_WARNING PFX "can not determine bus frequency\n");
                return -EINVAL;
        }
-       dprintk("FSB: %3dMHz\n", fsb/1000);
+       pr_debug("FSB: %3dMHz\n", fsb/1000);
 
        if (dmi_check_system(powernow_dmi_table) || acpi_force) {
                printk(KERN_INFO PFX "PSB/PST known to be broken.  "
similarity index 93%
rename from arch/x86/kernel/cpu/cpufreq/powernow-k8.c
rename to drivers/cpufreq/powernow-k8.c
index 2368e38..83479b6 100644 (file)
@@ -139,7 +139,7 @@ static int query_current_values_with_pending_wait(struct powernow_k8_data *data)
        }
        do {
                if (i++ > 10000) {
-                       dprintk("detected change pending stuck\n");
+                       pr_debug("detected change pending stuck\n");
                        return 1;
                }
                rdmsr(MSR_FIDVID_STATUS, lo, hi);
@@ -176,7 +176,7 @@ static void fidvid_msr_init(void)
        fid = lo & MSR_S_LO_CURRENT_FID;
        lo = fid | (vid << MSR_C_LO_VID_SHIFT);
        hi = MSR_C_HI_STP_GNT_BENIGN;
-       dprintk("cpu%d, init lo 0x%x, hi 0x%x\n", smp_processor_id(), lo, hi);
+       pr_debug("cpu%d, init lo 0x%x, hi 0x%x\n", smp_processor_id(), lo, hi);
        wrmsr(MSR_FIDVID_CTL, lo, hi);
 }
 
@@ -196,7 +196,7 @@ static int write_new_fid(struct powernow_k8_data *data, u32 fid)
        lo |= (data->currvid << MSR_C_LO_VID_SHIFT);
        lo |= MSR_C_LO_INIT_FID_VID;
 
-       dprintk("writing fid 0x%x, lo 0x%x, hi 0x%x\n",
+       pr_debug("writing fid 0x%x, lo 0x%x, hi 0x%x\n",
                fid, lo, data->plllock * PLL_LOCK_CONVERSION);
 
        do {
@@ -244,7 +244,7 @@ static int write_new_vid(struct powernow_k8_data *data, u32 vid)
        lo |= (vid << MSR_C_LO_VID_SHIFT);
        lo |= MSR_C_LO_INIT_FID_VID;
 
-       dprintk("writing vid 0x%x, lo 0x%x, hi 0x%x\n",
+       pr_debug("writing vid 0x%x, lo 0x%x, hi 0x%x\n",
                vid, lo, STOP_GRANT_5NS);
 
        do {
@@ -325,7 +325,7 @@ static int transition_fid_vid(struct powernow_k8_data *data,
                return 1;
        }
 
-       dprintk("transitioned (cpu%d): new fid 0x%x, vid 0x%x\n",
+       pr_debug("transitioned (cpu%d): new fid 0x%x, vid 0x%x\n",
                smp_processor_id(), data->currfid, data->currvid);
 
        return 0;
@@ -339,7 +339,7 @@ static int core_voltage_pre_transition(struct powernow_k8_data *data,
        u32 savefid = data->currfid;
        u32 maxvid, lo, rvomult = 1;
 
-       dprintk("ph1 (cpu%d): start, currfid 0x%x, currvid 0x%x, "
+       pr_debug("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);
@@ -349,12 +349,12 @@ static int core_voltage_pre_transition(struct powernow_k8_data *data,
        rvosteps *= rvomult;
        rdmsr(MSR_FIDVID_STATUS, lo, maxvid);
        maxvid = 0x1f & (maxvid >> 16);
-       dprintk("ph1 maxvid=0x%x\n", maxvid);
+       pr_debug("ph1 maxvid=0x%x\n", maxvid);
        if (reqvid < maxvid) /* lower numbers are higher voltages */
                reqvid = maxvid;
 
        while (data->currvid > reqvid) {
-               dprintk("ph1: curr 0x%x, req vid 0x%x\n",
+               pr_debug("ph1: curr 0x%x, req vid 0x%x\n",
                        data->currvid, reqvid);
                if (decrease_vid_code_by_step(data, reqvid, data->vidmvs))
                        return 1;
@@ -365,7 +365,7 @@ static int core_voltage_pre_transition(struct powernow_k8_data *data,
                if (data->currvid == maxvid) {
                        rvosteps = 0;
                } else {
-                       dprintk("ph1: changing vid for rvo, req 0x%x\n",
+                       pr_debug("ph1: changing vid for rvo, req 0x%x\n",
                                data->currvid - 1);
                        if (decrease_vid_code_by_step(data, data->currvid-1, 1))
                                return 1;
@@ -382,7 +382,7 @@ static int core_voltage_pre_transition(struct powernow_k8_data *data,
                return 1;
        }
 
-       dprintk("ph1 complete, currfid 0x%x, currvid 0x%x\n",
+       pr_debug("ph1 complete, currfid 0x%x, currvid 0x%x\n",
                data->currfid, data->currvid);
 
        return 0;
@@ -400,7 +400,7 @@ static int core_frequency_transition(struct powernow_k8_data *data, u32 reqfid)
                return 0;
        }
 
-       dprintk("ph2 (cpu%d): starting, currfid 0x%x, currvid 0x%x, "
+       pr_debug("ph2 (cpu%d): starting, currfid 0x%x, currvid 0x%x, "
                "reqfid 0x%x\n",
                smp_processor_id(),
                data->currfid, data->currvid, reqfid);
@@ -457,7 +457,7 @@ static int core_frequency_transition(struct powernow_k8_data *data, u32 reqfid)
                return 1;
        }
 
-       dprintk("ph2 complete, currfid 0x%x, currvid 0x%x\n",
+       pr_debug("ph2 complete, currfid 0x%x, currvid 0x%x\n",
                data->currfid, data->currvid);
 
        return 0;
@@ -470,7 +470,7 @@ static int core_voltage_post_transition(struct powernow_k8_data *data,
        u32 savefid = data->currfid;
        u32 savereqvid = reqvid;
 
-       dprintk("ph3 (cpu%d): starting, currfid 0x%x, currvid 0x%x\n",
+       pr_debug("ph3 (cpu%d): starting, currfid 0x%x, currvid 0x%x\n",
                smp_processor_id(),
                data->currfid, data->currvid);
 
@@ -498,17 +498,17 @@ static int core_voltage_post_transition(struct powernow_k8_data *data,
                return 1;
 
        if (savereqvid != data->currvid) {
-               dprintk("ph3 failed, currvid 0x%x\n", data->currvid);
+               pr_debug("ph3 failed, currvid 0x%x\n", data->currvid);
                return 1;
        }
 
        if (savefid != data->currfid) {
-               dprintk("ph3 failed, currfid changed 0x%x\n",
+               pr_debug("ph3 failed, currfid changed 0x%x\n",
                        data->currfid);
                return 1;
        }
 
-       dprintk("ph3 complete, currfid 0x%x, currvid 0x%x\n",
+       pr_debug("ph3 complete, currfid 0x%x, currvid 0x%x\n",
                data->currfid, data->currvid);
 
        return 0;
@@ -707,7 +707,7 @@ static int fill_powernow_table(struct powernow_k8_data *data,
                return -EIO;
        }
 
-       dprintk("cfid 0x%x, cvid 0x%x\n", data->currfid, data->currvid);
+       pr_debug("cfid 0x%x, cvid 0x%x\n", data->currfid, data->currvid);
        data->powernow_table = powernow_table;
        if (cpumask_first(cpu_core_mask(data->cpu)) == data->cpu)
                print_basics(data);
@@ -717,7 +717,7 @@ static int fill_powernow_table(struct powernow_k8_data *data,
                    (pst[j].vid == data->currvid))
                        return 0;
 
-       dprintk("currfid/vid do not match PST, ignoring\n");
+       pr_debug("currfid/vid do not match PST, ignoring\n");
        return 0;
 }
 
@@ -739,36 +739,36 @@ static int find_psb_table(struct powernow_k8_data *data)
                if (memcmp(psb, PSB_ID_STRING, PSB_ID_STRING_LEN) != 0)
                        continue;
 
-               dprintk("found PSB header at 0x%p\n", psb);
+               pr_debug("found PSB header at 0x%p\n", psb);
 
-               dprintk("table vers: 0x%x\n", psb->tableversion);
+               pr_debug("table vers: 0x%x\n", psb->tableversion);
                if (psb->tableversion != PSB_VERSION_1_4) {
                        printk(KERN_ERR FW_BUG PFX "PSB table is not v1.4\n");
                        return -ENODEV;
                }
 
-               dprintk("flags: 0x%x\n", psb->flags1);
+               pr_debug("flags: 0x%x\n", psb->flags1);
                if (psb->flags1) {
                        printk(KERN_ERR FW_BUG PFX "unknown flags\n");
                        return -ENODEV;
                }
 
                data->vstable = psb->vstable;
-               dprintk("voltage stabilization time: %d(*20us)\n",
+               pr_debug("voltage stabilization time: %d(*20us)\n",
                                data->vstable);
 
-               dprintk("flags2: 0x%x\n", psb->flags2);
+               pr_debug("flags2: 0x%x\n", psb->flags2);
                data->rvo = psb->flags2 & 3;
                data->irt = ((psb->flags2) >> 2) & 3;
                mvs = ((psb->flags2) >> 4) & 3;
                data->vidmvs = 1 << mvs;
                data->batps = ((psb->flags2) >> 6) & 3;
 
-               dprintk("ramp voltage offset: %d\n", data->rvo);
-               dprintk("isochronous relief time: %d\n", data->irt);
-               dprintk("maximum voltage step: %d - 0x%x\n", mvs, data->vidmvs);
+               pr_debug("ramp voltage offset: %d\n", data->rvo);
+               pr_debug("isochronous relief time: %d\n", data->irt);
+               pr_debug("maximum voltage step: %d - 0x%x\n", mvs, data->vidmvs);
 
-               dprintk("numpst: 0x%x\n", psb->num_tables);
+               pr_debug("numpst: 0x%x\n", psb->num_tables);
                cpst = psb->num_tables;
                if ((psb->cpuid == 0x00000fc0) ||
                    (psb->cpuid == 0x00000fe0)) {
@@ -783,13 +783,13 @@ static int find_psb_table(struct powernow_k8_data *data)
                }
 
                data->plllock = psb->plllocktime;
-               dprintk("plllocktime: 0x%x (units 1us)\n", psb->plllocktime);
-               dprintk("maxfid: 0x%x\n", psb->maxfid);
-               dprintk("maxvid: 0x%x\n", psb->maxvid);
+               pr_debug("plllocktime: 0x%x (units 1us)\n", psb->plllocktime);
+               pr_debug("maxfid: 0x%x\n", psb->maxfid);
+               pr_debug("maxvid: 0x%x\n", psb->maxvid);
                maxvid = psb->maxvid;
 
                data->numps = psb->numps;
-               dprintk("numpstates: 0x%x\n", data->numps);
+               pr_debug("numpstates: 0x%x\n", data->numps);
                return fill_powernow_table(data,
                                (struct pst_s *)(psb+1), maxvid);
        }
@@ -834,13 +834,13 @@ static int powernow_k8_cpu_init_acpi(struct powernow_k8_data *data)
        u64 control, status;
 
        if (acpi_processor_register_performance(&data->acpi_data, data->cpu)) {
-               dprintk("register performance failed: bad ACPI data\n");
+               pr_debug("register performance failed: bad ACPI data\n");
                return -EIO;
        }
 
        /* verify the data contained in the ACPI structures */
        if (data->acpi_data.state_count <= 1) {
-               dprintk("No ACPI P-States\n");
+               pr_debug("No ACPI P-States\n");
                goto err_out;
        }
 
@@ -849,7 +849,7 @@ static int powernow_k8_cpu_init_acpi(struct powernow_k8_data *data)
 
        if ((control != ACPI_ADR_SPACE_FIXED_HARDWARE) ||
            (status != ACPI_ADR_SPACE_FIXED_HARDWARE)) {
-               dprintk("Invalid control/status registers (%x - %x)\n",
+               pr_debug("Invalid control/status registers (%llx - %llx)\n",
                        control, status);
                goto err_out;
        }
@@ -858,7 +858,7 @@ static int powernow_k8_cpu_init_acpi(struct powernow_k8_data *data)
        powernow_table = kmalloc((sizeof(struct cpufreq_frequency_table)
                * (data->acpi_data.state_count + 1)), GFP_KERNEL);
        if (!powernow_table) {
-               dprintk("powernow_table memory alloc failure\n");
+               pr_debug("powernow_table memory alloc failure\n");
                goto err_out;
        }
 
@@ -928,7 +928,7 @@ static int fill_powernow_table_pstate(struct powernow_k8_data *data,
                }
                rdmsr(MSR_PSTATE_DEF_BASE + index, lo, hi);
                if (!(hi & HW_PSTATE_VALID_MASK)) {
-                       dprintk("invalid pstate %d, ignoring\n", index);
+                       pr_debug("invalid pstate %d, ignoring\n", index);
                        invalidate_entry(powernow_table, i);
                        continue;
                }
@@ -968,7 +968,7 @@ static int fill_powernow_table_fidvid(struct powernow_k8_data *data,
                        vid = (control >> VID_SHIFT) & VID_MASK;
                }
 
-               dprintk("   %d : fid 0x%x, vid 0x%x\n", i, fid, vid);
+               pr_debug("   %d : fid 0x%x, vid 0x%x\n", i, fid, vid);
 
                index = fid | (vid<<8);
                powernow_table[i].index = index;
@@ -978,7 +978,7 @@ static int fill_powernow_table_fidvid(struct powernow_k8_data *data,
 
                /* verify frequency is OK */
                if ((freq > (MAX_FREQ * 1000)) || (freq < (MIN_FREQ * 1000))) {
-                       dprintk("invalid freq %u kHz, ignoring\n", freq);
+                       pr_debug("invalid freq %u kHz, ignoring\n", freq);
                        invalidate_entry(powernow_table, i);
                        continue;
                }
@@ -986,7 +986,7 @@ static int fill_powernow_table_fidvid(struct powernow_k8_data *data,
                /* verify voltage is OK -
                 * BIOSs are using "off" to indicate invalid */
                if (vid == VID_OFF) {
-                       dprintk("invalid vid %u, ignoring\n", vid);
+                       pr_debug("invalid vid %u, ignoring\n", vid);
                        invalidate_entry(powernow_table, i);
                        continue;
                }
@@ -1047,7 +1047,7 @@ static int transition_frequency_fidvid(struct powernow_k8_data *data,
        int res, i;
        struct cpufreq_freqs freqs;
 
-       dprintk("cpu %d transition to index %u\n", smp_processor_id(), index);
+       pr_debug("cpu %d transition to index %u\n", smp_processor_id(), index);
 
        /* fid/vid correctness check for k8 */
        /* fid are the lower 8 bits of the index we stored into
@@ -1057,18 +1057,18 @@ static int transition_frequency_fidvid(struct powernow_k8_data *data,
        fid = data->powernow_table[index].index & 0xFF;
        vid = (data->powernow_table[index].index & 0xFF00) >> 8;
 
-       dprintk("table matched fid 0x%x, giving vid 0x%x\n", fid, vid);
+       pr_debug("table matched fid 0x%x, giving vid 0x%x\n", fid, vid);
 
        if (query_current_values_with_pending_wait(data))
                return 1;
 
        if ((data->currvid == vid) && (data->currfid == fid)) {
-               dprintk("target matches current values (fid 0x%x, vid 0x%x)\n",
+               pr_debug("target matches current values (fid 0x%x, vid 0x%x)\n",
                        fid, vid);
                return 0;
        }
 
-       dprintk("cpu %d, changing to fid 0x%x, vid 0x%x\n",
+       pr_debug("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);
        freqs.new = find_khz_freq_from_fid(fid);
@@ -1096,7 +1096,7 @@ static int transition_frequency_pstate(struct powernow_k8_data *data,
        int res, i;
        struct cpufreq_freqs freqs;
 
-       dprintk("cpu %d transition to index %u\n", smp_processor_id(), index);
+       pr_debug("cpu %d transition to index %u\n", smp_processor_id(), index);
 
        /* get MSR index for hardware pstate transition */
        pstate = index & HW_PSTATE_MASK;
@@ -1156,14 +1156,14 @@ static int powernowk8_target(struct cpufreq_policy *pol,
                goto err_out;
        }
 
-       dprintk("targ: cpu %d, %d kHz, min %d, max %d, relation %d\n",
+       pr_debug("targ: cpu %d, %d kHz, min %d, max %d, relation %d\n",
                pol->cpu, targfreq, pol->min, pol->max, relation);
 
        if (query_current_values_with_pending_wait(data))
                goto err_out;
 
        if (cpu_family != CPU_HW_PSTATE) {
-               dprintk("targ: curr fid 0x%x, vid 0x%x\n",
+               pr_debug("targ: curr fid 0x%x, vid 0x%x\n",
                data->currfid, data->currvid);
 
                if ((checkvid != data->currvid) ||
@@ -1319,7 +1319,7 @@ static int __cpuinit powernowk8_cpu_init(struct cpufreq_policy *pol)
                                data->currpstate);
        else
                pol->cur = find_khz_freq_from_fid(data->currfid);
-       dprintk("policy current frequency %d kHz\n", pol->cur);
+       pr_debug("policy current frequency %d kHz\n", pol->cur);
 
        /* min/max the cpu is capable of */
        if (cpufreq_frequency_table_cpuinfo(pol, data->powernow_table)) {
@@ -1337,10 +1337,10 @@ static int __cpuinit powernowk8_cpu_init(struct cpufreq_policy *pol)
        cpufreq_frequency_table_get_attr(data->powernow_table, pol->cpu);
 
        if (cpu_family == CPU_HW_PSTATE)
-               dprintk("cpu_init done, current pstate 0x%x\n",
+               pr_debug("cpu_init done, current pstate 0x%x\n",
                                data->currpstate);
        else
-               dprintk("cpu_init done, current fid 0x%x, vid 0x%x\n",
+               pr_debug("cpu_init done, current fid 0x%x, vid 0x%x\n",
                        data->currfid, data->currvid);
 
        per_cpu(powernow_data, pol->cpu) = data;
@@ -1586,7 +1586,7 @@ static int __cpuinit powernowk8_init(void)
 /* driver entry point for term */
 static void __exit powernowk8_exit(void)
 {
-       dprintk("exit\n");
+       pr_debug("exit\n");
 
        if (boot_cpu_has(X86_FEATURE_CPB)) {
                msrs_free(msrs);
similarity index 98%
rename from arch/x86/kernel/cpu/cpufreq/powernow-k8.h
rename to drivers/cpufreq/powernow-k8.h
index df3529b..3744d26 100644 (file)
@@ -211,8 +211,6 @@ struct pst_s {
        u8 vid;
 };
 
-#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, u32 regfid);
 static int core_voltage_post_transition(struct powernow_k8_data *data, u32 reqvid);
similarity index 95%
rename from arch/x86/kernel/cpu/cpufreq/sc520_freq.c
rename to drivers/cpufreq/sc520_freq.c
index 435a996..1e205e6 100644 (file)
@@ -29,8 +29,6 @@
 
 static __u8 __iomem *cpuctl;
 
-#define dprintk(msg...) cpufreq_debug_printk(CPUFREQ_DEBUG_DRIVER, \
-               "sc520_freq", msg)
 #define PFX "sc520_freq: "
 
 static struct cpufreq_frequency_table sc520_freq_table[] = {
@@ -66,7 +64,7 @@ static void sc520_freq_set_cpu_state(unsigned int state)
 
        cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
 
-       dprintk("attempting to set frequency to %i kHz\n",
+       pr_debug("attempting to set frequency to %i kHz\n",
                        sc520_freq_table[state].frequency);
 
        local_irq_disable();
@@ -161,7 +159,7 @@ static int __init sc520_freq_init(void)
        /* Test if we have the right hardware */
        if (c->x86_vendor != X86_VENDOR_AMD ||
            c->x86 != 4 || c->x86_model != 9) {
-               dprintk("no Elan SC520 processor found!\n");
+               pr_debug("no Elan SC520 processor found!\n");
                return -ENODEV;
        }
        cpuctl = ioremap((unsigned long)(MMCR_BASE + OFFS_CPUCTL), 1);
similarity index 96%
rename from arch/x86/kernel/cpu/cpufreq/speedstep-centrino.c
rename to drivers/cpufreq/speedstep-centrino.c
index 9b1ff37..6ea3455 100644 (file)
@@ -29,9 +29,6 @@
 #define PFX            "speedstep-centrino: "
 #define MAINTAINER     "cpufreq@vger.kernel.org"
 
-#define dprintk(msg...) \
-       cpufreq_debug_printk(CPUFREQ_DEBUG_DRIVER, "speedstep-centrino", msg)
-
 #define INTEL_MSR_RANGE        (0xffff)
 
 struct cpu_id
@@ -244,7 +241,7 @@ static int centrino_cpu_init_table(struct cpufreq_policy *policy)
 
        if (model->cpu_id == NULL) {
                /* No match at all */
-               dprintk("no support for CPU model \"%s\": "
+               pr_debug("no support for CPU model \"%s\": "
                       "send /proc/cpuinfo to " MAINTAINER "\n",
                       cpu->x86_model_id);
                return -ENOENT;
@@ -252,15 +249,15 @@ static int centrino_cpu_init_table(struct cpufreq_policy *policy)
 
        if (model->op_points == NULL) {
                /* Matched a non-match */
-               dprintk("no table support for CPU model \"%s\"\n",
+               pr_debug("no table support for CPU model \"%s\"\n",
                       cpu->x86_model_id);
-               dprintk("try using the acpi-cpufreq driver\n");
+               pr_debug("try using the acpi-cpufreq driver\n");
                return -ENOENT;
        }
 
        per_cpu(centrino_model, policy->cpu) = model;
 
-       dprintk("found \"%s\": max frequency: %dkHz\n",
+       pr_debug("found \"%s\": max frequency: %dkHz\n",
               model->model_name, model->max_freq);
 
        return 0;
@@ -369,7 +366,7 @@ static int centrino_cpu_init(struct cpufreq_policy *policy)
                per_cpu(centrino_cpu, policy->cpu) = &cpu_ids[i];
 
        if (!per_cpu(centrino_cpu, policy->cpu)) {
-               dprintk("found unsupported CPU with "
+               pr_debug("found unsupported CPU with "
                "Enhanced SpeedStep: send /proc/cpuinfo to "
                MAINTAINER "\n");
                return -ENODEV;
@@ -385,7 +382,7 @@ static int centrino_cpu_init(struct cpufreq_policy *policy)
 
        if (!(l & MSR_IA32_MISC_ENABLE_ENHANCED_SPEEDSTEP)) {
                l |= MSR_IA32_MISC_ENABLE_ENHANCED_SPEEDSTEP;
-               dprintk("trying to enable Enhanced SpeedStep (%x)\n", l);
+               pr_debug("trying to enable Enhanced SpeedStep (%x)\n", l);
                wrmsr(MSR_IA32_MISC_ENABLE, l, h);
 
                /* check to see if it stuck */
@@ -402,7 +399,7 @@ static int centrino_cpu_init(struct cpufreq_policy *policy)
                                                /* 10uS transition latency */
        policy->cur = freq;
 
-       dprintk("centrino_cpu_init: cur=%dkHz\n", policy->cur);
+       pr_debug("centrino_cpu_init: cur=%dkHz\n", policy->cur);
 
        ret = cpufreq_frequency_table_cpuinfo(policy,
                per_cpu(centrino_model, policy->cpu)->op_points);
@@ -498,7 +495,7 @@ static int centrino_target (struct cpufreq_policy *policy,
                        good_cpu = j;
 
                if (good_cpu >= nr_cpu_ids) {
-                       dprintk("couldn't limit to CPUs in this domain\n");
+                       pr_debug("couldn't limit to CPUs in this domain\n");
                        retval = -EAGAIN;
                        if (first_cpu) {
                                /* We haven't started the transition yet. */
@@ -512,7 +509,7 @@ static int centrino_target (struct cpufreq_policy *policy,
                if (first_cpu) {
                        rdmsr_on_cpu(good_cpu, MSR_IA32_PERF_CTL, &oldmsr, &h);
                        if (msr == (oldmsr & 0xffff)) {
-                               dprintk("no change needed - msr was and needs "
+                               pr_debug("no change needed - msr was and needs "
                                        "to be %x\n", oldmsr);
                                retval = 0;
                                goto out;
@@ -521,7 +518,7 @@ static int centrino_target (struct cpufreq_policy *policy,
                        freqs.old = extract_clock(oldmsr, cpu, 0);
                        freqs.new = extract_clock(msr, cpu, 0);
 
-                       dprintk("target=%dkHz old=%d new=%d msr=%04x\n",
+                       pr_debug("target=%dkHz old=%d new=%d msr=%04x\n",
                                target_freq, freqs.old, freqs.new, msr);
 
                        for_each_cpu(k, policy->cpus) {
similarity index 92%
rename from arch/x86/kernel/cpu/cpufreq/speedstep-ich.c
rename to drivers/cpufreq/speedstep-ich.c
index 561758e..a748ce7 100644 (file)
@@ -53,10 +53,6 @@ static struct cpufreq_frequency_table speedstep_freqs[] = {
 };
 
 
-#define dprintk(msg...) cpufreq_debug_printk(CPUFREQ_DEBUG_DRIVER, \
-               "speedstep-ich", msg)
-
-
 /**
  * speedstep_find_register - read the PMBASE address
  *
@@ -80,7 +76,7 @@ static int speedstep_find_register(void)
                return -ENODEV;
        }
 
-       dprintk("pmbase is 0x%x\n", pmbase);
+       pr_debug("pmbase is 0x%x\n", pmbase);
        return 0;
 }
 
@@ -106,13 +102,13 @@ static void speedstep_set_state(unsigned int state)
        /* read state */
        value = inb(pmbase + 0x50);
 
-       dprintk("read at pmbase 0x%x + 0x50 returned 0x%x\n", pmbase, value);
+       pr_debug("read at pmbase 0x%x + 0x50 returned 0x%x\n", pmbase, value);
 
        /* write new state */
        value &= 0xFE;
        value |= state;
 
-       dprintk("writing 0x%x to pmbase 0x%x + 0x50\n", value, pmbase);
+       pr_debug("writing 0x%x to pmbase 0x%x + 0x50\n", value, pmbase);
 
        /* Disable bus master arbitration */
        pm2_blk = inb(pmbase + 0x20);
@@ -132,10 +128,10 @@ static void speedstep_set_state(unsigned int state)
        /* Enable IRQs */
        local_irq_restore(flags);
 
-       dprintk("read at pmbase 0x%x + 0x50 returned 0x%x\n", pmbase, value);
+       pr_debug("read at pmbase 0x%x + 0x50 returned 0x%x\n", pmbase, value);
 
        if (state == (value & 0x1))
-               dprintk("change to %u MHz succeeded\n",
+               pr_debug("change to %u MHz succeeded\n",
                        speedstep_get_frequency(speedstep_processor) / 1000);
        else
                printk(KERN_ERR "cpufreq: change failed - I/O error\n");
@@ -165,7 +161,7 @@ static int speedstep_activate(void)
        pci_read_config_word(speedstep_chipset_dev, 0x00A0, &value);
        if (!(value & 0x08)) {
                value |= 0x08;
-               dprintk("activating SpeedStep (TM) registers\n");
+               pr_debug("activating SpeedStep (TM) registers\n");
                pci_write_config_word(speedstep_chipset_dev, 0x00A0, value);
        }
 
@@ -218,7 +214,7 @@ static unsigned int speedstep_detect_chipset(void)
                        return 2; /* 2-M */
 
                if (hostbridge->revision < 5) {
-                       dprintk("hostbridge does not support speedstep\n");
+                       pr_debug("hostbridge does not support speedstep\n");
                        speedstep_chipset_dev = NULL;
                        pci_dev_put(hostbridge);
                        return 0;
@@ -246,7 +242,7 @@ static unsigned int speedstep_get(unsigned int cpu)
        if (smp_call_function_single(cpu, get_freq_data, &speed, 1) != 0)
                BUG();
 
-       dprintk("detected %u kHz as current frequency\n", speed);
+       pr_debug("detected %u kHz as current frequency\n", speed);
        return speed;
 }
 
@@ -276,7 +272,7 @@ static int speedstep_target(struct cpufreq_policy *policy,
        freqs.new = speedstep_freqs[newstate].frequency;
        freqs.cpu = policy->cpu;
 
-       dprintk("transiting from %u to %u kHz\n", freqs.old, freqs.new);
+       pr_debug("transiting from %u to %u kHz\n", freqs.old, freqs.new);
 
        /* no transition necessary */
        if (freqs.old == freqs.new)
@@ -351,7 +347,7 @@ static int speedstep_cpu_init(struct cpufreq_policy *policy)
        if (!speed)
                return -EIO;
 
-       dprintk("currently at %s speed setting - %i MHz\n",
+       pr_debug("currently at %s speed setting - %i MHz\n",
                (speed == speedstep_freqs[SPEEDSTEP_LOW].frequency)
                ? "low" : "high",
                (speed / 1000));
@@ -405,14 +401,14 @@ static int __init speedstep_init(void)
        /* detect processor */
        speedstep_processor = speedstep_detect_processor();
        if (!speedstep_processor) {
-               dprintk("Intel(R) SpeedStep(TM) capable processor "
+               pr_debug("Intel(R) SpeedStep(TM) capable processor "
                                "not found\n");
                return -ENODEV;
        }
 
        /* detect chipset */
        if (!speedstep_detect_chipset()) {
-               dprintk("Intel(R) SpeedStep(TM) for this chipset not "
+               pr_debug("Intel(R) SpeedStep(TM) for this chipset not "
                                "(yet) available.\n");
                return -ENODEV;
        }
similarity index 90%
rename from arch/x86/kernel/cpu/cpufreq/speedstep-lib.c
rename to drivers/cpufreq/speedstep-lib.c
index a94ec6b..8af2d2f 100644 (file)
@@ -18,9 +18,6 @@
 #include <asm/tsc.h>
 #include "speedstep-lib.h"
 
-#define dprintk(msg...) cpufreq_debug_printk(CPUFREQ_DEBUG_DRIVER, \
-               "speedstep-lib", msg)
-
 #define PFX "speedstep-lib: "
 
 #ifdef CONFIG_X86_SPEEDSTEP_RELAXED_CAP_CHECK
@@ -75,7 +72,7 @@ static unsigned int pentium3_get_frequency(enum speedstep_processor processor)
 
        /* read MSR 0x2a - we only need the low 32 bits */
        rdmsr(MSR_IA32_EBL_CR_POWERON, msr_lo, msr_tmp);
-       dprintk("P3 - MSR_IA32_EBL_CR_POWERON: 0x%x 0x%x\n", msr_lo, msr_tmp);
+       pr_debug("P3 - MSR_IA32_EBL_CR_POWERON: 0x%x 0x%x\n", msr_lo, msr_tmp);
        msr_tmp = msr_lo;
 
        /* decode the FSB */
@@ -89,7 +86,7 @@ static unsigned int pentium3_get_frequency(enum speedstep_processor processor)
 
        /* decode the multiplier */
        if (processor == SPEEDSTEP_CPU_PIII_C_EARLY) {
-               dprintk("workaround for early PIIIs\n");
+               pr_debug("workaround for early PIIIs\n");
                msr_lo &= 0x03c00000;
        } else
                msr_lo &= 0x0bc00000;
@@ -100,7 +97,7 @@ static unsigned int pentium3_get_frequency(enum speedstep_processor processor)
                j++;
        }
 
-       dprintk("speed is %u\n",
+       pr_debug("speed is %u\n",
                (msr_decode_mult[j].ratio * msr_decode_fsb[i].value * 100));
 
        return msr_decode_mult[j].ratio * msr_decode_fsb[i].value * 100;
@@ -112,7 +109,7 @@ static unsigned int pentiumM_get_frequency(void)
        u32 msr_lo, msr_tmp;
 
        rdmsr(MSR_IA32_EBL_CR_POWERON, msr_lo, msr_tmp);
-       dprintk("PM - MSR_IA32_EBL_CR_POWERON: 0x%x 0x%x\n", msr_lo, msr_tmp);
+       pr_debug("PM - MSR_IA32_EBL_CR_POWERON: 0x%x 0x%x\n", msr_lo, msr_tmp);
 
        /* see table B-2 of 24547212.pdf */
        if (msr_lo & 0x00040000) {
@@ -122,7 +119,7 @@ static unsigned int pentiumM_get_frequency(void)
        }
 
        msr_tmp = (msr_lo >> 22) & 0x1f;
-       dprintk("bits 22-26 are 0x%x, speed is %u\n",
+       pr_debug("bits 22-26 are 0x%x, speed is %u\n",
                        msr_tmp, (msr_tmp * 100 * 1000));
 
        return msr_tmp * 100 * 1000;
@@ -160,11 +157,11 @@ static unsigned int pentium_core_get_frequency(void)
        }
 
        rdmsr(MSR_IA32_EBL_CR_POWERON, msr_lo, msr_tmp);
-       dprintk("PCORE - MSR_IA32_EBL_CR_POWERON: 0x%x 0x%x\n",
+       pr_debug("PCORE - MSR_IA32_EBL_CR_POWERON: 0x%x 0x%x\n",
                        msr_lo, msr_tmp);
 
        msr_tmp = (msr_lo >> 22) & 0x1f;
-       dprintk("bits 22-26 are 0x%x, speed is %u\n",
+       pr_debug("bits 22-26 are 0x%x, speed is %u\n",
                        msr_tmp, (msr_tmp * fsb));
 
        ret = (msr_tmp * fsb);
@@ -190,7 +187,7 @@ static unsigned int pentium4_get_frequency(void)
 
        rdmsr(0x2c, msr_lo, msr_hi);
 
-       dprintk("P4 - MSR_EBC_FREQUENCY_ID: 0x%x 0x%x\n", msr_lo, msr_hi);
+       pr_debug("P4 - MSR_EBC_FREQUENCY_ID: 0x%x 0x%x\n", msr_lo, msr_hi);
 
        /* decode the FSB: see IA-32 Intel (C) Architecture Software
         * Developer's Manual, Volume 3: System Prgramming Guide,
@@ -217,7 +214,7 @@ static unsigned int pentium4_get_frequency(void)
        /* Multiplier. */
        mult = msr_lo >> 24;
 
-       dprintk("P4 - FSB %u kHz; Multiplier %u; Speed %u kHz\n",
+       pr_debug("P4 - FSB %u kHz; Multiplier %u; Speed %u kHz\n",
                        fsb, mult, (fsb * mult));
 
        ret = (fsb * mult);
@@ -257,7 +254,7 @@ unsigned int speedstep_detect_processor(void)
        struct cpuinfo_x86 *c = &cpu_data(0);
        u32 ebx, msr_lo, msr_hi;
 
-       dprintk("x86: %x, model: %x\n", c->x86, c->x86_model);
+       pr_debug("x86: %x, model: %x\n", c->x86, c->x86_model);
 
        if ((c->x86_vendor != X86_VENDOR_INTEL) ||
            ((c->x86 != 6) && (c->x86 != 0xF)))
@@ -272,7 +269,7 @@ unsigned int speedstep_detect_processor(void)
                ebx = cpuid_ebx(0x00000001);
                ebx &= 0x000000FF;
 
-               dprintk("ebx value is %x, x86_mask is %x\n", ebx, c->x86_mask);
+               pr_debug("ebx value is %x, x86_mask is %x\n", ebx, c->x86_mask);
 
                switch (c->x86_mask) {
                case 4:
@@ -327,7 +324,7 @@ unsigned int speedstep_detect_processor(void)
                /* cpuid_ebx(1) is 0x04 for desktop PIII,
                 * 0x06 for mobile PIII-M */
                ebx = cpuid_ebx(0x00000001);
-               dprintk("ebx is %x\n", ebx);
+               pr_debug("ebx is %x\n", ebx);
 
                ebx &= 0x000000FF;
 
@@ -344,7 +341,7 @@ unsigned int speedstep_detect_processor(void)
                /* all mobile PIII Coppermines have FSB 100 MHz
                 * ==> sort out a few desktop PIIIs. */
                rdmsr(MSR_IA32_EBL_CR_POWERON, msr_lo, msr_hi);
-               dprintk("Coppermine: MSR_IA32_EBL_CR_POWERON is 0x%x, 0x%x\n",
+               pr_debug("Coppermine: MSR_IA32_EBL_CR_POWERON is 0x%x, 0x%x\n",
                                msr_lo, msr_hi);
                msr_lo &= 0x00c0000;
                if (msr_lo != 0x0080000)
@@ -357,12 +354,12 @@ unsigned int speedstep_detect_processor(void)
                 * bit 56 or 57 is set
                 */
                rdmsr(MSR_IA32_PLATFORM_ID, msr_lo, msr_hi);
-               dprintk("Coppermine: MSR_IA32_PLATFORM ID is 0x%x, 0x%x\n",
+               pr_debug("Coppermine: MSR_IA32_PLATFORM ID is 0x%x, 0x%x\n",
                                msr_lo, msr_hi);
                if ((msr_hi & (1<<18)) &&
                    (relaxed_check ? 1 : (msr_hi & (3<<24)))) {
                        if (c->x86_mask == 0x01) {
-                               dprintk("early PIII version\n");
+                               pr_debug("early PIII version\n");
                                return SPEEDSTEP_CPU_PIII_C_EARLY;
                        } else
                                return SPEEDSTEP_CPU_PIII_C;
@@ -393,14 +390,14 @@ unsigned int speedstep_get_freqs(enum speedstep_processor processor,
        if ((!processor) || (!low_speed) || (!high_speed) || (!set_state))
                return -EINVAL;
 
-       dprintk("trying to determine both speeds\n");
+       pr_debug("trying to determine both speeds\n");
 
        /* get current speed */
        prev_speed = speedstep_get_frequency(processor);
        if (!prev_speed)
                return -EIO;
 
-       dprintk("previous speed is %u\n", prev_speed);
+       pr_debug("previous speed is %u\n", prev_speed);
 
        local_irq_save(flags);
 
@@ -412,7 +409,7 @@ unsigned int speedstep_get_freqs(enum speedstep_processor processor,
                goto out;
        }
 
-       dprintk("low speed is %u\n", *low_speed);
+       pr_debug("low speed is %u\n", *low_speed);
 
        /* start latency measurement */
        if (transition_latency)
@@ -431,7 +428,7 @@ unsigned int speedstep_get_freqs(enum speedstep_processor processor,
                goto out;
        }
 
-       dprintk("high speed is %u\n", *high_speed);
+       pr_debug("high speed is %u\n", *high_speed);
 
        if (*low_speed == *high_speed) {
                ret = -ENODEV;
@@ -445,7 +442,7 @@ unsigned int speedstep_get_freqs(enum speedstep_processor processor,
        if (transition_latency) {
                *transition_latency = (tv2.tv_sec - tv1.tv_sec) * USEC_PER_SEC +
                        tv2.tv_usec - tv1.tv_usec;
-               dprintk("transition latency is %u uSec\n", *transition_latency);
+               pr_debug("transition latency is %u uSec\n", *transition_latency);
 
                /* convert uSec to nSec and add 20% for safety reasons */
                *transition_latency *= 1200;
similarity index 90%
rename from arch/x86/kernel/cpu/cpufreq/speedstep-smi.c
rename to drivers/cpufreq/speedstep-smi.c
index 91bc25b..c76ead3 100644 (file)
@@ -55,9 +55,6 @@ static struct cpufreq_frequency_table speedstep_freqs[] = {
  * of DMA activity going on? */
 #define SMI_TRIES 5
 
-#define dprintk(msg...) cpufreq_debug_printk(CPUFREQ_DEBUG_DRIVER, \
-               "speedstep-smi", msg)
-
 /**
  * speedstep_smi_ownership
  */
@@ -70,7 +67,7 @@ static int speedstep_smi_ownership(void)
        command = (smi_sig & 0xffffff00) | (smi_cmd & 0xff);
        magic = virt_to_phys(magic_data);
 
-       dprintk("trying to obtain ownership with command %x at port %x\n",
+       pr_debug("trying to obtain ownership with command %x at port %x\n",
                        command, smi_port);
 
        __asm__ __volatile__(
@@ -85,7 +82,7 @@ static int speedstep_smi_ownership(void)
                : "memory"
        );
 
-       dprintk("result is %x\n", result);
+       pr_debug("result is %x\n", result);
 
        return result;
 }
@@ -106,13 +103,13 @@ static int speedstep_smi_get_freqs(unsigned int *low, unsigned int *high)
        u32 function = GET_SPEEDSTEP_FREQS;
 
        if (!(ist_info.event & 0xFFFF)) {
-               dprintk("bug #1422 -- can't read freqs from BIOS\n");
+               pr_debug("bug #1422 -- can't read freqs from BIOS\n");
                return -ENODEV;
        }
 
        command = (smi_sig & 0xffffff00) | (smi_cmd & 0xff);
 
-       dprintk("trying to determine frequencies with command %x at port %x\n",
+       pr_debug("trying to determine frequencies with command %x at port %x\n",
                        command, smi_port);
 
        __asm__ __volatile__(
@@ -129,7 +126,7 @@ static int speedstep_smi_get_freqs(unsigned int *low, unsigned int *high)
                  "d" (smi_port), "S" (0), "D" (0)
        );
 
-       dprintk("result %x, low_freq %u, high_freq %u\n",
+       pr_debug("result %x, low_freq %u, high_freq %u\n",
                        result, low_mhz, high_mhz);
 
        /* abort if results are obviously incorrect... */
@@ -154,7 +151,7 @@ static int speedstep_get_state(void)
 
        command = (smi_sig & 0xffffff00) | (smi_cmd & 0xff);
 
-       dprintk("trying to determine current setting with command %x "
+       pr_debug("trying to determine current setting with command %x "
                "at port %x\n", command, smi_port);
 
        __asm__ __volatile__(
@@ -168,7 +165,7 @@ static int speedstep_get_state(void)
                  "d" (smi_port), "S" (0), "D" (0)
        );
 
-       dprintk("state is %x, result is %x\n", state, result);
+       pr_debug("state is %x, result is %x\n", state, result);
 
        return state & 1;
 }
@@ -194,13 +191,13 @@ static void speedstep_set_state(unsigned int state)
 
        command = (smi_sig & 0xffffff00) | (smi_cmd & 0xff);
 
-       dprintk("trying to set frequency to state %u "
+       pr_debug("trying to set frequency to state %u "
                "with command %x at port %x\n",
                state, command, smi_port);
 
        do {
                if (retry) {
-                       dprintk("retry %u, previous result %u, waiting...\n",
+                       pr_debug("retry %u, previous result %u, waiting...\n",
                                        retry, result);
                        mdelay(retry * 50);
                }
@@ -221,7 +218,7 @@ static void speedstep_set_state(unsigned int state)
        local_irq_restore(flags);
 
        if (new_state == state)
-               dprintk("change to %u MHz succeeded after %u tries "
+               pr_debug("change to %u MHz succeeded after %u tries "
                        "with result %u\n",
                        (speedstep_freqs[new_state].frequency / 1000),
                        retry, result);
@@ -292,7 +289,7 @@ static int speedstep_cpu_init(struct cpufreq_policy *policy)
 
        result = speedstep_smi_ownership();
        if (result) {
-               dprintk("fails in acquiring ownership of a SMI interface.\n");
+               pr_debug("fails in acquiring ownership of a SMI interface.\n");
                return -EINVAL;
        }
 
@@ -304,7 +301,7 @@ static int speedstep_cpu_init(struct cpufreq_policy *policy)
        if (result) {
                /* fall back to speedstep_lib.c dection mechanism:
                 * try both states out */
-               dprintk("could not detect low and high frequencies "
+               pr_debug("could not detect low and high frequencies "
                                "by SMI call.\n");
                result = speedstep_get_freqs(speedstep_processor,
                                low, high,
@@ -312,18 +309,18 @@ static int speedstep_cpu_init(struct cpufreq_policy *policy)
                                &speedstep_set_state);
 
                if (result) {
-                       dprintk("could not detect two different speeds"
+                       pr_debug("could not detect two different speeds"
                                        " -- aborting.\n");
                        return result;
                } else
-                       dprintk("workaround worked.\n");
+                       pr_debug("workaround worked.\n");
        }
 
        /* get current speed setting */
        state = speedstep_get_state();
        speed = speedstep_freqs[state].frequency;
 
-       dprintk("currently at %s speed setting - %i MHz\n",
+       pr_debug("currently at %s speed setting - %i MHz\n",
                (speed == speedstep_freqs[SPEEDSTEP_LOW].frequency)
                ? "low" : "high",
                (speed / 1000));
@@ -360,7 +357,7 @@ static int speedstep_resume(struct cpufreq_policy *policy)
        int result = speedstep_smi_ownership();
 
        if (result)
-               dprintk("fails in re-acquiring ownership of a SMI interface.\n");
+               pr_debug("fails in re-acquiring ownership of a SMI interface.\n");
 
        return result;
 }
@@ -403,12 +400,12 @@ static int __init speedstep_init(void)
        }
 
        if (!speedstep_processor) {
-               dprintk("No supported Intel CPU detected.\n");
+               pr_debug("No supported Intel CPU detected.\n");
                return -ENODEV;
        }
 
-       dprintk("signature:0x%.8lx, command:0x%.8lx, "
-               "event:0x%.8lx, perf_level:0x%.8lx.\n",
+       pr_debug("signature:0x%.8ulx, command:0x%.8ulx, "
+               "event:0x%.8ulx, perf_level:0x%.8ulx.\n",
                ist_info.signature, ist_info.command,
                ist_info.event, ist_info.perf_level);
 
index c1f0045..af8e7b1 100644 (file)
@@ -1019,7 +1019,7 @@ ppc4xx_edac_mc_init(struct mem_ctl_info *mci,
        struct ppc4xx_edac_pdata *pdata = NULL;
        const struct device_node *np = op->dev.of_node;
 
-       if (op->dev.of_match == NULL)
+       if (of_match_device(ppc4xx_edac_match, &op->dev) == NULL)
                return -EINVAL;
 
        /* Initial driver pointers and private data */
index b3a25a5..efba163 100644 (file)
@@ -157,4 +157,6 @@ config SIGMA
          If unsure, say N here.  Drivers that need these helpers will select
          this option automatically.
 
+source "drivers/firmware/google/Kconfig"
+
 endmenu
index 00bb0b8..47338c9 100644 (file)
@@ -13,3 +13,5 @@ obj-$(CONFIG_ISCSI_IBFT_FIND) += iscsi_ibft_find.o
 obj-$(CONFIG_ISCSI_IBFT)       += iscsi_ibft.o
 obj-$(CONFIG_FIRMWARE_MEMMAP)  += memmap.o
 obj-$(CONFIG_SIGMA)            += sigma.o
+
+obj-$(CONFIG_GOOGLE_FIRMWARE)  += google/
index 96c25d9..f1b7f65 100644 (file)
@@ -531,8 +531,8 @@ static int
 edd_has_edd30(struct edd_device *edev)
 {
        struct edd_info *info;
-       int i, nonzero_path = 0;
-       char c;
+       int i;
+       u8 csum = 0;
 
        if (!edev)
                return 0;
@@ -544,16 +544,16 @@ edd_has_edd30(struct edd_device *edev)
                return 0;
        }
 
-       for (i = 30; i <= 73; i++) {
-               c = *(((uint8_t *) info) + i + 4);
-               if (c) {
-                       nonzero_path++;
-                       break;
-               }
-       }
-       if (!nonzero_path) {
+
+       /* We support only T13 spec */
+       if (info->params.device_path_info_length != 44)
+               return 0;
+
+       for (i = 30; i < info->params.device_path_info_length + 30; i++)
+               csum += *(((u8 *)&info->params) + i);
+
+       if (csum)
                return 0;
-       }
 
        return 1;
 }
index ff0c373..a2d2f1f 100644 (file)
@@ -677,8 +677,8 @@ create_efivars_bin_attributes(struct efivars *efivars)
 
        return 0;
 out_free:
-       kfree(efivars->new_var);
-       efivars->new_var = NULL;
+       kfree(efivars->del_var);
+       efivars->del_var = NULL;
        kfree(efivars->new_var);
        efivars->new_var = NULL;
        return error;
@@ -803,6 +803,8 @@ efivars_init(void)
        ops.set_variable = efi.set_variable;
        ops.get_next_variable = efi.get_next_variable;
        error = register_efivars(&__efivars, &ops, efi_kobj);
+       if (error)
+               goto err_put;
 
        /* Don't forget the systab entry */
        error = sysfs_create_group(efi_kobj, &efi_subsys_attr_group);
@@ -810,18 +812,25 @@ efivars_init(void)
                printk(KERN_ERR
                       "efivars: Sysfs attribute export failed with error %d.\n",
                       error);
-               unregister_efivars(&__efivars);
-               kobject_put(efi_kobj);
+               goto err_unregister;
        }
 
+       return 0;
+
+err_unregister:
+       unregister_efivars(&__efivars);
+err_put:
+       kobject_put(efi_kobj);
        return error;
 }
 
 static void __exit
 efivars_exit(void)
 {
-       unregister_efivars(&__efivars);
-       kobject_put(efi_kobj);
+       if (efi_enabled) {
+               unregister_efivars(&__efivars);
+               kobject_put(efi_kobj);
+       }
 }
 
 module_init(efivars_init);
diff --git a/drivers/firmware/google/Kconfig b/drivers/firmware/google/Kconfig
new file mode 100644 (file)
index 0000000..87096b6
--- /dev/null
@@ -0,0 +1,31 @@
+config GOOGLE_FIRMWARE
+       bool "Google Firmware Drivers"
+       depends on X86
+       default n
+       help
+         These firmware drivers are used by Google's servers.  They are
+         only useful if you are working directly on one of their
+         proprietary servers.  If in doubt, say "N".
+
+menu "Google Firmware Drivers"
+       depends on GOOGLE_FIRMWARE
+
+config GOOGLE_SMI
+       tristate "SMI interface for Google platforms"
+       depends on ACPI && DMI
+       select EFI_VARS
+       help
+         Say Y here if you want to enable SMI callbacks for Google
+         platforms.  This provides an interface for writing to and
+         clearing the EFI event log and reading and writing NVRAM
+         variables.
+
+config GOOGLE_MEMCONSOLE
+       tristate "Firmware Memory Console"
+       depends on DMI
+       help
+         This option enables the kernel to search for a firmware log in
+         the EBDA on Google servers.  If found, this log is exported to
+         userland in the file /sys/firmware/log.
+
+endmenu
diff --git a/drivers/firmware/google/Makefile b/drivers/firmware/google/Makefile
new file mode 100644 (file)
index 0000000..54a294e
--- /dev/null
@@ -0,0 +1,3 @@
+
+obj-$(CONFIG_GOOGLE_SMI)               += gsmi.o
+obj-$(CONFIG_GOOGLE_MEMCONSOLE)                += memconsole.o
diff --git a/drivers/firmware/google/gsmi.c b/drivers/firmware/google/gsmi.c
new file mode 100644 (file)
index 0000000..fa7f0b3
--- /dev/null
@@ -0,0 +1,940 @@
+/*
+ * Copyright 2010 Google Inc. All Rights Reserved.
+ * Author: dlaurie@google.com (Duncan Laurie)
+ *
+ * Re-worked to expose sysfs APIs by mikew@google.com (Mike Waychison)
+ *
+ * EFI SMI interface for Google platforms
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/types.h>
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <linux/errno.h>
+#include <linux/string.h>
+#include <linux/spinlock.h>
+#include <linux/dma-mapping.h>
+#include <linux/dmapool.h>
+#include <linux/fs.h>
+#include <linux/slab.h>
+#include <linux/ioctl.h>
+#include <linux/acpi.h>
+#include <linux/io.h>
+#include <linux/uaccess.h>
+#include <linux/dmi.h>
+#include <linux/kdebug.h>
+#include <linux/reboot.h>
+#include <linux/efi.h>
+
+#define GSMI_SHUTDOWN_CLEAN    0       /* Clean Shutdown */
+/* TODO(mikew@google.com): Tie in HARDLOCKUP_DETECTOR with NMIWDT */
+#define GSMI_SHUTDOWN_NMIWDT   1       /* NMI Watchdog */
+#define GSMI_SHUTDOWN_PANIC    2       /* Panic */
+#define GSMI_SHUTDOWN_OOPS     3       /* Oops */
+#define GSMI_SHUTDOWN_DIE      4       /* Die -- No longer meaningful */
+#define GSMI_SHUTDOWN_MCE      5       /* Machine Check */
+#define GSMI_SHUTDOWN_SOFTWDT  6       /* Software Watchdog */
+#define GSMI_SHUTDOWN_MBE      7       /* Uncorrected ECC */
+#define GSMI_SHUTDOWN_TRIPLE   8       /* Triple Fault */
+
+#define DRIVER_VERSION         "1.0"
+#define GSMI_GUID_SIZE         16
+#define GSMI_BUF_SIZE          1024
+#define GSMI_BUF_ALIGN         sizeof(u64)
+#define GSMI_CALLBACK          0xef
+
+/* SMI return codes */
+#define GSMI_SUCCESS           0x00
+#define GSMI_UNSUPPORTED2      0x03
+#define GSMI_LOG_FULL          0x0b
+#define GSMI_VAR_NOT_FOUND     0x0e
+#define GSMI_HANDSHAKE_SPIN    0x7d
+#define GSMI_HANDSHAKE_CF      0x7e
+#define GSMI_HANDSHAKE_NONE    0x7f
+#define GSMI_INVALID_PARAMETER 0x82
+#define GSMI_UNSUPPORTED       0x83
+#define GSMI_BUFFER_TOO_SMALL  0x85
+#define GSMI_NOT_READY         0x86
+#define GSMI_DEVICE_ERROR      0x87
+#define GSMI_NOT_FOUND         0x8e
+
+#define QUIRKY_BOARD_HASH 0x78a30a50
+
+/* Internally used commands passed to the firmware */
+#define GSMI_CMD_GET_NVRAM_VAR         0x01
+#define GSMI_CMD_GET_NEXT_VAR          0x02
+#define GSMI_CMD_SET_NVRAM_VAR         0x03
+#define GSMI_CMD_SET_EVENT_LOG         0x08
+#define GSMI_CMD_CLEAR_EVENT_LOG       0x09
+#define GSMI_CMD_CLEAR_CONFIG          0x20
+#define GSMI_CMD_HANDSHAKE_TYPE                0xC1
+
+/* Magic entry type for kernel events */
+#define GSMI_LOG_ENTRY_TYPE_KERNEL     0xDEAD
+
+/* SMI buffers must be in 32bit physical address space */
+struct gsmi_buf {
+       u8 *start;                      /* start of buffer */
+       size_t length;                  /* length of buffer */
+       dma_addr_t handle;              /* dma allocation handle */
+       u32 address;                    /* physical address of buffer */
+};
+
+struct gsmi_device {
+       struct platform_device *pdev;   /* platform device */
+       struct gsmi_buf *name_buf;      /* variable name buffer */
+       struct gsmi_buf *data_buf;      /* generic data buffer */
+       struct gsmi_buf *param_buf;     /* parameter buffer */
+       spinlock_t lock;                /* serialize access to SMIs */
+       u16 smi_cmd;                    /* SMI command port */
+       int handshake_type;             /* firmware handler interlock type */
+       struct dma_pool *dma_pool;      /* DMA buffer pool */
+} gsmi_dev;
+
+/* Packed structures for communicating with the firmware */
+struct gsmi_nvram_var_param {
+       efi_guid_t      guid;
+       u32             name_ptr;
+       u32             attributes;
+       u32             data_len;
+       u32             data_ptr;
+} __packed;
+
+struct gsmi_get_next_var_param {
+       u8      guid[GSMI_GUID_SIZE];
+       u32     name_ptr;
+       u32     name_len;
+} __packed;
+
+struct gsmi_set_eventlog_param {
+       u32     data_ptr;
+       u32     data_len;
+       u32     type;
+} __packed;
+
+/* Event log formats */
+struct gsmi_log_entry_type_1 {
+       u16     type;
+       u32     instance;
+} __packed;
+
+
+/*
+ * Some platforms don't have explicit SMI handshake
+ * and need to wait for SMI to complete.
+ */
+#define GSMI_DEFAULT_SPINCOUNT 0x10000
+static unsigned int spincount = GSMI_DEFAULT_SPINCOUNT;
+module_param(spincount, uint, 0600);
+MODULE_PARM_DESC(spincount,
+       "The number of loop iterations to use when using the spin handshake.");
+
+static struct gsmi_buf *gsmi_buf_alloc(void)
+{
+       struct gsmi_buf *smibuf;
+
+       smibuf = kzalloc(sizeof(*smibuf), GFP_KERNEL);
+       if (!smibuf) {
+               printk(KERN_ERR "gsmi: out of memory\n");
+               return NULL;
+       }
+
+       /* allocate buffer in 32bit address space */
+       smibuf->start = dma_pool_alloc(gsmi_dev.dma_pool, GFP_KERNEL,
+                                      &smibuf->handle);
+       if (!smibuf->start) {
+               printk(KERN_ERR "gsmi: failed to allocate name buffer\n");
+               kfree(smibuf);
+               return NULL;
+       }
+
+       /* fill in the buffer handle */
+       smibuf->length = GSMI_BUF_SIZE;
+       smibuf->address = (u32)virt_to_phys(smibuf->start);
+
+       return smibuf;
+}
+
+static void gsmi_buf_free(struct gsmi_buf *smibuf)
+{
+       if (smibuf) {
+               if (smibuf->start)
+                       dma_pool_free(gsmi_dev.dma_pool, smibuf->start,
+                                     smibuf->handle);
+               kfree(smibuf);
+       }
+}
+
+/*
+ * Make a call to gsmi func(sub).  GSMI error codes are translated to
+ * in-kernel errnos (0 on success, -ERRNO on error).
+ */
+static int gsmi_exec(u8 func, u8 sub)
+{
+       u16 cmd = (sub << 8) | func;
+       u16 result = 0;
+       int rc = 0;
+
+       /*
+        * AH  : Subfunction number
+        * AL  : Function number
+        * EBX : Parameter block address
+        * DX  : SMI command port
+        *
+        * Three protocols here. See also the comment in gsmi_init().
+        */
+       if (gsmi_dev.handshake_type == GSMI_HANDSHAKE_CF) {
+               /*
+                * If handshake_type == HANDSHAKE_CF then set CF on the
+                * way in and wait for the handler to clear it; this avoids
+                * corrupting register state on those chipsets which have
+                * a delay between writing the SMI trigger register and
+                * entering SMM.
+                */
+               asm volatile (
+                       "stc\n"
+                       "outb %%al, %%dx\n"
+               "1:      jc 1b\n"
+                       : "=a" (result)
+                       : "0" (cmd),
+                         "d" (gsmi_dev.smi_cmd),
+                         "b" (gsmi_dev.param_buf->address)
+                       : "memory", "cc"
+               );
+       } else if (gsmi_dev.handshake_type == GSMI_HANDSHAKE_SPIN) {
+               /*
+                * If handshake_type == HANDSHAKE_SPIN we spin a
+                * hundred-ish usecs to ensure the SMI has triggered.
+                */
+               asm volatile (
+                       "outb %%al, %%dx\n"
+               "1:      loop 1b\n"
+                       : "=a" (result)
+                       : "0" (cmd),
+                         "d" (gsmi_dev.smi_cmd),
+                         "b" (gsmi_dev.param_buf->address),
+                         "c" (spincount)
+                       : "memory", "cc"
+               );
+       } else {
+               /*
+                * If handshake_type == HANDSHAKE_NONE we do nothing;
+                * either we don't need to or it's legacy firmware that
+                * doesn't understand the CF protocol.
+                */
+               asm volatile (
+                       "outb %%al, %%dx\n\t"
+                       : "=a" (result)
+                       : "0" (cmd),
+                         "d" (gsmi_dev.smi_cmd),
+                         "b" (gsmi_dev.param_buf->address)
+                       : "memory", "cc"
+               );
+       }
+
+       /* check return code from SMI handler */
+       switch (result) {
+       case GSMI_SUCCESS:
+               break;
+       case GSMI_VAR_NOT_FOUND:
+               /* not really an error, but let the caller know */
+               rc = 1;
+               break;
+       case GSMI_INVALID_PARAMETER:
+               printk(KERN_ERR "gsmi: exec 0x%04x: Invalid parameter\n", cmd);
+               rc = -EINVAL;
+               break;
+       case GSMI_BUFFER_TOO_SMALL:
+               printk(KERN_ERR "gsmi: exec 0x%04x: Buffer too small\n", cmd);
+               rc = -ENOMEM;
+               break;
+       case GSMI_UNSUPPORTED:
+       case GSMI_UNSUPPORTED2:
+               if (sub != GSMI_CMD_HANDSHAKE_TYPE)
+                       printk(KERN_ERR "gsmi: exec 0x%04x: Not supported\n",
+                              cmd);
+               rc = -ENOSYS;
+               break;
+       case GSMI_NOT_READY:
+               printk(KERN_ERR "gsmi: exec 0x%04x: Not ready\n", cmd);
+               rc = -EBUSY;
+               break;
+       case GSMI_DEVICE_ERROR:
+               printk(KERN_ERR "gsmi: exec 0x%04x: Device error\n", cmd);
+               rc = -EFAULT;
+               break;
+       case GSMI_NOT_FOUND:
+               printk(KERN_ERR "gsmi: exec 0x%04x: Data not found\n", cmd);
+               rc = -ENOENT;
+               break;
+       case GSMI_LOG_FULL:
+               printk(KERN_ERR "gsmi: exec 0x%04x: Log full\n", cmd);
+               rc = -ENOSPC;
+               break;
+       case GSMI_HANDSHAKE_CF:
+       case GSMI_HANDSHAKE_SPIN:
+       case GSMI_HANDSHAKE_NONE:
+               rc = result;
+               break;
+       default:
+               printk(KERN_ERR "gsmi: exec 0x%04x: Unknown error 0x%04x\n",
+                      cmd, result);
+               rc = -ENXIO;
+       }
+
+       return rc;
+}
+
+/* Return the number of unicode characters in data */
+static size_t
+utf16_strlen(efi_char16_t *data, unsigned long maxlength)
+{
+       unsigned long length = 0;
+
+       while (*data++ != 0 && length < maxlength)
+               length++;
+       return length;
+}
+
+static efi_status_t gsmi_get_variable(efi_char16_t *name,
+                                     efi_guid_t *vendor, u32 *attr,
+                                     unsigned long *data_size,
+                                     void *data)
+{
+       struct gsmi_nvram_var_param param = {
+               .name_ptr = gsmi_dev.name_buf->address,
+               .data_ptr = gsmi_dev.data_buf->address,
+               .data_len = (u32)*data_size,
+       };
+       efi_status_t ret = EFI_SUCCESS;
+       unsigned long flags;
+       size_t name_len = utf16_strlen(name, GSMI_BUF_SIZE / 2);
+       int rc;
+
+       if (name_len >= GSMI_BUF_SIZE / 2)
+               return EFI_BAD_BUFFER_SIZE;
+
+       spin_lock_irqsave(&gsmi_dev.lock, flags);
+
+       /* Vendor guid */
+       memcpy(&param.guid, vendor, sizeof(param.guid));
+
+       /* variable name, already in UTF-16 */
+       memset(gsmi_dev.name_buf->start, 0, gsmi_dev.name_buf->length);
+       memcpy(gsmi_dev.name_buf->start, name, name_len * 2);
+
+       /* data pointer */
+       memset(gsmi_dev.data_buf->start, 0, gsmi_dev.data_buf->length);
+
+       /* parameter buffer */
+       memset(gsmi_dev.param_buf->start, 0, gsmi_dev.param_buf->length);
+       memcpy(gsmi_dev.param_buf->start, &param, sizeof(param));
+
+       rc = gsmi_exec(GSMI_CALLBACK, GSMI_CMD_GET_NVRAM_VAR);
+       if (rc < 0) {
+               printk(KERN_ERR "gsmi: Get Variable failed\n");
+               ret = EFI_LOAD_ERROR;
+       } else if (rc == 1) {
+               /* variable was not found */
+               ret = EFI_NOT_FOUND;
+       } else {
+               /* Get the arguments back */
+               memcpy(&param, gsmi_dev.param_buf->start, sizeof(param));
+
+               /* The size reported is the min of all of our buffers */
+               *data_size = min(*data_size, gsmi_dev.data_buf->length);
+               *data_size = min_t(unsigned long, *data_size, param.data_len);
+
+               /* Copy data back to return buffer. */
+               memcpy(data, gsmi_dev.data_buf->start, *data_size);
+
+               /* All variables are have the following attributes */
+               *attr = EFI_VARIABLE_NON_VOLATILE |
+                       EFI_VARIABLE_BOOTSERVICE_ACCESS |
+                       EFI_VARIABLE_RUNTIME_ACCESS;
+       }
+
+       spin_unlock_irqrestore(&gsmi_dev.lock, flags);
+
+       return ret;
+}
+
+static efi_status_t gsmi_get_next_variable(unsigned long *name_size,
+                                          efi_char16_t *name,
+                                          efi_guid_t *vendor)
+{
+       struct gsmi_get_next_var_param param = {
+               .name_ptr = gsmi_dev.name_buf->address,
+               .name_len = gsmi_dev.name_buf->length,
+       };
+       efi_status_t ret = EFI_SUCCESS;
+       int rc;
+       unsigned long flags;
+
+       /* For the moment, only support buffers that exactly match in size */
+       if (*name_size != GSMI_BUF_SIZE)
+               return EFI_BAD_BUFFER_SIZE;
+
+       /* Let's make sure the thing is at least null-terminated */
+       if (utf16_strlen(name, GSMI_BUF_SIZE / 2) == GSMI_BUF_SIZE / 2)
+               return EFI_INVALID_PARAMETER;
+
+       spin_lock_irqsave(&gsmi_dev.lock, flags);
+
+       /* guid */
+       memcpy(&param.guid, vendor, sizeof(param.guid));
+
+       /* variable name, already in UTF-16 */
+       memcpy(gsmi_dev.name_buf->start, name, *name_size);
+
+       /* parameter buffer */
+       memset(gsmi_dev.param_buf->start, 0, gsmi_dev.param_buf->length);
+       memcpy(gsmi_dev.param_buf->start, &param, sizeof(param));
+
+       rc = gsmi_exec(GSMI_CALLBACK, GSMI_CMD_GET_NEXT_VAR);
+       if (rc < 0) {
+               printk(KERN_ERR "gsmi: Get Next Variable Name failed\n");
+               ret = EFI_LOAD_ERROR;
+       } else if (rc == 1) {
+               /* variable not found -- end of list */
+               ret = EFI_NOT_FOUND;
+       } else {
+               /* copy variable data back to return buffer */
+               memcpy(&param, gsmi_dev.param_buf->start, sizeof(param));
+
+               /* Copy the name back */
+               memcpy(name, gsmi_dev.name_buf->start, GSMI_BUF_SIZE);
+               *name_size = utf16_strlen(name, GSMI_BUF_SIZE / 2) * 2;
+
+               /* copy guid to return buffer */
+               memcpy(vendor, &param.guid, sizeof(param.guid));
+               ret = EFI_SUCCESS;
+       }
+
+       spin_unlock_irqrestore(&gsmi_dev.lock, flags);
+
+       return ret;
+}
+
+static efi_status_t gsmi_set_variable(efi_char16_t *name,
+                                     efi_guid_t *vendor,
+                                     unsigned long attr,
+                                     unsigned long data_size,
+                                     void *data)
+{
+       struct gsmi_nvram_var_param param = {
+               .name_ptr = gsmi_dev.name_buf->address,
+               .data_ptr = gsmi_dev.data_buf->address,
+               .data_len = (u32)data_size,
+               .attributes = EFI_VARIABLE_NON_VOLATILE |
+                             EFI_VARIABLE_BOOTSERVICE_ACCESS |
+                             EFI_VARIABLE_RUNTIME_ACCESS,
+       };
+       size_t name_len = utf16_strlen(name, GSMI_BUF_SIZE / 2);
+       efi_status_t ret = EFI_SUCCESS;
+       int rc;
+       unsigned long flags;
+
+       if (name_len >= GSMI_BUF_SIZE / 2)
+               return EFI_BAD_BUFFER_SIZE;
+
+       spin_lock_irqsave(&gsmi_dev.lock, flags);
+
+       /* guid */
+       memcpy(&param.guid, vendor, sizeof(param.guid));
+
+       /* variable name, already in UTF-16 */
+       memset(gsmi_dev.name_buf->start, 0, gsmi_dev.name_buf->length);
+       memcpy(gsmi_dev.name_buf->start, name, name_len * 2);
+
+       /* data pointer */
+       memset(gsmi_dev.data_buf->start, 0, gsmi_dev.data_buf->length);
+       memcpy(gsmi_dev.data_buf->start, data, data_size);
+
+       /* parameter buffer */
+       memset(gsmi_dev.param_buf->start, 0, gsmi_dev.param_buf->length);
+       memcpy(gsmi_dev.param_buf->start, &param, sizeof(param));
+
+       rc = gsmi_exec(GSMI_CALLBACK, GSMI_CMD_SET_NVRAM_VAR);
+       if (rc < 0) {
+               printk(KERN_ERR "gsmi: Set Variable failed\n");
+               ret = EFI_INVALID_PARAMETER;
+       }
+
+       spin_unlock_irqrestore(&gsmi_dev.lock, flags);
+
+       return ret;
+}
+
+static const struct efivar_operations efivar_ops = {
+       .get_variable = gsmi_get_variable,
+       .set_variable = gsmi_set_variable,
+       .get_next_variable = gsmi_get_next_variable,
+};
+
+static ssize_t eventlog_write(struct file *filp, struct kobject *kobj,
+                              struct bin_attribute *bin_attr,
+                              char *buf, loff_t pos, size_t count)
+{
+       struct gsmi_set_eventlog_param param = {
+               .data_ptr = gsmi_dev.data_buf->address,
+       };
+       int rc = 0;
+       unsigned long flags;
+
+       /* Pull the type out */
+       if (count < sizeof(u32))
+               return -EINVAL;
+       param.type = *(u32 *)buf;
+       count -= sizeof(u32);
+       buf += sizeof(u32);
+
+       /* The remaining buffer is the data payload */
+       if (count > gsmi_dev.data_buf->length)
+               return -EINVAL;
+       param.data_len = count - sizeof(u32);
+
+       spin_lock_irqsave(&gsmi_dev.lock, flags);
+
+       /* data pointer */
+       memset(gsmi_dev.data_buf->start, 0, gsmi_dev.data_buf->length);
+       memcpy(gsmi_dev.data_buf->start, buf, param.data_len);
+
+       /* parameter buffer */
+       memset(gsmi_dev.param_buf->start, 0, gsmi_dev.param_buf->length);
+       memcpy(gsmi_dev.param_buf->start, &param, sizeof(param));
+
+       rc = gsmi_exec(GSMI_CALLBACK, GSMI_CMD_SET_EVENT_LOG);
+       if (rc < 0)
+               printk(KERN_ERR "gsmi: Set Event Log failed\n");
+
+       spin_unlock_irqrestore(&gsmi_dev.lock, flags);
+
+       return rc;
+
+}
+
+static struct bin_attribute eventlog_bin_attr = {
+       .attr = {.name = "append_to_eventlog", .mode = 0200},
+       .write = eventlog_write,
+};
+
+static ssize_t gsmi_clear_eventlog_store(struct kobject *kobj,
+                                        struct kobj_attribute *attr,
+                                        const char *buf, size_t count)
+{
+       int rc;
+       unsigned long flags;
+       unsigned long val;
+       struct {
+               u32 percentage;
+               u32 data_type;
+       } param;
+
+       rc = strict_strtoul(buf, 0, &val);
+       if (rc)
+               return rc;
+
+       /*
+        * Value entered is a percentage, 0 through 100, anything else
+        * is invalid.
+        */
+       if (val > 100)
+               return -EINVAL;
+
+       /* data_type here selects the smbios event log. */
+       param.percentage = val;
+       param.data_type = 0;
+
+       spin_lock_irqsave(&gsmi_dev.lock, flags);
+
+       /* parameter buffer */
+       memset(gsmi_dev.param_buf->start, 0, gsmi_dev.param_buf->length);
+       memcpy(gsmi_dev.param_buf->start, &param, sizeof(param));
+
+       rc = gsmi_exec(GSMI_CALLBACK, GSMI_CMD_CLEAR_EVENT_LOG);
+
+       spin_unlock_irqrestore(&gsmi_dev.lock, flags);
+
+       if (rc)
+               return rc;
+       return count;
+}
+
+static struct kobj_attribute gsmi_clear_eventlog_attr = {
+       .attr = {.name = "clear_eventlog", .mode = 0200},
+       .store = gsmi_clear_eventlog_store,
+};
+
+static ssize_t gsmi_clear_config_store(struct kobject *kobj,
+                                      struct kobj_attribute *attr,
+                                      const char *buf, size_t count)
+{
+       int rc;
+       unsigned long flags;
+
+       spin_lock_irqsave(&gsmi_dev.lock, flags);
+
+       /* clear parameter buffer */
+       memset(gsmi_dev.param_buf->start, 0, gsmi_dev.param_buf->length);
+
+       rc = gsmi_exec(GSMI_CALLBACK, GSMI_CMD_CLEAR_CONFIG);
+
+       spin_unlock_irqrestore(&gsmi_dev.lock, flags);
+
+       if (rc)
+               return rc;
+       return count;
+}
+
+static struct kobj_attribute gsmi_clear_config_attr = {
+       .attr = {.name = "clear_config", .mode = 0200},
+       .store = gsmi_clear_config_store,
+};
+
+static const struct attribute *gsmi_attrs[] = {
+       &gsmi_clear_config_attr.attr,
+       &gsmi_clear_eventlog_attr.attr,
+       NULL,
+};
+
+static int gsmi_shutdown_reason(int reason)
+{
+       struct gsmi_log_entry_type_1 entry = {
+               .type     = GSMI_LOG_ENTRY_TYPE_KERNEL,
+               .instance = reason,
+       };
+       struct gsmi_set_eventlog_param param = {
+               .data_len = sizeof(entry),
+               .type     = 1,
+       };
+       static int saved_reason;
+       int rc = 0;
+       unsigned long flags;
+
+       /* avoid duplicate entries in the log */
+       if (saved_reason & (1 << reason))
+               return 0;
+
+       spin_lock_irqsave(&gsmi_dev.lock, flags);
+
+       saved_reason |= (1 << reason);
+
+       /* data pointer */
+       memset(gsmi_dev.data_buf->start, 0, gsmi_dev.data_buf->length);
+       memcpy(gsmi_dev.data_buf->start, &entry, sizeof(entry));
+
+       /* parameter buffer */
+       param.data_ptr = gsmi_dev.data_buf->address;
+       memset(gsmi_dev.param_buf->start, 0, gsmi_dev.param_buf->length);
+       memcpy(gsmi_dev.param_buf->start, &param, sizeof(param));
+
+       rc = gsmi_exec(GSMI_CALLBACK, GSMI_CMD_SET_EVENT_LOG);
+
+       spin_unlock_irqrestore(&gsmi_dev.lock, flags);
+
+       if (rc < 0)
+               printk(KERN_ERR "gsmi: Log Shutdown Reason failed\n");
+       else
+               printk(KERN_EMERG "gsmi: Log Shutdown Reason 0x%02x\n",
+                      reason);
+
+       return rc;
+}
+
+static int gsmi_reboot_callback(struct notifier_block *nb,
+                               unsigned long reason, void *arg)
+{
+       gsmi_shutdown_reason(GSMI_SHUTDOWN_CLEAN);
+       return NOTIFY_DONE;
+}
+
+static struct notifier_block gsmi_reboot_notifier = {
+       .notifier_call = gsmi_reboot_callback
+};
+
+static int gsmi_die_callback(struct notifier_block *nb,
+                            unsigned long reason, void *arg)
+{
+       if (reason == DIE_OOPS)
+               gsmi_shutdown_reason(GSMI_SHUTDOWN_OOPS);
+       return NOTIFY_DONE;
+}
+
+static struct notifier_block gsmi_die_notifier = {
+       .notifier_call = gsmi_die_callback
+};
+
+static int gsmi_panic_callback(struct notifier_block *nb,
+                              unsigned long reason, void *arg)
+{
+       gsmi_shutdown_reason(GSMI_SHUTDOWN_PANIC);
+       return NOTIFY_DONE;
+}
+
+static struct notifier_block gsmi_panic_notifier = {
+       .notifier_call = gsmi_panic_callback,
+};
+
+/*
+ * This hash function was blatantly copied from include/linux/hash.h.
+ * It is used by this driver to obfuscate a board name that requires a
+ * quirk within this driver.
+ *
+ * Please do not remove this copy of the function as any changes to the
+ * global utility hash_64() function would break this driver's ability
+ * to identify a board and provide the appropriate quirk -- mikew@google.com
+ */
+static u64 __init local_hash_64(u64 val, unsigned bits)
+{
+       u64 hash = val;
+
+       /*  Sigh, gcc can't optimise this alone like it does for 32 bits. */
+       u64 n = hash;
+       n <<= 18;
+       hash -= n;
+       n <<= 33;
+       hash -= n;
+       n <<= 3;
+       hash += n;
+       n <<= 3;
+       hash -= n;
+       n <<= 4;
+       hash += n;
+       n <<= 2;
+       hash += n;
+
+       /* High bits are more random, so use them. */
+       return hash >> (64 - bits);
+}
+
+static u32 __init hash_oem_table_id(char s[8])
+{
+       u64 input;
+       memcpy(&input, s, 8);
+       return local_hash_64(input, 32);
+}
+
+static struct dmi_system_id gsmi_dmi_table[] __initdata = {
+       {
+               .ident = "Google Board",
+               .matches = {
+                       DMI_MATCH(DMI_BOARD_VENDOR, "Google, Inc."),
+               },
+       },
+       {}
+};
+MODULE_DEVICE_TABLE(dmi, gsmi_dmi_table);
+
+static __init int gsmi_system_valid(void)
+{
+       u32 hash;
+
+       if (!dmi_check_system(gsmi_dmi_table))
+               return -ENODEV;
+
+       /*
+        * Only newer firmware supports the gsmi interface.  All older
+        * firmware that didn't support this interface used to plug the
+        * table name in the first four bytes of the oem_table_id field.
+        * Newer firmware doesn't do that though, so use that as the
+        * discriminant factor.  We have to do this in order to
+        * whitewash our board names out of the public driver.
+        */
+       if (!strncmp(acpi_gbl_FADT.header.oem_table_id, "FACP", 4)) {
+               printk(KERN_INFO "gsmi: Board is too old\n");
+               return -ENODEV;
+       }
+
+       /* Disable on board with 1.0 BIOS due to Google bug 2602657 */
+       hash = hash_oem_table_id(acpi_gbl_FADT.header.oem_table_id);
+       if (hash == QUIRKY_BOARD_HASH) {
+               const char *bios_ver = dmi_get_system_info(DMI_BIOS_VERSION);
+               if (strncmp(bios_ver, "1.0", 3) == 0) {
+                       pr_info("gsmi: disabled on this board's BIOS %s\n",
+                               bios_ver);
+                       return -ENODEV;
+               }
+       }
+
+       /* check for valid SMI command port in ACPI FADT */
+       if (acpi_gbl_FADT.smi_command == 0) {
+               pr_info("gsmi: missing smi_command\n");
+               return -ENODEV;
+       }
+
+       /* Found */
+       return 0;
+}
+
+static struct kobject *gsmi_kobj;
+static struct efivars efivars;
+
+static __init int gsmi_init(void)
+{
+       unsigned long flags;
+       int ret;
+
+       ret = gsmi_system_valid();
+       if (ret)
+               return ret;
+
+       gsmi_dev.smi_cmd = acpi_gbl_FADT.smi_command;
+
+       /* register device */
+       gsmi_dev.pdev = platform_device_register_simple("gsmi", -1, NULL, 0);
+       if (IS_ERR(gsmi_dev.pdev)) {
+               printk(KERN_ERR "gsmi: unable to register platform device\n");
+               return PTR_ERR(gsmi_dev.pdev);
+       }
+
+       /* SMI access needs to be serialized */
+       spin_lock_init(&gsmi_dev.lock);
+
+       /* SMI callbacks require 32bit addresses */
+       gsmi_dev.pdev->dev.coherent_dma_mask = DMA_BIT_MASK(32);
+       gsmi_dev.pdev->dev.dma_mask =
+               &gsmi_dev.pdev->dev.coherent_dma_mask;
+       ret = -ENOMEM;
+       gsmi_dev.dma_pool = dma_pool_create("gsmi", &gsmi_dev.pdev->dev,
+                                            GSMI_BUF_SIZE, GSMI_BUF_ALIGN, 0);
+       if (!gsmi_dev.dma_pool)
+               goto out_err;
+
+       /*
+        * pre-allocate buffers because sometimes we are called when
+        * this is not feasible: oops, panic, die, mce, etc
+        */
+       gsmi_dev.name_buf = gsmi_buf_alloc();
+       if (!gsmi_dev.name_buf) {
+               printk(KERN_ERR "gsmi: failed to allocate name buffer\n");
+               goto out_err;
+       }
+
+       gsmi_dev.data_buf = gsmi_buf_alloc();
+       if (!gsmi_dev.data_buf) {
+               printk(KERN_ERR "gsmi: failed to allocate data buffer\n");
+               goto out_err;
+       }
+
+       gsmi_dev.param_buf = gsmi_buf_alloc();
+       if (!gsmi_dev.param_buf) {
+               printk(KERN_ERR "gsmi: failed to allocate param buffer\n");
+               goto out_err;
+       }
+
+       /*
+        * Determine type of handshake used to serialize the SMI
+        * entry. See also gsmi_exec().
+        *
+        * There's a "behavior" present on some chipsets where writing the
+        * SMI trigger register in the southbridge doesn't result in an
+        * immediate SMI. Rather, the processor can execute "a few" more
+        * instructions before the SMI takes effect. To ensure synchronous
+        * behavior, implement a handshake between the kernel driver and the
+        * firmware handler to spin until released. This ioctl determines
+        * the type of handshake.
+        *
+        * NONE: The firmware handler does not implement any
+        * handshake. Either it doesn't need to, or it's legacy firmware
+        * that doesn't know it needs to and never will.
+        *
+        * CF: The firmware handler will clear the CF in the saved
+        * state before returning. The driver may set the CF and test for
+        * it to clear before proceeding.
+        *
+        * SPIN: The firmware handler does not implement any handshake
+        * but the driver should spin for a hundred or so microseconds
+        * to ensure the SMI has triggered.
+        *
+        * Finally, the handler will return -ENOSYS if
+        * GSMI_CMD_HANDSHAKE_TYPE is unimplemented, which implies
+        * HANDSHAKE_NONE.
+        */
+       spin_lock_irqsave(&gsmi_dev.lock, flags);
+       gsmi_dev.handshake_type = GSMI_HANDSHAKE_SPIN;
+       gsmi_dev.handshake_type =
+           gsmi_exec(GSMI_CALLBACK, GSMI_CMD_HANDSHAKE_TYPE);
+       if (gsmi_dev.handshake_type == -ENOSYS)
+               gsmi_dev.handshake_type = GSMI_HANDSHAKE_NONE;
+       spin_unlock_irqrestore(&gsmi_dev.lock, flags);
+
+       /* Remove and clean up gsmi if the handshake could not complete. */
+       if (gsmi_dev.handshake_type == -ENXIO) {
+               printk(KERN_INFO "gsmi version " DRIVER_VERSION
+                      " failed to load\n");
+               ret = -ENODEV;
+               goto out_err;
+       }
+
+       printk(KERN_INFO "gsmi version " DRIVER_VERSION " loaded\n");
+
+       /* Register in the firmware directory */
+       ret = -ENOMEM;
+       gsmi_kobj = kobject_create_and_add("gsmi", firmware_kobj);
+       if (!gsmi_kobj) {
+               printk(KERN_INFO "gsmi: Failed to create firmware kobj\n");
+               goto out_err;
+       }
+
+       /* Setup eventlog access */
+       ret = sysfs_create_bin_file(gsmi_kobj, &eventlog_bin_attr);
+       if (ret) {
+               printk(KERN_INFO "gsmi: Failed to setup eventlog");
+               goto out_err;
+       }
+
+       /* Other attributes */
+       ret = sysfs_create_files(gsmi_kobj, gsmi_attrs);
+       if (ret) {
+               printk(KERN_INFO "gsmi: Failed to add attrs");
+               goto out_err;
+       }
+
+       if (register_efivars(&efivars, &efivar_ops, gsmi_kobj)) {
+               printk(KERN_INFO "gsmi: Failed to register efivars\n");
+               goto out_err;
+       }
+
+       register_reboot_notifier(&gsmi_reboot_notifier);
+       register_die_notifier(&gsmi_die_notifier);
+       atomic_notifier_chain_register(&panic_notifier_list,
+                                      &gsmi_panic_notifier);
+
+       return 0;
+
+ out_err:
+       kobject_put(gsmi_kobj);
+       gsmi_buf_free(gsmi_dev.param_buf);
+       gsmi_buf_free(gsmi_dev.data_buf);
+       gsmi_buf_free(gsmi_dev.name_buf);
+       if (gsmi_dev.dma_pool)
+               dma_pool_destroy(gsmi_dev.dma_pool);
+       platform_device_unregister(gsmi_dev.pdev);
+       pr_info("gsmi: failed to load: %d\n", ret);
+       return ret;
+}
+
+static void __exit gsmi_exit(void)
+{
+       unregister_reboot_notifier(&gsmi_reboot_notifier);
+       unregister_die_notifier(&gsmi_die_notifier);
+       atomic_notifier_chain_unregister(&panic_notifier_list,
+                                        &gsmi_panic_notifier);
+       unregister_efivars(&efivars);
+
+       kobject_put(gsmi_kobj);
+       gsmi_buf_free(gsmi_dev.param_buf);
+       gsmi_buf_free(gsmi_dev.data_buf);
+       gsmi_buf_free(gsmi_dev.name_buf);
+       dma_pool_destroy(gsmi_dev.dma_pool);
+       platform_device_unregister(gsmi_dev.pdev);
+}
+
+module_init(gsmi_init);
+module_exit(gsmi_exit);
+
+MODULE_AUTHOR("Google, Inc.");
+MODULE_LICENSE("GPL");
diff --git a/drivers/firmware/google/memconsole.c b/drivers/firmware/google/memconsole.c
new file mode 100644 (file)
index 0000000..2a90ba6
--- /dev/null
@@ -0,0 +1,166 @@
+/*
+ * memconsole.c
+ *
+ * Infrastructure for importing the BIOS memory based console
+ * into the kernel log ringbuffer.
+ *
+ * Copyright 2010 Google Inc. All rights reserved.
+ */
+
+#include <linux/ctype.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/sysfs.h>
+#include <linux/kobject.h>
+#include <linux/module.h>
+#include <linux/dmi.h>
+#include <asm/bios_ebda.h>
+
+#define BIOS_MEMCONSOLE_V1_MAGIC       0xDEADBABE
+#define BIOS_MEMCONSOLE_V2_MAGIC       (('M')|('C'<<8)|('O'<<16)|('N'<<24))
+
+struct biosmemcon_ebda {
+       u32 signature;
+       union {
+               struct {
+                       u8  enabled;
+                       u32 buffer_addr;
+                       u16 start;
+                       u16 end;
+                       u16 num_chars;
+                       u8  wrapped;
+               } __packed v1;
+               struct {
+                       u32 buffer_addr;
+                       /* Misdocumented as number of pages! */
+                       u16 num_bytes;
+                       u16 start;
+                       u16 end;
+               } __packed v2;
+       };
+} __packed;
+
+static char *memconsole_baseaddr;
+static size_t memconsole_length;
+
+static ssize_t memconsole_read(struct file *filp, struct kobject *kobp,
+                              struct bin_attribute *bin_attr, char *buf,
+                              loff_t pos, size_t count)
+{
+       return memory_read_from_buffer(buf, count, &pos, memconsole_baseaddr,
+                                      memconsole_length);
+}
+
+static struct bin_attribute memconsole_bin_attr = {
+       .attr = {.name = "log", .mode = 0444},
+       .read = memconsole_read,
+};
+
+
+static void found_v1_header(struct biosmemcon_ebda *hdr)
+{
+       printk(KERN_INFO "BIOS console v1 EBDA structure found at %p\n", hdr);
+       printk(KERN_INFO "BIOS console buffer at 0x%.8x, "
+              "start = %d, end = %d, num = %d\n",
+              hdr->v1.buffer_addr, hdr->v1.start,
+              hdr->v1.end, hdr->v1.num_chars);
+
+       memconsole_length = hdr->v1.num_chars;
+       memconsole_baseaddr = phys_to_virt(hdr->v1.buffer_addr);
+}
+
+static void found_v2_header(struct biosmemcon_ebda *hdr)
+{
+       printk(KERN_INFO "BIOS console v2 EBDA structure found at %p\n", hdr);
+       printk(KERN_INFO "BIOS console buffer at 0x%.8x, "
+              "start = %d, end = %d, num_bytes = %d\n",
+              hdr->v2.buffer_addr, hdr->v2.start,
+              hdr->v2.end, hdr->v2.num_bytes);
+
+       memconsole_length = hdr->v2.end - hdr->v2.start;
+       memconsole_baseaddr = phys_to_virt(hdr->v2.buffer_addr
+                                          + hdr->v2.start);
+}
+
+/*
+ * Search through the EBDA for the BIOS Memory Console, and
+ * set the global variables to point to it.  Return true if found.
+ */
+static bool found_memconsole(void)
+{
+       unsigned int address;
+       size_t length, cur;
+
+       address = get_bios_ebda();
+       if (!address) {
+               printk(KERN_INFO "BIOS EBDA non-existent.\n");
+               return false;
+       }
+
+       /* EBDA length is byte 0 of EBDA (in KB) */
+       length = *(u8 *)phys_to_virt(address);
+       length <<= 10; /* convert to bytes */
+
+       /*
+        * Search through EBDA for BIOS memory console structure
+        * note: signature is not necessarily dword-aligned
+        */
+       for (cur = 0; cur < length; cur++) {
+               struct biosmemcon_ebda *hdr = phys_to_virt(address + cur);
+
+               /* memconsole v1 */
+               if (hdr->signature == BIOS_MEMCONSOLE_V1_MAGIC) {
+                       found_v1_header(hdr);
+                       return true;
+               }
+
+               /* memconsole v2 */
+               if (hdr->signature == BIOS_MEMCONSOLE_V2_MAGIC) {
+                       found_v2_header(hdr);
+                       return true;
+               }
+       }
+
+       printk(KERN_INFO "BIOS console EBDA structure not found!\n");
+       return false;
+}
+
+static struct dmi_system_id memconsole_dmi_table[] __initdata = {
+       {
+               .ident = "Google Board",
+               .matches = {
+                       DMI_MATCH(DMI_BOARD_VENDOR, "Google, Inc."),
+               },
+       },
+       {}
+};
+MODULE_DEVICE_TABLE(dmi, memconsole_dmi_table);
+
+static int __init memconsole_init(void)
+{
+       int ret;
+
+       if (!dmi_check_system(memconsole_dmi_table))
+               return -ENODEV;
+
+       if (!found_memconsole())
+               return -ENODEV;
+
+       memconsole_bin_attr.size = memconsole_length;
+
+       ret = sysfs_create_bin_file(firmware_kobj, &memconsole_bin_attr);
+
+       return ret;
+}
+
+static void __exit memconsole_exit(void)
+{
+       sysfs_remove_bin_file(firmware_kobj, &memconsole_bin_attr);
+}
+
+module_init(memconsole_init);
+module_exit(memconsole_exit);
+
+MODULE_AUTHOR("Google, Inc.");
+MODULE_LICENSE("GPL");
index 2192456..f032e44 100644 (file)
 struct acpi_table_ibft *ibft_addr;
 EXPORT_SYMBOL_GPL(ibft_addr);
 
-#define IBFT_SIGN "iBFT"
+static const struct {
+       char *sign;
+} ibft_signs[] = {
+#ifdef CONFIG_ACPI
+       /*
+        * One spec says "IBFT", the other says "iBFT". We have to check
+        * for both.
+        */
+       { ACPI_SIG_IBFT },
+#endif
+       { "iBFT" },
+       { "BIFT" },     /* Broadcom iSCSI Offload */
+};
+
 #define IBFT_SIGN_LEN 4
 #define IBFT_START 0x80000 /* 512kB */
 #define IBFT_END 0x100000 /* 1MB */
@@ -62,6 +75,7 @@ static int __init find_ibft_in_mem(void)
        unsigned long pos;
        unsigned int len = 0;
        void *virt;
+       int i;
 
        for (pos = IBFT_START; pos < IBFT_END; pos += 16) {
                /* The table can't be inside the VGA BIOS reserved space,
@@ -69,18 +83,23 @@ static int __init find_ibft_in_mem(void)
                if (pos == VGA_MEM)
                        pos += VGA_SIZE;
                virt = isa_bus_to_virt(pos);
-               if (memcmp(virt, IBFT_SIGN, IBFT_SIGN_LEN) == 0) {
-                       unsigned long *addr =
-                           (unsigned long *)isa_bus_to_virt(pos + 4);
-                       len = *addr;
-                       /* if the length of the table extends past 1M,
-                        * the table cannot be valid. */
-                       if (pos + len <= (IBFT_END-1)) {
-                               ibft_addr = (struct acpi_table_ibft *)virt;
-                               break;
+
+               for (i = 0; i < ARRAY_SIZE(ibft_signs); i++) {
+                       if (memcmp(virt, ibft_signs[i].sign, IBFT_SIGN_LEN) ==
+                           0) {
+                               unsigned long *addr =
+                                   (unsigned long *)isa_bus_to_virt(pos + 4);
+                               len = *addr;
+                               /* if the length of the table extends past 1M,
+                                * the table cannot be valid. */
+                               if (pos + len <= (IBFT_END-1)) {
+                                       ibft_addr = (struct acpi_table_ibft *)virt;
+                                       goto done;
+                               }
                        }
                }
        }
+done:
        return len;
 }
 /*
@@ -89,18 +108,12 @@ static int __init find_ibft_in_mem(void)
  */
 unsigned long __init find_ibft_region(unsigned long *sizep)
 {
-
+       int i;
        ibft_addr = NULL;
 
 #ifdef CONFIG_ACPI
-       /*
-        * One spec says "IBFT", the other says "iBFT". We have to check
-        * for both.
-        */
-       if (!ibft_addr)
-               acpi_table_parse(ACPI_SIG_IBFT, acpi_find_ibft);
-       if (!ibft_addr)
-               acpi_table_parse(IBFT_SIGN, acpi_find_ibft);
+       for (i = 0; i < ARRAY_SIZE(ibft_signs) && !ibft_addr; i++)
+               acpi_table_parse(ibft_signs[i].sign, acpi_find_ibft);
 #endif /* CONFIG_ACPI */
 
        /* iBFT 1.03 section 1.4.3.1 mandates that UEFI machines will
index 11d7a72..140b952 100644 (file)
@@ -1516,17 +1516,33 @@ bool drm_fb_helper_initial_config(struct drm_fb_helper *fb_helper, int bpp_sel)
 }
 EXPORT_SYMBOL(drm_fb_helper_initial_config);
 
-bool drm_fb_helper_hotplug_event(struct drm_fb_helper *fb_helper)
+/**
+ * drm_fb_helper_hotplug_event - respond to a hotplug notification by
+ *                               probing all the outputs attached to the fb.
+ * @fb_helper: the drm_fb_helper
+ *
+ * LOCKING:
+ * Called at runtime, must take mode config lock.
+ *
+ * Scan the connectors attached to the fb_helper and try to put together a
+ * setup after *notification of a change in output configuration.
+ *
+ * RETURNS:
+ * 0 on success and a non-zero error code otherwise.
+ */
+int drm_fb_helper_hotplug_event(struct drm_fb_helper *fb_helper)
 {
+       struct drm_device *dev = fb_helper->dev;
        int count = 0;
        u32 max_width, max_height, bpp_sel;
        bool bound = false, crtcs_bound = false;
        struct drm_crtc *crtc;
 
        if (!fb_helper->fb)
-               return false;
+               return 0;
 
-       list_for_each_entry(crtc, &fb_helper->dev->mode_config.crtc_list, head) {
+       mutex_lock(&dev->mode_config.mutex);
+       list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
                if (crtc->fb)
                        crtcs_bound = true;
                if (crtc->fb == fb_helper->fb)
@@ -1535,7 +1551,8 @@ bool drm_fb_helper_hotplug_event(struct drm_fb_helper *fb_helper)
 
        if (!bound && crtcs_bound) {
                fb_helper->delayed_hotplug = true;
-               return false;
+               mutex_unlock(&dev->mode_config.mutex);
+               return 0;
        }
        DRM_DEBUG_KMS("\n");
 
@@ -1546,6 +1563,7 @@ bool drm_fb_helper_hotplug_event(struct drm_fb_helper *fb_helper)
        count = drm_fb_helper_probe_connector_modes(fb_helper, max_width,
                                                    max_height);
        drm_setup_crtcs(fb_helper);
+       mutex_unlock(&dev->mode_config.mutex);
 
        return drm_fb_helper_single_fb_probe(fb_helper, bpp_sel);
 }
index c34a8dd..32d1b3e 100644 (file)
@@ -49,7 +49,7 @@ module_param_named(panel_ignore_lid, i915_panel_ignore_lid, int, 0600);
 unsigned int i915_powersave = 1;
 module_param_named(powersave, i915_powersave, int, 0600);
 
-unsigned int i915_semaphores = 1;
+unsigned int i915_semaphores = 0;
 module_param_named(semaphores, i915_semaphores, int, 0600);
 
 unsigned int i915_enable_rc6 = 0;
index 373c2a0..2166ee0 100644 (file)
@@ -5154,6 +5154,8 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc,
 
        I915_WRITE(DSPCNTR(plane), dspcntr);
        POSTING_READ(DSPCNTR(plane));
+       if (!HAS_PCH_SPLIT(dev))
+               intel_enable_plane(dev_priv, plane, pipe);
 
        ret = intel_pipe_set_base(crtc, x, y, old_fb);
 
index 4bce801..c77111e 100644 (file)
@@ -42,7 +42,8 @@ nouveau_sgdma_populate(struct ttm_backend *be, unsigned long num_pages,
 
        nvbe->nr_pages = 0;
        while (num_pages--) {
-               if (dma_addrs[nvbe->nr_pages] != DMA_ERROR_CODE) {
+               /* this code path isn't called and is incorrect anyways */
+               if (0) { /*dma_addrs[nvbe->nr_pages] != DMA_ERROR_CODE)*/
                        nvbe->pages[nvbe->nr_pages] =
                                        dma_addrs[nvbe->nr_pages];
                        nvbe->ttm_alloced[nvbe->nr_pages] = true;
index c20eac3..9073e3b 100644 (file)
@@ -1780,7 +1780,10 @@ static void evergreen_gpu_init(struct radeon_device *rdev)
 
 
        mc_shared_chmap = RREG32(MC_SHARED_CHMAP);
-       mc_arb_ramcfg = RREG32(MC_ARB_RAMCFG);
+       if (rdev->flags & RADEON_IS_IGP)
+               mc_arb_ramcfg = RREG32(FUS_MC_ARB_RAMCFG);
+       else
+               mc_arb_ramcfg = RREG32(MC_ARB_RAMCFG);
 
        switch (rdev->config.evergreen.max_tile_pipes) {
        case 1:
index 9453384..fc40e0c 100644 (file)
 #define                BURSTLENGTH_SHIFT                               9
 #define                BURSTLENGTH_MASK                                0x00000200
 #define                CHANSIZE_OVERRIDE                               (1 << 11)
+#define        FUS_MC_ARB_RAMCFG                               0x2768
 #define        MC_VM_AGP_TOP                                   0x2028
 #define        MC_VM_AGP_BOT                                   0x202C
 #define        MC_VM_AGP_BASE                                  0x2030
index 7aade20..3d8a763 100644 (file)
@@ -674,7 +674,7 @@ static void cayman_gpu_init(struct radeon_device *rdev)
 
        cc_rb_backend_disable = RREG32(CC_RB_BACKEND_DISABLE);
        cc_gc_shader_pipe_config = RREG32(CC_GC_SHADER_PIPE_CONFIG);
-       cgts_tcc_disable = RREG32(CGTS_TCC_DISABLE);
+       cgts_tcc_disable = 0xff000000;
        gc_user_rb_backend_disable = RREG32(GC_USER_RB_BACKEND_DISABLE);
        gc_user_shader_pipe_config = RREG32(GC_USER_SHADER_PIPE_CONFIG);
        cgts_user_tcc_disable = RREG32(CGTS_USER_TCC_DISABLE);
@@ -871,7 +871,7 @@ static void cayman_gpu_init(struct radeon_device *rdev)
 
        smx_dc_ctl0 = RREG32(SMX_DC_CTL0);
        smx_dc_ctl0 &= ~NUMBER_OF_SETS(0x1ff);
-       smx_dc_ctl0 |= NUMBER_OF_SETS(rdev->config.evergreen.sx_num_of_sets);
+       smx_dc_ctl0 |= NUMBER_OF_SETS(rdev->config.cayman.sx_num_of_sets);
        WREG32(SMX_DC_CTL0, smx_dc_ctl0);
 
        WREG32(SPI_CONFIG_CNTL_1, VTX_DONE_DELAY(4) | CRC_SIMD_ID_WADDR_DISABLE);
@@ -887,20 +887,20 @@ static void cayman_gpu_init(struct radeon_device *rdev)
 
        WREG32(TA_CNTL_AUX, DISABLE_CUBE_ANISO);
 
-       WREG32(SX_EXPORT_BUFFER_SIZES, (COLOR_BUFFER_SIZE((rdev->config.evergreen.sx_max_export_size / 4) - 1) |
-                                       POSITION_BUFFER_SIZE((rdev->config.evergreen.sx_max_export_pos_size / 4) - 1) |
-                                       SMX_BUFFER_SIZE((rdev->config.evergreen.sx_max_export_smx_size / 4) - 1)));
+       WREG32(SX_EXPORT_BUFFER_SIZES, (COLOR_BUFFER_SIZE((rdev->config.cayman.sx_max_export_size / 4) - 1) |
+                                       POSITION_BUFFER_SIZE((rdev->config.cayman.sx_max_export_pos_size / 4) - 1) |
+                                       SMX_BUFFER_SIZE((rdev->config.cayman.sx_max_export_smx_size / 4) - 1)));
 
-       WREG32(PA_SC_FIFO_SIZE, (SC_PRIM_FIFO_SIZE(rdev->config.evergreen.sc_prim_fifo_size) |
-                                SC_HIZ_TILE_FIFO_SIZE(rdev->config.evergreen.sc_hiz_tile_fifo_size) |
-                                SC_EARLYZ_TILE_FIFO_SIZE(rdev->config.evergreen.sc_earlyz_tile_fifo_size)));
+       WREG32(PA_SC_FIFO_SIZE, (SC_PRIM_FIFO_SIZE(rdev->config.cayman.sc_prim_fifo_size) |
+                                SC_HIZ_TILE_FIFO_SIZE(rdev->config.cayman.sc_hiz_tile_fifo_size) |
+                                SC_EARLYZ_TILE_FIFO_SIZE(rdev->config.cayman.sc_earlyz_tile_fifo_size)));
 
 
        WREG32(VGT_NUM_INSTANCES, 1);
 
        WREG32(CP_PERFMON_CNTL, 0);
 
-       WREG32(SQ_MS_FIFO_SIZES, (CACHE_FIFO_SIZE(16 * rdev->config.evergreen.sq_num_cf_insts) |
+       WREG32(SQ_MS_FIFO_SIZES, (CACHE_FIFO_SIZE(16 * rdev->config.cayman.sq_num_cf_insts) |
                                  FETCH_FIFO_HIWATER(0x4) |
                                  DONE_FIFO_HIWATER(0xe0) |
                                  ALU_UPDATE_FIFO_HIWATER(0x8)));
index dd881d0..90dfb2b 100644 (file)
@@ -1574,9 +1574,17 @@ struct radeon_encoder_atom_dig *radeon_atombios_get_lvds_info(struct
                        ATOM_FAKE_EDID_PATCH_RECORD *fake_edid_record;
                        ATOM_PANEL_RESOLUTION_PATCH_RECORD *panel_res_record;
                        bool bad_record = false;
-                       u8 *record = (u8 *)(mode_info->atom_context->bios +
-                                           data_offset +
-                                           le16_to_cpu(lvds_info->info.usModePatchTableOffset));
+                       u8 *record;
+
+                       if ((frev == 1) && (crev < 2))
+                               /* absolute */
+                               record = (u8 *)(mode_info->atom_context->bios +
+                                               le16_to_cpu(lvds_info->info.usModePatchTableOffset));
+                       else
+                               /* relative */
+                               record = (u8 *)(mode_info->atom_context->bios +
+                                               data_offset +
+                                               le16_to_cpu(lvds_info->info.usModePatchTableOffset));
                        while (*record != ATOM_RECORD_END_TYPE) {
                                switch (*record) {
                                case LCD_MODE_PATCH_RECORD_MODE_TYPE:
index 8a955bb..a533f52 100644 (file)
@@ -181,9 +181,9 @@ int radeon_gart_bind(struct radeon_device *rdev, unsigned offset,
        p = t / (PAGE_SIZE / RADEON_GPU_PAGE_SIZE);
 
        for (i = 0; i < pages; i++, p++) {
-               /* On TTM path, we only use the DMA API if TTM_PAGE_FLAG_DMA32
-                * is requested. */
-               if (dma_addr[i] != DMA_ERROR_CODE) {
+               /* we reverted the patch using dma_addr in TTM for now but this
+                * code stops building on alpha so just comment it out for now */
+               if (0) { /*dma_addr[i] != DMA_ERROR_CODE) */
                        rdev->gart.ttm_alloced[p] = true;
                        rdev->gart.pages_addr[p] = dma_addr[i];
                } else {
index 6334f8a..0aa8e85 100644 (file)
@@ -33,6 +33,7 @@ cayman 0x9400
 0x00008E48 SQ_EX_ALLOC_TABLE_SLOTS
 0x00009100 SPI_CONFIG_CNTL
 0x0000913C SPI_CONFIG_CNTL_1
+0x00009508 TA_CNTL_AUX
 0x00009830 DB_DEBUG
 0x00009834 DB_DEBUG2
 0x00009838 DB_DEBUG3
index 7e16371..0e28cae 100644 (file)
@@ -46,6 +46,7 @@ evergreen 0x9400
 0x00008E48 SQ_EX_ALLOC_TABLE_SLOTS
 0x00009100 SPI_CONFIG_CNTL
 0x0000913C SPI_CONFIG_CNTL_1
+0x00009508 TA_CNTL_AUX
 0x00009700 VC_CNTL
 0x00009714 VC_ENHANCE
 0x00009830 DB_DEBUG
index e01cacb..498b284 100644 (file)
@@ -219,9 +219,6 @@ static int vga_switchto_stage1(struct vga_switcheroo_client *new_client)
        int i;
        struct vga_switcheroo_client *active = NULL;
 
-       if (new_client->active == true)
-               return 0;
-
        for (i = 0; i < VGA_SWITCHEROO_MAX_CLIENTS; i++) {
                if (vgasr_priv.clients[i].active == true) {
                        active = &vgasr_priv.clients[i];
@@ -372,6 +369,9 @@ vga_switcheroo_debugfs_write(struct file *filp, const char __user *ubuf,
                goto out;
        }
 
+       if (client->active == true)
+               goto out;
+
        /* okay we want a switch - test if devices are willing to switch */
        can_switch = true;
        for (i = 0; i < VGA_SWITCHEROO_MAX_CLIENTS; i++) {
index 75b984c..107397a 100644 (file)
@@ -560,15 +560,18 @@ static struct i2c_adapter mpc_ops = {
        .timeout = HZ,
 };
 
+static const struct of_device_id mpc_i2c_of_match[];
 static int __devinit fsl_i2c_probe(struct platform_device *op)
 {
+       const struct of_device_id *match;
        struct mpc_i2c *i2c;
        const u32 *prop;
        u32 clock = MPC_I2C_CLOCK_LEGACY;
        int result = 0;
        int plen;
 
-       if (!op->dev.of_match)
+       match = of_match_device(mpc_i2c_of_match, &op->dev);
+       if (!match)
                return -EINVAL;
 
        i2c = kzalloc(sizeof(*i2c), GFP_KERNEL);
@@ -605,8 +608,8 @@ static int __devinit fsl_i2c_probe(struct platform_device *op)
                        clock = *prop;
        }
 
-       if (op->dev.of_match->data) {
-               struct mpc_i2c_data *data = op->dev.of_match->data;
+       if (match->data) {
+               struct mpc_i2c_data *data = match->data;
                data->setup(op->dev.of_node, i2c, clock, data->prescaler);
        } else {
                /* Backwards compatibility */
index a97e3fe..04be9f8 100644 (file)
@@ -65,7 +65,7 @@ static inline void i2c_pnx_arm_timer(struct i2c_pnx_algo_data *alg_data)
                jiffies, expires);
 
        timer->expires = jiffies + expires;
-       timer->data = (unsigned long)&alg_data;
+       timer->data = (unsigned long)alg_data;
 
        add_timer(timer);
 }
index 5ed9d25..99dde87 100644 (file)
@@ -148,6 +148,7 @@ struct rdma_id_private {
        u32                     qp_num;
        u8                      srq;
        u8                      tos;
+       u8                      reuseaddr;
 };
 
 struct cma_multicast {
@@ -712,6 +713,21 @@ static inline int cma_any_addr(struct sockaddr *addr)
        return cma_zero_addr(addr) || cma_loopback_addr(addr);
 }
 
+static int cma_addr_cmp(struct sockaddr *src, struct sockaddr *dst)
+{
+       if (src->sa_family != dst->sa_family)
+               return -1;
+
+       switch (src->sa_family) {
+       case AF_INET:
+               return ((struct sockaddr_in *) src)->sin_addr.s_addr !=
+                      ((struct sockaddr_in *) dst)->sin_addr.s_addr;
+       default:
+               return ipv6_addr_cmp(&((struct sockaddr_in6 *) src)->sin6_addr,
+                                    &((struct sockaddr_in6 *) dst)->sin6_addr);
+       }
+}
+
 static inline __be16 cma_port(struct sockaddr *addr)
 {
        if (addr->sa_family == AF_INET)
@@ -1564,50 +1580,6 @@ static void cma_listen_on_all(struct rdma_id_private *id_priv)
        mutex_unlock(&lock);
 }
 
-int rdma_listen(struct rdma_cm_id *id, int backlog)
-{
-       struct rdma_id_private *id_priv;
-       int ret;
-
-       id_priv = container_of(id, struct rdma_id_private, id);
-       if (id_priv->state == CMA_IDLE) {
-               ((struct sockaddr *) &id->route.addr.src_addr)->sa_family = AF_INET;
-               ret = rdma_bind_addr(id, (struct sockaddr *) &id->route.addr.src_addr);
-               if (ret)
-                       return ret;
-       }
-
-       if (!cma_comp_exch(id_priv, CMA_ADDR_BOUND, CMA_LISTEN))
-               return -EINVAL;
-
-       id_priv->backlog = backlog;
-       if (id->device) {
-               switch (rdma_node_get_transport(id->device->node_type)) {
-               case RDMA_TRANSPORT_IB:
-                       ret = cma_ib_listen(id_priv);
-                       if (ret)
-                               goto err;
-                       break;
-               case RDMA_TRANSPORT_IWARP:
-                       ret = cma_iw_listen(id_priv, backlog);
-                       if (ret)
-                               goto err;
-                       break;
-               default:
-                       ret = -ENOSYS;
-                       goto err;
-               }
-       } else
-               cma_listen_on_all(id_priv);
-
-       return 0;
-err:
-       id_priv->backlog = 0;
-       cma_comp_exch(id_priv, CMA_LISTEN, CMA_ADDR_BOUND);
-       return ret;
-}
-EXPORT_SYMBOL(rdma_listen);
-
 void rdma_set_service_type(struct rdma_cm_id *id, int tos)
 {
        struct rdma_id_private *id_priv;
@@ -2090,6 +2062,25 @@ err:
 }
 EXPORT_SYMBOL(rdma_resolve_addr);
 
+int rdma_set_reuseaddr(struct rdma_cm_id *id, int reuse)
+{
+       struct rdma_id_private *id_priv;
+       unsigned long flags;
+       int ret;
+
+       id_priv = container_of(id, struct rdma_id_private, id);
+       spin_lock_irqsave(&id_priv->lock, flags);
+       if (id_priv->state == CMA_IDLE) {
+               id_priv->reuseaddr = reuse;
+               ret = 0;
+       } else {
+               ret = -EINVAL;
+       }
+       spin_unlock_irqrestore(&id_priv->lock, flags);
+       return ret;
+}
+EXPORT_SYMBOL(rdma_set_reuseaddr);
+
 static void cma_bind_port(struct rdma_bind_list *bind_list,
                          struct rdma_id_private *id_priv)
 {
@@ -2165,41 +2156,71 @@ retry:
        return -EADDRNOTAVAIL;
 }
 
-static int cma_use_port(struct idr *ps, struct rdma_id_private *id_priv)
+/*
+ * Check that the requested port is available.  This is called when trying to
+ * bind to a specific port, or when trying to listen on a bound port.  In
+ * the latter case, the provided id_priv may already be on the bind_list, but
+ * we still need to check that it's okay to start listening.
+ */
+static int cma_check_port(struct rdma_bind_list *bind_list,
+                         struct rdma_id_private *id_priv, uint8_t reuseaddr)
 {
        struct rdma_id_private *cur_id;
-       struct sockaddr_in *sin, *cur_sin;
-       struct rdma_bind_list *bind_list;
+       struct sockaddr *addr, *cur_addr;
        struct hlist_node *node;
+
+       addr = (struct sockaddr *) &id_priv->id.route.addr.src_addr;
+       if (cma_any_addr(addr) && !reuseaddr)
+               return -EADDRNOTAVAIL;
+
+       hlist_for_each_entry(cur_id, node, &bind_list->owners, node) {
+               if (id_priv == cur_id)
+                       continue;
+
+               if ((cur_id->state == CMA_LISTEN) ||
+                   !reuseaddr || !cur_id->reuseaddr) {
+                       cur_addr = (struct sockaddr *) &cur_id->id.route.addr.src_addr;
+                       if (cma_any_addr(cur_addr))
+                               return -EADDRNOTAVAIL;
+
+                       if (!cma_addr_cmp(addr, cur_addr))
+                               return -EADDRINUSE;
+               }
+       }
+       return 0;
+}
+
+static int cma_use_port(struct idr *ps, struct rdma_id_private *id_priv)
+{
+       struct rdma_bind_list *bind_list;
        unsigned short snum;
+       int ret;
 
-       sin = (struct sockaddr_in *) &id_priv->id.route.addr.src_addr;
-       snum = ntohs(sin->sin_port);
+       snum = ntohs(cma_port((struct sockaddr *) &id_priv->id.route.addr.src_addr));
        if (snum < PROT_SOCK && !capable(CAP_NET_BIND_SERVICE))
                return -EACCES;
 
        bind_list = idr_find(ps, snum);
-       if (!bind_list)
-               return cma_alloc_port(ps, id_priv, snum);
-
-       /*
-        * We don't support binding to any address if anyone is bound to
-        * a specific address on the same port.
-        */
-       if (cma_any_addr((struct sockaddr *) &id_priv->id.route.addr.src_addr))
-               return -EADDRNOTAVAIL;
-
-       hlist_for_each_entry(cur_id, node, &bind_list->owners, node) {
-               if (cma_any_addr((struct sockaddr *) &cur_id->id.route.addr.src_addr))
-                       return -EADDRNOTAVAIL;
-
-               cur_sin = (struct sockaddr_in *) &cur_id->id.route.addr.src_addr;
-               if (sin->sin_addr.s_addr == cur_sin->sin_addr.s_addr)
-                       return -EADDRINUSE;
+       if (!bind_list) {
+               ret = cma_alloc_port(ps, id_priv, snum);
+       } else {
+               ret = cma_check_port(bind_list, id_priv, id_priv->reuseaddr);
+               if (!ret)
+                       cma_bind_port(bind_list, id_priv);
        }
+       return ret;
+}
 
-       cma_bind_port(bind_list, id_priv);
-       return 0;
+static int cma_bind_listen(struct rdma_id_private *id_priv)
+{
+       struct rdma_bind_list *bind_list = id_priv->bind_list;
+       int ret = 0;
+
+       mutex_lock(&lock);
+       if (bind_list->owners.first->next)
+               ret = cma_check_port(bind_list, id_priv, 0);
+       mutex_unlock(&lock);
+       return ret;
 }
 
 static int cma_get_port(struct rdma_id_private *id_priv)
@@ -2253,6 +2274,56 @@ static int cma_check_linklocal(struct rdma_dev_addr *dev_addr,
        return 0;
 }
 
+int rdma_listen(struct rdma_cm_id *id, int backlog)
+{
+       struct rdma_id_private *id_priv;
+       int ret;
+
+       id_priv = container_of(id, struct rdma_id_private, id);
+       if (id_priv->state == CMA_IDLE) {
+               ((struct sockaddr *) &id->route.addr.src_addr)->sa_family = AF_INET;
+               ret = rdma_bind_addr(id, (struct sockaddr *) &id->route.addr.src_addr);
+               if (ret)
+                       return ret;
+       }
+
+       if (!cma_comp_exch(id_priv, CMA_ADDR_BOUND, CMA_LISTEN))
+               return -EINVAL;
+
+       if (id_priv->reuseaddr) {
+               ret = cma_bind_listen(id_priv);
+               if (ret)
+                       goto err;
+       }
+
+       id_priv->backlog = backlog;
+       if (id->device) {
+               switch (rdma_node_get_transport(id->device->node_type)) {
+               case RDMA_TRANSPORT_IB:
+                       ret = cma_ib_listen(id_priv);
+                       if (ret)
+                               goto err;
+                       break;
+               case RDMA_TRANSPORT_IWARP:
+                       ret = cma_iw_listen(id_priv, backlog);
+                       if (ret)
+                               goto err;
+                       break;
+               default:
+                       ret = -ENOSYS;
+                       goto err;
+               }
+       } else
+               cma_listen_on_all(id_priv);
+
+       return 0;
+err:
+       id_priv->backlog = 0;
+       cma_comp_exch(id_priv, CMA_LISTEN, CMA_ADDR_BOUND);
+       return ret;
+}
+EXPORT_SYMBOL(rdma_listen);
+
 int rdma_bind_addr(struct rdma_cm_id *id, struct sockaddr *addr)
 {
        struct rdma_id_private *id_priv;
index 2a1e9ae..a9c0423 100644 (file)
@@ -725,7 +725,7 @@ static int cm_conn_rep_handler(struct iwcm_id_private *cm_id_priv,
         */
        clear_bit(IWCM_F_CONNECT_WAIT, &cm_id_priv->flags);
        BUG_ON(cm_id_priv->state != IW_CM_STATE_CONN_SENT);
-       if (iw_event->status == IW_CM_EVENT_STATUS_ACCEPTED) {
+       if (iw_event->status == 0) {
                cm_id_priv->id.local_addr = iw_event->local_addr;
                cm_id_priv->id.remote_addr = iw_event->remote_addr;
                cm_id_priv->state = IW_CM_STATE_ESTABLISHED;
index ec1e9da..b3fa798 100644 (file)
@@ -883,6 +883,13 @@ static int ucma_set_option_id(struct ucma_context *ctx, int optname,
                }
                rdma_set_service_type(ctx->cm_id, *((u8 *) optval));
                break;
+       case RDMA_OPTION_ID_REUSEADDR:
+               if (optlen != sizeof(int)) {
+                       ret = -EINVAL;
+                       break;
+               }
+               ret = rdma_set_reuseaddr(ctx->cm_id, *((int *) optval) ? 1 : 0);
+               break;
        default:
                ret = -ENOSYS;
        }
index 9d8dcfa..d7ee70f 100644 (file)
@@ -1198,9 +1198,7 @@ static int pass_open_rpl(struct c4iw_dev *dev, struct sk_buff *skb)
        }
        PDBG("%s ep %p status %d error %d\n", __func__, ep,
             rpl->status, status2errno(rpl->status));
-       ep->com.wr_wait.ret = status2errno(rpl->status);
-       ep->com.wr_wait.done = 1;
-       wake_up(&ep->com.wr_wait.wait);
+       c4iw_wake_up(&ep->com.wr_wait, status2errno(rpl->status));
 
        return 0;
 }
@@ -1234,9 +1232,7 @@ static int close_listsrv_rpl(struct c4iw_dev *dev, struct sk_buff *skb)
        struct c4iw_listen_ep *ep = lookup_stid(t, stid);
 
        PDBG("%s ep %p\n", __func__, ep);
-       ep->com.wr_wait.ret = status2errno(rpl->status);
-       ep->com.wr_wait.done = 1;
-       wake_up(&ep->com.wr_wait.wait);
+       c4iw_wake_up(&ep->com.wr_wait, status2errno(rpl->status));
        return 0;
 }
 
@@ -1466,7 +1462,7 @@ static int peer_close(struct c4iw_dev *dev, struct sk_buff *skb)
        struct c4iw_qp_attributes attrs;
        int disconnect = 1;
        int release = 0;
-       int closing = 0;
+       int abort = 0;
        struct tid_info *t = dev->rdev.lldi.tids;
        unsigned int tid = GET_TID(hdr);
 
@@ -1492,23 +1488,22 @@ static int peer_close(struct c4iw_dev *dev, struct sk_buff *skb)
                 * in rdma connection migration (see c4iw_accept_cr()).
                 */
                __state_set(&ep->com, CLOSING);
-               ep->com.wr_wait.done = 1;
-               ep->com.wr_wait.ret = -ECONNRESET;
                PDBG("waking up ep %p tid %u\n", ep, ep->hwtid);
-               wake_up(&ep->com.wr_wait.wait);
+               c4iw_wake_up(&ep->com.wr_wait, -ECONNRESET);
                break;
        case MPA_REP_SENT:
                __state_set(&ep->com, CLOSING);
-               ep->com.wr_wait.done = 1;
-               ep->com.wr_wait.ret = -ECONNRESET;
                PDBG("waking up ep %p tid %u\n", ep, ep->hwtid);
-               wake_up(&ep->com.wr_wait.wait);
+               c4iw_wake_up(&ep->com.wr_wait, -ECONNRESET);
                break;
        case FPDU_MODE:
                start_ep_timer(ep);
                __state_set(&ep->com, CLOSING);
-               closing = 1;
+               attrs.next_state = C4IW_QP_STATE_CLOSING;
+               abort = c4iw_modify_qp(ep->com.qp->rhp, ep->com.qp,
+                                      C4IW_QP_ATTR_NEXT_STATE, &attrs, 1);
                peer_close_upcall(ep);
+               disconnect = 1;
                break;
        case ABORTING:
                disconnect = 0;
@@ -1536,11 +1531,6 @@ static int peer_close(struct c4iw_dev *dev, struct sk_buff *skb)
                BUG_ON(1);
        }
        mutex_unlock(&ep->com.mutex);
-       if (closing) {
-               attrs.next_state = C4IW_QP_STATE_CLOSING;
-               c4iw_modify_qp(ep->com.qp->rhp, ep->com.qp,
-                              C4IW_QP_ATTR_NEXT_STATE, &attrs, 1);
-       }
        if (disconnect)
                c4iw_ep_disconnect(ep, 0, GFP_KERNEL);
        if (release)
@@ -1581,9 +1571,7 @@ static int peer_abort(struct c4iw_dev *dev, struct sk_buff *skb)
        /*
         * Wake up any threads in rdma_init() or rdma_fini().
         */
-       ep->com.wr_wait.done = 1;
-       ep->com.wr_wait.ret = -ECONNRESET;
-       wake_up(&ep->com.wr_wait.wait);
+       c4iw_wake_up(&ep->com.wr_wait, -ECONNRESET);
 
        mutex_lock(&ep->com.mutex);
        switch (ep->com.state) {
@@ -1710,14 +1698,14 @@ static int terminate(struct c4iw_dev *dev, struct sk_buff *skb)
        ep = lookup_tid(t, tid);
        BUG_ON(!ep);
 
-       if (ep->com.qp) {
+       if (ep && ep->com.qp) {
                printk(KERN_WARNING MOD "TERM received tid %u qpid %u\n", tid,
                       ep->com.qp->wq.sq.qid);
                attrs.next_state = C4IW_QP_STATE_TERMINATE;
                c4iw_modify_qp(ep->com.qp->rhp, ep->com.qp,
                               C4IW_QP_ATTR_NEXT_STATE, &attrs, 1);
        } else
-               printk(KERN_WARNING MOD "TERM received tid %u no qp\n", tid);
+               printk(KERN_WARNING MOD "TERM received tid %u no ep/qp\n", tid);
 
        return 0;
 }
@@ -2296,14 +2284,8 @@ static int fw6_msg(struct c4iw_dev *dev, struct sk_buff *skb)
                ret = (int)((be64_to_cpu(rpl->data[0]) >> 8) & 0xff);
                wr_waitp = (struct c4iw_wr_wait *)(__force unsigned long) rpl->data[1];
                PDBG("%s wr_waitp %p ret %u\n", __func__, wr_waitp, ret);
-               if (wr_waitp) {
-                       if (ret)
-                               wr_waitp->ret = -ret;
-                       else
-                               wr_waitp->ret = 0;
-                       wr_waitp->done = 1;
-                       wake_up(&wr_waitp->wait);
-               }
+               if (wr_waitp)
+                       c4iw_wake_up(wr_waitp, ret ? -ret : 0);
                kfree_skb(skb);
                break;
        case 2:
index e29172c..40a13cc 100644 (file)
@@ -44,7 +44,7 @@ MODULE_DESCRIPTION("Chelsio T4 RDMA Driver");
 MODULE_LICENSE("Dual BSD/GPL");
 MODULE_VERSION(DRV_VERSION);
 
-static LIST_HEAD(dev_list);
+static LIST_HEAD(uld_ctx_list);
 static DEFINE_MUTEX(dev_mutex);
 
 static struct dentry *c4iw_debugfs_root;
@@ -370,18 +370,23 @@ static void c4iw_rdev_close(struct c4iw_rdev *rdev)
        c4iw_destroy_resource(&rdev->resource);
 }
 
-static void c4iw_remove(struct c4iw_dev *dev)
+struct uld_ctx {
+       struct list_head entry;
+       struct cxgb4_lld_info lldi;
+       struct c4iw_dev *dev;
+};
+
+static void c4iw_remove(struct uld_ctx *ctx)
 {
-       PDBG("%s c4iw_dev %p\n", __func__,  dev);
-       list_del(&dev->entry);
-       if (dev->registered)
-               c4iw_unregister_device(dev);
-       c4iw_rdev_close(&dev->rdev);
-       idr_destroy(&dev->cqidr);
-       idr_destroy(&dev->qpidr);
-       idr_destroy(&dev->mmidr);
-       iounmap(dev->rdev.oc_mw_kva);
-       ib_dealloc_device(&dev->ibdev);
+       PDBG("%s c4iw_dev %p\n", __func__,  ctx->dev);
+       c4iw_unregister_device(ctx->dev);
+       c4iw_rdev_close(&ctx->dev->rdev);
+       idr_destroy(&ctx->dev->cqidr);
+       idr_destroy(&ctx->dev->qpidr);
+       idr_destroy(&ctx->dev->mmidr);
+       iounmap(ctx->dev->rdev.oc_mw_kva);
+       ib_dealloc_device(&ctx->dev->ibdev);
+       ctx->dev = NULL;
 }
 
 static struct c4iw_dev *c4iw_alloc(const struct cxgb4_lld_info *infop)
@@ -392,7 +397,7 @@ static struct c4iw_dev *c4iw_alloc(const struct cxgb4_lld_info *infop)
        devp = (struct c4iw_dev *)ib_alloc_device(sizeof(*devp));
        if (!devp) {
                printk(KERN_ERR MOD "Cannot allocate ib device\n");
-               return NULL;
+               return ERR_PTR(-ENOMEM);
        }
        devp->rdev.lldi = *infop;
 
@@ -402,27 +407,23 @@ static struct c4iw_dev *c4iw_alloc(const struct cxgb4_lld_info *infop)
        devp->rdev.oc_mw_kva = ioremap_wc(devp->rdev.oc_mw_pa,
                                               devp->rdev.lldi.vr->ocq.size);
 
-       printk(KERN_INFO MOD "ocq memory: "
+       PDBG(KERN_INFO MOD "ocq memory: "
               "hw_start 0x%x size %u mw_pa 0x%lx mw_kva %p\n",
               devp->rdev.lldi.vr->ocq.start, devp->rdev.lldi.vr->ocq.size,
               devp->rdev.oc_mw_pa, devp->rdev.oc_mw_kva);
 
-       mutex_lock(&dev_mutex);
-
        ret = c4iw_rdev_open(&devp->rdev);
        if (ret) {
                mutex_unlock(&dev_mutex);
                printk(KERN_ERR MOD "Unable to open CXIO rdev err %d\n", ret);
                ib_dealloc_device(&devp->ibdev);
-               return NULL;
+               return ERR_PTR(ret);
        }
 
        idr_init(&devp->cqidr);
        idr_init(&devp->qpidr);
        idr_init(&devp->mmidr);
        spin_lock_init(&devp->lock);
-       list_add_tail(&devp->entry, &dev_list);
-       mutex_unlock(&dev_mutex);
 
        if (c4iw_debugfs_root) {
                devp->debugfs_root = debugfs_create_dir(
@@ -435,7 +436,7 @@ static struct c4iw_dev *c4iw_alloc(const struct cxgb4_lld_info *infop)
 
 static void *c4iw_uld_add(const struct cxgb4_lld_info *infop)
 {
-       struct c4iw_dev *dev;
+       struct uld_ctx *ctx;
        static int vers_printed;
        int i;
 
@@ -443,25 +444,33 @@ static void *c4iw_uld_add(const struct cxgb4_lld_info *infop)
                printk(KERN_INFO MOD "Chelsio T4 RDMA Driver - version %s\n",
                       DRV_VERSION);
 
-       dev = c4iw_alloc(infop);
-       if (!dev)
+       ctx = kzalloc(sizeof *ctx, GFP_KERNEL);
+       if (!ctx) {
+               ctx = ERR_PTR(-ENOMEM);
                goto out;
+       }
+       ctx->lldi = *infop;
 
        PDBG("%s found device %s nchan %u nrxq %u ntxq %u nports %u\n",
-            __func__, pci_name(dev->rdev.lldi.pdev),
-            dev->rdev.lldi.nchan, dev->rdev.lldi.nrxq,
-            dev->rdev.lldi.ntxq, dev->rdev.lldi.nports);
+            __func__, pci_name(ctx->lldi.pdev),
+            ctx->lldi.nchan, ctx->lldi.nrxq,
+            ctx->lldi.ntxq, ctx->lldi.nports);
+
+       mutex_lock(&dev_mutex);
+       list_add_tail(&ctx->entry, &uld_ctx_list);
+       mutex_unlock(&dev_mutex);
 
-       for (i = 0; i < dev->rdev.lldi.nrxq; i++)
-               PDBG("rxqid[%u] %u\n", i, dev->rdev.lldi.rxq_ids[i]);
+       for (i = 0; i < ctx->lldi.nrxq; i++)
+               PDBG("rxqid[%u] %u\n", i, ctx->lldi.rxq_ids[i]);
 out:
-       return dev;
+       return ctx;
 }
 
 static int c4iw_uld_rx_handler(void *handle, const __be64 *rsp,
                        const struct pkt_gl *gl)
 {
-       struct c4iw_dev *dev = handle;
+       struct uld_ctx *ctx = handle;
+       struct c4iw_dev *dev = ctx->dev;
        struct sk_buff *skb;
        const struct cpl_act_establish *rpl;
        unsigned int opcode;
@@ -503,47 +512,49 @@ nomem:
 
 static int c4iw_uld_state_change(void *handle, enum cxgb4_state new_state)
 {
-       struct c4iw_dev *dev = handle;
+       struct uld_ctx *ctx = handle;
 
        PDBG("%s new_state %u\n", __func__, new_state);
        switch (new_state) {
        case CXGB4_STATE_UP:
-               printk(KERN_INFO MOD "%s: Up\n", pci_name(dev->rdev.lldi.pdev));
-               if (!dev->registered) {
-                       int ret;
-                       ret = c4iw_register_device(dev);
-                       if (ret)
+               printk(KERN_INFO MOD "%s: Up\n", pci_name(ctx->lldi.pdev));
+               if (!ctx->dev) {
+                       int ret = 0;
+
+                       ctx->dev = c4iw_alloc(&ctx->lldi);
+                       if (!IS_ERR(ctx->dev))
+                               ret = c4iw_register_device(ctx->dev);
+                       if (IS_ERR(ctx->dev) || ret)
                                printk(KERN_ERR MOD
                                       "%s: RDMA registration failed: %d\n",
-                                      pci_name(dev->rdev.lldi.pdev), ret);
+                                      pci_name(ctx->lldi.pdev), ret);
                }
                break;
        case CXGB4_STATE_DOWN:
                printk(KERN_INFO MOD "%s: Down\n",
-                      pci_name(dev->rdev.lldi.pdev));
-               if (dev->registered)
-                       c4iw_unregister_device(dev);
+                      pci_name(ctx->lldi.pdev));
+               if (ctx->dev)
+                       c4iw_remove(ctx);
                break;
        case CXGB4_STATE_START_RECOVERY:
                printk(KERN_INFO MOD "%s: Fatal Error\n",
-                      pci_name(dev->rdev.lldi.pdev));
-               dev->rdev.flags |= T4_FATAL_ERROR;
-               if (dev->registered) {
+                      pci_name(ctx->lldi.pdev));
+               if (ctx->dev) {
                        struct ib_event event;
 
+                       ctx->dev->rdev.flags |= T4_FATAL_ERROR;
                        memset(&event, 0, sizeof event);
                        event.event  = IB_EVENT_DEVICE_FATAL;
-                       event.device = &dev->ibdev;
+                       event.device = &ctx->dev->ibdev;
                        ib_dispatch_event(&event);
-                       c4iw_unregister_device(dev);
+                       c4iw_remove(ctx);
                }
                break;
        case CXGB4_STATE_DETACH:
                printk(KERN_INFO MOD "%s: Detach\n",
-                      pci_name(dev->rdev.lldi.pdev));
-               mutex_lock(&dev_mutex);
-               c4iw_remove(dev);
-               mutex_unlock(&dev_mutex);
+                      pci_name(ctx->lldi.pdev));
+               if (ctx->dev)
+                       c4iw_remove(ctx);
                break;
        }
        return 0;
@@ -576,11 +587,13 @@ static int __init c4iw_init_module(void)
 
 static void __exit c4iw_exit_module(void)
 {
-       struct c4iw_dev *dev, *tmp;
+       struct uld_ctx *ctx, *tmp;
 
        mutex_lock(&dev_mutex);
-       list_for_each_entry_safe(dev, tmp, &dev_list, entry) {
-               c4iw_remove(dev);
+       list_for_each_entry_safe(ctx, tmp, &uld_ctx_list, entry) {
+               if (ctx->dev)
+                       c4iw_remove(ctx);
+               kfree(ctx);
        }
        mutex_unlock(&dev_mutex);
        cxgb4_unregister_uld(CXGB4_ULD_RDMA);
index 9f6166f..35d2a5d 100644 (file)
@@ -131,42 +131,58 @@ static inline int c4iw_num_stags(struct c4iw_rdev *rdev)
 
 #define C4IW_WR_TO (10*HZ)
 
+enum {
+       REPLY_READY = 0,
+};
+
 struct c4iw_wr_wait {
        wait_queue_head_t wait;
-       int done;
+       unsigned long status;
        int ret;
 };
 
 static inline void c4iw_init_wr_wait(struct c4iw_wr_wait *wr_waitp)
 {
        wr_waitp->ret = 0;
-       wr_waitp->done = 0;
+       wr_waitp->status = 0;
        init_waitqueue_head(&wr_waitp->wait);
 }
 
+static inline void c4iw_wake_up(struct c4iw_wr_wait *wr_waitp, int ret)
+{
+       wr_waitp->ret = ret;
+       set_bit(REPLY_READY, &wr_waitp->status);
+       wake_up(&wr_waitp->wait);
+}
+
 static inline int c4iw_wait_for_reply(struct c4iw_rdev *rdev,
                                 struct c4iw_wr_wait *wr_waitp,
                                 u32 hwtid, u32 qpid,
                                 const char *func)
 {
        unsigned to = C4IW_WR_TO;
-       do {
+       int ret;
 
-               wait_event_timeout(wr_waitp->wait, wr_waitp->done, to);
-               if (!wr_waitp->done) {
+       do {
+               ret = wait_event_timeout(wr_waitp->wait,
+                       test_and_clear_bit(REPLY_READY, &wr_waitp->status), to);
+               if (!ret) {
                        printk(KERN_ERR MOD "%s - Device %s not responding - "
                               "tid %u qpid %u\n", func,
                               pci_name(rdev->lldi.pdev), hwtid, qpid);
+                       if (c4iw_fatal_error(rdev)) {
+                               wr_waitp->ret = -EIO;
+                               break;
+                       }
                        to = to << 2;
                }
-       } while (!wr_waitp->done);
+       } while (!ret);
        if (wr_waitp->ret)
-               printk(KERN_WARNING MOD "%s: FW reply %d tid %u qpid %u\n",
-                      pci_name(rdev->lldi.pdev), wr_waitp->ret, hwtid, qpid);
+               PDBG("%s: FW reply %d tid %u qpid %u\n",
+                    pci_name(rdev->lldi.pdev), wr_waitp->ret, hwtid, qpid);
        return wr_waitp->ret;
 }
 
-
 struct c4iw_dev {
        struct ib_device ibdev;
        struct c4iw_rdev rdev;
@@ -175,9 +191,7 @@ struct c4iw_dev {
        struct idr qpidr;
        struct idr mmidr;
        spinlock_t lock;
-       struct list_head entry;
        struct dentry *debugfs_root;
-       u8 registered;
 };
 
 static inline struct c4iw_dev *to_c4iw_dev(struct ib_device *ibdev)
index f66dd8b..5b9e422 100644 (file)
@@ -516,7 +516,6 @@ int c4iw_register_device(struct c4iw_dev *dev)
                if (ret)
                        goto bail2;
        }
-       dev->registered = 1;
        return 0;
 bail2:
        ib_unregister_device(&dev->ibdev);
@@ -535,6 +534,5 @@ void c4iw_unregister_device(struct c4iw_dev *dev)
                                   c4iw_class_attributes[i]);
        ib_unregister_device(&dev->ibdev);
        kfree(dev->ibdev.iwcm);
-       dev->registered = 0;
        return;
 }
index 70a5a3c..3b773b0 100644 (file)
@@ -214,7 +214,7 @@ static int create_qp(struct c4iw_rdev *rdev, struct t4_wq *wq,
                V_FW_RI_RES_WR_HOSTFCMODE(0) |  /* no host cidx updates */
                V_FW_RI_RES_WR_CPRIO(0) |       /* don't keep in chip cache */
                V_FW_RI_RES_WR_PCIECHN(0) |     /* set by uP at ri_init time */
-               t4_sq_onchip(&wq->sq) ? F_FW_RI_RES_WR_ONCHIP : 0 |
+               (t4_sq_onchip(&wq->sq) ? F_FW_RI_RES_WR_ONCHIP : 0) |
                V_FW_RI_RES_WR_IQID(scq->cqid));
        res->u.sqrq.dcaen_to_eqsize = cpu_to_be32(
                V_FW_RI_RES_WR_DCAEN(0) |
@@ -1210,7 +1210,6 @@ int c4iw_modify_qp(struct c4iw_dev *rhp, struct c4iw_qp *qhp,
                        if (ret) {
                                if (internal)
                                        c4iw_get_ep(&qhp->ep->com);
-                               disconnect = abort = 1;
                                goto err;
                        }
                        break;
index 58c0e41..be24ac7 100644 (file)
@@ -398,7 +398,6 @@ static int __devinit ipath_init_one(struct pci_dev *pdev,
        struct ipath_devdata *dd;
        unsigned long long addr;
        u32 bar0 = 0, bar1 = 0;
-       u8 rev;
 
        dd = ipath_alloc_devdata(pdev);
        if (IS_ERR(dd)) {
@@ -540,13 +539,7 @@ static int __devinit ipath_init_one(struct pci_dev *pdev,
                goto bail_regions;
        }
 
-       ret = pci_read_config_byte(pdev, PCI_REVISION_ID, &rev);
-       if (ret) {
-               ipath_dev_err(dd, "Failed to read PCI revision ID unit "
-                             "%u: err %d\n", dd->ipath_unit, -ret);
-               goto bail_regions;      /* shouldn't ever happen */
-       }
-       dd->ipath_pcirev = rev;
+       dd->ipath_pcirev = pdev->revision;
 
 #if defined(__powerpc__)
        /* There isn't a generic way to specify writethrough mappings */
index 33c7eed..e74cdf9 100644 (file)
@@ -2563,7 +2563,7 @@ static int nes_cm_disconn_true(struct nes_qp *nesqp)
        u16 last_ae;
        u8 original_hw_tcp_state;
        u8 original_ibqp_state;
-       enum iw_cm_event_status disconn_status = IW_CM_EVENT_STATUS_OK;
+       int disconn_status = 0;
        int issue_disconn = 0;
        int issue_close = 0;
        int issue_flush = 0;
@@ -2605,7 +2605,7 @@ static int nes_cm_disconn_true(struct nes_qp *nesqp)
                        (last_ae == NES_AEQE_AEID_LLP_CONNECTION_RESET))) {
                issue_disconn = 1;
                if (last_ae == NES_AEQE_AEID_LLP_CONNECTION_RESET)
-                       disconn_status = IW_CM_EVENT_STATUS_RESET;
+                       disconn_status = -ECONNRESET;
        }
 
        if (((original_hw_tcp_state == NES_AEQE_TCP_STATE_CLOSED) ||
@@ -2666,7 +2666,7 @@ static int nes_cm_disconn_true(struct nes_qp *nesqp)
                        cm_id->provider_data = nesqp;
                        /* Send up the close complete event */
                        cm_event.event = IW_CM_EVENT_CLOSE;
-                       cm_event.status = IW_CM_EVENT_STATUS_OK;
+                       cm_event.status = 0;
                        cm_event.provider_data = cm_id->provider_data;
                        cm_event.local_addr = cm_id->local_addr;
                        cm_event.remote_addr = cm_id->remote_addr;
@@ -2966,7 +2966,7 @@ int nes_accept(struct iw_cm_id *cm_id, struct iw_cm_conn_param *conn_param)
        nes_add_ref(&nesqp->ibqp);
 
        cm_event.event = IW_CM_EVENT_ESTABLISHED;
-       cm_event.status = IW_CM_EVENT_STATUS_ACCEPTED;
+       cm_event.status = 0;
        cm_event.provider_data = (void *)nesqp;
        cm_event.local_addr = cm_id->local_addr;
        cm_event.remote_addr = cm_id->remote_addr;
@@ -3377,7 +3377,7 @@ static void cm_event_connected(struct nes_cm_event *event)
 
        /* notify OF layer we successfully created the requested connection */
        cm_event.event = IW_CM_EVENT_CONNECT_REPLY;
-       cm_event.status = IW_CM_EVENT_STATUS_ACCEPTED;
+       cm_event.status = 0;
        cm_event.provider_data = cm_id->provider_data;
        cm_event.local_addr.sin_family = AF_INET;
        cm_event.local_addr.sin_port = cm_id->local_addr.sin_port;
@@ -3484,7 +3484,7 @@ static void cm_event_reset(struct nes_cm_event *event)
        nesqp->cm_id = NULL;
        /* cm_id->provider_data = NULL; */
        cm_event.event = IW_CM_EVENT_DISCONNECT;
-       cm_event.status = IW_CM_EVENT_STATUS_RESET;
+       cm_event.status = -ECONNRESET;
        cm_event.provider_data = cm_id->provider_data;
        cm_event.local_addr = cm_id->local_addr;
        cm_event.remote_addr = cm_id->remote_addr;
@@ -3495,7 +3495,7 @@ static void cm_event_reset(struct nes_cm_event *event)
        ret = cm_id->event_handler(cm_id, &cm_event);
        atomic_inc(&cm_closes);
        cm_event.event = IW_CM_EVENT_CLOSE;
-       cm_event.status = IW_CM_EVENT_STATUS_OK;
+       cm_event.status = 0;
        cm_event.provider_data = cm_id->provider_data;
        cm_event.local_addr = cm_id->local_addr;
        cm_event.remote_addr = cm_id->remote_addr;
@@ -3534,7 +3534,7 @@ static void cm_event_mpa_req(struct nes_cm_event *event)
                        cm_node, cm_id, jiffies);
 
        cm_event.event = IW_CM_EVENT_CONNECT_REQUEST;
-       cm_event.status = IW_CM_EVENT_STATUS_OK;
+       cm_event.status = 0;
        cm_event.provider_data = (void *)cm_node;
 
        cm_event.local_addr.sin_family = AF_INET;
index 26d8018..95ca93c 100644 (file)
@@ -1484,7 +1484,7 @@ static int nes_destroy_qp(struct ib_qp *ibqp)
                        (nesqp->ibqp_state == IB_QPS_RTR)) && (nesqp->cm_id)) {
                cm_id = nesqp->cm_id;
                cm_event.event = IW_CM_EVENT_CONNECT_REPLY;
-               cm_event.status = IW_CM_EVENT_STATUS_TIMEOUT;
+               cm_event.status = -ETIMEDOUT;
                cm_event.local_addr = cm_id->local_addr;
                cm_event.remote_addr = cm_id->remote_addr;
                cm_event.private_data = NULL;
index 6bab3ea..9f53e68 100644 (file)
@@ -7534,7 +7534,8 @@ static int serdes_7322_init_new(struct qib_pportdata *ppd)
        ibsd_wr_allchans(ppd, 4, (1 << 10), BMASK(10, 10));
        tstart = get_jiffies_64();
        while (chan_done &&
-              !time_after64(tstart, tstart + msecs_to_jiffies(500))) {
+              !time_after64(get_jiffies_64(),
+                       tstart + msecs_to_jiffies(500))) {
                msleep(20);
                for (chan = 0; chan < SERDES_CHANS; ++chan) {
                        rxcaldone = ahb_mod(ppd->dd, IBSD(ppd->hw_pidx),
index 48b6674..891cc2f 100644 (file)
@@ -526,11 +526,8 @@ static int qib_tune_pcie_coalesce(struct qib_devdata *dd)
         */
        devid = parent->device;
        if (devid >= 0x25e2 && devid <= 0x25fa) {
-               u8 rev;
-
                /* 5000 P/V/X/Z */
-               pci_read_config_byte(parent, PCI_REVISION_ID, &rev);
-               if (rev <= 0xb2)
+               if (parent->revision <= 0xb2)
                        bits = 1U << 10;
                else
                        bits = 7U << 10;
index 1839194..10bcd4a 100644 (file)
@@ -223,8 +223,9 @@ static int __init atakbd_init(void)
                return -ENODEV;
 
        // need to init core driver if not already done so
-       if (atari_keyb_init())
-               return -ENODEV;
+       error = atari_keyb_init();
+       if (error)
+               return error;
 
        atakbd_dev = input_allocate_device();
        if (!atakbd_dev)
index adf45b3..5c4a692 100644 (file)
@@ -77,15 +77,15 @@ static void atamouse_interrupt(char *buf)
 #endif
 
        /* only relative events get here */
-       dx =  buf[1];
-       dy = -buf[2];
+       dx = buf[1];
+       dy = buf[2];
 
        input_report_rel(atamouse_dev, REL_X, dx);
        input_report_rel(atamouse_dev, REL_Y, dy);
 
-       input_report_key(atamouse_dev, BTN_LEFT,   buttons & 0x1);
+       input_report_key(atamouse_dev, BTN_LEFT,   buttons & 0x4);
        input_report_key(atamouse_dev, BTN_MIDDLE, buttons & 0x2);
-       input_report_key(atamouse_dev, BTN_RIGHT,  buttons & 0x4);
+       input_report_key(atamouse_dev, BTN_RIGHT,  buttons & 0x1);
 
        input_sync(atamouse_dev);
 
@@ -108,7 +108,7 @@ static int atamouse_open(struct input_dev *dev)
 static void atamouse_close(struct input_dev *dev)
 {
        ikbd_mouse_disable();
-       atari_mouse_interrupt_hook = NULL;
+       atari_input_mouse_interrupt_hook = NULL;
 }
 
 static int __init atamouse_init(void)
@@ -118,8 +118,9 @@ static int __init atamouse_init(void)
        if (!MACH_IS_ATARI || !ATARIHW_PRESENT(ST_MFP))
                return -ENODEV;
 
-       if (!atari_keyb_init())
-               return -ENODEV;
+       error = atari_keyb_init();
+       if (error)
+               return error;
 
        atamouse_dev = input_allocate_device();
        if (!atamouse_dev)
index c24946f..1de1c19 100644 (file)
@@ -281,17 +281,24 @@ struct ser_req {
        u8                      command;
        u8                      ref_off;
        u16                     scratch;
-       __be16                  sample;
        struct spi_message      msg;
        struct spi_transfer     xfer[6];
+       /*
+        * DMA (thus cache coherency maintenance) requires the
+        * transfer buffers to live in their own cache lines.
+        */
+       __be16 sample ____cacheline_aligned;
 };
 
 struct ads7845_ser_req {
        u8                      command[3];
-       u8                      pwrdown[3];
-       u8                      sample[3];
        struct spi_message      msg;
        struct spi_transfer     xfer[2];
+       /*
+        * DMA (thus cache coherency maintenance) requires the
+        * transfer buffers to live in their own cache lines.
+        */
+       u8 sample[3] ____cacheline_aligned;
 };
 
 static int ads7846_read12_ser(struct device *dev, unsigned command)
index e7089a1..b37e618 100644 (file)
@@ -349,6 +349,7 @@ static const struct i2c_device_id lm3530_id[] = {
        {LM3530_NAME, 0},
        {}
 };
+MODULE_DEVICE_TABLE(i2c, lm3530_id);
 
 static struct i2c_driver lm3530_i2c_driver = {
        .probe = lm3530_probe,
index 0aaa059..34ae49d 100644 (file)
@@ -5,8 +5,10 @@ config LGUEST
        ---help---
          This is a very simple module which allows you to run
          multiple instances of the same Linux kernel, using the
-         "lguest" command found in the Documentation/lguest directory.
+         "lguest" command found in the Documentation/virtual/lguest
+         directory.
+
          Note that "lguest" is pronounced to rhyme with "fell quest",
-         not "rustyvisor".  See Documentation/lguest/lguest.txt.
+         not "rustyvisor". See Documentation/virtual/lguest/lguest.txt.
 
          If unsure, say N.  If curious, say M.  If masochistic, say Y.
index 7d463c2..8ac947c 100644 (file)
@@ -18,7 +18,7 @@ Mastery: PREFIX=M
 Beer:
        @for f in Preparation Guest Drivers Launcher Host Switcher Mastery; do echo "{==- $$f -==}"; make -s $$f; done; echo "{==-==}"
 Preparation Preparation! Guest Drivers Launcher Host Switcher Mastery:
-       @sh ../../Documentation/lguest/extract $(PREFIX) `find ../../* -name '*.[chS]' -wholename '*lguest*'`
+       @sh ../../Documentation/virtual/lguest/extract $(PREFIX) `find ../../* -name '*.[chS]' -wholename '*lguest*'`
 Puppy:
        @clear
        @printf "      __  \n (___()'\`;\n /,    /\`\n \\\\\\\"--\\\\\\   \n"
index c820e2f..3f44200 100644 (file)
@@ -524,7 +524,7 @@ void cx88_ir_irq(struct cx88_core *core)
        for (todo = 32; todo > 0; todo -= bits) {
                ev.pulse = samples & 0x80000000 ? false : true;
                bits = min(todo, 32U - fls(ev.pulse ? samples : ~samples));
-               ev.duration = (bits * NSEC_PER_SEC) / (1000 * ir_samplerate);
+               ev.duration = (bits * (NSEC_PER_SEC / 1000)) / ir_samplerate;
                ir_raw_event_store_with_filter(ir->dev, &ev);
                samples <<= bits;
        }
index 3973f9a..ddb4c09 100644 (file)
@@ -136,11 +136,50 @@ unsigned long soc_camera_apply_sensor_flags(struct soc_camera_link *icl,
 }
 EXPORT_SYMBOL(soc_camera_apply_sensor_flags);
 
+#define pixfmtstr(x) (x) & 0xff, ((x) >> 8) & 0xff, ((x) >> 16) & 0xff, \
+       ((x) >> 24) & 0xff
+
+static int soc_camera_try_fmt(struct soc_camera_device *icd,
+                             struct v4l2_format *f)
+{
+       struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
+       struct v4l2_pix_format *pix = &f->fmt.pix;
+       int ret;
+
+       dev_dbg(&icd->dev, "TRY_FMT(%c%c%c%c, %ux%u)\n",
+               pixfmtstr(pix->pixelformat), pix->width, pix->height);
+
+       pix->bytesperline = 0;
+       pix->sizeimage = 0;
+
+       ret = ici->ops->try_fmt(icd, f);
+       if (ret < 0)
+               return ret;
+
+       if (!pix->sizeimage) {
+               if (!pix->bytesperline) {
+                       const struct soc_camera_format_xlate *xlate;
+
+                       xlate = soc_camera_xlate_by_fourcc(icd, pix->pixelformat);
+                       if (!xlate)
+                               return -EINVAL;
+
+                       ret = soc_mbus_bytes_per_line(pix->width,
+                                                     xlate->host_fmt);
+                       if (ret > 0)
+                               pix->bytesperline = ret;
+               }
+               if (pix->bytesperline)
+                       pix->sizeimage = pix->bytesperline * pix->height;
+       }
+
+       return 0;
+}
+
 static int soc_camera_try_fmt_vid_cap(struct file *file, void *priv,
                                      struct v4l2_format *f)
 {
        struct soc_camera_device *icd = file->private_data;
-       struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
 
        WARN_ON(priv != file->private_data);
 
@@ -149,7 +188,7 @@ static int soc_camera_try_fmt_vid_cap(struct file *file, void *priv,
                return -EINVAL;
 
        /* limit format to hardware capabilities */
-       return ici->ops->try_fmt(icd, f);
+       return soc_camera_try_fmt(icd, f);
 }
 
 static int soc_camera_enum_input(struct file *file, void *priv,
@@ -362,9 +401,6 @@ static void soc_camera_free_user_formats(struct soc_camera_device *icd)
        icd->user_formats = NULL;
 }
 
-#define pixfmtstr(x) (x) & 0xff, ((x) >> 8) & 0xff, ((x) >> 16) & 0xff, \
-       ((x) >> 24) & 0xff
-
 /* Called with .vb_lock held, or from the first open(2), see comment there */
 static int soc_camera_set_fmt(struct soc_camera_device *icd,
                              struct v4l2_format *f)
@@ -377,7 +413,7 @@ static int soc_camera_set_fmt(struct soc_camera_device *icd,
                pixfmtstr(pix->pixelformat), pix->width, pix->height);
 
        /* We always call try_fmt() before set_fmt() or set_crop() */
-       ret = ici->ops->try_fmt(icd, f);
+       ret = soc_camera_try_fmt(icd, f);
        if (ret < 0)
                return ret;
 
index 5aeaf87..4aae501 100644 (file)
@@ -155,8 +155,10 @@ int v4l2_device_register_subdev(struct v4l2_device *v4l2_dev,
        sd->v4l2_dev = v4l2_dev;
        if (sd->internal_ops && sd->internal_ops->registered) {
                err = sd->internal_ops->registered(sd);
-               if (err)
+               if (err) {
+                       module_put(sd->owner);
                        return err;
+               }
        }
 
        /* This just returns 0 if either of the two args is NULL */
@@ -164,6 +166,7 @@ int v4l2_device_register_subdev(struct v4l2_device *v4l2_dev,
        if (err) {
                if (sd->internal_ops && sd->internal_ops->unregistered)
                        sd->internal_ops->unregistered(sd);
+               module_put(sd->owner);
                return err;
        }
 
index 0b80644..812729e 100644 (file)
@@ -155,25 +155,25 @@ static long subdev_do_ioctl(struct file *file, unsigned int cmd, void *arg)
 
        switch (cmd) {
        case VIDIOC_QUERYCTRL:
-               return v4l2_subdev_queryctrl(sd, arg);
+               return v4l2_queryctrl(sd->ctrl_handler, arg);
 
        case VIDIOC_QUERYMENU:
-               return v4l2_subdev_querymenu(sd, arg);
+               return v4l2_querymenu(sd->ctrl_handler, arg);
 
        case VIDIOC_G_CTRL:
-               return v4l2_subdev_g_ctrl(sd, arg);
+               return v4l2_g_ctrl(sd->ctrl_handler, arg);
 
        case VIDIOC_S_CTRL:
-               return v4l2_subdev_s_ctrl(sd, arg);
+               return v4l2_s_ctrl(sd->ctrl_handler, arg);
 
        case VIDIOC_G_EXT_CTRLS:
-               return v4l2_subdev_g_ext_ctrls(sd, arg);
+               return v4l2_g_ext_ctrls(sd->ctrl_handler, arg);
 
        case VIDIOC_S_EXT_CTRLS:
-               return v4l2_subdev_s_ext_ctrls(sd, arg);
+               return v4l2_s_ext_ctrls(sd->ctrl_handler, arg);
 
        case VIDIOC_TRY_EXT_CTRLS:
-               return v4l2_subdev_try_ext_ctrls(sd, arg);
+               return v4l2_try_ext_ctrls(sd->ctrl_handler, arg);
 
        case VIDIOC_DQEVENT:
                if (!(sd->flags & V4L2_SUBDEV_FL_HAS_EVENTS))
index 643ad52..4796bbf 100644 (file)
@@ -1000,7 +1000,6 @@ static struct i2o_block_device *i2o_block_device_alloc(void)
        gd->major = I2O_MAJOR;
        gd->queue = queue;
        gd->fops = &i2o_block_fops;
-       gd->events = DISK_EVENT_MEDIA_CHANGE;
        gd->private_data = dev;
 
        dev->gd = gd;
index d4a851c..0b4d5b2 100644 (file)
@@ -144,7 +144,7 @@ static void asic3_irq_demux(unsigned int irq, struct irq_desc *desc)
        int iter, i;
        unsigned long flags;
 
-       data->chip->irq_ack(irq_data);
+       data->chip->irq_ack(data);
 
        for (iter = 0 ; iter < MAX_ASIC_ISR_LOOPS; iter++) {
                u32 status;
index 2e16511..3ab9ffa 100644 (file)
@@ -717,14 +717,14 @@ static int usbhs_enable(struct device *dev)
                        gpio_request(pdata->ehci_data->reset_gpio_port[0],
                                                "USB1 PHY reset");
                        gpio_direction_output
-                               (pdata->ehci_data->reset_gpio_port[0], 1);
+                               (pdata->ehci_data->reset_gpio_port[0], 0);
                }
 
                if (gpio_is_valid(pdata->ehci_data->reset_gpio_port[1])) {
                        gpio_request(pdata->ehci_data->reset_gpio_port[1],
                                                "USB2 PHY reset");
                        gpio_direction_output
-                               (pdata->ehci_data->reset_gpio_port[1], 1);
+                               (pdata->ehci_data->reset_gpio_port[1], 0);
                }
 
                /* Hold the PHY in RESET for enough time till DIR is high */
@@ -904,11 +904,11 @@ static int usbhs_enable(struct device *dev)
 
                if (gpio_is_valid(pdata->ehci_data->reset_gpio_port[0]))
                        gpio_set_value
-                               (pdata->ehci_data->reset_gpio_port[0], 0);
+                               (pdata->ehci_data->reset_gpio_port[0], 1);
 
                if (gpio_is_valid(pdata->ehci_data->reset_gpio_port[1]))
                        gpio_set_value
-                               (pdata->ehci_data->reset_gpio_port[1], 0);
+                               (pdata->ehci_data->reset_gpio_port[1], 1);
        }
 
 end_count:
index 16422de..2c0d4d1 100644 (file)
@@ -447,12 +447,13 @@ static int __init load_twl4030_script(struct twl4030_script *tscript,
                if (err)
                        goto out;
        }
-       if (tscript->flags & TWL4030_SLEEP_SCRIPT)
+       if (tscript->flags & TWL4030_SLEEP_SCRIPT) {
                if (order)
                        pr_warning("TWL4030: Bad order of scripts (sleep "\
                                        "script before wakeup) Leads to boot"\
                                        "failure on some boards\n");
                err = twl4030_config_sleep_sequence(address);
+       }
 out:
        return err;
 }
index 2c8c3f3..abb5de1 100644 (file)
@@ -5,7 +5,7 @@
 menu "Texas Instruments shared transport line discipline"
 config TI_ST
        tristate "Shared transport core driver"
-       depends on RFKILL
+       depends on NET && GPIOLIB
        select FW_LOADER
        help
          This enables the shared transport core driver for TI
index 486117f..f91f82e 100644 (file)
@@ -43,13 +43,15 @@ static void add_channel_to_table(struct st_data_s *st_gdata,
        pr_info("%s: id %d\n", __func__, new_proto->chnl_id);
        /* list now has the channel id as index itself */
        st_gdata->list[new_proto->chnl_id] = new_proto;
+       st_gdata->is_registered[new_proto->chnl_id] = true;
 }
 
 static void remove_channel_from_table(struct st_data_s *st_gdata,
                struct st_proto_s *proto)
 {
        pr_info("%s: id %d\n", __func__, proto->chnl_id);
-       st_gdata->list[proto->chnl_id] = NULL;
+/*     st_gdata->list[proto->chnl_id] = NULL; */
+       st_gdata->is_registered[proto->chnl_id] = false;
 }
 
 /*
@@ -104,7 +106,7 @@ void st_send_frame(unsigned char chnl_id, struct st_data_s *st_gdata)
 
        if (unlikely
            (st_gdata == NULL || st_gdata->rx_skb == NULL
-            || st_gdata->list[chnl_id] == NULL)) {
+            || st_gdata->is_registered[chnl_id] == false)) {
                pr_err("chnl_id %d not registered, no data to send?",
                           chnl_id);
                kfree_skb(st_gdata->rx_skb);
@@ -141,14 +143,15 @@ void st_reg_complete(struct st_data_s *st_gdata, char err)
        unsigned char i = 0;
        pr_info(" %s ", __func__);
        for (i = 0; i < ST_MAX_CHANNELS; i++) {
-               if (likely(st_gdata != NULL && st_gdata->list[i] != NULL &&
-                          st_gdata->list[i]->reg_complete_cb != NULL)) {
+               if (likely(st_gdata != NULL &&
+                       st_gdata->is_registered[i] == true &&
+                               st_gdata->list[i]->reg_complete_cb != NULL)) {
                        st_gdata->list[i]->reg_complete_cb
                                (st_gdata->list[i]->priv_data, err);
                        pr_info("protocol %d's cb sent %d\n", i, err);
                        if (err) { /* cleanup registered protocol */
                                st_gdata->protos_registered--;
-                               st_gdata->list[i] = NULL;
+                               st_gdata->is_registered[i] = false;
                        }
                }
        }
@@ -475,9 +478,9 @@ void kim_st_list_protocols(struct st_data_s *st_gdata, void *buf)
 {
        seq_printf(buf, "[%d]\nBT=%c\nFM=%c\nGPS=%c\n",
                        st_gdata->protos_registered,
-                       st_gdata->list[0x04] != NULL ? 'R' : 'U',
-                       st_gdata->list[0x08] != NULL ? 'R' : 'U',
-                       st_gdata->list[0x09] != NULL ? 'R' : 'U');
+                       st_gdata->is_registered[0x04] == true ? 'R' : 'U',
+                       st_gdata->is_registered[0x08] == true ? 'R' : 'U',
+                       st_gdata->is_registered[0x09] == true ? 'R' : 'U');
 }
 
 /********************************************************************/
@@ -504,7 +507,7 @@ long st_register(struct st_proto_s *new_proto)
                return -EPROTONOSUPPORT;
        }
 
-       if (st_gdata->list[new_proto->chnl_id] != NULL) {
+       if (st_gdata->is_registered[new_proto->chnl_id] == true) {
                pr_err("chnl_id %d already registered", new_proto->chnl_id);
                return -EALREADY;
        }
@@ -563,7 +566,7 @@ long st_register(struct st_proto_s *new_proto)
                /* check for already registered once more,
                 * since the above check is old
                 */
-               if (st_gdata->list[new_proto->chnl_id] != NULL) {
+               if (st_gdata->is_registered[new_proto->chnl_id] == true) {
                        pr_err(" proto %d already registered ",
                                   new_proto->chnl_id);
                        return -EALREADY;
index b4488c8..5da93ee 100644 (file)
@@ -30,6 +30,7 @@
 #include <linux/debugfs.h>
 #include <linux/seq_file.h>
 #include <linux/sched.h>
+#include <linux/sysfs.h>
 #include <linux/tty.h>
 
 #include <linux/skbuff.h>
index 2b200c1..461e6a1 100644 (file)
@@ -94,7 +94,7 @@ static void mmc_host_clk_gate_delayed(struct mmc_host *host)
                spin_unlock_irqrestore(&host->clk_lock, flags);
                return;
        }
-       mmc_claim_host(host);
+       mutex_lock(&host->clk_gate_mutex);
        spin_lock_irqsave(&host->clk_lock, flags);
        if (!host->clk_requests) {
                spin_unlock_irqrestore(&host->clk_lock, flags);
@@ -104,7 +104,7 @@ static void mmc_host_clk_gate_delayed(struct mmc_host *host)
                pr_debug("%s: gated MCI clock\n", mmc_hostname(host));
        }
        spin_unlock_irqrestore(&host->clk_lock, flags);
-       mmc_release_host(host);
+       mutex_unlock(&host->clk_gate_mutex);
 }
 
 /*
@@ -130,7 +130,7 @@ void mmc_host_clk_ungate(struct mmc_host *host)
 {
        unsigned long flags;
 
-       mmc_claim_host(host);
+       mutex_lock(&host->clk_gate_mutex);
        spin_lock_irqsave(&host->clk_lock, flags);
        if (host->clk_gated) {
                spin_unlock_irqrestore(&host->clk_lock, flags);
@@ -140,7 +140,7 @@ void mmc_host_clk_ungate(struct mmc_host *host)
        }
        host->clk_requests++;
        spin_unlock_irqrestore(&host->clk_lock, flags);
-       mmc_release_host(host);
+       mutex_unlock(&host->clk_gate_mutex);
 }
 
 /**
@@ -215,6 +215,7 @@ static inline void mmc_host_clk_init(struct mmc_host *host)
        host->clk_gated = false;
        INIT_WORK(&host->clk_gate_work, mmc_host_clk_gate_work);
        spin_lock_init(&host->clk_lock);
+       mutex_init(&host->clk_gate_mutex);
 }
 
 /**
index f9b611f..60e4186 100644 (file)
@@ -124,8 +124,10 @@ static bool __devinit sdhci_of_wp_inverted(struct device_node *np)
 #endif
 }
 
+static const struct of_device_id sdhci_of_match[];
 static int __devinit sdhci_of_probe(struct platform_device *ofdev)
 {
+       const struct of_device_id *match;
        struct device_node *np = ofdev->dev.of_node;
        struct sdhci_of_data *sdhci_of_data;
        struct sdhci_host *host;
@@ -134,9 +136,10 @@ static int __devinit sdhci_of_probe(struct platform_device *ofdev)
        int size;
        int ret;
 
-       if (!ofdev->dev.of_match)
+       match = of_match_device(sdhci_of_match, &ofdev->dev);
+       if (!match)
                return -EINVAL;
-       sdhci_of_data = ofdev->dev.of_match->data;
+       sdhci_of_data = match->data;
 
        if (!of_device_is_available(np))
                return -ENODEV;
index 44b1f46..5069111 100644 (file)
@@ -260,6 +260,13 @@ config MTD_BCM963XX
          Support for parsing CFE image tag and creating MTD partitions on
          Broadcom BCM63xx boards.
 
+config MTD_LANTIQ
+       tristate "Lantiq SoC NOR support"
+       depends on LANTIQ
+       select MTD_PARTITIONS
+       help
+         Support for NOR flash attached to the Lantiq SoC's External Bus Unit.
+
 config MTD_DILNETPC
        tristate "CFI Flash device mapped on DIL/Net PC"
        depends on X86 && MTD_PARTITIONS && MTD_CFI_INTELEXT && BROKEN
index 08533bd..6adf4c9 100644 (file)
@@ -60,3 +60,4 @@ obj-$(CONFIG_MTD_VMU)         += vmu-flash.o
 obj-$(CONFIG_MTD_GPIO_ADDR)    += gpio-addr-flash.o
 obj-$(CONFIG_MTD_BCM963XX)     += bcm963xx-flash.o
 obj-$(CONFIG_MTD_LATCH_ADDR)   += latch-addr-flash.o
+obj-$(CONFIG_MTD_LANTIQ)       += lantiq-flash.o
diff --git a/drivers/mtd/maps/lantiq-flash.c b/drivers/mtd/maps/lantiq-flash.c
new file mode 100644 (file)
index 0000000..a90cabd
--- /dev/null
@@ -0,0 +1,251 @@
+/*
+ *  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.
+ *
+ *  Copyright (C) 2004 Liu Peng Infineon IFAP DC COM CPE
+ *  Copyright (C) 2010 John Crispin <blogic@openwrt.org>
+ */
+
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/io.h>
+#include <linux/slab.h>
+#include <linux/init.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/map.h>
+#include <linux/mtd/partitions.h>
+#include <linux/mtd/cfi.h>
+#include <linux/platform_device.h>
+#include <linux/mtd/physmap.h>
+
+#include <lantiq_soc.h>
+#include <lantiq_platform.h>
+
+/*
+ * The NOR flash is connected to the same external bus unit (EBU) as PCI.
+ * To make PCI work we need to enable the endianness swapping for the address
+ * written to the EBU. This endianness swapping works for PCI correctly but
+ * fails for attached NOR devices. To workaround this we need to use a complex
+ * map. The workaround involves swapping all addresses whilst probing the chip.
+ * Once probing is complete we stop swapping the addresses but swizzle the
+ * unlock addresses to ensure that access to the NOR device works correctly.
+ */
+
+enum {
+       LTQ_NOR_PROBING,
+       LTQ_NOR_NORMAL
+};
+
+struct ltq_mtd {
+       struct resource *res;
+       struct mtd_info *mtd;
+       struct map_info *map;
+};
+
+static char ltq_map_name[] = "ltq_nor";
+
+static map_word
+ltq_read16(struct map_info *map, unsigned long adr)
+{
+       unsigned long flags;
+       map_word temp;
+
+       if (map->map_priv_1 == LTQ_NOR_PROBING)
+               adr ^= 2;
+       spin_lock_irqsave(&ebu_lock, flags);
+       temp.x[0] = *(u16 *)(map->virt + adr);
+       spin_unlock_irqrestore(&ebu_lock, flags);
+       return temp;
+}
+
+static void
+ltq_write16(struct map_info *map, map_word d, unsigned long adr)
+{
+       unsigned long flags;
+
+       if (map->map_priv_1 == LTQ_NOR_PROBING)
+               adr ^= 2;
+       spin_lock_irqsave(&ebu_lock, flags);
+       *(u16 *)(map->virt + adr) = d.x[0];
+       spin_unlock_irqrestore(&ebu_lock, flags);
+}
+
+/*
+ * The following 2 functions copy data between iomem and a cached memory
+ * section. As memcpy() makes use of pre-fetching we cannot use it here.
+ * The normal alternative of using memcpy_{to,from}io also makes use of
+ * memcpy() on MIPS so it is not applicable either. We are therefore stuck
+ * with having to use our own loop.
+ */
+static void
+ltq_copy_from(struct map_info *map, void *to,
+       unsigned long from, ssize_t len)
+{
+       unsigned char *f = (unsigned char *)map->virt + from;
+       unsigned char *t = (unsigned char *)to;
+       unsigned long flags;
+
+       spin_lock_irqsave(&ebu_lock, flags);
+       while (len--)
+               *t++ = *f++;
+       spin_unlock_irqrestore(&ebu_lock, flags);
+}
+
+static void
+ltq_copy_to(struct map_info *map, unsigned long to,
+       const void *from, ssize_t len)
+{
+       unsigned char *f = (unsigned char *)from;
+       unsigned char *t = (unsigned char *)map->virt + to;
+       unsigned long flags;
+
+       spin_lock_irqsave(&ebu_lock, flags);
+       while (len--)
+               *t++ = *f++;
+       spin_unlock_irqrestore(&ebu_lock, flags);
+}
+
+static const char const *part_probe_types[] = { "cmdlinepart", NULL };
+
+static int __init
+ltq_mtd_probe(struct platform_device *pdev)
+{
+       struct physmap_flash_data *ltq_mtd_data = dev_get_platdata(&pdev->dev);
+       struct ltq_mtd *ltq_mtd;
+       struct mtd_partition *parts;
+       struct resource *res;
+       int nr_parts = 0;
+       struct cfi_private *cfi;
+       int err;
+
+       ltq_mtd = kzalloc(sizeof(struct ltq_mtd), GFP_KERNEL);
+       platform_set_drvdata(pdev, ltq_mtd);
+
+       ltq_mtd->res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (!ltq_mtd->res) {
+               dev_err(&pdev->dev, "failed to get memory resource");
+               err = -ENOENT;
+               goto err_out;
+       }
+
+       res = devm_request_mem_region(&pdev->dev, ltq_mtd->res->start,
+               resource_size(ltq_mtd->res), dev_name(&pdev->dev));
+       if (!ltq_mtd->res) {
+               dev_err(&pdev->dev, "failed to request mem resource");
+               err = -EBUSY;
+               goto err_out;
+       }
+
+       ltq_mtd->map = kzalloc(sizeof(struct map_info), GFP_KERNEL);
+       ltq_mtd->map->phys = res->start;
+       ltq_mtd->map->size = resource_size(res);
+       ltq_mtd->map->virt = devm_ioremap_nocache(&pdev->dev,
+                               ltq_mtd->map->phys, ltq_mtd->map->size);
+       if (!ltq_mtd->map->virt) {
+               dev_err(&pdev->dev, "failed to ioremap!\n");
+               err = -ENOMEM;
+               goto err_free;
+       }
+
+       ltq_mtd->map->name = ltq_map_name;
+       ltq_mtd->map->bankwidth = 2;
+       ltq_mtd->map->read = ltq_read16;
+       ltq_mtd->map->write = ltq_write16;
+       ltq_mtd->map->copy_from = ltq_copy_from;
+       ltq_mtd->map->copy_to = ltq_copy_to;
+
+       ltq_mtd->map->map_priv_1 = LTQ_NOR_PROBING;
+       ltq_mtd->mtd = do_map_probe("cfi_probe", ltq_mtd->map);
+       ltq_mtd->map->map_priv_1 = LTQ_NOR_NORMAL;
+
+       if (!ltq_mtd->mtd) {
+               dev_err(&pdev->dev, "probing failed\n");
+               err = -ENXIO;
+               goto err_unmap;
+       }
+
+       ltq_mtd->mtd->owner = THIS_MODULE;
+
+       cfi = ltq_mtd->map->fldrv_priv;
+       cfi->addr_unlock1 ^= 1;
+       cfi->addr_unlock2 ^= 1;
+
+       nr_parts = parse_mtd_partitions(ltq_mtd->mtd,
+                               part_probe_types, &parts, 0);
+       if (nr_parts > 0) {
+               dev_info(&pdev->dev,
+                       "using %d partitions from cmdline", nr_parts);
+       } else {
+               nr_parts = ltq_mtd_data->nr_parts;
+               parts = ltq_mtd_data->parts;
+       }
+
+       err = add_mtd_partitions(ltq_mtd->mtd, parts, nr_parts);
+       if (err) {
+               dev_err(&pdev->dev, "failed to add partitions\n");
+               goto err_destroy;
+       }
+
+       return 0;
+
+err_destroy:
+       map_destroy(ltq_mtd->mtd);
+err_unmap:
+       iounmap(ltq_mtd->map->virt);
+err_free:
+       kfree(ltq_mtd->map);
+err_out:
+       kfree(ltq_mtd);
+       return err;
+}
+
+static int __devexit
+ltq_mtd_remove(struct platform_device *pdev)
+{
+       struct ltq_mtd *ltq_mtd = platform_get_drvdata(pdev);
+
+       if (ltq_mtd) {
+               if (ltq_mtd->mtd) {
+                       del_mtd_partitions(ltq_mtd->mtd);
+                       map_destroy(ltq_mtd->mtd);
+               }
+               if (ltq_mtd->map->virt)
+                       iounmap(ltq_mtd->map->virt);
+               kfree(ltq_mtd->map);
+               kfree(ltq_mtd);
+       }
+       return 0;
+}
+
+static struct platform_driver ltq_mtd_driver = {
+       .remove = __devexit_p(ltq_mtd_remove),
+       .driver = {
+               .name = "ltq_nor",
+               .owner = THIS_MODULE,
+       },
+};
+
+static int __init
+init_ltq_mtd(void)
+{
+       int ret = platform_driver_probe(&ltq_mtd_driver, ltq_mtd_probe);
+
+       if (ret)
+               pr_err("ltq_nor: error registering platform driver");
+       return ret;
+}
+
+static void __exit
+exit_ltq_mtd(void)
+{
+       platform_driver_unregister(&ltq_mtd_driver);
+}
+
+module_init(init_ltq_mtd);
+module_exit(exit_ltq_mtd);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("John Crispin <blogic@openwrt.org>");
+MODULE_DESCRIPTION("Lantiq SoC NOR");
index bd483f0..c1d3346 100644 (file)
@@ -214,11 +214,13 @@ static void __devinit of_free_probes(const char **probes)
 }
 #endif
 
+static struct of_device_id of_flash_match[];
 static int __devinit of_flash_probe(struct platform_device *dev)
 {
 #ifdef CONFIG_MTD_PARTITIONS
        const char **part_probe_types;
 #endif
+       const struct of_device_id *match;
        struct device_node *dp = dev->dev.of_node;
        struct resource res;
        struct of_flash *info;
@@ -232,9 +234,10 @@ static int __devinit of_flash_probe(struct platform_device *dev)
        struct mtd_info **mtd_list = NULL;
        resource_size_t res_size;
 
-       if (!dev->dev.of_match)
+       match = of_match_device(of_flash_match, &dev->dev);
+       if (!match)
                return -EINVAL;
-       probe_type = dev->dev.of_match->data;
+       probe_type = match->data;
 
        reg_tuple_size = (of_n_addr_cells(dp) + of_n_size_cells(dp)) * sizeof(u32);
 
index 3ffe05d..5d513b5 100644 (file)
@@ -10,6 +10,7 @@
  */
 
 #include <linux/slab.h>
+#include <linux/gpio.h>
 #include <linux/init.h>
 #include <linux/module.h>
 #include <linux/interrupt.h>
@@ -470,7 +471,7 @@ static int __init au1xxx_nand_init(void)
 
 #ifdef CONFIG_MIPS_PB1550
        /* set gpio206 high */
-       au_writel(au_readl(GPIO2_DIR) & ~(1 << 6), GPIO2_DIR);
+       gpio_direction_input(206);
 
        boot_swapboot = (au_readl(MEM_STSTAT) & (0x7 << 1)) | ((bcsr_read(BCSR_STATUS) >> 6) & 0x1);
 
index dc280bc..19f04a3 100644 (file)
@@ -2017,6 +2017,13 @@ config FTMAC100
          from Faraday. It is used on Faraday A320, Andes AG101 and some
          other ARM/NDS32 SoC's.
 
+config LANTIQ_ETOP
+       tristate "Lantiq SoC ETOP driver"
+       depends on SOC_TYPE_XWAY
+       help
+         Support for the MII0 inside the Lantiq SoC
+
+
 source "drivers/net/fs_enet/Kconfig"
 
 source "drivers/net/octeon/Kconfig"
@@ -2536,7 +2543,7 @@ config S6GMAC
 source "drivers/net/stmmac/Kconfig"
 
 config PCH_GBE
-       tristate "PCH Gigabit Ethernet"
+       tristate "Intel EG20T PCH / OKI SEMICONDUCTOR ML7223 IOH GbE"
        depends on PCI
        select MII
        ---help---
@@ -2548,6 +2555,12 @@ config PCH_GBE
          to Gigabit Ethernet.
          This driver enables Gigabit Ethernet function.
 
+         This driver also can be used for OKI SEMICONDUCTOR IOH(Input/
+         Output Hub), ML7223.
+         ML7223 IOH is for MP(Media Phone) use.
+         ML7223 is companion chip for Intel Atom E6xx series.
+         ML7223 is completely compatible for Intel EG20T PCH.
+
 endif # NETDEV_1000
 
 #
index 01b604a..209fbb7 100644 (file)
@@ -144,7 +144,7 @@ obj-$(CONFIG_NE3210) += ne3210.o 8390.o
 obj-$(CONFIG_SB1250_MAC) += sb1250-mac.o
 obj-$(CONFIG_B44) += b44.o
 obj-$(CONFIG_FORCEDETH) += forcedeth.o
-obj-$(CONFIG_NE_H8300) += ne-h8300.o 8390.o
+obj-$(CONFIG_NE_H8300) += ne-h8300.o
 obj-$(CONFIG_AX88796) += ax88796.o
 obj-$(CONFIG_BCM63XX_ENET) += bcm63xx_enet.o
 obj-$(CONFIG_FTMAC100) += ftmac100.o
@@ -219,7 +219,7 @@ obj-$(CONFIG_SC92031) += sc92031.o
 obj-$(CONFIG_LP486E) += lp486e.o
 
 obj-$(CONFIG_ETH16I) += eth16i.o
-obj-$(CONFIG_ZORRO8390) += zorro8390.o 8390.o
+obj-$(CONFIG_ZORRO8390) += zorro8390.o
 obj-$(CONFIG_HPLANCE) += hplance.o 7990.o
 obj-$(CONFIG_MVME147_NET) += mvme147.o 7990.o
 obj-$(CONFIG_EQUALIZER) += eql.o
@@ -231,7 +231,7 @@ obj-$(CONFIG_SGI_IOC3_ETH) += ioc3-eth.o
 obj-$(CONFIG_DECLANCE) += declance.o
 obj-$(CONFIG_ATARILANCE) += atarilance.o
 obj-$(CONFIG_A2065) += a2065.o
-obj-$(CONFIG_HYDRA) += hydra.o 8390.o
+obj-$(CONFIG_HYDRA) += hydra.o
 obj-$(CONFIG_ARIADNE) += ariadne.o
 obj-$(CONFIG_CS89x0) += cs89x0.o
 obj-$(CONFIG_MACSONIC) += macsonic.o
@@ -259,6 +259,7 @@ obj-$(CONFIG_MLX4_CORE) += mlx4/
 obj-$(CONFIG_ENC28J60) += enc28j60.o
 obj-$(CONFIG_ETHOC) += ethoc.o
 obj-$(CONFIG_GRETH) += greth.o
+obj-$(CONFIG_LANTIQ_ETOP) += lantiq_etop.o
 
 obj-$(CONFIG_XTENSA_XT2000_SONIC) += xtsonic.o
 
index 4af235d..fbfb5b4 100644 (file)
@@ -527,7 +527,7 @@ static void __init etherh_banner(void)
  * Read the ethernet address string from the on board rom.
  * This is an ascii string...
  */
-static int __init etherh_addr(char *addr, struct expansion_card *ec)
+static int __devinit etherh_addr(char *addr, struct expansion_card *ec)
 {
        struct in_chunk_dir cd;
        char *s;
@@ -655,7 +655,7 @@ static const struct net_device_ops etherh_netdev_ops = {
 static u32 etherh_regoffsets[16];
 static u32 etherm_regoffsets[16];
 
-static int __init
+static int __devinit
 etherh_probe(struct expansion_card *ec, const struct ecard_id *id)
 {
        const struct etherh_data *data = id->data;
index ce0091e..1264d78 100644 (file)
@@ -554,7 +554,7 @@ static unsigned long __init lance_probe1( struct net_device *dev,
                memaddr == (unsigned short *)0xffe00000) {
                /* PAMs card and Riebl on ST use level 5 autovector */
                if (request_irq(IRQ_AUTO_5, lance_interrupt, IRQ_TYPE_PRIO,
-                           "PAM/Riebl-ST Ethernet", dev)) {
+                           "PAM,Riebl-ST Ethernet", dev)) {
                        printk( "Lance: request for irq %d failed\n", IRQ_AUTO_5 );
                        return 0;
                }
index 66823ed..2353eca 100644 (file)
@@ -213,7 +213,7 @@ struct be_rx_stats {
 
 struct be_rx_compl_info {
        u32 rss_hash;
-       u16 vid;
+       u16 vlan_tag;
        u16 pkt_size;
        u16 rxq_idx;
        u16 mac_id;
index 1e2d825..9dc9394 100644 (file)
@@ -132,7 +132,7 @@ static void be_async_grp5_pvid_state_process(struct be_adapter *adapter,
                struct be_async_event_grp5_pvid_state *evt)
 {
        if (evt->enabled)
-               adapter->pvid = evt->tag;
+               adapter->pvid = le16_to_cpu(evt->tag);
        else
                adapter->pvid = 0;
 }
index 02a0443..9187fb4 100644 (file)
@@ -1018,7 +1018,8 @@ static void be_rx_compl_process(struct be_adapter *adapter,
                        kfree_skb(skb);
                        return;
                }
-               vlan_hwaccel_receive_skb(skb, adapter->vlan_grp, rxcp->vid);
+               vlan_hwaccel_receive_skb(skb, adapter->vlan_grp,
+                                       rxcp->vlan_tag);
        } else {
                netif_receive_skb(skb);
        }
@@ -1076,7 +1077,8 @@ static void be_rx_compl_process_gro(struct be_adapter *adapter,
        if (likely(!rxcp->vlanf))
                napi_gro_frags(&eq_obj->napi);
        else
-               vlan_gro_frags(&eq_obj->napi, adapter->vlan_grp, rxcp->vid);
+               vlan_gro_frags(&eq_obj->napi, adapter->vlan_grp,
+                               rxcp->vlan_tag);
 }
 
 static void be_parse_rx_compl_v1(struct be_adapter *adapter,
@@ -1102,7 +1104,8 @@ static void be_parse_rx_compl_v1(struct be_adapter *adapter,
        rxcp->pkt_type =
                AMAP_GET_BITS(struct amap_eth_rx_compl_v1, cast_enc, compl);
        rxcp->vtm = AMAP_GET_BITS(struct amap_eth_rx_compl_v1, vtm, compl);
-       rxcp->vid = AMAP_GET_BITS(struct amap_eth_rx_compl_v1, vlan_tag, compl);
+       rxcp->vlan_tag = AMAP_GET_BITS(struct amap_eth_rx_compl_v1, vlan_tag,
+                                       compl);
 }
 
 static void be_parse_rx_compl_v0(struct be_adapter *adapter,
@@ -1128,7 +1131,8 @@ static void be_parse_rx_compl_v0(struct be_adapter *adapter,
        rxcp->pkt_type =
                AMAP_GET_BITS(struct amap_eth_rx_compl_v0, cast_enc, compl);
        rxcp->vtm = AMAP_GET_BITS(struct amap_eth_rx_compl_v0, vtm, compl);
-       rxcp->vid = AMAP_GET_BITS(struct amap_eth_rx_compl_v0, vlan_tag, compl);
+       rxcp->vlan_tag = AMAP_GET_BITS(struct amap_eth_rx_compl_v0, vlan_tag,
+                                       compl);
 }
 
 static struct be_rx_compl_info *be_rx_compl_get(struct be_rx_obj *rxo)
@@ -1155,9 +1159,11 @@ static struct be_rx_compl_info *be_rx_compl_get(struct be_rx_obj *rxo)
                rxcp->vlanf = 0;
 
        if (!lancer_chip(adapter))
-               rxcp->vid = swab16(rxcp->vid);
+               rxcp->vlan_tag = swab16(rxcp->vlan_tag);
 
-       if ((adapter->pvid == rxcp->vid) && !adapter->vlan_tag[rxcp->vid])
+       if (((adapter->pvid & VLAN_VID_MASK) ==
+               (rxcp->vlan_tag & VLAN_VID_MASK)) &&
+               !adapter->vlan_tag[rxcp->vlan_tag])
                rxcp->vlanf = 0;
 
        /* As the compl has been parsed, reset it; we wont touch it again */
index b28baff..01b8a6a 100644 (file)
@@ -39,7 +39,7 @@
 
 typedef struct mac_addr {
        u8 mac_addr_value[ETH_ALEN];
-} mac_addr_t;
+} __packed mac_addr_t;
 
 enum {
        BOND_AD_STABLE = 0,
@@ -134,12 +134,12 @@ typedef struct lacpdu {
        u8 tlv_type_terminator;      // = terminator
        u8 terminator_length;        // = 0
        u8 reserved_50[50];          // = 0
-} lacpdu_t;
+} __packed lacpdu_t;
 
 typedef struct lacpdu_header {
        struct ethhdr hdr;
        struct lacpdu lacpdu;
-} lacpdu_header_t;
+} __packed lacpdu_header_t;
 
 // Marker Protocol Data Unit(PDU) structure(43.5.3.2 in the 802.3ad standard)
 typedef struct bond_marker {
@@ -155,12 +155,12 @@ typedef struct bond_marker {
        u8 tlv_type_terminator;      //  = 0x00
        u8 terminator_length;        //  = 0x00
        u8 reserved_90[90];          //  = 0
-} bond_marker_t;
+} __packed bond_marker_t;
 
 typedef struct bond_marker_header {
        struct ethhdr hdr;
        struct bond_marker marker;
-} bond_marker_header_t;
+} __packed bond_marker_header_t;
 
 #pragma pack()
 
index bd1d811..5fedc33 100644 (file)
@@ -247,8 +247,10 @@ static u32 __devinit mpc512x_can_get_clock(struct platform_device *ofdev,
 }
 #endif /* CONFIG_PPC_MPC512x */
 
+static struct of_device_id mpc5xxx_can_table[];
 static int __devinit mpc5xxx_can_probe(struct platform_device *ofdev)
 {
+       const struct of_device_id *match;
        struct mpc5xxx_can_data *data;
        struct device_node *np = ofdev->dev.of_node;
        struct net_device *dev;
@@ -258,9 +260,10 @@ static int __devinit mpc5xxx_can_probe(struct platform_device *ofdev)
        int irq, mscan_clksrc = 0;
        int err = -ENOMEM;
 
-       if (!ofdev->dev.of_match)
+       match = of_match_device(mpc5xxx_can_table, &ofdev->dev);
+       if (!match)
                return -EINVAL;
-       data = (struct mpc5xxx_can_data *)ofdev->dev.of_match->data;
+       data = match->data;
 
        base = of_iomap(np, 0);
        if (!base) {
index a358ea9..f501bba 100644 (file)
@@ -346,10 +346,10 @@ static void sja1000_rx(struct net_device *dev)
                    | (priv->read_reg(priv, REG_ID2) >> 5);
        }
 
+       cf->can_dlc = get_can_dlc(fi & 0x0F);
        if (fi & FI_RTR) {
                id |= CAN_RTR_FLAG;
        } else {
-               cf->can_dlc = get_can_dlc(fi & 0x0F);
                for (i = 0; i < cf->can_dlc; i++)
                        cf->data[i] = priv->read_reg(priv, dreg++);
        }
index b423965..1b49df6 100644 (file)
@@ -583,7 +583,9 @@ static int slcan_open(struct tty_struct *tty)
        /* Done.  We have linked the TTY line to a channel. */
        rtnl_unlock();
        tty->receive_room = 65536;      /* We don't flow control */
-       return sl->dev->base_addr;
+
+       /* TTY layer expects 0 on success */
+       return 0;
 
 err_free_chan:
        sl->tty = NULL;
index 3e2e734..f3bbdce 100644 (file)
@@ -55,15 +55,20 @@ static int ehea_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
                cmd->duplex = -1;
        }
 
-       cmd->supported = (SUPPORTED_10000baseT_Full | SUPPORTED_1000baseT_Full
-                      | SUPPORTED_100baseT_Full |  SUPPORTED_100baseT_Half
-                      | SUPPORTED_10baseT_Full | SUPPORTED_10baseT_Half
-                      | SUPPORTED_Autoneg | SUPPORTED_FIBRE);
-
-       cmd->advertising = (ADVERTISED_10000baseT_Full | ADVERTISED_Autoneg
-                        | ADVERTISED_FIBRE);
+       if (cmd->speed == SPEED_10000) {
+               cmd->supported = (SUPPORTED_10000baseT_Full | SUPPORTED_FIBRE);
+               cmd->advertising = (ADVERTISED_10000baseT_Full | ADVERTISED_FIBRE);
+               cmd->port = PORT_FIBRE;
+       } else {
+               cmd->supported = (SUPPORTED_1000baseT_Full | SUPPORTED_100baseT_Full
+                              | SUPPORTED_100baseT_Half | SUPPORTED_10baseT_Full
+                              | SUPPORTED_10baseT_Half | SUPPORTED_Autoneg
+                              | SUPPORTED_TP);
+               cmd->advertising = (ADVERTISED_1000baseT_Full | ADVERTISED_Autoneg
+                                | ADVERTISED_TP);
+               cmd->port = PORT_TP;
+       }
 
-       cmd->port = PORT_FIBRE;
        cmd->autoneg = port->autoneg == 1 ? AUTONEG_ENABLE : AUTONEG_DISABLE;
 
        return 0;
index 53c0f04..cf79cf7 100644 (file)
@@ -2688,9 +2688,6 @@ static int ehea_open(struct net_device *dev)
                netif_start_queue(dev);
        }
 
-       init_waitqueue_head(&port->swqe_avail_wq);
-       init_waitqueue_head(&port->restart_wq);
-
        mutex_unlock(&port->port_lock);
 
        return ret;
@@ -3276,6 +3273,9 @@ struct ehea_port *ehea_setup_single_port(struct ehea_adapter *adapter,
 
        INIT_WORK(&port->reset_task, ehea_reset_port);
 
+       init_waitqueue_head(&port->swqe_avail_wq);
+       init_waitqueue_head(&port->restart_wq);
+
        ret = register_netdev(dev);
        if (ret) {
                pr_err("register_netdev failed. ret=%d\n", ret);
index 24cb953..5131e61 100644 (file)
@@ -998,8 +998,10 @@ static const struct net_device_ops fs_enet_netdev_ops = {
 #endif
 };
 
+static struct of_device_id fs_enet_match[];
 static int __devinit fs_enet_probe(struct platform_device *ofdev)
 {
+       const struct of_device_id *match;
        struct net_device *ndev;
        struct fs_enet_private *fep;
        struct fs_platform_info *fpi;
@@ -1007,14 +1009,15 @@ static int __devinit fs_enet_probe(struct platform_device *ofdev)
        const u8 *mac_addr;
        int privsize, len, ret = -ENODEV;
 
-       if (!ofdev->dev.of_match)
+       match = of_match_device(fs_enet_match, &ofdev->dev);
+       if (!match)
                return -EINVAL;
 
        fpi = kzalloc(sizeof(*fpi), GFP_KERNEL);
        if (!fpi)
                return -ENOMEM;
 
-       if (!IS_FEC(ofdev->dev.of_match)) {
+       if (!IS_FEC(match)) {
                data = of_get_property(ofdev->dev.of_node, "fsl,cpm-command", &len);
                if (!data || len != 4)
                        goto out_free_fpi;
@@ -1049,7 +1052,7 @@ static int __devinit fs_enet_probe(struct platform_device *ofdev)
        fep->dev = &ofdev->dev;
        fep->ndev = ndev;
        fep->fpi = fpi;
-       fep->ops = ofdev->dev.of_match->data;
+       fep->ops = match->data;
 
        ret = fep->ops->setup_data(ndev);
        if (ret)
index 7e840d3..6a2e150 100644 (file)
@@ -101,17 +101,20 @@ static int fs_enet_fec_mii_reset(struct mii_bus *bus)
        return 0;
 }
 
+static struct of_device_id fs_enet_mdio_fec_match[];
 static int __devinit fs_enet_mdio_probe(struct platform_device *ofdev)
 {
+       const struct of_device_id *match;
        struct resource res;
        struct mii_bus *new_bus;
        struct fec_info *fec;
        int (*get_bus_freq)(struct device_node *);
        int ret = -ENOMEM, clock, speed;
 
-       if (!ofdev->dev.of_match)
+       match = of_match_device(fs_enet_mdio_fec_match, &ofdev->dev);
+       if (!match)
                return -EINVAL;
-       get_bus_freq = ofdev->dev.of_match->data;
+       get_bus_freq = match->data;
 
        new_bus = mdiobus_alloc();
        if (!new_bus)
index c5ef62c..1cd481c 100644 (file)
@@ -98,15 +98,15 @@ static const struct net_device_ops hydra_netdev_ops = {
        .ndo_open               = hydra_open,
        .ndo_stop               = hydra_close,
 
-       .ndo_start_xmit         = ei_start_xmit,
-       .ndo_tx_timeout         = ei_tx_timeout,
-       .ndo_get_stats          = ei_get_stats,
-       .ndo_set_multicast_list = ei_set_multicast_list,
+       .ndo_start_xmit         = __ei_start_xmit,
+       .ndo_tx_timeout         = __ei_tx_timeout,
+       .ndo_get_stats          = __ei_get_stats,
+       .ndo_set_multicast_list = __ei_set_multicast_list,
        .ndo_validate_addr      = eth_validate_addr,
-       .ndo_set_mac_address    = eth_mac_addr,
+       .ndo_set_mac_address    = eth_mac_addr,
        .ndo_change_mtu         = eth_change_mtu,
 #ifdef CONFIG_NET_POLL_CONTROLLER
-       .ndo_poll_controller    = ei_poll,
+       .ndo_poll_controller    = __ei_poll,
 #endif
 };
 
@@ -125,7 +125,7 @@ static int __devinit hydra_init(struct zorro_dev *z)
        0x10, 0x12, 0x14, 0x16, 0x18, 0x1a, 0x1c, 0x1e,
     };
 
-    dev = alloc_ei_netdev();
+    dev = ____alloc_ei_netdev(0);
     if (!dev)
        return -ENOMEM;
 
index 6f8adc7..e145f2c 100644 (file)
@@ -5100,11 +5100,6 @@ err_set_interrupt:
        return err;
 }
 
-static void ring_free_rcu(struct rcu_head *head)
-{
-       kfree(container_of(head, struct ixgbe_ring, rcu));
-}
-
 /**
  * ixgbe_clear_interrupt_scheme - Clear the current interrupt scheme settings
  * @adapter: board private structure to clear interrupt scheme on
@@ -5126,7 +5121,7 @@ void ixgbe_clear_interrupt_scheme(struct ixgbe_adapter *adapter)
                /* ixgbe_get_stats64() might access this ring, we must wait
                 * a grace period before freeing it.
                 */
-               call_rcu(&ring->rcu, ring_free_rcu);
+               kfree_rcu(ring, rcu);
                adapter->rx_ring[i] = NULL;
        }
 
diff --git a/drivers/net/lantiq_etop.c b/drivers/net/lantiq_etop.c
new file mode 100644 (file)
index 0000000..45f252b
--- /dev/null
@@ -0,0 +1,805 @@
+/*
+ *   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 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) 2011 John Crispin <blogic@openwrt.org>
+ */
+
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/errno.h>
+#include <linux/types.h>
+#include <linux/interrupt.h>
+#include <linux/uaccess.h>
+#include <linux/in.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/phy.h>
+#include <linux/ip.h>
+#include <linux/tcp.h>
+#include <linux/skbuff.h>
+#include <linux/mm.h>
+#include <linux/platform_device.h>
+#include <linux/ethtool.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/io.h>
+
+#include <asm/checksum.h>
+
+#include <lantiq_soc.h>
+#include <xway_dma.h>
+#include <lantiq_platform.h>
+
+#define LTQ_ETOP_MDIO          0x11804
+#define MDIO_REQUEST           0x80000000
+#define MDIO_READ              0x40000000
+#define MDIO_ADDR_MASK         0x1f
+#define MDIO_ADDR_OFFSET       0x15
+#define MDIO_REG_MASK          0x1f
+#define MDIO_REG_OFFSET                0x10
+#define MDIO_VAL_MASK          0xffff
+
+#define PPE32_CGEN             0x800
+#define LQ_PPE32_ENET_MAC_CFG  0x1840
+
+#define LTQ_ETOP_ENETS0                0x11850
+#define LTQ_ETOP_MAC_DA0       0x1186C
+#define LTQ_ETOP_MAC_DA1       0x11870
+#define LTQ_ETOP_CFG           0x16020
+#define LTQ_ETOP_IGPLEN                0x16080
+
+#define MAX_DMA_CHAN           0x8
+#define MAX_DMA_CRC_LEN                0x4
+#define MAX_DMA_DATA_LEN       0x600
+
+#define ETOP_FTCU              BIT(28)
+#define ETOP_MII_MASK          0xf
+#define ETOP_MII_NORMAL                0xd
+#define ETOP_MII_REVERSE       0xe
+#define ETOP_PLEN_UNDER                0x40
+#define ETOP_CGEN              0x800
+
+/* use 2 static channels for TX/RX */
+#define LTQ_ETOP_TX_CHANNEL    1
+#define LTQ_ETOP_RX_CHANNEL    6
+#define IS_TX(x)               (x == LTQ_ETOP_TX_CHANNEL)
+#define IS_RX(x)               (x == LTQ_ETOP_RX_CHANNEL)
+
+#define ltq_etop_r32(x)                ltq_r32(ltq_etop_membase + (x))
+#define ltq_etop_w32(x, y)     ltq_w32(x, ltq_etop_membase + (y))
+#define ltq_etop_w32_mask(x, y, z)     \
+               ltq_w32_mask(x, y, ltq_etop_membase + (z))
+
+#define DRV_VERSION    "1.0"
+
+static void __iomem *ltq_etop_membase;
+
+struct ltq_etop_chan {
+       int idx;
+       int tx_free;
+       struct net_device *netdev;
+       struct napi_struct napi;
+       struct ltq_dma_channel dma;
+       struct sk_buff *skb[LTQ_DESC_NUM];
+};
+
+struct ltq_etop_priv {
+       struct net_device *netdev;
+       struct ltq_eth_data *pldata;
+       struct resource *res;
+
+       struct mii_bus *mii_bus;
+       struct phy_device *phydev;
+
+       struct ltq_etop_chan ch[MAX_DMA_CHAN];
+       int tx_free[MAX_DMA_CHAN >> 1];
+
+       spinlock_t lock;
+};
+
+static int
+ltq_etop_alloc_skb(struct ltq_etop_chan *ch)
+{
+       ch->skb[ch->dma.desc] = dev_alloc_skb(MAX_DMA_DATA_LEN);
+       if (!ch->skb[ch->dma.desc])
+               return -ENOMEM;
+       ch->dma.desc_base[ch->dma.desc].addr = dma_map_single(NULL,
+               ch->skb[ch->dma.desc]->data, MAX_DMA_DATA_LEN,
+               DMA_FROM_DEVICE);
+       ch->dma.desc_base[ch->dma.desc].addr =
+               CPHYSADDR(ch->skb[ch->dma.desc]->data);
+       ch->dma.desc_base[ch->dma.desc].ctl =
+               LTQ_DMA_OWN | LTQ_DMA_RX_OFFSET(NET_IP_ALIGN) |
+               MAX_DMA_DATA_LEN;
+       skb_reserve(ch->skb[ch->dma.desc], NET_IP_ALIGN);
+       return 0;
+}
+
+static void
+ltq_etop_hw_receive(struct ltq_etop_chan *ch)
+{
+       struct ltq_etop_priv *priv = netdev_priv(ch->netdev);
+       struct ltq_dma_desc *desc = &ch->dma.desc_base[ch->dma.desc];
+       struct sk_buff *skb = ch->skb[ch->dma.desc];
+       int len = (desc->ctl & LTQ_DMA_SIZE_MASK) - MAX_DMA_CRC_LEN;
+       unsigned long flags;
+
+       spin_lock_irqsave(&priv->lock, flags);
+       if (ltq_etop_alloc_skb(ch)) {
+               netdev_err(ch->netdev,
+                       "failed to allocate new rx buffer, stopping DMA\n");
+               ltq_dma_close(&ch->dma);
+       }
+       ch->dma.desc++;
+       ch->dma.desc %= LTQ_DESC_NUM;
+       spin_unlock_irqrestore(&priv->lock, flags);
+
+       skb_put(skb, len);
+       skb->dev = ch->netdev;
+       skb->protocol = eth_type_trans(skb, ch->netdev);
+       netif_receive_skb(skb);
+}
+
+static int
+ltq_etop_poll_rx(struct napi_struct *napi, int budget)
+{
+       struct ltq_etop_chan *ch = container_of(napi,
+                               struct ltq_etop_chan, napi);
+       int rx = 0;
+       int complete = 0;
+
+       while ((rx < budget) && !complete) {
+               struct ltq_dma_desc *desc = &ch->dma.desc_base[ch->dma.desc];
+
+               if ((desc->ctl & (LTQ_DMA_OWN | LTQ_DMA_C)) == LTQ_DMA_C) {
+                       ltq_etop_hw_receive(ch);
+                       rx++;
+               } else {
+                       complete = 1;
+               }
+       }
+       if (complete || !rx) {
+               napi_complete(&ch->napi);
+               ltq_dma_ack_irq(&ch->dma);
+       }
+       return rx;
+}
+
+static int
+ltq_etop_poll_tx(struct napi_struct *napi, int budget)
+{
+       struct ltq_etop_chan *ch =
+               container_of(napi, struct ltq_etop_chan, napi);
+       struct ltq_etop_priv *priv = netdev_priv(ch->netdev);
+       struct netdev_queue *txq =
+               netdev_get_tx_queue(ch->netdev, ch->idx >> 1);
+       unsigned long flags;
+
+       spin_lock_irqsave(&priv->lock, flags);
+       while ((ch->dma.desc_base[ch->tx_free].ctl &
+                       (LTQ_DMA_OWN | LTQ_DMA_C)) == LTQ_DMA_C) {
+               dev_kfree_skb_any(ch->skb[ch->tx_free]);
+               ch->skb[ch->tx_free] = NULL;
+               memset(&ch->dma.desc_base[ch->tx_free], 0,
+                       sizeof(struct ltq_dma_desc));
+               ch->tx_free++;
+               ch->tx_free %= LTQ_DESC_NUM;
+       }
+       spin_unlock_irqrestore(&priv->lock, flags);
+
+       if (netif_tx_queue_stopped(txq))
+               netif_tx_start_queue(txq);
+       napi_complete(&ch->napi);
+       ltq_dma_ack_irq(&ch->dma);
+       return 1;
+}
+
+static irqreturn_t
+ltq_etop_dma_irq(int irq, void *_priv)
+{
+       struct ltq_etop_priv *priv = _priv;
+       int ch = irq - LTQ_DMA_CH0_INT;
+
+       napi_schedule(&priv->ch[ch].napi);
+       return IRQ_HANDLED;
+}
+
+static void
+ltq_etop_free_channel(struct net_device *dev, struct ltq_etop_chan *ch)
+{
+       struct ltq_etop_priv *priv = netdev_priv(dev);
+
+       ltq_dma_free(&ch->dma);
+       if (ch->dma.irq)
+               free_irq(ch->dma.irq, priv);
+       if (IS_RX(ch->idx)) {
+               int desc;
+               for (desc = 0; desc < LTQ_DESC_NUM; desc++)
+                       dev_kfree_skb_any(ch->skb[ch->dma.desc]);
+       }
+}
+
+static void
+ltq_etop_hw_exit(struct net_device *dev)
+{
+       struct ltq_etop_priv *priv = netdev_priv(dev);
+       int i;
+
+       ltq_pmu_disable(PMU_PPE);
+       for (i = 0; i < MAX_DMA_CHAN; i++)
+               if (IS_TX(i) || IS_RX(i))
+                       ltq_etop_free_channel(dev, &priv->ch[i]);
+}
+
+static int
+ltq_etop_hw_init(struct net_device *dev)
+{
+       struct ltq_etop_priv *priv = netdev_priv(dev);
+       int i;
+
+       ltq_pmu_enable(PMU_PPE);
+
+       switch (priv->pldata->mii_mode) {
+       case PHY_INTERFACE_MODE_RMII:
+               ltq_etop_w32_mask(ETOP_MII_MASK,
+                       ETOP_MII_REVERSE, LTQ_ETOP_CFG);
+               break;
+
+       case PHY_INTERFACE_MODE_MII:
+               ltq_etop_w32_mask(ETOP_MII_MASK,
+                       ETOP_MII_NORMAL, LTQ_ETOP_CFG);
+               break;
+
+       default:
+               netdev_err(dev, "unknown mii mode %d\n",
+                       priv->pldata->mii_mode);
+               return -ENOTSUPP;
+       }
+
+       /* enable crc generation */
+       ltq_etop_w32(PPE32_CGEN, LQ_PPE32_ENET_MAC_CFG);
+
+       ltq_dma_init_port(DMA_PORT_ETOP);
+
+       for (i = 0; i < MAX_DMA_CHAN; i++) {
+               int irq = LTQ_DMA_CH0_INT + i;
+               struct ltq_etop_chan *ch = &priv->ch[i];
+
+               ch->idx = ch->dma.nr = i;
+
+               if (IS_TX(i)) {
+                       ltq_dma_alloc_tx(&ch->dma);
+                       request_irq(irq, ltq_etop_dma_irq, IRQF_DISABLED,
+                               "etop_tx", priv);
+               } else if (IS_RX(i)) {
+                       ltq_dma_alloc_rx(&ch->dma);
+                       for (ch->dma.desc = 0; ch->dma.desc < LTQ_DESC_NUM;
+                                       ch->dma.desc++)
+                               if (ltq_etop_alloc_skb(ch))
+                                       return -ENOMEM;
+                       ch->dma.desc = 0;
+                       request_irq(irq, ltq_etop_dma_irq, IRQF_DISABLED,
+                               "etop_rx", priv);
+               }
+               ch->dma.irq = irq;
+       }
+       return 0;
+}
+
+static void
+ltq_etop_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info)
+{
+       strcpy(info->driver, "Lantiq ETOP");
+       strcpy(info->bus_info, "internal");
+       strcpy(info->version, DRV_VERSION);
+}
+
+static int
+ltq_etop_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
+{
+       struct ltq_etop_priv *priv = netdev_priv(dev);
+
+       return phy_ethtool_gset(priv->phydev, cmd);
+}
+
+static int
+ltq_etop_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
+{
+       struct ltq_etop_priv *priv = netdev_priv(dev);
+
+       return phy_ethtool_sset(priv->phydev, cmd);
+}
+
+static int
+ltq_etop_nway_reset(struct net_device *dev)
+{
+       struct ltq_etop_priv *priv = netdev_priv(dev);
+
+       return phy_start_aneg(priv->phydev);
+}
+
+static const struct ethtool_ops ltq_etop_ethtool_ops = {
+       .get_drvinfo = ltq_etop_get_drvinfo,
+       .get_settings = ltq_etop_get_settings,
+       .set_settings = ltq_etop_set_settings,
+       .nway_reset = ltq_etop_nway_reset,
+};
+
+static int
+ltq_etop_mdio_wr(struct mii_bus *bus, int phy_addr, int phy_reg, u16 phy_data)
+{
+       u32 val = MDIO_REQUEST |
+               ((phy_addr & MDIO_ADDR_MASK) << MDIO_ADDR_OFFSET) |
+               ((phy_reg & MDIO_REG_MASK) << MDIO_REG_OFFSET) |
+               phy_data;
+
+       while (ltq_etop_r32(LTQ_ETOP_MDIO) & MDIO_REQUEST)
+               ;
+       ltq_etop_w32(val, LTQ_ETOP_MDIO);
+       return 0;
+}
+
+static int
+ltq_etop_mdio_rd(struct mii_bus *bus, int phy_addr, int phy_reg)
+{
+       u32 val = MDIO_REQUEST | MDIO_READ |
+               ((phy_addr & MDIO_ADDR_MASK) << MDIO_ADDR_OFFSET) |
+               ((phy_reg & MDIO_REG_MASK) << MDIO_REG_OFFSET);
+
+       while (ltq_etop_r32(LTQ_ETOP_MDIO) & MDIO_REQUEST)
+               ;
+       ltq_etop_w32(val, LTQ_ETOP_MDIO);
+       while (ltq_etop_r32(LTQ_ETOP_MDIO) & MDIO_REQUEST)
+               ;
+       val = ltq_etop_r32(LTQ_ETOP_MDIO) & MDIO_VAL_MASK;
+       return val;
+}
+
+static void
+ltq_etop_mdio_link(struct net_device *dev)
+{
+       /* nothing to do  */
+}
+
+static int
+ltq_etop_mdio_probe(struct net_device *dev)
+{
+       struct ltq_etop_priv *priv = netdev_priv(dev);
+       struct phy_device *phydev = NULL;
+       int phy_addr;
+
+       for (phy_addr = 0; phy_addr < PHY_MAX_ADDR; phy_addr++) {
+               if (priv->mii_bus->phy_map[phy_addr]) {
+                       phydev = priv->mii_bus->phy_map[phy_addr];
+                       break;
+               }
+       }
+
+       if (!phydev) {
+               netdev_err(dev, "no PHY found\n");
+               return -ENODEV;
+       }
+
+       phydev = phy_connect(dev, dev_name(&phydev->dev), &ltq_etop_mdio_link,
+                       0, priv->pldata->mii_mode);
+
+       if (IS_ERR(phydev)) {
+               netdev_err(dev, "Could not attach to PHY\n");
+               return PTR_ERR(phydev);
+       }
+
+       phydev->supported &= (SUPPORTED_10baseT_Half
+                             | SUPPORTED_10baseT_Full
+                             | SUPPORTED_100baseT_Half
+                             | SUPPORTED_100baseT_Full
+                             | SUPPORTED_Autoneg
+                             | SUPPORTED_MII
+                             | SUPPORTED_TP);
+
+       phydev->advertising = phydev->supported;
+       priv->phydev = phydev;
+       pr_info("%s: attached PHY [%s] (phy_addr=%s, irq=%d)\n",
+              dev->name, phydev->drv->name,
+              dev_name(&phydev->dev), phydev->irq);
+
+       return 0;
+}
+
+static int
+ltq_etop_mdio_init(struct net_device *dev)
+{
+       struct ltq_etop_priv *priv = netdev_priv(dev);
+       int i;
+       int err;
+
+       priv->mii_bus = mdiobus_alloc();
+       if (!priv->mii_bus) {
+               netdev_err(dev, "failed to allocate mii bus\n");
+               err = -ENOMEM;
+               goto err_out;
+       }
+
+       priv->mii_bus->priv = dev;
+       priv->mii_bus->read = ltq_etop_mdio_rd;
+       priv->mii_bus->write = ltq_etop_mdio_wr;
+       priv->mii_bus->name = "ltq_mii";
+       snprintf(priv->mii_bus->id, MII_BUS_ID_SIZE, "%x", 0);
+       priv->mii_bus->irq = kmalloc(sizeof(int) * PHY_MAX_ADDR, GFP_KERNEL);
+       if (!priv->mii_bus->irq) {
+               err = -ENOMEM;
+               goto err_out_free_mdiobus;
+       }
+
+       for (i = 0; i < PHY_MAX_ADDR; ++i)
+               priv->mii_bus->irq[i] = PHY_POLL;
+
+       if (mdiobus_register(priv->mii_bus)) {
+               err = -ENXIO;
+               goto err_out_free_mdio_irq;
+       }
+
+       if (ltq_etop_mdio_probe(dev)) {
+               err = -ENXIO;
+               goto err_out_unregister_bus;
+       }
+       return 0;
+
+err_out_unregister_bus:
+       mdiobus_unregister(priv->mii_bus);
+err_out_free_mdio_irq:
+       kfree(priv->mii_bus->irq);
+err_out_free_mdiobus:
+       mdiobus_free(priv->mii_bus);
+err_out:
+       return err;
+}
+
+static void
+ltq_etop_mdio_cleanup(struct net_device *dev)
+{
+       struct ltq_etop_priv *priv = netdev_priv(dev);
+
+       phy_disconnect(priv->phydev);
+       mdiobus_unregister(priv->mii_bus);
+       kfree(priv->mii_bus->irq);
+       mdiobus_free(priv->mii_bus);
+}
+
+static int
+ltq_etop_open(struct net_device *dev)
+{
+       struct ltq_etop_priv *priv = netdev_priv(dev);
+       int i;
+
+       for (i = 0; i < MAX_DMA_CHAN; i++) {
+               struct ltq_etop_chan *ch = &priv->ch[i];
+
+               if (!IS_TX(i) && (!IS_RX(i)))
+                       continue;
+               ltq_dma_open(&ch->dma);
+               napi_enable(&ch->napi);
+       }
+       phy_start(priv->phydev);
+       netif_tx_start_all_queues(dev);
+       return 0;
+}
+
+static int
+ltq_etop_stop(struct net_device *dev)
+{
+       struct ltq_etop_priv *priv = netdev_priv(dev);
+       int i;
+
+       netif_tx_stop_all_queues(dev);
+       phy_stop(priv->phydev);
+       for (i = 0; i < MAX_DMA_CHAN; i++) {
+               struct ltq_etop_chan *ch = &priv->ch[i];
+
+               if (!IS_RX(i) && !IS_TX(i))
+                       continue;
+               napi_disable(&ch->napi);
+               ltq_dma_close(&ch->dma);
+       }
+       return 0;
+}
+
+static int
+ltq_etop_tx(struct sk_buff *skb, struct net_device *dev)
+{
+       int queue = skb_get_queue_mapping(skb);
+       struct netdev_queue *txq = netdev_get_tx_queue(dev, queue);
+       struct ltq_etop_priv *priv = netdev_priv(dev);
+       struct ltq_etop_chan *ch = &priv->ch[(queue << 1) | 1];
+       struct ltq_dma_desc *desc = &ch->dma.desc_base[ch->dma.desc];
+       int len;
+       unsigned long flags;
+       u32 byte_offset;
+
+       len = skb->len < ETH_ZLEN ? ETH_ZLEN : skb->len;
+
+       if ((desc->ctl & (LTQ_DMA_OWN | LTQ_DMA_C)) || ch->skb[ch->dma.desc]) {
+               dev_kfree_skb_any(skb);
+               netdev_err(dev, "tx ring full\n");
+               netif_tx_stop_queue(txq);
+               return NETDEV_TX_BUSY;
+       }
+
+       /* dma needs to start on a 16 byte aligned address */
+       byte_offset = CPHYSADDR(skb->data) % 16;
+       ch->skb[ch->dma.desc] = skb;
+
+       dev->trans_start = jiffies;
+
+       spin_lock_irqsave(&priv->lock, flags);
+       desc->addr = ((unsigned int) dma_map_single(NULL, skb->data, len,
+                                               DMA_TO_DEVICE)) - byte_offset;
+       wmb();
+       desc->ctl = LTQ_DMA_OWN | LTQ_DMA_SOP | LTQ_DMA_EOP |
+               LTQ_DMA_TX_OFFSET(byte_offset) | (len & LTQ_DMA_SIZE_MASK);
+       ch->dma.desc++;
+       ch->dma.desc %= LTQ_DESC_NUM;
+       spin_unlock_irqrestore(&priv->lock, flags);
+
+       if (ch->dma.desc_base[ch->dma.desc].ctl & LTQ_DMA_OWN)
+               netif_tx_stop_queue(txq);
+
+       return NETDEV_TX_OK;
+}
+
+static int
+ltq_etop_change_mtu(struct net_device *dev, int new_mtu)
+{
+       int ret = eth_change_mtu(dev, new_mtu);
+
+       if (!ret) {
+               struct ltq_etop_priv *priv = netdev_priv(dev);
+               unsigned long flags;
+
+               spin_lock_irqsave(&priv->lock, flags);
+               ltq_etop_w32((ETOP_PLEN_UNDER << 16) | new_mtu,
+                       LTQ_ETOP_IGPLEN);
+               spin_unlock_irqrestore(&priv->lock, flags);
+       }
+       return ret;
+}
+
+static int
+ltq_etop_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
+{
+       struct ltq_etop_priv *priv = netdev_priv(dev);
+
+       /* TODO: mii-toll reports "No MII transceiver present!." ?!*/
+       return phy_mii_ioctl(priv->phydev, rq, cmd);
+}
+
+static int
+ltq_etop_set_mac_address(struct net_device *dev, void *p)
+{
+       int ret = eth_mac_addr(dev, p);
+
+       if (!ret) {
+               struct ltq_etop_priv *priv = netdev_priv(dev);
+               unsigned long flags;
+
+               /* store the mac for the unicast filter */
+               spin_lock_irqsave(&priv->lock, flags);
+               ltq_etop_w32(*((u32 *)dev->dev_addr), LTQ_ETOP_MAC_DA0);
+               ltq_etop_w32(*((u16 *)&dev->dev_addr[4]) << 16,
+                       LTQ_ETOP_MAC_DA1);
+               spin_unlock_irqrestore(&priv->lock, flags);
+       }
+       return ret;
+}
+
+static void
+ltq_etop_set_multicast_list(struct net_device *dev)
+{
+       struct ltq_etop_priv *priv = netdev_priv(dev);
+       unsigned long flags;
+
+       /* ensure that the unicast filter is not enabled in promiscious mode */
+       spin_lock_irqsave(&priv->lock, flags);
+       if ((dev->flags & IFF_PROMISC) || (dev->flags & IFF_ALLMULTI))
+               ltq_etop_w32_mask(ETOP_FTCU, 0, LTQ_ETOP_ENETS0);
+       else
+               ltq_etop_w32_mask(0, ETOP_FTCU, LTQ_ETOP_ENETS0);
+       spin_unlock_irqrestore(&priv->lock, flags);
+}
+
+static u16
+ltq_etop_select_queue(struct net_device *dev, struct sk_buff *skb)
+{
+       /* we are currently only using the first queue */
+       return 0;
+}
+
+static int
+ltq_etop_init(struct net_device *dev)
+{
+       struct ltq_etop_priv *priv = netdev_priv(dev);
+       struct sockaddr mac;
+       int err;
+
+       ether_setup(dev);
+       dev->watchdog_timeo = 10 * HZ;
+       err = ltq_etop_hw_init(dev);
+       if (err)
+               goto err_hw;
+       ltq_etop_change_mtu(dev, 1500);
+
+       memcpy(&mac, &priv->pldata->mac, sizeof(struct sockaddr));
+       if (!is_valid_ether_addr(mac.sa_data)) {
+               pr_warn("etop: invalid MAC, using random\n");
+               random_ether_addr(mac.sa_data);
+       }
+
+       err = ltq_etop_set_mac_address(dev, &mac);
+       if (err)
+               goto err_netdev;
+       ltq_etop_set_multicast_list(dev);
+       err = ltq_etop_mdio_init(dev);
+       if (err)
+               goto err_netdev;
+       return 0;
+
+err_netdev:
+       unregister_netdev(dev);
+       free_netdev(dev);
+err_hw:
+       ltq_etop_hw_exit(dev);
+       return err;
+}
+
+static void
+ltq_etop_tx_timeout(struct net_device *dev)
+{
+       int err;
+
+       ltq_etop_hw_exit(dev);
+       err = ltq_etop_hw_init(dev);
+       if (err)
+               goto err_hw;
+       dev->trans_start = jiffies;
+       netif_wake_queue(dev);
+       return;
+
+err_hw:
+       ltq_etop_hw_exit(dev);
+       netdev_err(dev, "failed to restart etop after TX timeout\n");
+}
+
+static const struct net_device_ops ltq_eth_netdev_ops = {
+       .ndo_open = ltq_etop_open,
+       .ndo_stop = ltq_etop_stop,
+       .ndo_start_xmit = ltq_etop_tx,
+       .ndo_change_mtu = ltq_etop_change_mtu,
+       .ndo_do_ioctl = ltq_etop_ioctl,
+       .ndo_set_mac_address = ltq_etop_set_mac_address,
+       .ndo_validate_addr = eth_validate_addr,
+       .ndo_set_multicast_list = ltq_etop_set_multicast_list,
+       .ndo_select_queue = ltq_etop_select_queue,
+       .ndo_init = ltq_etop_init,
+       .ndo_tx_timeout = ltq_etop_tx_timeout,
+};
+
+static int __init
+ltq_etop_probe(struct platform_device *pdev)
+{
+       struct net_device *dev;
+       struct ltq_etop_priv *priv;
+       struct resource *res;
+       int err;
+       int i;
+
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (!res) {
+               dev_err(&pdev->dev, "failed to get etop resource\n");
+               err = -ENOENT;
+               goto err_out;
+       }
+
+       res = devm_request_mem_region(&pdev->dev, res->start,
+               resource_size(res), dev_name(&pdev->dev));
+       if (!res) {
+               dev_err(&pdev->dev, "failed to request etop resource\n");
+               err = -EBUSY;
+               goto err_out;
+       }
+
+       ltq_etop_membase = devm_ioremap_nocache(&pdev->dev,
+               res->start, resource_size(res));
+       if (!ltq_etop_membase) {
+               dev_err(&pdev->dev, "failed to remap etop engine %d\n",
+                       pdev->id);
+               err = -ENOMEM;
+               goto err_out;
+       }
+
+       dev = alloc_etherdev_mq(sizeof(struct ltq_etop_priv), 4);
+       strcpy(dev->name, "eth%d");
+       dev->netdev_ops = &ltq_eth_netdev_ops;
+       dev->ethtool_ops = &ltq_etop_ethtool_ops;
+       priv = netdev_priv(dev);
+       priv->res = res;
+       priv->pldata = dev_get_platdata(&pdev->dev);
+       priv->netdev = dev;
+       spin_lock_init(&priv->lock);
+
+       for (i = 0; i < MAX_DMA_CHAN; i++) {
+               if (IS_TX(i))
+                       netif_napi_add(dev, &priv->ch[i].napi,
+                               ltq_etop_poll_tx, 8);
+               else if (IS_RX(i))
+                       netif_napi_add(dev, &priv->ch[i].napi,
+                               ltq_etop_poll_rx, 32);
+               priv->ch[i].netdev = dev;
+       }
+
+       err = register_netdev(dev);
+       if (err)
+               goto err_free;
+
+       platform_set_drvdata(pdev, dev);
+       return 0;
+
+err_free:
+       kfree(dev);
+err_out:
+       return err;
+}
+
+static int __devexit
+ltq_etop_remove(struct platform_device *pdev)
+{
+       struct net_device *dev = platform_get_drvdata(pdev);
+
+       if (dev) {
+               netif_tx_stop_all_queues(dev);
+               ltq_etop_hw_exit(dev);
+               ltq_etop_mdio_cleanup(dev);
+               unregister_netdev(dev);
+       }
+       return 0;
+}
+
+static struct platform_driver ltq_mii_driver = {
+       .remove = __devexit_p(ltq_etop_remove),
+       .driver = {
+               .name = "ltq_etop",
+               .owner = THIS_MODULE,
+       },
+};
+
+int __init
+init_ltq_etop(void)
+{
+       int ret = platform_driver_probe(&ltq_mii_driver, ltq_etop_probe);
+
+       if (ret)
+               pr_err("ltq_etop: Error registering platfom driver!");
+       return ret;
+}
+
+static void __exit
+exit_ltq_etop(void)
+{
+       platform_driver_unregister(&ltq_mii_driver);
+}
+
+module_init(init_ltq_etop);
+module_exit(exit_ltq_etop);
+
+MODULE_AUTHOR("John Crispin <blogic@openwrt.org>");
+MODULE_DESCRIPTION("Lantiq SoC ETOP");
+MODULE_LICENSE("GPL");
index 78e34e9..d8e4e69 100644 (file)
@@ -603,21 +603,13 @@ static int macvlan_port_create(struct net_device *dev)
        return err;
 }
 
-static void macvlan_port_rcu_free(struct rcu_head *head)
-{
-       struct macvlan_port *port;
-
-       port = container_of(head, struct macvlan_port, rcu);
-       kfree(port);
-}
-
 static void macvlan_port_destroy(struct net_device *dev)
 {
        struct macvlan_port *port = macvlan_port_get(dev);
 
        dev->priv_flags &= ~IFF_MACVLAN_PORT;
        netdev_rx_handler_unregister(dev);
-       call_rcu(&port->rcu, macvlan_port_rcu_free);
+       kfree_rcu(port, rcu);
 }
 
 static int macvlan_validate(struct nlattr *tb[], struct nlattr *data[])
index 30be8c6..7298a34 100644 (file)
@@ -167,7 +167,7 @@ static void cleanup_card(struct net_device *dev)
 #ifndef MODULE
 struct net_device * __init ne_probe(int unit)
 {
-       struct net_device *dev = alloc_ei_netdev();
+       struct net_device *dev = ____alloc_ei_netdev(0);
        int err;
 
        if (!dev)
@@ -197,15 +197,15 @@ static const struct net_device_ops ne_netdev_ops = {
        .ndo_open               = ne_open,
        .ndo_stop               = ne_close,
 
-       .ndo_start_xmit         = ei_start_xmit,
-       .ndo_tx_timeout         = ei_tx_timeout,
-       .ndo_get_stats          = ei_get_stats,
-       .ndo_set_multicast_list = ei_set_multicast_list,
+       .ndo_start_xmit         = __ei_start_xmit,
+       .ndo_tx_timeout         = __ei_tx_timeout,
+       .ndo_get_stats          = __ei_get_stats,
+       .ndo_set_multicast_list = __ei_set_multicast_list,
        .ndo_validate_addr      = eth_validate_addr,
-       .ndo_set_mac_address    = eth_mac_addr,
+       .ndo_set_mac_address    = eth_mac_addr,
        .ndo_change_mtu         = eth_change_mtu,
 #ifdef CONFIG_NET_POLL_CONTROLLER
-       .ndo_poll_controller    = ei_poll,
+       .ndo_poll_controller    = __ei_poll,
 #endif
 };
 
@@ -637,7 +637,7 @@ int init_module(void)
        int err;
 
        for (this_dev = 0; this_dev < MAX_NE_CARDS; this_dev++) {
-               struct net_device *dev = alloc_ei_netdev();
+               struct net_device *dev = ____alloc_ei_netdev(0);
                if (!dev)
                        break;
                if (io[this_dev]) {
index 2ef2f9c..56d049a 100644 (file)
@@ -34,6 +34,10 @@ const char pch_driver_version[] = DRV_VERSION;
 #define PCH_GBE_COPYBREAK_DEFAULT      256
 #define PCH_GBE_PCI_BAR                        1
 
+/* Macros for ML7223 */
+#define PCI_VENDOR_ID_ROHM                     0x10db
+#define PCI_DEVICE_ID_ROHM_ML7223_GBE          0x8013
+
 #define PCH_GBE_TX_WEIGHT         64
 #define PCH_GBE_RX_WEIGHT         64
 #define PCH_GBE_RX_BUFFER_WRITE   16
@@ -43,8 +47,7 @@ const char pch_driver_version[] = DRV_VERSION;
 
 #define PCH_GBE_MAC_RGMII_CTRL_SETTING ( \
        PCH_GBE_CHIP_TYPE_INTERNAL | \
-       PCH_GBE_RGMII_MODE_RGMII   | \
-       PCH_GBE_CRS_SEL              \
+       PCH_GBE_RGMII_MODE_RGMII     \
        )
 
 /* Ethertype field values */
@@ -1494,12 +1497,11 @@ pch_gbe_clean_rx(struct pch_gbe_adapter *adapter,
                        /* Write meta date of skb */
                        skb_put(skb, length);
                        skb->protocol = eth_type_trans(skb, netdev);
-                       if ((tcp_ip_status & PCH_GBE_RXD_ACC_STAT_TCPIPOK) ==
-                           PCH_GBE_RXD_ACC_STAT_TCPIPOK) {
-                               skb->ip_summed = CHECKSUM_UNNECESSARY;
-                       } else {
+                       if (tcp_ip_status & PCH_GBE_RXD_ACC_STAT_TCPIPOK)
                                skb->ip_summed = CHECKSUM_NONE;
-                       }
+                       else
+                               skb->ip_summed = CHECKSUM_UNNECESSARY;
+
                        napi_gro_receive(&adapter->napi, skb);
                        (*work_done)++;
                        pr_debug("Receive skb->ip_summed: %d length: %d\n",
@@ -2420,6 +2422,13 @@ static DEFINE_PCI_DEVICE_TABLE(pch_gbe_pcidev_id) = {
         .class = (PCI_CLASS_NETWORK_ETHERNET << 8),
         .class_mask = (0xFFFF00)
         },
+       {.vendor = PCI_VENDOR_ID_ROHM,
+        .device = PCI_DEVICE_ID_ROHM_ML7223_GBE,
+        .subvendor = PCI_ANY_ID,
+        .subdevice = PCI_ANY_ID,
+        .class = (PCI_CLASS_NETWORK_ETHERNET << 8),
+        .class_mask = (0xFFFF00)
+        },
        /* required last entry */
        {0}
 };
index d984790..3dd45ed 100644 (file)
@@ -50,6 +50,20 @@ static inline struct efx_mcdi_iface *efx_mcdi(struct efx_nic *efx)
        return &nic_data->mcdi;
 }
 
+static inline void
+efx_mcdi_readd(struct efx_nic *efx, efx_dword_t *value, unsigned reg)
+{
+       struct siena_nic_data *nic_data = efx->nic_data;
+       value->u32[0] = (__force __le32)__raw_readl(nic_data->mcdi_smem + reg);
+}
+
+static inline void
+efx_mcdi_writed(struct efx_nic *efx, const efx_dword_t *value, unsigned reg)
+{
+       struct siena_nic_data *nic_data = efx->nic_data;
+       __raw_writel((__force u32)value->u32[0], nic_data->mcdi_smem + reg);
+}
+
 void efx_mcdi_init(struct efx_nic *efx)
 {
        struct efx_mcdi_iface *mcdi;
@@ -70,8 +84,8 @@ static void efx_mcdi_copyin(struct efx_nic *efx, unsigned cmd,
                            const u8 *inbuf, size_t inlen)
 {
        struct efx_mcdi_iface *mcdi = efx_mcdi(efx);
-       unsigned pdu = FR_CZ_MC_TREG_SMEM + MCDI_PDU(efx);
-       unsigned doorbell = FR_CZ_MC_TREG_SMEM + MCDI_DOORBELL(efx);
+       unsigned pdu = MCDI_PDU(efx);
+       unsigned doorbell = MCDI_DOORBELL(efx);
        unsigned int i;
        efx_dword_t hdr;
        u32 xflags, seqno;
@@ -92,30 +106,28 @@ static void efx_mcdi_copyin(struct efx_nic *efx, unsigned cmd,
                             MCDI_HEADER_SEQ, seqno,
                             MCDI_HEADER_XFLAGS, xflags);
 
-       efx_writed(efx, &hdr, pdu);
+       efx_mcdi_writed(efx, &hdr, pdu);
 
-       for (i = 0; i < inlen; i += 4) {
-               _efx_writed(efx, *((__le32 *)(inbuf + i)), pdu + 4 + i);
-               /* use wmb() within loop to inhibit write combining */
-               wmb();
-       }
+       for (i = 0; i < inlen; i += 4)
+               efx_mcdi_writed(efx, (const efx_dword_t *)(inbuf + i),
+                               pdu + 4 + i);
 
        /* ring the doorbell with a distinctive value */
-       _efx_writed(efx, (__force __le32) 0x45789abc, doorbell);
-       wmb();
+       EFX_POPULATE_DWORD_1(hdr, EFX_DWORD_0, 0x45789abc);
+       efx_mcdi_writed(efx, &hdr, doorbell);
 }
 
 static void efx_mcdi_copyout(struct efx_nic *efx, u8 *outbuf, size_t outlen)
 {
        struct efx_mcdi_iface *mcdi = efx_mcdi(efx);
-       unsigned int pdu = FR_CZ_MC_TREG_SMEM + MCDI_PDU(efx);
+       unsigned int pdu = MCDI_PDU(efx);
        int i;
 
        BUG_ON(atomic_read(&mcdi->state) == MCDI_STATE_QUIESCENT);
        BUG_ON(outlen & 3 || outlen >= 0x100);
 
        for (i = 0; i < outlen; i += 4)
-               *((__le32 *)(outbuf + i)) = _efx_readd(efx, pdu + 4 + i);
+               efx_mcdi_readd(efx, (efx_dword_t *)(outbuf + i), pdu + 4 + i);
 }
 
 static int efx_mcdi_poll(struct efx_nic *efx)
@@ -123,7 +135,7 @@ static int efx_mcdi_poll(struct efx_nic *efx)
        struct efx_mcdi_iface *mcdi = efx_mcdi(efx);
        unsigned int time, finish;
        unsigned int respseq, respcmd, error;
-       unsigned int pdu = FR_CZ_MC_TREG_SMEM + MCDI_PDU(efx);
+       unsigned int pdu = MCDI_PDU(efx);
        unsigned int rc, spins;
        efx_dword_t reg;
 
@@ -149,8 +161,7 @@ static int efx_mcdi_poll(struct efx_nic *efx)
 
                time = get_seconds();
 
-               rmb();
-               efx_readd(efx, &reg, pdu);
+               efx_mcdi_readd(efx, &reg, pdu);
 
                /* All 1's indicates that shared memory is in reset (and is
                 * not a valid header). Wait for it to come out reset before
@@ -177,7 +188,7 @@ static int efx_mcdi_poll(struct efx_nic *efx)
                          respseq, mcdi->seqno);
                rc = EIO;
        } else if (error) {
-               efx_readd(efx, &reg, pdu + 4);
+               efx_mcdi_readd(efx, &reg, pdu + 4);
                switch (EFX_DWORD_FIELD(reg, EFX_DWORD_0)) {
 #define TRANSLATE_ERROR(name)                                  \
                case MC_CMD_ERR_ ## name:                       \
@@ -211,21 +222,21 @@ out:
 /* Test and clear MC-rebooted flag for this port/function */
 int efx_mcdi_poll_reboot(struct efx_nic *efx)
 {
-       unsigned int addr = FR_CZ_MC_TREG_SMEM + MCDI_REBOOT_FLAG(efx);
+       unsigned int addr = MCDI_REBOOT_FLAG(efx);
        efx_dword_t reg;
        uint32_t value;
 
        if (efx_nic_rev(efx) < EFX_REV_SIENA_A0)
                return false;
 
-       efx_readd(efx, &reg, addr);
+       efx_mcdi_readd(efx, &reg, addr);
        value = EFX_DWORD_FIELD(reg, EFX_DWORD_0);
 
        if (value == 0)
                return 0;
 
        EFX_ZERO_DWORD(reg);
-       efx_writed(efx, &reg, addr);
+       efx_mcdi_writed(efx, &reg, addr);
 
        if (value == MC_STATUS_DWORD_ASSERT)
                return -EINTR;
index 10f1cb7..9b29a8d 100644 (file)
@@ -1937,6 +1937,13 @@ void efx_nic_get_regs(struct efx_nic *efx, void *buf)
 
                size = min_t(size_t, table->step, 16);
 
+               if (table->offset >= efx->type->mem_map_size) {
+                       /* No longer mapped; return dummy data */
+                       memcpy(buf, "\xde\xc0\xad\xde", 4);
+                       buf += table->rows * size;
+                       continue;
+               }
+
                for (i = 0; i < table->rows; i++) {
                        switch (table->step) {
                        case 4: /* 32-bit register or SRAM */
index a42db6e..d91701a 100644 (file)
@@ -143,10 +143,12 @@ static inline struct falcon_board *falcon_board(struct efx_nic *efx)
 /**
  * struct siena_nic_data - Siena NIC state
  * @mcdi: Management-Controller-to-Driver Interface
+ * @mcdi_smem: MCDI shared memory mapping. The mapping is always uncacheable.
  * @wol_filter_id: Wake-on-LAN packet filter id
  */
 struct siena_nic_data {
        struct efx_mcdi_iface mcdi;
+       void __iomem *mcdi_smem;
        int wol_filter_id;
 };
 
index e4dd898..837869b 100644 (file)
@@ -220,12 +220,26 @@ static int siena_probe_nic(struct efx_nic *efx)
        efx_reado(efx, &reg, FR_AZ_CS_DEBUG);
        efx->net_dev->dev_id = EFX_OWORD_FIELD(reg, FRF_CZ_CS_PORT_NUM) - 1;
 
+       /* Initialise MCDI */
+       nic_data->mcdi_smem = ioremap_nocache(efx->membase_phys +
+                                             FR_CZ_MC_TREG_SMEM,
+                                             FR_CZ_MC_TREG_SMEM_STEP *
+                                             FR_CZ_MC_TREG_SMEM_ROWS);
+       if (!nic_data->mcdi_smem) {
+               netif_err(efx, probe, efx->net_dev,
+                         "could not map MCDI at %llx+%x\n",
+                         (unsigned long long)efx->membase_phys +
+                         FR_CZ_MC_TREG_SMEM,
+                         FR_CZ_MC_TREG_SMEM_STEP * FR_CZ_MC_TREG_SMEM_ROWS);
+               rc = -ENOMEM;
+               goto fail1;
+       }
        efx_mcdi_init(efx);
 
        /* Recover from a failed assertion before probing */
        rc = efx_mcdi_handle_assertion(efx);
        if (rc)
-               goto fail1;
+               goto fail2;
 
        /* Let the BMC know that the driver is now in charge of link and
         * filter settings. We must do this before we reset the NIC */
@@ -280,6 +294,7 @@ fail4:
 fail3:
        efx_mcdi_drv_attach(efx, false, NULL);
 fail2:
+       iounmap(nic_data->mcdi_smem);
 fail1:
        kfree(efx->nic_data);
        return rc;
@@ -359,6 +374,8 @@ static int siena_init_nic(struct efx_nic *efx)
 
 static void siena_remove_nic(struct efx_nic *efx)
 {
+       struct siena_nic_data *nic_data = efx->nic_data;
+
        efx_nic_free_buffer(efx, &efx->irq_status);
 
        siena_reset_hw(efx, RESET_TYPE_ALL);
@@ -368,7 +385,8 @@ static void siena_remove_nic(struct efx_nic *efx)
                efx_mcdi_drv_attach(efx, false, NULL);
 
        /* Tear down the private nic state */
-       kfree(efx->nic_data);
+       iounmap(nic_data->mcdi_smem);
+       kfree(nic_data);
        efx->nic_data = NULL;
 }
 
@@ -606,8 +624,7 @@ struct efx_nic_type siena_a0_nic_type = {
        .default_mac_ops = &efx_mcdi_mac_operations,
 
        .revision = EFX_REV_SIENA_A0,
-       .mem_map_size = (FR_CZ_MC_TREG_SMEM +
-                        FR_CZ_MC_TREG_SMEM_STEP * FR_CZ_MC_TREG_SMEM_ROWS),
+       .mem_map_size = FR_CZ_MC_TREG_SMEM, /* MC_TREG_SMEM mapped separately */
        .txd_ptr_tbl_base = FR_BZ_TX_DESC_PTR_TBL,
        .rxd_ptr_tbl_base = FR_BZ_RX_DESC_PTR_TBL,
        .buf_tbl_base = FR_BZ_BUF_FULL_TBL,
index 86cbb9e..8ec1a9a 100644 (file)
@@ -853,7 +853,9 @@ static int slip_open(struct tty_struct *tty)
        /* Done.  We have linked the TTY line to a channel. */
        rtnl_unlock();
        tty->receive_room = 65536;      /* We don't flow control */
-       return sl->dev->base_addr;
+
+       /* TTY layer expects 0 on success */
+       return 0;
 
 err_free_bufs:
        sl_free_bufs(sl);
index eb4f59f..bff2f79 100644 (file)
@@ -3237,15 +3237,18 @@ static void happy_meal_pci_exit(void)
 #endif
 
 #ifdef CONFIG_SBUS
+static const struct of_device_id hme_sbus_match[];
 static int __devinit hme_sbus_probe(struct platform_device *op)
 {
+       const struct of_device_id *match;
        struct device_node *dp = op->dev.of_node;
        const char *model = of_get_property(dp, "model", NULL);
        int is_qfe;
 
-       if (!op->dev.of_match)
+       match = of_match_device(hme_sbus_match, &op->dev);
+       if (!match)
                return -EINVAL;
-       is_qfe = (op->dev.of_match->data != NULL);
+       is_qfe = (match->data != NULL);
 
        if (!is_qfe && model && !strcmp(model, "SUNW,sbus-qfe"))
                is_qfe = 1;
index a301479..c924ea2 100644 (file)
@@ -567,7 +567,7 @@ static const struct usb_device_id   products [] = {
 {
        USB_DEVICE_AND_INTERFACE_INFO(0x1004, 0x61aa, USB_CLASS_COMM,
                        USB_CDC_SUBCLASS_ETHERNET, USB_CDC_PROTO_NONE),
-       .driver_info            = 0,
+       .driver_info = (unsigned long)&wwan_info,
 },
 
 /*
index 7d42f9a..81126ff 100644 (file)
@@ -65,6 +65,7 @@
 #define IPHETH_USBINTF_PROTO    1
 
 #define IPHETH_BUF_SIZE         1516
+#define IPHETH_IP_ALIGN                2       /* padding at front of URB */
 #define IPHETH_TX_TIMEOUT       (5 * HZ)
 
 #define IPHETH_INTFNUM          2
@@ -202,18 +203,21 @@ static void ipheth_rcvbulk_callback(struct urb *urb)
                return;
        }
 
-       len = urb->actual_length;
-       buf = urb->transfer_buffer;
+       if (urb->actual_length <= IPHETH_IP_ALIGN) {
+               dev->net->stats.rx_length_errors++;
+               return;
+       }
+       len = urb->actual_length - IPHETH_IP_ALIGN;
+       buf = urb->transfer_buffer + IPHETH_IP_ALIGN;
 
-       skb = dev_alloc_skb(NET_IP_ALIGN + len);
+       skb = dev_alloc_skb(len);
        if (!skb) {
                err("%s: dev_alloc_skb: -ENOMEM", __func__);
                dev->net->stats.rx_dropped++;
                return;
        }
 
-       skb_reserve(skb, NET_IP_ALIGN);
-       memcpy(skb_put(skb, len), buf + NET_IP_ALIGN, len - NET_IP_ALIGN);
+       memcpy(skb_put(skb, len), buf, len);
        skb->dev = dev->net;
        skb->protocol = eth_type_trans(skb, dev->net);
 
index 009bba3..9ab439d 100644 (file)
@@ -645,6 +645,7 @@ int usbnet_stop (struct net_device *net)
        struct driver_info      *info = dev->driver_info;
        int                     retval;
 
+       clear_bit(EVENT_DEV_OPEN, &dev->flags);
        netif_stop_queue (net);
 
        netif_info(dev, ifdown, dev->net,
@@ -1524,9 +1525,12 @@ int usbnet_resume (struct usb_interface *intf)
                smp_mb();
                clear_bit(EVENT_DEV_ASLEEP, &dev->flags);
                spin_unlock_irq(&dev->txq.lock);
-               if (!(dev->txq.qlen >= TX_QLEN(dev)))
-                       netif_start_queue(dev->net);
-               tasklet_schedule (&dev->bh);
+
+               if (test_bit(EVENT_DEV_OPEN, &dev->flags)) {
+                       if (!(dev->txq.qlen >= TX_QLEN(dev)))
+                               netif_start_queue(dev->net);
+                       tasklet_schedule (&dev->bh);
+               }
        }
        return 0;
 }
index 0d47c3a..c16ed96 100644 (file)
@@ -178,6 +178,7 @@ static void
 vmxnet3_process_events(struct vmxnet3_adapter *adapter)
 {
        int i;
+       unsigned long flags;
        u32 events = le32_to_cpu(adapter->shared->ecr);
        if (!events)
                return;
@@ -190,10 +191,10 @@ vmxnet3_process_events(struct vmxnet3_adapter *adapter)
 
        /* Check if there is an error on xmit/recv queues */
        if (events & (VMXNET3_ECR_TQERR | VMXNET3_ECR_RQERR)) {
-               spin_lock(&adapter->cmd_lock);
+               spin_lock_irqsave(&adapter->cmd_lock, flags);
                VMXNET3_WRITE_BAR1_REG(adapter, VMXNET3_REG_CMD,
                                       VMXNET3_CMD_GET_QUEUE_STATUS);
-               spin_unlock(&adapter->cmd_lock);
+               spin_unlock_irqrestore(&adapter->cmd_lock, flags);
 
                for (i = 0; i < adapter->num_tx_queues; i++)
                        if (adapter->tqd_start[i].status.stopped)
@@ -2733,13 +2734,14 @@ static void
 vmxnet3_alloc_intr_resources(struct vmxnet3_adapter *adapter)
 {
        u32 cfg;
+       unsigned long flags;
 
        /* intr settings */
-       spin_lock(&adapter->cmd_lock);
+       spin_lock_irqsave(&adapter->cmd_lock, flags);
        VMXNET3_WRITE_BAR1_REG(adapter, VMXNET3_REG_CMD,
                               VMXNET3_CMD_GET_CONF_INTR);
        cfg = VMXNET3_READ_BAR1_REG(adapter, VMXNET3_REG_CMD);
-       spin_unlock(&adapter->cmd_lock);
+       spin_unlock_irqrestore(&adapter->cmd_lock, flags);
        adapter->intr.type = cfg & 0x3;
        adapter->intr.mask_mode = (cfg >> 2) & 0x3;
 
index 51f2ef1..9764672 100644 (file)
@@ -311,6 +311,9 @@ vmxnet3_set_flags(struct net_device *netdev, u32 data)
                /* toggle the LRO feature*/
                netdev->features ^= NETIF_F_LRO;
 
+               /* Update private LRO flag */
+               adapter->lro = lro_requested;
+
                /* update harware LRO capability accordingly */
                if (lro_requested)
                        adapter->shared->devRead.misc.uptFeatures |=
index 17d04ff..1482fa6 100644 (file)
@@ -2141,6 +2141,8 @@ static void ath9k_set_coverage_class(struct ieee80211_hw *hw, u8 coverage_class)
 static void ath9k_flush(struct ieee80211_hw *hw, bool drop)
 {
        struct ath_softc *sc = hw->priv;
+       struct ath_hw *ah = sc->sc_ah;
+       struct ath_common *common = ath9k_hw_common(ah);
        int timeout = 200; /* ms */
        int i, j;
 
@@ -2149,6 +2151,12 @@ static void ath9k_flush(struct ieee80211_hw *hw, bool drop)
 
        cancel_delayed_work_sync(&sc->tx_complete_work);
 
+       if (sc->sc_flags & SC_OP_INVALID) {
+               ath_dbg(common, ATH_DBG_ANY, "Device not present\n");
+               mutex_unlock(&sc->mutex);
+               return;
+       }
+
        if (drop)
                timeout = 1;
 
index c1511b1..42db0fc 100644 (file)
@@ -2155,6 +2155,13 @@ int iwl_legacy_mac_config(struct ieee80211_hw *hw, u32 changed)
                        goto set_ch_out;
                }
 
+               if (priv->iw_mode == NL80211_IFTYPE_ADHOC &&
+                   !iwl_legacy_is_channel_ibss(ch_info)) {
+                       IWL_DEBUG_MAC80211(priv, "leave - not IBSS channel\n");
+                       ret = -EINVAL;
+                       goto set_ch_out;
+               }
+
                spin_lock_irqsave(&priv->lock, flags);
 
                for_each_context(priv, ctx) {
index 9ee849d..f43ac1e 100644 (file)
@@ -1411,6 +1411,12 @@ iwl_legacy_is_channel_passive(const struct iwl_channel_info *ch)
        return (!(ch->flags & EEPROM_CHANNEL_ACTIVE)) ? 1 : 0;
 }
 
+static inline int
+iwl_legacy_is_channel_ibss(const struct iwl_channel_info *ch)
+{
+       return (ch->flags & EEPROM_CHANNEL_IBSS) ? 1 : 0;
+}
+
 static inline void
 __iwl_legacy_free_pages(struct iwl_priv *priv, struct page *page)
 {
index 7e8a658..f3ac624 100644 (file)
@@ -1339,8 +1339,8 @@ int lbs_execute_next_command(struct lbs_private *priv)
                                    cpu_to_le16(PS_MODE_ACTION_EXIT_PS)) {
                                        lbs_deb_host(
                                               "EXEC_NEXT_CMD: ignore ENTER_PS cmd\n");
-                                       list_del(&cmdnode->list);
                                        spin_lock_irqsave(&priv->driver_lock, flags);
+                                       list_del(&cmdnode->list);
                                        lbs_complete_command(priv, cmdnode, 0);
                                        spin_unlock_irqrestore(&priv->driver_lock, flags);
 
@@ -1352,8 +1352,8 @@ int lbs_execute_next_command(struct lbs_private *priv)
                                    (priv->psstate == PS_STATE_PRE_SLEEP)) {
                                        lbs_deb_host(
                                               "EXEC_NEXT_CMD: ignore EXIT_PS cmd in sleep\n");
-                                       list_del(&cmdnode->list);
                                        spin_lock_irqsave(&priv->driver_lock, flags);
+                                       list_del(&cmdnode->list);
                                        lbs_complete_command(priv, cmdnode, 0);
                                        spin_unlock_irqrestore(&priv->driver_lock, flags);
                                        priv->needtowakeup = 1;
@@ -1366,7 +1366,9 @@ int lbs_execute_next_command(struct lbs_private *priv)
                                       "EXEC_NEXT_CMD: sending EXIT_PS\n");
                        }
                }
+               spin_lock_irqsave(&priv->driver_lock, flags);
                list_del(&cmdnode->list);
+               spin_unlock_irqrestore(&priv->driver_lock, flags);
                lbs_deb_host("EXEC_NEXT_CMD: sending command 0x%04x\n",
                            le16_to_cpu(cmd->command));
                lbs_submit_command(priv, cmdnode);
index b78a38d..8c7c522 100644 (file)
@@ -126,7 +126,7 @@ static int __devinit zorro8390_init_one(struct zorro_dev *z,
 
     board = z->resource.start;
     ioaddr = board+cards[i].offset;
-    dev = alloc_ei_netdev();
+    dev = ____alloc_ei_netdev(0);
     if (!dev)
        return -ENOMEM;
     if (!request_mem_region(ioaddr, NE_IO_EXTENT*2, DRV_NAME)) {
@@ -146,15 +146,15 @@ static int __devinit zorro8390_init_one(struct zorro_dev *z,
 static const struct net_device_ops zorro8390_netdev_ops = {
        .ndo_open               = zorro8390_open,
        .ndo_stop               = zorro8390_close,
-       .ndo_start_xmit         = ei_start_xmit,
-       .ndo_tx_timeout         = ei_tx_timeout,
-       .ndo_get_stats          = ei_get_stats,
-       .ndo_set_multicast_list = ei_set_multicast_list,
+       .ndo_start_xmit         = __ei_start_xmit,
+       .ndo_tx_timeout         = __ei_tx_timeout,
+       .ndo_get_stats          = __ei_get_stats,
+       .ndo_set_multicast_list = __ei_set_multicast_list,
        .ndo_validate_addr      = eth_validate_addr,
        .ndo_set_mac_address    = eth_mac_addr,
        .ndo_change_mtu         = eth_change_mtu,
 #ifdef CONFIG_NET_POLL_CONTROLLER
-       .ndo_poll_controller    = ei_poll,
+       .ndo_poll_controller    = __ei_poll,
 #endif
 };
 
index d552d2c..6af6b62 100644 (file)
@@ -39,6 +39,7 @@
 #include <linux/syscore_ops.h>
 #include <linux/tboot.h>
 #include <linux/dmi.h>
+#include <linux/pci-ats.h>
 #include <asm/cacheflush.h>
 #include <asm/iommu.h>
 #include "pci.h"
index 553d8ee..42fae47 100644 (file)
@@ -13,6 +13,7 @@
 #include <linux/mutex.h>
 #include <linux/string.h>
 #include <linux/delay.h>
+#include <linux/pci-ats.h>
 #include "pci.h"
 
 #define VIRTFN_ID_LEN  16
index a6ec200..4020025 100644 (file)
@@ -250,15 +250,6 @@ struct pci_sriov {
        u8 __iomem *mstate;     /* VF Migration State Array */
 };
 
-/* Address Translation Service */
-struct pci_ats {
-       int pos;        /* capability position */
-       int stu;        /* Smallest Translation Unit */
-       int qdep;       /* Invalidate Queue Depth */
-       int ref_cnt;    /* Physical Function reference count */
-       unsigned int is_enabled:1;      /* Enable bit is set */
-};
-
 #ifdef CONFIG_PCI_IOV
 extern int pci_iov_init(struct pci_dev *dev);
 extern void pci_iov_release(struct pci_dev *dev);
@@ -269,19 +260,6 @@ extern resource_size_t pci_sriov_resource_alignment(struct pci_dev *dev,
 extern void pci_restore_iov_state(struct pci_dev *dev);
 extern int pci_iov_bus_range(struct pci_bus *bus);
 
-extern int pci_enable_ats(struct pci_dev *dev, int ps);
-extern void pci_disable_ats(struct pci_dev *dev);
-extern int pci_ats_queue_depth(struct pci_dev *dev);
-/**
- * pci_ats_enabled - query the ATS status
- * @dev: the PCI device
- *
- * Returns 1 if ATS capability is enabled, or 0 if not.
- */
-static inline int pci_ats_enabled(struct pci_dev *dev)
-{
-       return dev->ats && dev->ats->is_enabled;
-}
 #else
 static inline int pci_iov_init(struct pci_dev *dev)
 {
@@ -304,21 +282,6 @@ static inline int pci_iov_bus_range(struct pci_bus *bus)
        return 0;
 }
 
-static inline int pci_enable_ats(struct pci_dev *dev, int ps)
-{
-       return -ENODEV;
-}
-static inline void pci_disable_ats(struct pci_dev *dev)
-{
-}
-static inline int pci_ats_queue_depth(struct pci_dev *dev)
-{
-       return -ENODEV;
-}
-static inline int pci_ats_enabled(struct pci_dev *dev)
-{
-       return 0;
-}
 #endif /* CONFIG_PCI_IOV */
 
 static inline resource_size_t pci_resource_alignment(struct pci_dev *dev,
index ebf51ad..a806cb3 100644 (file)
@@ -579,7 +579,7 @@ static void pbus_size_io(struct pci_bus *bus, resource_size_t min_size,
        }
        size0 = calculate_iosize(size, min_size, size1,
                        resource_size(b_res), 4096);
-       size1 = !add_size? size0:
+       size1 = (!add_head || (add_head && !add_size)) ? size0 :
                calculate_iosize(size, min_size+add_size, size1,
                        resource_size(b_res), 4096);
        if (!size0 && !size1) {
@@ -677,7 +677,7 @@ static int pbus_size_mem(struct pci_bus *bus, unsigned long mask,
                align += aligns[order];
        }
        size0 = calculate_memsize(size, min_size, 0, resource_size(b_res), min_align);
-       size1 = !add_size ? size :
+       size1 = (!add_head || (add_head && !add_size)) ? size0 :
                calculate_memsize(size, min_size+add_size, 0,
                                resource_size(b_res), min_align);
        if (!size0 && !size1) {
index ac2701b..043ee31 100644 (file)
@@ -95,6 +95,9 @@ idtg2_route_add_entry(struct rio_mport *mport, u16 destid, u8 hopcount,
        else
                table++;
 
+       if (route_port == RIO_INVALID_ROUTE)
+               route_port = IDT_DEFAULT_ROUTE;
+
        rio_mport_write_config_32(mport, destid, hopcount,
                                  LOCAL_RTE_CONF_DESTID_SEL, table);
 
@@ -411,6 +414,12 @@ static int idtg2_switch_init(struct rio_dev *rdev, int do_enum)
        rdev->rswitch->em_handle = idtg2_em_handler;
        rdev->rswitch->sw_sysfs = idtg2_sysfs;
 
+       if (do_enum) {
+               /* Ensure that default routing is disabled on startup */
+               rio_write_config_32(rdev,
+                                   RIO_STD_RTE_DEFAULT_PORT, IDT_NO_ROUTE);
+       }
+
        return 0;
 }
 
index 3a97107..d06ee2d 100644 (file)
@@ -26,6 +26,9 @@ idtcps_route_add_entry(struct rio_mport *mport, u16 destid, u8 hopcount,
 {
        u32 result;
 
+       if (route_port == RIO_INVALID_ROUTE)
+               route_port = CPS_DEFAULT_ROUTE;
+
        if (table == RIO_GLOBAL_TABLE) {
                rio_mport_write_config_32(mport, destid, hopcount,
                                RIO_STD_RTE_CONF_DESTID_SEL_CSR, route_destid);
@@ -130,6 +133,9 @@ static int idtcps_switch_init(struct rio_dev *rdev, int do_enum)
                /* set TVAL = ~50us */
                rio_write_config_32(rdev,
                        rdev->phys_efptr + RIO_PORT_LINKTO_CTL_CSR, 0x8e << 8);
+               /* Ensure that default routing is disabled on startup */
+               rio_write_config_32(rdev,
+                                   RIO_STD_RTE_DEFAULT_PORT, CPS_NO_ROUTE);
        }
 
        return 0;
index 1a62934..db8b802 100644 (file)
@@ -303,6 +303,12 @@ static int tsi57x_switch_init(struct rio_dev *rdev, int do_enum)
        rdev->rswitch->em_init = tsi57x_em_init;
        rdev->rswitch->em_handle = tsi57x_em_handler;
 
+       if (do_enum) {
+               /* Ensure that default routing is disabled on startup */
+               rio_write_config_32(rdev, RIO_STD_RTE_DEFAULT_PORT,
+                                   RIO_INVALID_ROUTE);
+       }
+
        return 0;
 }
 
index e187887..4289172 100644 (file)
@@ -3,10 +3,10 @@
 #
 
 config RTC_LIB
-       tristate
+       bool
 
 menuconfig RTC_CLASS
-       tristate "Real Time Clock"
+       bool "Real Time Clock"
        default n
        depends on !S390
        select RTC_LIB
@@ -15,9 +15,6 @@ menuconfig RTC_CLASS
          be allowed to plug one or more RTCs to your system. You will
          probably want to enable one or more of the interfaces below.
 
-         This driver can also be built as a module. If so, the module
-         will be called rtc-core.
-
 if RTC_CLASS
 
 config RTC_HCTOSYS
index 3901386..4194e59 100644 (file)
@@ -41,26 +41,21 @@ static void rtc_device_release(struct device *dev)
  * system's wall clock; restore it on resume().
  */
 
-static struct timespec delta;
 static time_t          oldtime;
+static struct timespec oldts;
 
 static int rtc_suspend(struct device *dev, pm_message_t mesg)
 {
        struct rtc_device       *rtc = to_rtc_device(dev);
        struct rtc_time         tm;
-       struct timespec         ts = current_kernel_time();
 
        if (strcmp(dev_name(&rtc->dev), CONFIG_RTC_HCTOSYS_DEVICE) != 0)
                return 0;
 
        rtc_read_time(rtc, &tm);
+       ktime_get_ts(&oldts);
        rtc_tm_to_time(&tm, &oldtime);
 
-       /* RTC precision is 1 second; adjust delta for avg 1/2 sec err */
-       set_normalized_timespec(&delta,
-                               ts.tv_sec - oldtime,
-                               ts.tv_nsec - (NSEC_PER_SEC >> 1));
-
        return 0;
 }
 
@@ -70,10 +65,12 @@ static int rtc_resume(struct device *dev)
        struct rtc_time         tm;
        time_t                  newtime;
        struct timespec         time;
+       struct timespec         newts;
 
        if (strcmp(dev_name(&rtc->dev), CONFIG_RTC_HCTOSYS_DEVICE) != 0)
                return 0;
 
+       ktime_get_ts(&newts);
        rtc_read_time(rtc, &tm);
        if (rtc_valid_tm(&tm) != 0) {
                pr_debug("%s:  bogus resume time\n", dev_name(&rtc->dev));
@@ -85,15 +82,13 @@ static int rtc_resume(struct device *dev)
                        pr_debug("%s:  time travel!\n", dev_name(&rtc->dev));
                return 0;
        }
+       /* calculate the RTC time delta */
+       set_normalized_timespec(&time, newtime - oldtime, 0);
 
-       /* restore wall clock using delta against this RTC;
-        * adjust again for avg 1/2 second RTC sampling error
-        */
-       set_normalized_timespec(&time,
-                               newtime + delta.tv_sec,
-                               (NSEC_PER_SEC >> 1) + delta.tv_nsec);
-       do_settimeofday(&time);
+       /* subtract kernel time between rtc_suspend to rtc_resume */
+       time = timespec_sub(time, timespec_sub(newts, oldts));
 
+       timekeeping_inject_sleeptime(&time);
        return 0;
 }
 
index 8d46838..755e1fe 100644 (file)
@@ -524,6 +524,8 @@ static int __init davinci_rtc_probe(struct platform_device *pdev)
                goto fail2;
        }
 
+       platform_set_drvdata(pdev, davinci_rtc);
+
        davinci_rtc->rtc = rtc_device_register(pdev->name, &pdev->dev,
                                    &davinci_rtc_ops, THIS_MODULE);
        if (IS_ERR(davinci_rtc->rtc)) {
@@ -553,8 +555,6 @@ static int __init davinci_rtc_probe(struct platform_device *pdev)
 
        rtcss_write(davinci_rtc, PRTCSS_RTC_CCTRL_CAEN, PRTCSS_RTC_CCTRL);
 
-       platform_set_drvdata(pdev, davinci_rtc);
-
        device_init_wakeup(&pdev->dev, 0);
 
        return 0;
@@ -562,6 +562,7 @@ static int __init davinci_rtc_probe(struct platform_device *pdev)
 fail4:
        rtc_device_unregister(davinci_rtc->rtc);
 fail3:
+       platform_set_drvdata(pdev, NULL);
        iounmap(davinci_rtc->base);
 fail2:
        release_mem_region(davinci_rtc->pbase, davinci_rtc->base_size);
index 60ce696..47e681d 100644 (file)
@@ -355,6 +355,7 @@ static int __devinit ds1286_probe(struct platform_device *pdev)
                goto out;
        }
        spin_lock_init(&priv->lock);
+       platform_set_drvdata(pdev, priv);
        rtc = rtc_device_register("ds1286", &pdev->dev,
                                  &ds1286_ops, THIS_MODULE);
        if (IS_ERR(rtc)) {
@@ -362,7 +363,6 @@ static int __devinit ds1286_probe(struct platform_device *pdev)
                goto out;
        }
        priv->rtc = rtc;
-       platform_set_drvdata(pdev, priv);
        return 0;
 
 out:
index 11ae64d..335551d 100644 (file)
@@ -151,6 +151,7 @@ static int __init ep93xx_rtc_probe(struct platform_device *pdev)
                return -ENXIO;
 
        pdev->dev.platform_data = ep93xx_rtc;
+       platform_set_drvdata(pdev, rtc);
 
        rtc = rtc_device_register(pdev->name,
                                &pdev->dev, &ep93xx_rtc_ops, THIS_MODULE);
@@ -159,8 +160,6 @@ static int __init ep93xx_rtc_probe(struct platform_device *pdev)
                goto exit;
        }
 
-       platform_set_drvdata(pdev, rtc);
-
        err = sysfs_create_group(&pdev->dev.kobj, &ep93xx_rtc_sysfs_files);
        if (err)
                goto fail;
@@ -168,9 +167,9 @@ static int __init ep93xx_rtc_probe(struct platform_device *pdev)
        return 0;
 
 fail:
-       platform_set_drvdata(pdev, NULL);
        rtc_device_unregister(rtc);
 exit:
+       platform_set_drvdata(pdev, NULL);
        pdev->dev.platform_data = NULL;
        return err;
 }
index 69fe664..eda128f 100644 (file)
@@ -783,6 +783,9 @@ static int m41t80_probe(struct i2c_client *client,
                goto exit;
        }
 
+       clientdata->features = id->driver_data;
+       i2c_set_clientdata(client, clientdata);
+
        rtc = rtc_device_register(client->name, &client->dev,
                                  &m41t80_rtc_ops, THIS_MODULE);
        if (IS_ERR(rtc)) {
@@ -792,8 +795,6 @@ static int m41t80_probe(struct i2c_client *client,
        }
 
        clientdata->rtc = rtc;
-       clientdata->features = id->driver_data;
-       i2c_set_clientdata(client, clientdata);
 
        /* Make sure HT (Halt Update) bit is cleared */
        rc = i2c_smbus_read_byte_data(client, M41T80_REG_ALARM_HOUR);
index 20494b5..3bc046f 100644 (file)
@@ -258,6 +258,8 @@ static int __devinit max8925_rtc_probe(struct platform_device *pdev)
        }
 
        dev_set_drvdata(&pdev->dev, info);
+       /* XXX - isn't this redundant? */
+       platform_set_drvdata(pdev, info);
 
        info->rtc_dev = rtc_device_register("max8925-rtc", &pdev->dev,
                                        &max8925_rtc_ops, THIS_MODULE);
@@ -267,10 +269,9 @@ static int __devinit max8925_rtc_probe(struct platform_device *pdev)
                goto out_rtc;
        }
 
-       platform_set_drvdata(pdev, info);
-
        return 0;
 out_rtc:
+       platform_set_drvdata(pdev, NULL);
        free_irq(chip->irq_base + MAX8925_IRQ_RTC_ALARM0, info);
 out_irq:
        kfree(info);
index 3f7bc6b..2e48aa6 100644 (file)
@@ -265,6 +265,8 @@ static int __devinit max8998_rtc_probe(struct platform_device *pdev)
        info->rtc = max8998->rtc;
        info->irq = max8998->irq_base + MAX8998_IRQ_ALARM0;
 
+       platform_set_drvdata(pdev, info);
+
        info->rtc_dev = rtc_device_register("max8998-rtc", &pdev->dev,
                        &max8998_rtc_ops, THIS_MODULE);
 
@@ -274,8 +276,6 @@ static int __devinit max8998_rtc_probe(struct platform_device *pdev)
                goto out_rtc;
        }
 
-       platform_set_drvdata(pdev, info);
-
        ret = request_threaded_irq(info->irq, NULL, max8998_rtc_alarm_irq, 0,
                        "rtc-alarm0", info);
 
@@ -293,6 +293,7 @@ static int __devinit max8998_rtc_probe(struct platform_device *pdev)
        return 0;
 
 out_rtc:
+       platform_set_drvdata(pdev, NULL);
        kfree(info);
        return ret;
 }
index c5ac037..a1a278b 100644 (file)
@@ -349,11 +349,15 @@ static int __devinit mc13xxx_rtc_probe(struct platform_device *pdev)
        if (ret)
                goto err_alarm_irq_request;
 
+       mc13xxx_unlock(mc13xxx);
+
        priv->rtc = rtc_device_register(pdev->name,
                        &pdev->dev, &mc13xxx_rtc_ops, THIS_MODULE);
        if (IS_ERR(priv->rtc)) {
                ret = PTR_ERR(priv->rtc);
 
+               mc13xxx_lock(mc13xxx);
+
                mc13xxx_irq_free(mc13xxx, MC13XXX_IRQ_TODA, priv);
 err_alarm_irq_request:
 
@@ -365,12 +369,12 @@ err_reset_irq_status:
                mc13xxx_irq_free(mc13xxx, MC13XXX_IRQ_RTCRST, priv);
 err_reset_irq_request:
 
+               mc13xxx_unlock(mc13xxx);
+
                platform_set_drvdata(pdev, NULL);
                kfree(priv);
        }
 
-       mc13xxx_unlock(mc13xxx);
-
        return ret;
 }
 
index 6782062..fcb113c 100644 (file)
@@ -214,6 +214,7 @@ static int __init msm6242_rtc_probe(struct platform_device *dev)
                error = -ENOMEM;
                goto out_free_priv;
        }
+       platform_set_drvdata(dev, priv);
 
        rtc = rtc_device_register("rtc-msm6242", &dev->dev, &msm6242_rtc_ops,
                                  THIS_MODULE);
@@ -223,10 +224,10 @@ static int __init msm6242_rtc_probe(struct platform_device *dev)
        }
 
        priv->rtc = rtc;
-       platform_set_drvdata(dev, priv);
        return 0;
 
 out_unmap:
+       platform_set_drvdata(dev, NULL);
        iounmap(priv->regs);
 out_free_priv:
        kfree(priv);
index 826ab64..d814417 100644 (file)
@@ -418,14 +418,6 @@ static int __init mxc_rtc_probe(struct platform_device *pdev)
                goto exit_put_clk;
        }
 
-       rtc = rtc_device_register(pdev->name, &pdev->dev, &mxc_rtc_ops,
-                                 THIS_MODULE);
-       if (IS_ERR(rtc)) {
-               ret = PTR_ERR(rtc);
-               goto exit_put_clk;
-       }
-
-       pdata->rtc = rtc;
        platform_set_drvdata(pdev, pdata);
 
        /* Configure and enable the RTC */
@@ -438,8 +430,19 @@ static int __init mxc_rtc_probe(struct platform_device *pdev)
                pdata->irq = -1;
        }
 
+       rtc = rtc_device_register(pdev->name, &pdev->dev, &mxc_rtc_ops,
+                                 THIS_MODULE);
+       if (IS_ERR(rtc)) {
+               ret = PTR_ERR(rtc);
+               goto exit_clr_drvdata;
+       }
+
+       pdata->rtc = rtc;
+
        return 0;
 
+exit_clr_drvdata:
+       platform_set_drvdata(pdev, NULL);
 exit_put_clk:
        clk_disable(pdata->clk);
        clk_put(pdata->clk);
index a633abc..cd4f198 100644 (file)
@@ -151,6 +151,8 @@ static int __devinit pcap_rtc_probe(struct platform_device *pdev)
 
        pcap_rtc->pcap = dev_get_drvdata(pdev->dev.parent);
 
+       platform_set_drvdata(pdev, pcap_rtc);
+
        pcap_rtc->rtc = rtc_device_register("pcap", &pdev->dev,
                                  &pcap_rtc_ops, THIS_MODULE);
        if (IS_ERR(pcap_rtc->rtc)) {
@@ -158,7 +160,6 @@ static int __devinit pcap_rtc_probe(struct platform_device *pdev)
                goto fail_rtc;
        }
 
-       platform_set_drvdata(pdev, pcap_rtc);
 
        timer_irq = pcap_to_irq(pcap_rtc->pcap, PCAP_IRQ_1HZ);
        alarm_irq = pcap_to_irq(pcap_rtc->pcap, PCAP_IRQ_TODA);
@@ -177,6 +178,7 @@ fail_alarm:
 fail_timer:
        rtc_device_unregister(pcap_rtc->rtc);
 fail_rtc:
+       platform_set_drvdata(pdev, NULL);
        kfree(pcap_rtc);
        return err;
 }
index 694da39..359da6d 100644 (file)
@@ -249,15 +249,15 @@ static int __init rp5c01_rtc_probe(struct platform_device *dev)
 
        spin_lock_init(&priv->lock);
 
+       platform_set_drvdata(dev, priv);
+
        rtc = rtc_device_register("rtc-rp5c01", &dev->dev, &rp5c01_rtc_ops,
                                  THIS_MODULE);
        if (IS_ERR(rtc)) {
                error = PTR_ERR(rtc);
                goto out_unmap;
        }
-
        priv->rtc = rtc;
-       platform_set_drvdata(dev, priv);
 
        error = sysfs_create_bin_file(&dev->dev.kobj, &priv->nvram_attr);
        if (error)
@@ -268,6 +268,7 @@ static int __init rp5c01_rtc_probe(struct platform_device *dev)
 out_unregister:
        rtc_device_unregister(rtc);
 out_unmap:
+       platform_set_drvdata(dev, NULL);
        iounmap(priv->regs);
 out_free_priv:
        kfree(priv);
index b3466c4..16512ec 100644 (file)
@@ -46,6 +46,7 @@ static struct clk *rtc_clk;
 static void __iomem *s3c_rtc_base;
 static int s3c_rtc_alarmno = NO_IRQ;
 static int s3c_rtc_tickno  = NO_IRQ;
+static bool wake_en;
 static enum s3c_cpu_type s3c_rtc_cpu_type;
 
 static DEFINE_SPINLOCK(s3c_rtc_pie_lock);
@@ -562,8 +563,12 @@ static int s3c_rtc_suspend(struct platform_device *pdev, pm_message_t state)
        }
        s3c_rtc_enable(pdev, 0);
 
-       if (device_may_wakeup(&pdev->dev))
-               enable_irq_wake(s3c_rtc_alarmno);
+       if (device_may_wakeup(&pdev->dev) && !wake_en) {
+               if (enable_irq_wake(s3c_rtc_alarmno) == 0)
+                       wake_en = true;
+               else
+                       dev_err(&pdev->dev, "enable_irq_wake failed\n");
+       }
 
        return 0;
 }
@@ -579,8 +584,10 @@ static int s3c_rtc_resume(struct platform_device *pdev)
                writew(tmp | ticnt_en_save, s3c_rtc_base + S3C2410_RTCCON);
        }
 
-       if (device_may_wakeup(&pdev->dev))
+       if (device_may_wakeup(&pdev->dev) && wake_en) {
                disable_irq_wake(s3c_rtc_alarmno);
+               wake_en = false;
+       }
 
        return 0;
 }
index 475e603..86b6f1c 100644 (file)
@@ -1742,11 +1742,20 @@ int dasd_sleep_on_interruptible(struct dasd_ccw_req *cqr)
 static inline int _dasd_term_running_cqr(struct dasd_device *device)
 {
        struct dasd_ccw_req *cqr;
+       int rc;
 
        if (list_empty(&device->ccw_queue))
                return 0;
        cqr = list_entry(device->ccw_queue.next, struct dasd_ccw_req, devlist);
-       return device->discipline->term_IO(cqr);
+       rc = device->discipline->term_IO(cqr);
+       if (!rc)
+               /*
+                * CQR terminated because a more important request is pending.
+                * Undo decreasing of retry counter because this is
+                * not an error case.
+                */
+               cqr->retries++;
+       return rc;
 }
 
 int dasd_sleep_on_immediatly(struct dasd_ccw_req *cqr)
index 4b60ede..be55fb2 100644 (file)
@@ -518,6 +518,8 @@ static void __init insert_increment(u16 rn, int standby, int assigned)
                return;
        new_incr->rn = rn;
        new_incr->standby = standby;
+       if (!standby)
+               new_incr->usecount = 1;
        last_rn = 0;
        prev = &sclp_mem_list;
        list_for_each_entry(incr, &sclp_mem_list, list) {
index 83cea9a..1b3924c 100644 (file)
@@ -236,7 +236,6 @@ tapeblock_setup_device(struct tape_device * device)
        disk->major = tapeblock_major;
        disk->first_minor = device->first_minor;
        disk->fops = &tapeblock_fops;
-       disk->events = DISK_EVENT_MEDIA_CHANGE;
        disk->private_data = tape_get_device(device);
        disk->queue = blkdat->request_queue;
        set_capacity(disk, 0);
index e2d45c9..9689d41 100644 (file)
@@ -1292,8 +1292,10 @@ static struct scsi_host_template qpti_template = {
        .use_clustering         = ENABLE_CLUSTERING,
 };
 
+static const struct of_device_id qpti_match[];
 static int __devinit qpti_sbus_probe(struct platform_device *op)
 {
+       const struct of_device_id *match;
        struct scsi_host_template *tpnt;
        struct device_node *dp = op->dev.of_node;
        struct Scsi_Host *host;
@@ -1301,9 +1303,10 @@ static int __devinit qpti_sbus_probe(struct platform_device *op)
        static int nqptis;
        const char *fcode;
 
-       if (!op->dev.of_match)
+       match = of_match_device(qpti_match, &op->dev);
+       if (!match)
                return -EINVAL;
-       tpnt = op->dev.of_match->data;
+       tpnt = match->data;
 
        /* Sometimes Antares cards come up not completely
         * setup, and we get a report of a zero IRQ.
index 0bac91e..ec1803a 100644 (file)
@@ -74,8 +74,6 @@ struct kmem_cache *scsi_sdb_cache;
  */
 #define SCSI_QUEUE_DELAY       3
 
-static void scsi_run_queue(struct request_queue *q);
-
 /*
  * Function:   scsi_unprep_request()
  *
@@ -161,7 +159,7 @@ static int __scsi_queue_insert(struct scsi_cmnd *cmd, int reason, int unbusy)
        blk_requeue_request(q, cmd->request);
        spin_unlock_irqrestore(q->queue_lock, flags);
 
-       scsi_run_queue(q);
+       kblockd_schedule_work(q, &device->requeue_work);
 
        return 0;
 }
@@ -438,7 +436,11 @@ static void scsi_run_queue(struct request_queue *q)
                        continue;
                }
 
-               blk_run_queue_async(sdev->request_queue);
+               spin_unlock(shost->host_lock);
+               spin_lock(sdev->request_queue->queue_lock);
+               __blk_run_queue(sdev->request_queue);
+               spin_unlock(sdev->request_queue->queue_lock);
+               spin_lock(shost->host_lock);
        }
        /* put any unprocessed entries back */
        list_splice(&starved_list, &shost->starved_list);
@@ -447,6 +449,16 @@ static void scsi_run_queue(struct request_queue *q)
        blk_run_queue(q);
 }
 
+void scsi_requeue_run_queue(struct work_struct *work)
+{
+       struct scsi_device *sdev;
+       struct request_queue *q;
+
+       sdev = container_of(work, struct scsi_device, requeue_work);
+       q = sdev->request_queue;
+       scsi_run_queue(q);
+}
+
 /*
  * Function:   scsi_requeue_command()
  *
index 087821f..58584dc 100644 (file)
@@ -242,6 +242,7 @@ static struct scsi_device *scsi_alloc_sdev(struct scsi_target *starget,
        int display_failure_msg = 1, ret;
        struct Scsi_Host *shost = dev_to_shost(starget->dev.parent);
        extern void scsi_evt_thread(struct work_struct *work);
+       extern void scsi_requeue_run_queue(struct work_struct *work);
 
        sdev = kzalloc(sizeof(*sdev) + shost->transportt->device_size,
                       GFP_ATOMIC);
@@ -264,6 +265,7 @@ static struct scsi_device *scsi_alloc_sdev(struct scsi_target *starget,
        INIT_LIST_HEAD(&sdev->event_list);
        spin_lock_init(&sdev->list_lock);
        INIT_WORK(&sdev->event_work, scsi_evt_thread);
+       INIT_WORK(&sdev->requeue_work, scsi_requeue_run_queue);
 
        sdev->sdev_gendev.parent = get_device(&starget->dev);
        sdev->sdev_target = starget;
index 6f34963..7ad4858 100644 (file)
@@ -662,7 +662,6 @@ static int sprom_extract(struct ssb_bus *bus, struct ssb_sprom *out,
 static int ssb_pci_sprom_get(struct ssb_bus *bus,
                             struct ssb_sprom *sprom)
 {
-       const struct ssb_sprom *fallback;
        int err;
        u16 *buf;
 
@@ -707,10 +706,17 @@ static int ssb_pci_sprom_get(struct ssb_bus *bus,
                if (err) {
                        /* All CRC attempts failed.
                         * Maybe there is no SPROM on the device?
-                        * If we have a fallback, use that. */
-                       fallback = ssb_get_fallback_sprom();
-                       if (fallback) {
-                               memcpy(sprom, fallback, sizeof(*sprom));
+                        * Now we ask the arch code if there is some sprom
+                        * available for this device in some other storage */
+                       err = ssb_fill_sprom_with_fallback(bus, sprom);
+                       if (err) {
+                               ssb_printk(KERN_WARNING PFX "WARNING: Using"
+                                          " fallback SPROM failed (err %d)\n",
+                                          err);
+                       } else {
+                               ssb_dprintk(KERN_DEBUG PFX "Using SPROM"
+                                           " revision %d provided by"
+                                           " platform.\n", sprom->revision);
                                err = 0;
                                goto out_free;
                        }
index 5f34d7a..45ff0e3 100644 (file)
@@ -17,7 +17,7 @@
 #include <linux/slab.h>
 
 
-static const struct ssb_sprom *fallback_sprom;
+static int(*get_fallback_sprom)(struct ssb_bus *dev, struct ssb_sprom *out);
 
 
 static int sprom2hex(const u16 *sprom, char *buf, size_t buf_len,
@@ -145,36 +145,43 @@ out:
 }
 
 /**
- * ssb_arch_set_fallback_sprom - Set a fallback SPROM for use if no SPROM is found.
+ * ssb_arch_register_fallback_sprom - Registers a method providing a
+ * fallback SPROM if no SPROM is found.
  *
- * @sprom: The SPROM data structure to register.
+ * @sprom_callback: The callback function.
  *
- * With this function the architecture implementation may register a fallback
- * SPROM data structure. The fallback is only used for PCI based SSB devices,
- * where no valid SPROM can be found in the shadow registers.
+ * With this function the architecture implementation may register a
+ * callback handler which fills the SPROM data structure. The fallback is
+ * only used for PCI based SSB devices, where no valid SPROM can be found
+ * in the shadow registers.
  *
- * This function is useful for weird architectures that have a half-assed SSB device
- * hardwired to their PCI bus.
+ * This function is useful for weird architectures that have a half-assed
+ * SSB device hardwired to their PCI bus.
  *
- * Note that it does only work with PCI attached SSB devices. PCMCIA devices currently
- * don't use this fallback.
- * Architectures must provide the SPROM for native SSB devices anyway,
- * so the fallback also isn't used for native devices.
+ * Note that it does only work with PCI attached SSB devices. PCMCIA
+ * devices currently don't use this fallback.
+ * Architectures must provide the SPROM for native SSB devices anyway, so
+ * the fallback also isn't used for native devices.
  *
- * This function is available for architecture code, only. So it is not exported.
+ * This function is available for architecture code, only. So it is not
+ * exported.
  */
-int ssb_arch_set_fallback_sprom(const struct ssb_sprom *sprom)
+int ssb_arch_register_fallback_sprom(int (*sprom_callback)(struct ssb_bus *bus,
+                                    struct ssb_sprom *out))
 {
-       if (fallback_sprom)
+       if (get_fallback_sprom)
                return -EEXIST;
-       fallback_sprom = sprom;
+       get_fallback_sprom = sprom_callback;
 
        return 0;
 }
 
-const struct ssb_sprom *ssb_get_fallback_sprom(void)
+int ssb_fill_sprom_with_fallback(struct ssb_bus *bus, struct ssb_sprom *out)
 {
-       return fallback_sprom;
+       if (!get_fallback_sprom)
+               return -ENOENT;
+
+       return get_fallback_sprom(bus, out);
 }
 
 /* http://bcm-v4.sipsolutions.net/802.11/IsSpromAvailable */
index 0331139..7765301 100644 (file)
@@ -171,7 +171,8 @@ ssize_t ssb_attr_sprom_store(struct ssb_bus *bus,
                             const char *buf, size_t count,
                             int (*sprom_check_crc)(const u16 *sprom, size_t size),
                             int (*sprom_write)(struct ssb_bus *bus, const u16 *sprom));
-extern const struct ssb_sprom *ssb_get_fallback_sprom(void);
+extern int ssb_fill_sprom_with_fallback(struct ssb_bus *bus,
+                                       struct ssb_sprom *out);
 
 
 /* core.c */
index 80484af..b1f0f83 100644 (file)
@@ -1391,6 +1391,14 @@ config SERIAL_OF_PLATFORM_NWPSERIAL_CONSOLE
        help
          Support for Console on the NWP serial ports.
 
+config SERIAL_LANTIQ
+       bool "Lantiq serial driver"
+       depends on LANTIQ
+       select SERIAL_CORE
+       select SERIAL_CORE_CONSOLE
+       help
+         Support for console and UART on Lantiq SoCs.
+
 config SERIAL_QE
        tristate "Freescale QUICC Engine serial port support"
        depends on QUICC_ENGINE
index fee0690..3527604 100644 (file)
@@ -94,3 +94,4 @@ obj-$(CONFIG_SERIAL_IFX6X60)          += ifx6x60.o
 obj-$(CONFIG_SERIAL_PCH_UART)  += pch_uart.o
 obj-$(CONFIG_SERIAL_MSM_SMD)   += msm_smd_tty.o
 obj-$(CONFIG_SERIAL_MXS_AUART) += mxs-auart.o
+obj-$(CONFIG_SERIAL_LANTIQ)    += lantiq.o
diff --git a/drivers/tty/serial/lantiq.c b/drivers/tty/serial/lantiq.c
new file mode 100644 (file)
index 0000000..58cf279
--- /dev/null
@@ -0,0 +1,756 @@
+/*
+ *  Based on drivers/char/serial.c, by Linus Torvalds, Theodore Ts'o.
+ *
+ * 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 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) 2004 Infineon IFAP DC COM CPE
+ * Copyright (C) 2007 Felix Fietkau <nbd@openwrt.org>
+ * Copyright (C) 2007 John Crispin <blogic@openwrt.org>
+ * Copyright (C) 2010 Thomas Langer, <thomas.langer@lantiq.com>
+ */
+
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/ioport.h>
+#include <linux/init.h>
+#include <linux/console.h>
+#include <linux/sysrq.h>
+#include <linux/device.h>
+#include <linux/tty.h>
+#include <linux/tty_flip.h>
+#include <linux/serial_core.h>
+#include <linux/serial.h>
+#include <linux/platform_device.h>
+#include <linux/io.h>
+#include <linux/clk.h>
+
+#include <lantiq_soc.h>
+
+#define PORT_LTQ_ASC           111
+#define MAXPORTS               2
+#define UART_DUMMY_UER_RX      1
+#define DRVNAME                        "ltq_asc"
+#ifdef __BIG_ENDIAN
+#define LTQ_ASC_TBUF           (0x0020 + 3)
+#define LTQ_ASC_RBUF           (0x0024 + 3)
+#else
+#define LTQ_ASC_TBUF           0x0020
+#define LTQ_ASC_RBUF           0x0024
+#endif
+#define LTQ_ASC_FSTAT          0x0048
+#define LTQ_ASC_WHBSTATE       0x0018
+#define LTQ_ASC_STATE          0x0014
+#define LTQ_ASC_IRNCR          0x00F8
+#define LTQ_ASC_CLC            0x0000
+#define LTQ_ASC_ID             0x0008
+#define LTQ_ASC_PISEL          0x0004
+#define LTQ_ASC_TXFCON         0x0044
+#define LTQ_ASC_RXFCON         0x0040
+#define LTQ_ASC_CON            0x0010
+#define LTQ_ASC_BG             0x0050
+#define LTQ_ASC_IRNREN         0x00F4
+
+#define ASC_IRNREN_TX          0x1
+#define ASC_IRNREN_RX          0x2
+#define ASC_IRNREN_ERR         0x4
+#define ASC_IRNREN_TX_BUF      0x8
+#define ASC_IRNCR_TIR          0x1
+#define ASC_IRNCR_RIR          0x2
+#define ASC_IRNCR_EIR          0x4
+
+#define ASCOPT_CSIZE           0x3
+#define TXFIFO_FL              1
+#define RXFIFO_FL              1
+#define ASCCLC_DISS            0x2
+#define ASCCLC_RMCMASK         0x0000FF00
+#define ASCCLC_RMCOFFSET       8
+#define ASCCON_M_8ASYNC                0x0
+#define ASCCON_M_7ASYNC                0x2
+#define ASCCON_ODD             0x00000020
+#define ASCCON_STP             0x00000080
+#define ASCCON_BRS             0x00000100
+#define ASCCON_FDE             0x00000200
+#define ASCCON_R               0x00008000
+#define ASCCON_FEN             0x00020000
+#define ASCCON_ROEN            0x00080000
+#define ASCCON_TOEN            0x00100000
+#define ASCSTATE_PE            0x00010000
+#define ASCSTATE_FE            0x00020000
+#define ASCSTATE_ROE           0x00080000
+#define ASCSTATE_ANY           (ASCSTATE_ROE|ASCSTATE_PE|ASCSTATE_FE)
+#define ASCWHBSTATE_CLRREN     0x00000001
+#define ASCWHBSTATE_SETREN     0x00000002
+#define ASCWHBSTATE_CLRPE      0x00000004
+#define ASCWHBSTATE_CLRFE      0x00000008
+#define ASCWHBSTATE_CLRROE     0x00000020
+#define ASCTXFCON_TXFEN                0x0001
+#define ASCTXFCON_TXFFLU       0x0002
+#define ASCTXFCON_TXFITLMASK   0x3F00
+#define ASCTXFCON_TXFITLOFF    8
+#define ASCRXFCON_RXFEN                0x0001
+#define ASCRXFCON_RXFFLU       0x0002
+#define ASCRXFCON_RXFITLMASK   0x3F00
+#define ASCRXFCON_RXFITLOFF    8
+#define ASCFSTAT_RXFFLMASK     0x003F
+#define ASCFSTAT_TXFFLMASK     0x3F00
+#define ASCFSTAT_TXFREEMASK    0x3F000000
+#define ASCFSTAT_TXFREEOFF     24
+
+static void lqasc_tx_chars(struct uart_port *port);
+static struct ltq_uart_port *lqasc_port[MAXPORTS];
+static struct uart_driver lqasc_reg;
+static DEFINE_SPINLOCK(ltq_asc_lock);
+
+struct ltq_uart_port {
+       struct uart_port        port;
+       struct clk              *clk;
+       unsigned int            tx_irq;
+       unsigned int            rx_irq;
+       unsigned int            err_irq;
+};
+
+static inline struct
+ltq_uart_port *to_ltq_uart_port(struct uart_port *port)
+{
+       return container_of(port, struct ltq_uart_port, port);
+}
+
+static void
+lqasc_stop_tx(struct uart_port *port)
+{
+       return;
+}
+
+static void
+lqasc_start_tx(struct uart_port *port)
+{
+       unsigned long flags;
+       spin_lock_irqsave(&ltq_asc_lock, flags);
+       lqasc_tx_chars(port);
+       spin_unlock_irqrestore(&ltq_asc_lock, flags);
+       return;
+}
+
+static void
+lqasc_stop_rx(struct uart_port *port)
+{
+       ltq_w32(ASCWHBSTATE_CLRREN, port->membase + LTQ_ASC_WHBSTATE);
+}
+
+static void
+lqasc_enable_ms(struct uart_port *port)
+{
+}
+
+static int
+lqasc_rx_chars(struct uart_port *port)
+{
+       struct tty_struct *tty = tty_port_tty_get(&port->state->port);
+       unsigned int ch = 0, rsr = 0, fifocnt;
+
+       if (!tty) {
+               dev_dbg(port->dev, "%s:tty is busy now", __func__);
+               return -EBUSY;
+       }
+       fifocnt =
+               ltq_r32(port->membase + LTQ_ASC_FSTAT) & ASCFSTAT_RXFFLMASK;
+       while (fifocnt--) {
+               u8 flag = TTY_NORMAL;
+               ch = ltq_r8(port->membase + LTQ_ASC_RBUF);
+               rsr = (ltq_r32(port->membase + LTQ_ASC_STATE)
+                       & ASCSTATE_ANY) | UART_DUMMY_UER_RX;
+               tty_flip_buffer_push(tty);
+               port->icount.rx++;
+
+               /*
+                * Note that the error handling code is
+                * out of the main execution path
+                */
+               if (rsr & ASCSTATE_ANY) {
+                       if (rsr & ASCSTATE_PE) {
+                               port->icount.parity++;
+                               ltq_w32_mask(0, ASCWHBSTATE_CLRPE,
+                                       port->membase + LTQ_ASC_WHBSTATE);
+                       } else if (rsr & ASCSTATE_FE) {
+                               port->icount.frame++;
+                               ltq_w32_mask(0, ASCWHBSTATE_CLRFE,
+                                       port->membase + LTQ_ASC_WHBSTATE);
+                       }
+                       if (rsr & ASCSTATE_ROE) {
+                               port->icount.overrun++;
+                               ltq_w32_mask(0, ASCWHBSTATE_CLRROE,
+                                       port->membase + LTQ_ASC_WHBSTATE);
+                       }
+
+                       rsr &= port->read_status_mask;
+
+                       if (rsr & ASCSTATE_PE)
+                               flag = TTY_PARITY;
+                       else if (rsr & ASCSTATE_FE)
+                               flag = TTY_FRAME;
+               }
+
+               if ((rsr & port->ignore_status_mask) == 0)
+                       tty_insert_flip_char(tty, ch, flag);
+
+               if (rsr & ASCSTATE_ROE)
+                       /*
+                        * Overrun is special, since it's reported
+                        * immediately, and doesn't affect the current
+                        * character
+                        */
+                       tty_insert_flip_char(tty, 0, TTY_OVERRUN);
+       }
+       if (ch != 0)
+               tty_flip_buffer_push(tty);
+       tty_kref_put(tty);
+       return 0;
+}
+
+static void
+lqasc_tx_chars(struct uart_port *port)
+{
+       struct circ_buf *xmit = &port->state->xmit;
+       if (uart_tx_stopped(port)) {
+               lqasc_stop_tx(port);
+               return;
+       }
+
+       while (((ltq_r32(port->membase + LTQ_ASC_FSTAT) &
+               ASCFSTAT_TXFREEMASK) >> ASCFSTAT_TXFREEOFF) != 0) {
+               if (port->x_char) {
+                       ltq_w8(port->x_char, port->membase + LTQ_ASC_TBUF);
+                       port->icount.tx++;
+                       port->x_char = 0;
+                       continue;
+               }
+
+               if (uart_circ_empty(xmit))
+                       break;
+
+               ltq_w8(port->state->xmit.buf[port->state->xmit.tail],
+                       port->membase + LTQ_ASC_TBUF);
+               xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
+               port->icount.tx++;
+       }
+
+       if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
+               uart_write_wakeup(port);
+}
+
+static irqreturn_t
+lqasc_tx_int(int irq, void *_port)
+{
+       unsigned long flags;
+       struct uart_port *port = (struct uart_port *)_port;
+       spin_lock_irqsave(&ltq_asc_lock, flags);
+       ltq_w32(ASC_IRNCR_TIR, port->membase + LTQ_ASC_IRNCR);
+       spin_unlock_irqrestore(&ltq_asc_lock, flags);
+       lqasc_start_tx(port);
+       return IRQ_HANDLED;
+}
+
+static irqreturn_t
+lqasc_err_int(int irq, void *_port)
+{
+       unsigned long flags;
+       struct uart_port *port = (struct uart_port *)_port;
+       spin_lock_irqsave(&ltq_asc_lock, flags);
+       /* clear any pending interrupts */
+       ltq_w32_mask(0, ASCWHBSTATE_CLRPE | ASCWHBSTATE_CLRFE |
+               ASCWHBSTATE_CLRROE, port->membase + LTQ_ASC_WHBSTATE);
+       spin_unlock_irqrestore(&ltq_asc_lock, flags);
+       return IRQ_HANDLED;
+}
+
+static irqreturn_t
+lqasc_rx_int(int irq, void *_port)
+{
+       unsigned long flags;
+       struct uart_port *port = (struct uart_port *)_port;
+       spin_lock_irqsave(&ltq_asc_lock, flags);
+       ltq_w32(ASC_IRNCR_RIR, port->membase + LTQ_ASC_IRNCR);
+       lqasc_rx_chars(port);
+       spin_unlock_irqrestore(&ltq_asc_lock, flags);
+       return IRQ_HANDLED;
+}
+
+static unsigned int
+lqasc_tx_empty(struct uart_port *port)
+{
+       int status;
+       status = ltq_r32(port->membase + LTQ_ASC_FSTAT) & ASCFSTAT_TXFFLMASK;
+       return status ? 0 : TIOCSER_TEMT;
+}
+
+static unsigned int
+lqasc_get_mctrl(struct uart_port *port)
+{
+       return TIOCM_CTS | TIOCM_CAR | TIOCM_DSR;
+}
+
+static void
+lqasc_set_mctrl(struct uart_port *port, u_int mctrl)
+{
+}
+
+static void
+lqasc_break_ctl(struct uart_port *port, int break_state)
+{
+}
+
+static int
+lqasc_startup(struct uart_port *port)
+{
+       struct ltq_uart_port *ltq_port = to_ltq_uart_port(port);
+       int retval;
+
+       port->uartclk = clk_get_rate(ltq_port->clk);
+
+       ltq_w32_mask(ASCCLC_DISS | ASCCLC_RMCMASK, (1 << ASCCLC_RMCOFFSET),
+               port->membase + LTQ_ASC_CLC);
+
+       ltq_w32(0, port->membase + LTQ_ASC_PISEL);
+       ltq_w32(
+               ((TXFIFO_FL << ASCTXFCON_TXFITLOFF) & ASCTXFCON_TXFITLMASK) |
+               ASCTXFCON_TXFEN | ASCTXFCON_TXFFLU,
+               port->membase + LTQ_ASC_TXFCON);
+       ltq_w32(
+               ((RXFIFO_FL << ASCRXFCON_RXFITLOFF) & ASCRXFCON_RXFITLMASK)
+               | ASCRXFCON_RXFEN | ASCRXFCON_RXFFLU,
+               port->membase + LTQ_ASC_RXFCON);
+       /* make sure other settings are written to hardware before
+        * setting enable bits
+        */
+       wmb();
+       ltq_w32_mask(0, ASCCON_M_8ASYNC | ASCCON_FEN | ASCCON_TOEN |
+               ASCCON_ROEN, port->membase + LTQ_ASC_CON);
+
+       retval = request_irq(ltq_port->tx_irq, lqasc_tx_int,
+               IRQF_DISABLED, "asc_tx", port);
+       if (retval) {
+               pr_err("failed to request lqasc_tx_int\n");
+               return retval;
+       }
+
+       retval = request_irq(ltq_port->rx_irq, lqasc_rx_int,
+               IRQF_DISABLED, "asc_rx", port);
+       if (retval) {
+               pr_err("failed to request lqasc_rx_int\n");
+               goto err1;
+       }
+
+       retval = request_irq(ltq_port->err_irq, lqasc_err_int,
+               IRQF_DISABLED, "asc_err", port);
+       if (retval) {
+               pr_err("failed to request lqasc_err_int\n");
+               goto err2;
+       }
+
+       ltq_w32(ASC_IRNREN_RX | ASC_IRNREN_ERR | ASC_IRNREN_TX,
+               port->membase + LTQ_ASC_IRNREN);
+       return 0;
+
+err2:
+       free_irq(ltq_port->rx_irq, port);
+err1:
+       free_irq(ltq_port->tx_irq, port);
+       return retval;
+}
+
+static void
+lqasc_shutdown(struct uart_port *port)
+{
+       struct ltq_uart_port *ltq_port = to_ltq_uart_port(port);
+       free_irq(ltq_port->tx_irq, port);
+       free_irq(ltq_port->rx_irq, port);
+       free_irq(ltq_port->err_irq, port);
+
+       ltq_w32(0, port->membase + LTQ_ASC_CON);
+       ltq_w32_mask(ASCRXFCON_RXFEN, ASCRXFCON_RXFFLU,
+               port->membase + LTQ_ASC_RXFCON);
+       ltq_w32_mask(ASCTXFCON_TXFEN, ASCTXFCON_TXFFLU,
+               port->membase + LTQ_ASC_TXFCON);
+}
+
+static void
+lqasc_set_termios(struct uart_port *port,
+       struct ktermios *new, struct ktermios *old)
+{
+       unsigned int cflag;
+       unsigned int iflag;
+       unsigned int divisor;
+       unsigned int baud;
+       unsigned int con = 0;
+       unsigned long flags;
+
+       cflag = new->c_cflag;
+       iflag = new->c_iflag;
+
+       switch (cflag & CSIZE) {
+       case CS7:
+               con = ASCCON_M_7ASYNC;
+               break;
+
+       case CS5:
+       case CS6:
+       default:
+               new->c_cflag &= ~ CSIZE;
+               new->c_cflag |= CS8;
+               con = ASCCON_M_8ASYNC;
+               break;
+       }
+
+       cflag &= ~CMSPAR; /* Mark/Space parity is not supported */
+
+       if (cflag & CSTOPB)
+               con |= ASCCON_STP;
+
+       if (cflag & PARENB) {
+               if (!(cflag & PARODD))
+                       con &= ~ASCCON_ODD;
+               else
+                       con |= ASCCON_ODD;
+       }
+
+       port->read_status_mask = ASCSTATE_ROE;
+       if (iflag & INPCK)
+               port->read_status_mask |= ASCSTATE_FE | ASCSTATE_PE;
+
+       port->ignore_status_mask = 0;
+       if (iflag & IGNPAR)
+               port->ignore_status_mask |= ASCSTATE_FE | ASCSTATE_PE;
+
+       if (iflag & IGNBRK) {
+               /*
+                * If we're ignoring parity and break indicators,
+                * ignore overruns too (for real raw support).
+                */
+               if (iflag & IGNPAR)
+                       port->ignore_status_mask |= ASCSTATE_ROE;
+       }
+
+       if ((cflag & CREAD) == 0)
+               port->ignore_status_mask |= UART_DUMMY_UER_RX;
+
+       /* set error signals  - framing, parity  and overrun, enable receiver */
+       con |= ASCCON_FEN | ASCCON_TOEN | ASCCON_ROEN;
+
+       spin_lock_irqsave(&ltq_asc_lock, flags);
+
+       /* set up CON */
+       ltq_w32_mask(0, con, port->membase + LTQ_ASC_CON);
+
+       /* Set baud rate - take a divider of 2 into account */
+       baud = uart_get_baud_rate(port, new, old, 0, port->uartclk / 16);
+       divisor = uart_get_divisor(port, baud);
+       divisor = divisor / 2 - 1;
+
+       /* disable the baudrate generator */
+       ltq_w32_mask(ASCCON_R, 0, port->membase + LTQ_ASC_CON);
+
+       /* make sure the fractional divider is off */
+       ltq_w32_mask(ASCCON_FDE, 0, port->membase + LTQ_ASC_CON);
+
+       /* set up to use divisor of 2 */
+       ltq_w32_mask(ASCCON_BRS, 0, port->membase + LTQ_ASC_CON);
+
+       /* now we can write the new baudrate into the register */
+       ltq_w32(divisor, port->membase + LTQ_ASC_BG);
+
+       /* turn the baudrate generator back on */
+       ltq_w32_mask(0, ASCCON_R, port->membase + LTQ_ASC_CON);
+
+       /* enable rx */
+       ltq_w32(ASCWHBSTATE_SETREN, port->membase + LTQ_ASC_WHBSTATE);
+
+       spin_unlock_irqrestore(&ltq_asc_lock, flags);
+
+       /* Don't rewrite B0 */
+        if (tty_termios_baud_rate(new))
+               tty_termios_encode_baud_rate(new, baud, baud);
+}
+
+static const char*
+lqasc_type(struct uart_port *port)
+{
+       if (port->type == PORT_LTQ_ASC)
+               return DRVNAME;
+       else
+               return NULL;
+}
+
+static void
+lqasc_release_port(struct uart_port *port)
+{
+       if (port->flags & UPF_IOREMAP) {
+               iounmap(port->membase);
+               port->membase = NULL;
+       }
+}
+
+static int
+lqasc_request_port(struct uart_port *port)
+{
+       struct platform_device *pdev = to_platform_device(port->dev);
+       struct resource *res;
+       int size;
+
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (!res) {
+               dev_err(&pdev->dev, "cannot obtain I/O memory region");
+               return -ENODEV;
+       }
+       size = resource_size(res);
+
+       res = devm_request_mem_region(&pdev->dev, res->start,
+               size, dev_name(&pdev->dev));
+       if (!res) {
+               dev_err(&pdev->dev, "cannot request I/O memory region");
+               return -EBUSY;
+       }
+
+       if (port->flags & UPF_IOREMAP) {
+               port->membase = devm_ioremap_nocache(&pdev->dev,
+                       port->mapbase, size);
+               if (port->membase == NULL)
+                       return -ENOMEM;
+       }
+       return 0;
+}
+
+static void
+lqasc_config_port(struct uart_port *port, int flags)
+{
+       if (flags & UART_CONFIG_TYPE) {
+               port->type = PORT_LTQ_ASC;
+               lqasc_request_port(port);
+       }
+}
+
+static int
+lqasc_verify_port(struct uart_port *port,
+       struct serial_struct *ser)
+{
+       int ret = 0;
+       if (ser->type != PORT_UNKNOWN && ser->type != PORT_LTQ_ASC)
+               ret = -EINVAL;
+       if (ser->irq < 0 || ser->irq >= NR_IRQS)
+               ret = -EINVAL;
+       if (ser->baud_base < 9600)
+               ret = -EINVAL;
+       return ret;
+}
+
+static struct uart_ops lqasc_pops = {
+       .tx_empty =     lqasc_tx_empty,
+       .set_mctrl =    lqasc_set_mctrl,
+       .get_mctrl =    lqasc_get_mctrl,
+       .stop_tx =      lqasc_stop_tx,
+       .start_tx =     lqasc_start_tx,
+       .stop_rx =      lqasc_stop_rx,
+       .enable_ms =    lqasc_enable_ms,
+       .break_ctl =    lqasc_break_ctl,
+       .startup =      lqasc_startup,
+       .shutdown =     lqasc_shutdown,
+       .set_termios =  lqasc_set_termios,
+       .type =         lqasc_type,
+       .release_port = lqasc_release_port,
+       .request_port = lqasc_request_port,
+       .config_port =  lqasc_config_port,
+       .verify_port =  lqasc_verify_port,
+};
+
+static void
+lqasc_console_putchar(struct uart_port *port, int ch)
+{
+       int fifofree;
+
+       if (!port->membase)
+               return;
+
+       do {
+               fifofree = (ltq_r32(port->membase + LTQ_ASC_FSTAT)
+                       & ASCFSTAT_TXFREEMASK) >> ASCFSTAT_TXFREEOFF;
+       } while (fifofree == 0);
+       ltq_w8(ch, port->membase + LTQ_ASC_TBUF);
+}
+
+
+static void
+lqasc_console_write(struct console *co, const char *s, u_int count)
+{
+       struct ltq_uart_port *ltq_port;
+       struct uart_port *port;
+       unsigned long flags;
+
+       if (co->index >= MAXPORTS)
+               return;
+
+       ltq_port = lqasc_port[co->index];
+       if (!ltq_port)
+               return;
+
+       port = &ltq_port->port;
+
+       spin_lock_irqsave(&ltq_asc_lock, flags);
+       uart_console_write(port, s, count, lqasc_console_putchar);
+       spin_unlock_irqrestore(&ltq_asc_lock, flags);
+}
+
+static int __init
+lqasc_console_setup(struct console *co, char *options)
+{
+       struct ltq_uart_port *ltq_port;
+       struct uart_port *port;
+       int baud = 115200;
+       int bits = 8;
+       int parity = 'n';
+       int flow = 'n';
+
+       if (co->index >= MAXPORTS)
+               return -ENODEV;
+
+       ltq_port = lqasc_port[co->index];
+       if (!ltq_port)
+               return -ENODEV;
+
+       port = &ltq_port->port;
+
+       port->uartclk = clk_get_rate(ltq_port->clk);
+
+       if (options)
+               uart_parse_options(options, &baud, &parity, &bits, &flow);
+       return uart_set_options(port, co, baud, parity, bits, flow);
+}
+
+static struct console lqasc_console = {
+       .name =         "ttyLTQ",
+       .write =        lqasc_console_write,
+       .device =       uart_console_device,
+       .setup =        lqasc_console_setup,
+       .flags =        CON_PRINTBUFFER,
+       .index =        -1,
+       .data =         &lqasc_reg,
+};
+
+static int __init
+lqasc_console_init(void)
+{
+       register_console(&lqasc_console);
+       return 0;
+}
+console_initcall(lqasc_console_init);
+
+static struct uart_driver lqasc_reg = {
+       .owner =        THIS_MODULE,
+       .driver_name =  DRVNAME,
+       .dev_name =     "ttyLTQ",
+       .major =        0,
+       .minor =        0,
+       .nr =           MAXPORTS,
+       .cons =         &lqasc_console,
+};
+
+static int __init
+lqasc_probe(struct platform_device *pdev)
+{
+       struct ltq_uart_port *ltq_port;
+       struct uart_port *port;
+       struct resource *mmres, *irqres;
+       int tx_irq, rx_irq, err_irq;
+       struct clk *clk;
+       int ret;
+
+       mmres = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       irqres = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+       if (!mmres || !irqres)
+               return -ENODEV;
+
+       if (pdev->id >= MAXPORTS)
+               return -EBUSY;
+
+       if (lqasc_port[pdev->id] != NULL)
+               return -EBUSY;
+
+       clk = clk_get(&pdev->dev, "fpi");
+       if (IS_ERR(clk)) {
+               pr_err("failed to get fpi clk\n");
+               return -ENOENT;
+       }
+
+       tx_irq = platform_get_irq_byname(pdev, "tx");
+       rx_irq = platform_get_irq_byname(pdev, "rx");
+       err_irq = platform_get_irq_byname(pdev, "err");
+       if ((tx_irq < 0) | (rx_irq < 0) | (err_irq < 0))
+               return -ENODEV;
+
+       ltq_port = kzalloc(sizeof(struct ltq_uart_port), GFP_KERNEL);
+       if (!ltq_port)
+               return -ENOMEM;
+
+       port = &ltq_port->port;
+
+       port->iotype    = SERIAL_IO_MEM;
+       port->flags     = ASYNC_BOOT_AUTOCONF | UPF_IOREMAP;
+       port->ops       = &lqasc_pops;
+       port->fifosize  = 16;
+       port->type      = PORT_LTQ_ASC,
+       port->line      = pdev->id;
+       port->dev       = &pdev->dev;
+
+       port->irq       = tx_irq; /* unused, just to be backward-compatibe */
+       port->mapbase   = mmres->start;
+
+       ltq_port->clk   = clk;
+
+       ltq_port->tx_irq = tx_irq;
+       ltq_port->rx_irq = rx_irq;
+       ltq_port->err_irq = err_irq;
+
+       lqasc_port[pdev->id] = ltq_port;
+       platform_set_drvdata(pdev, ltq_port);
+
+       ret = uart_add_one_port(&lqasc_reg, port);
+
+       return ret;
+}
+
+static struct platform_driver lqasc_driver = {
+       .driver         = {
+               .name   = DRVNAME,
+               .owner  = THIS_MODULE,
+       },
+};
+
+int __init
+init_lqasc(void)
+{
+       int ret;
+
+       ret = uart_register_driver(&lqasc_reg);
+       if (ret != 0)
+               return ret;
+
+       ret = platform_driver_probe(&lqasc_driver, lqasc_probe);
+       if (ret != 0)
+               uart_unregister_driver(&lqasc_reg);
+
+       return ret;
+}
+
+module_init(init_lqasc);
+
+MODULE_DESCRIPTION("Lantiq serial port driver");
+MODULE_LICENSE("GPL");
index 0e8eec5..c911b24 100644 (file)
@@ -80,14 +80,17 @@ static int __devinit of_platform_serial_setup(struct platform_device *ofdev,
 /*
  * Try to register a serial port
  */
+static struct of_device_id of_platform_serial_table[];
 static int __devinit of_platform_serial_probe(struct platform_device *ofdev)
 {
+       const struct of_device_id *match;
        struct of_serial_info *info;
        struct uart_port port;
        int port_type;
        int ret;
 
-       if (!ofdev->dev.of_match)
+       match = of_match_device(of_platform_serial_table, &ofdev->dev);
+       if (!match)
                return -EINVAL;
 
        if (of_find_property(ofdev->dev.of_node, "used-by-rtas", NULL))
@@ -97,7 +100,7 @@ static int __devinit of_platform_serial_probe(struct platform_device *ofdev)
        if (info == NULL)
                return -ENOMEM;
 
-       port_type = (unsigned long)ofdev->dev.of_match->data;
+       port_type = (unsigned long)match->data;
        ret = of_platform_serial_setup(ofdev, port_type, &port);
        if (ret)
                goto out;
index 51fe179..d2efe82 100644 (file)
@@ -381,7 +381,13 @@ static int uio_get_minor(struct uio_device *idev)
                        retval = -ENOMEM;
                goto exit;
        }
-       idev->minor = id & MAX_ID_MASK;
+       if (id < UIO_MAX_DEVICES) {
+               idev->minor = id;
+       } else {
+               dev_err(idev->dev, "too many uio devices\n");
+               retval = -EINVAL;
+               idr_remove(&uio_idr, id);
+       }
 exit:
        mutex_unlock(&minor_lock);
        return retval;
@@ -587,14 +593,12 @@ static ssize_t uio_write(struct file *filep, const char __user *buf,
 
 static int uio_find_mem_index(struct vm_area_struct *vma)
 {
-       int mi;
        struct uio_device *idev = vma->vm_private_data;
 
-       for (mi = 0; mi < MAX_UIO_MAPS; mi++) {
-               if (idev->info->mem[mi].size == 0)
+       if (vma->vm_pgoff < MAX_UIO_MAPS) {
+               if (idev->info->mem[vma->vm_pgoff].size == 0)
                        return -1;
-               if (vma->vm_pgoff == mi)
-                       return mi;
+               return (int)vma->vm_pgoff;
        }
        return -1;
 }
index 5ffdb48..a879fd5 100644 (file)
@@ -18,6 +18,9 @@
 
 #define PCI_VENDOR_ID_HILSCHER         0x15CF
 #define PCI_DEVICE_ID_HILSCHER_NETX    0x0000
+#define PCI_DEVICE_ID_HILSCHER_NETPLC  0x0010
+#define PCI_SUBDEVICE_ID_NETPLC_RAM    0x0000
+#define PCI_SUBDEVICE_ID_NETPLC_FLASH  0x0001
 #define PCI_SUBDEVICE_ID_NXSB_PCA      0x3235
 #define PCI_SUBDEVICE_ID_NXPCA         0x3335
 
@@ -66,6 +69,10 @@ static int __devinit netx_pci_probe(struct pci_dev *dev,
                bar = 0;
                info->name = "netx";
                break;
+       case PCI_DEVICE_ID_HILSCHER_NETPLC:
+               bar = 0;
+               info->name = "netplc";
+               break;
        default:
                bar = 2;
                info->name = "netx_plx";
@@ -134,6 +141,18 @@ static struct pci_device_id netx_pci_ids[] = {
                .subdevice =    0,
        },
        {
+               .vendor =       PCI_VENDOR_ID_HILSCHER,
+               .device =       PCI_DEVICE_ID_HILSCHER_NETPLC,
+               .subvendor =    PCI_VENDOR_ID_HILSCHER,
+               .subdevice =    PCI_SUBDEVICE_ID_NETPLC_RAM,
+       },
+       {
+               .vendor =       PCI_VENDOR_ID_HILSCHER,
+               .device =       PCI_DEVICE_ID_HILSCHER_NETPLC,
+               .subvendor =    PCI_VENDOR_ID_HILSCHER,
+               .subdevice =    PCI_SUBDEVICE_ID_NETPLC_FLASH,
+       },
+       {
                .vendor =       PCI_VENDOR_ID_PLX,
                .device =       PCI_DEVICE_ID_PLX_9030,
                .subvendor =    PCI_VENDOR_ID_PLX,
index 7174d51..0f424af 100644 (file)
@@ -189,6 +189,10 @@ static int uio_pdrv_genirq_remove(struct platform_device *pdev)
 
        uio_unregister_device(priv->uioinfo);
        pm_runtime_disable(&pdev->dev);
+
+       priv->uioinfo->handler = NULL;
+       priv->uioinfo->irqcontrol = NULL;
+
        kfree(priv);
        return 0;
 }
index 36613b3..3a68e09 100644 (file)
@@ -2539,15 +2539,18 @@ static void qe_udc_release(struct device *dev)
 }
 
 /* Driver probe functions */
+static const struct of_device_id qe_udc_match[];
 static int __devinit qe_udc_probe(struct platform_device *ofdev)
 {
+       const struct of_device_id *match;
        struct device_node *np = ofdev->dev.of_node;
        struct qe_ep *ep;
        unsigned int ret = 0;
        unsigned int i;
        const void *prop;
 
-       if (!ofdev->dev.of_match)
+       match = of_match_device(qe_udc_match, &ofdev->dev);
+       if (!match)
                return -EINVAL;
 
        prop = of_get_property(np, "mode", NULL);
@@ -2561,7 +2564,7 @@ static int __devinit qe_udc_probe(struct platform_device *ofdev)
                return -ENOMEM;
        }
 
-       udc_controller->soc_type = (unsigned long)ofdev->dev.of_match->data;
+       udc_controller->soc_type = (unsigned long)match->data;
        udc_controller->usb_regs = of_iomap(np, 0);
        if (!udc_controller->usb_regs) {
                ret = -ENOMEM;
index 2ab2912..7aa4eea 100644 (file)
@@ -4,7 +4,7 @@
  * Author: Michael S. Tsirkin <mst@redhat.com>
  *
  * Inspiration, some code, and most witty comments come from
- * Documentation/lguest/lguest.c, by Rusty Russell
+ * Documentation/virtual/lguest/lguest.c, by Rusty Russell
  *
  * This work is licensed under the terms of the GNU GPL, version 2.
  *
index 82acb8d..6183a57 100644 (file)
@@ -66,7 +66,7 @@
  * have.  Allow 1% either way on the nominal for TVs.
  */
 #define NR_MONTYPES    6
-static struct fb_monspecs monspecs[NR_MONTYPES] __initdata = {
+static struct fb_monspecs monspecs[NR_MONTYPES] __devinitdata = {
        {       /* TV           */
                .hfmin  = 15469,
                .hfmax  = 15781,
@@ -873,7 +873,7 @@ static struct fb_ops acornfb_ops = {
 /*
  * Everything after here is initialisation!!!
  */
-static struct fb_videomode modedb[] __initdata = {
+static struct fb_videomode modedb[] __devinitdata = {
        {       /* 320x256 @ 50Hz */
                NULL, 50,  320,  256, 125000,  92,  62,  35, 19,  38, 2,
                FB_SYNC_COMP_HIGH_ACT,
@@ -925,8 +925,7 @@ static struct fb_videomode modedb[] __initdata = {
        }
 };
 
-static struct fb_videomode __initdata
-acornfb_default_mode = {
+static struct fb_videomode acornfb_default_mode __devinitdata = {
        .name =         NULL,
        .refresh =      60,
        .xres =         640,
@@ -942,7 +941,7 @@ acornfb_default_mode = {
        .vmode =        FB_VMODE_NONINTERLACED
 };
 
-static void __init acornfb_init_fbinfo(void)
+static void __devinit acornfb_init_fbinfo(void)
 {
        static int first = 1;
 
@@ -1018,8 +1017,7 @@ static void __init acornfb_init_fbinfo(void)
  *     size can optionally be followed by 'M' or 'K' for
  *     MB or KB respectively.
  */
-static void __init
-acornfb_parse_mon(char *opt)
+static void __devinit acornfb_parse_mon(char *opt)
 {
        char *p = opt;
 
@@ -1066,8 +1064,7 @@ bad:
        current_par.montype = -1;
 }
 
-static void __init
-acornfb_parse_montype(char *opt)
+static void __devinit acornfb_parse_montype(char *opt)
 {
        current_par.montype = -2;
 
@@ -1108,8 +1105,7 @@ acornfb_parse_montype(char *opt)
        }
 }
 
-static void __init
-acornfb_parse_dram(char *opt)
+static void __devinit acornfb_parse_dram(char *opt)
 {
        unsigned int size;
 
@@ -1134,15 +1130,14 @@ acornfb_parse_dram(char *opt)
 static struct options {
        char *name;
        void (*parse)(char *opt);
-} opt_table[] __initdata = {
+} opt_table[] __devinitdata = {
        { "mon",     acornfb_parse_mon     },
        { "montype", acornfb_parse_montype },
        { "dram",    acornfb_parse_dram    },
        { NULL, NULL }
 };
 
-int __init
-acornfb_setup(char *options)
+static int __devinit acornfb_setup(char *options)
 {
        struct options *optp;
        char *opt;
@@ -1179,8 +1174,7 @@ acornfb_setup(char *options)
  * Detect type of monitor connected
  *  For now, we just assume SVGA
  */
-static int __init
-acornfb_detect_monitortype(void)
+static int __devinit acornfb_detect_monitortype(void)
 {
        return 4;
 }
index 5b2b5ef..64e41f5 100644 (file)
@@ -3117,7 +3117,7 @@ int __init atafb_init(void)
                        atafb_ops.fb_setcolreg = &falcon_setcolreg;
                        error = request_irq(IRQ_AUTO_4, falcon_vbl_switcher,
                                            IRQ_TYPE_PRIO,
-                                           "framebuffer/modeswitch",
+                                           "framebuffer:modeswitch",
                                            falcon_vbl_switcher);
                        if (error)
                                return error;
index e0c2284..5aac00e 100644 (file)
 
 #define FBPIXMAPSIZE   (1024 * 8)
 
+static DEFINE_MUTEX(registration_lock);
 struct fb_info *registered_fb[FB_MAX] __read_mostly;
 int num_registered_fb __read_mostly;
 
+static struct fb_info *get_fb_info(unsigned int idx)
+{
+       struct fb_info *fb_info;
+
+       if (idx >= FB_MAX)
+               return ERR_PTR(-ENODEV);
+
+       mutex_lock(&registration_lock);
+       fb_info = registered_fb[idx];
+       if (fb_info)
+               atomic_inc(&fb_info->count);
+       mutex_unlock(&registration_lock);
+
+       return fb_info;
+}
+
+static void put_fb_info(struct fb_info *fb_info)
+{
+       if (!atomic_dec_and_test(&fb_info->count))
+               return;
+       if (fb_info->fbops->fb_destroy)
+               fb_info->fbops->fb_destroy(fb_info);
+}
+
 int lock_fb_info(struct fb_info *info)
 {
        mutex_lock(&info->lock);
@@ -647,6 +672,7 @@ int fb_show_logo(struct fb_info *info, int rotate) { return 0; }
 
 static void *fb_seq_start(struct seq_file *m, loff_t *pos)
 {
+       mutex_lock(&registration_lock);
        return (*pos < FB_MAX) ? pos : NULL;
 }
 
@@ -658,6 +684,7 @@ static void *fb_seq_next(struct seq_file *m, void *v, loff_t *pos)
 
 static void fb_seq_stop(struct seq_file *m, void *v)
 {
+       mutex_unlock(&registration_lock);
 }
 
 static int fb_seq_show(struct seq_file *m, void *v)
@@ -690,13 +717,30 @@ static const struct file_operations fb_proc_fops = {
        .release        = seq_release,
 };
 
-static ssize_t
-fb_read(struct file *file, char __user *buf, size_t count, loff_t *ppos)
+/*
+ * We hold a reference to the fb_info in file->private_data,
+ * but if the current registered fb has changed, we don't
+ * actually want to use it.
+ *
+ * So look up the fb_info using the inode minor number,
+ * and just verify it against the reference we have.
+ */
+static struct fb_info *file_fb_info(struct file *file)
 {
-       unsigned long p = *ppos;
        struct inode *inode = file->f_path.dentry->d_inode;
        int fbidx = iminor(inode);
        struct fb_info *info = registered_fb[fbidx];
+
+       if (info != file->private_data)
+               info = NULL;
+       return info;
+}
+
+static ssize_t
+fb_read(struct file *file, char __user *buf, size_t count, loff_t *ppos)
+{
+       unsigned long p = *ppos;
+       struct fb_info *info = file_fb_info(file);
        u8 *buffer, *dst;
        u8 __iomem *src;
        int c, cnt = 0, err = 0;
@@ -761,9 +805,7 @@ static ssize_t
 fb_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos)
 {
        unsigned long p = *ppos;
-       struct inode *inode = file->f_path.dentry->d_inode;
-       int fbidx = iminor(inode);
-       struct fb_info *info = registered_fb[fbidx];
+       struct fb_info *info = file_fb_info(file);
        u8 *buffer, *src;
        u8 __iomem *dst;
        int c, cnt = 0, err = 0;
@@ -1141,10 +1183,10 @@ static long do_fb_ioctl(struct fb_info *info, unsigned int cmd,
 
 static long fb_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
 {
-       struct inode *inode = file->f_path.dentry->d_inode;
-       int fbidx = iminor(inode);
-       struct fb_info *info = registered_fb[fbidx];
+       struct fb_info *info = file_fb_info(file);
 
+       if (!info)
+               return -ENODEV;
        return do_fb_ioctl(info, cmd, arg);
 }
 
@@ -1265,12 +1307,13 @@ static int fb_get_fscreeninfo(struct fb_info *info, unsigned int cmd,
 static long fb_compat_ioctl(struct file *file, unsigned int cmd,
                            unsigned long arg)
 {
-       struct inode *inode = file->f_path.dentry->d_inode;
-       int fbidx = iminor(inode);
-       struct fb_info *info = registered_fb[fbidx];
-       struct fb_ops *fb = info->fbops;
+       struct fb_info *info = file_fb_info(file);
+       struct fb_ops *fb;
        long ret = -ENOIOCTLCMD;
 
+       if (!info)
+               return -ENODEV;
+       fb = info->fbops;
        switch(cmd) {
        case FBIOGET_VSCREENINFO:
        case FBIOPUT_VSCREENINFO:
@@ -1303,16 +1346,18 @@ static long fb_compat_ioctl(struct file *file, unsigned int cmd,
 static int
 fb_mmap(struct file *file, struct vm_area_struct * vma)
 {
-       int fbidx = iminor(file->f_path.dentry->d_inode);
-       struct fb_info *info = registered_fb[fbidx];
-       struct fb_ops *fb = info->fbops;
+       struct fb_info *info = file_fb_info(file);
+       struct fb_ops *fb;
        unsigned long off;
        unsigned long start;
        u32 len;
 
+       if (!info)
+               return -ENODEV;
        if (vma->vm_pgoff > (~0UL >> PAGE_SHIFT))
                return -EINVAL;
        off = vma->vm_pgoff << PAGE_SHIFT;
+       fb = info->fbops;
        if (!fb)
                return -ENODEV;
        mutex_lock(&info->mm_lock);
@@ -1361,14 +1406,16 @@ __releases(&info->lock)
        struct fb_info *info;
        int res = 0;
 
-       if (fbidx >= FB_MAX)
-               return -ENODEV;
-       info = registered_fb[fbidx];
-       if (!info)
+       info = get_fb_info(fbidx);
+       if (!info) {
                request_module("fb%d", fbidx);
-       info = registered_fb[fbidx];
-       if (!info)
-               return -ENODEV;
+               info = get_fb_info(fbidx);
+               if (!info)
+                       return -ENODEV;
+       }
+       if (IS_ERR(info))
+               return PTR_ERR(info);
+
        mutex_lock(&info->lock);
        if (!try_module_get(info->fbops->owner)) {
                res = -ENODEV;
@@ -1386,6 +1433,8 @@ __releases(&info->lock)
 #endif
 out:
        mutex_unlock(&info->lock);
+       if (res)
+               put_fb_info(info);
        return res;
 }
 
@@ -1401,6 +1450,7 @@ __releases(&info->lock)
                info->fbops->fb_release(info,1);
        module_put(info->fbops->owner);
        mutex_unlock(&info->lock);
+       put_fb_info(info);
        return 0;
 }
 
@@ -1487,8 +1537,10 @@ static bool fb_do_apertures_overlap(struct apertures_struct *gena,
        return false;
 }
 
+static int do_unregister_framebuffer(struct fb_info *fb_info);
+
 #define VGA_FB_PHYS 0xA0000
-void remove_conflicting_framebuffers(struct apertures_struct *a,
+static void do_remove_conflicting_framebuffers(struct apertures_struct *a,
                                     const char *name, bool primary)
 {
        int i;
@@ -1510,43 +1562,32 @@ void remove_conflicting_framebuffers(struct apertures_struct *a,
                        printk(KERN_INFO "fb: conflicting fb hw usage "
                               "%s vs %s - removing generic driver\n",
                               name, registered_fb[i]->fix.id);
-                       unregister_framebuffer(registered_fb[i]);
+                       do_unregister_framebuffer(registered_fb[i]);
                }
        }
 }
-EXPORT_SYMBOL(remove_conflicting_framebuffers);
 
-/**
- *     register_framebuffer - registers a frame buffer device
- *     @fb_info: frame buffer info structure
- *
- *     Registers a frame buffer device @fb_info.
- *
- *     Returns negative errno on error, or zero for success.
- *
- */
-
-int
-register_framebuffer(struct fb_info *fb_info)
+static int do_register_framebuffer(struct fb_info *fb_info)
 {
        int i;
        struct fb_event event;
        struct fb_videomode mode;
 
-       if (num_registered_fb == FB_MAX)
-               return -ENXIO;
-
        if (fb_check_foreignness(fb_info))
                return -ENOSYS;
 
-       remove_conflicting_framebuffers(fb_info->apertures, fb_info->fix.id,
+       do_remove_conflicting_framebuffers(fb_info->apertures, fb_info->fix.id,
                                         fb_is_primary_device(fb_info));
 
+       if (num_registered_fb == FB_MAX)
+               return -ENXIO;
+
        num_registered_fb++;
        for (i = 0 ; i < FB_MAX; i++)
                if (!registered_fb[i])
                        break;
        fb_info->node = i;
+       atomic_set(&fb_info->count, 1);
        mutex_init(&fb_info->lock);
        mutex_init(&fb_info->mm_lock);
 
@@ -1592,36 +1633,14 @@ register_framebuffer(struct fb_info *fb_info)
        return 0;
 }
 
-
-/**
- *     unregister_framebuffer - releases a frame buffer device
- *     @fb_info: frame buffer info structure
- *
- *     Unregisters a frame buffer device @fb_info.
- *
- *     Returns negative errno on error, or zero for success.
- *
- *      This function will also notify the framebuffer console
- *      to release the driver.
- *
- *      This is meant to be called within a driver's module_exit()
- *      function. If this is called outside module_exit(), ensure
- *      that the driver implements fb_open() and fb_release() to
- *      check that no processes are using the device.
- */
-
-int
-unregister_framebuffer(struct fb_info *fb_info)
+static int do_unregister_framebuffer(struct fb_info *fb_info)
 {
        struct fb_event event;
        int i, ret = 0;
 
        i = fb_info->node;
-       if (!registered_fb[i]) {
-               ret = -EINVAL;
-               goto done;
-       }
-
+       if (i < 0 || i >= FB_MAX || registered_fb[i] != fb_info)
+               return -EINVAL;
 
        if (!lock_fb_info(fb_info))
                return -ENODEV;
@@ -1629,16 +1648,14 @@ unregister_framebuffer(struct fb_info *fb_info)
        ret = fb_notifier_call_chain(FB_EVENT_FB_UNBIND, &event);
        unlock_fb_info(fb_info);
 
-       if (ret) {
-               ret = -EINVAL;
-               goto done;
-       }
+       if (ret)
+               return -EINVAL;
 
        if (fb_info->pixmap.addr &&
            (fb_info->pixmap.flags & FB_PIXMAP_DEFAULT))
                kfree(fb_info->pixmap.addr);
        fb_destroy_modelist(&fb_info->modelist);
-       registered_fb[i]=NULL;
+       registered_fb[i] = NULL;
        num_registered_fb--;
        fb_cleanup_device(fb_info);
        device_destroy(fb_class, MKDEV(FB_MAJOR, i));
@@ -1646,9 +1663,65 @@ unregister_framebuffer(struct fb_info *fb_info)
        fb_notifier_call_chain(FB_EVENT_FB_UNREGISTERED, &event);
 
        /* this may free fb info */
-       if (fb_info->fbops->fb_destroy)
-               fb_info->fbops->fb_destroy(fb_info);
-done:
+       put_fb_info(fb_info);
+       return 0;
+}
+
+void remove_conflicting_framebuffers(struct apertures_struct *a,
+                                    const char *name, bool primary)
+{
+       mutex_lock(&registration_lock);
+       do_remove_conflicting_framebuffers(a, name, primary);
+       mutex_unlock(&registration_lock);
+}
+EXPORT_SYMBOL(remove_conflicting_framebuffers);
+
+/**
+ *     register_framebuffer - registers a frame buffer device
+ *     @fb_info: frame buffer info structure
+ *
+ *     Registers a frame buffer device @fb_info.
+ *
+ *     Returns negative errno on error, or zero for success.
+ *
+ */
+int
+register_framebuffer(struct fb_info *fb_info)
+{
+       int ret;
+
+       mutex_lock(&registration_lock);
+       ret = do_register_framebuffer(fb_info);
+       mutex_unlock(&registration_lock);
+
+       return ret;
+}
+
+/**
+ *     unregister_framebuffer - releases a frame buffer device
+ *     @fb_info: frame buffer info structure
+ *
+ *     Unregisters a frame buffer device @fb_info.
+ *
+ *     Returns negative errno on error, or zero for success.
+ *
+ *      This function will also notify the framebuffer console
+ *      to release the driver.
+ *
+ *      This is meant to be called within a driver's module_exit()
+ *      function. If this is called outside module_exit(), ensure
+ *      that the driver implements fb_open() and fb_release() to
+ *      check that no processes are using the device.
+ */
+int
+unregister_framebuffer(struct fb_info *fb_info)
+{
+       int ret;
+
+       mutex_lock(&registration_lock);
+       ret = do_unregister_framebuffer(fb_info);
+       mutex_unlock(&registration_lock);
+
        return ret;
 }
 
index 1b0f98b..022f9eb 100644 (file)
@@ -990,6 +990,12 @@ config BCM63XX_WDT
          To compile this driver as a loadable module, choose M here.
          The module will be called bcm63xx_wdt.
 
+config LANTIQ_WDT
+       tristate "Lantiq SoC watchdog"
+       depends on LANTIQ
+       help
+         Hardware driver for the Lantiq SoC Watchdog Timer.
+
 # PARISC Architecture
 
 # POWERPC Architecture
index 3f8608b..ed26f70 100644 (file)
@@ -123,6 +123,7 @@ obj-$(CONFIG_AR7_WDT) += ar7_wdt.o
 obj-$(CONFIG_TXX9_WDT) += txx9wdt.o
 obj-$(CONFIG_OCTEON_WDT) += octeon-wdt.o
 octeon-wdt-y := octeon-wdt-main.o octeon-wdt-nmi.o
+obj-$(CONFIG_LANTIQ_WDT) += lantiq_wdt.o
 
 # PARISC Architecture
 
diff --git a/drivers/watchdog/lantiq_wdt.c b/drivers/watchdog/lantiq_wdt.c
new file mode 100644 (file)
index 0000000..7d82ada
--- /dev/null
@@ -0,0 +1,261 @@
+/*
+ *  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.
+ *
+ *  Copyright (C) 2010 John Crispin <blogic@openwrt.org>
+ *  Based on EP93xx wdt driver
+ */
+
+#include <linux/module.h>
+#include <linux/fs.h>
+#include <linux/miscdevice.h>
+#include <linux/watchdog.h>
+#include <linux/platform_device.h>
+#include <linux/uaccess.h>
+#include <linux/clk.h>
+#include <linux/io.h>
+
+#include <lantiq.h>
+
+/* Section 3.4 of the datasheet
+ * The password sequence protects the WDT control register from unintended
+ * write actions, which might cause malfunction of the WDT.
+ *
+ * essentially the following two magic passwords need to be written to allow
+ * IO access to the WDT core
+ */
+#define LTQ_WDT_PW1            0x00BE0000
+#define LTQ_WDT_PW2            0x00DC0000
+
+#define LTQ_WDT_CR             0x0     /* watchdog control register */
+#define LTQ_WDT_SR             0x8     /* watchdog status register */
+
+#define LTQ_WDT_SR_EN          (0x1 << 31)     /* enable bit */
+#define LTQ_WDT_SR_PWD         (0x3 << 26)     /* turn on power */
+#define LTQ_WDT_SR_CLKDIV      (0x3 << 24)     /* turn on clock and set */
+                                               /* divider to 0x40000 */
+#define LTQ_WDT_DIVIDER                0x40000
+#define LTQ_MAX_TIMEOUT                ((1 << 16) - 1) /* the reload field is 16 bit */
+
+static int nowayout = WATCHDOG_NOWAYOUT;
+
+static void __iomem *ltq_wdt_membase;
+static unsigned long ltq_io_region_clk_rate;
+
+static unsigned long ltq_wdt_bootstatus;
+static unsigned long ltq_wdt_in_use;
+static int ltq_wdt_timeout = 30;
+static int ltq_wdt_ok_to_close;
+
+static void
+ltq_wdt_enable(void)
+{
+       ltq_wdt_timeout = ltq_wdt_timeout *
+                       (ltq_io_region_clk_rate / LTQ_WDT_DIVIDER) + 0x1000;
+       if (ltq_wdt_timeout > LTQ_MAX_TIMEOUT)
+               ltq_wdt_timeout = LTQ_MAX_TIMEOUT;
+
+       /* write the first password magic */
+       ltq_w32(LTQ_WDT_PW1, ltq_wdt_membase + LTQ_WDT_CR);
+       /* write the second magic plus the configuration and new timeout */
+       ltq_w32(LTQ_WDT_SR_EN | LTQ_WDT_SR_PWD | LTQ_WDT_SR_CLKDIV |
+               LTQ_WDT_PW2 | ltq_wdt_timeout, ltq_wdt_membase + LTQ_WDT_CR);
+}
+
+static void
+ltq_wdt_disable(void)
+{
+       /* write the first password magic */
+       ltq_w32(LTQ_WDT_PW1, ltq_wdt_membase + LTQ_WDT_CR);
+       /* write the second password magic with no config
+        * this turns the watchdog off
+        */
+       ltq_w32(LTQ_WDT_PW2, ltq_wdt_membase + LTQ_WDT_CR);
+}
+
+static ssize_t
+ltq_wdt_write(struct file *file, const char __user *data,
+               size_t len, loff_t *ppos)
+{
+       if (len) {
+               if (!nowayout) {
+                       size_t i;
+
+                       ltq_wdt_ok_to_close = 0;
+                       for (i = 0; i != len; i++) {
+                               char c;
+
+                               if (get_user(c, data + i))
+                                       return -EFAULT;
+                               if (c == 'V')
+                                       ltq_wdt_ok_to_close = 1;
+                               else
+                                       ltq_wdt_ok_to_close = 0;
+                       }
+               }
+               ltq_wdt_enable();
+       }
+
+       return len;
+}
+
+static struct watchdog_info ident = {
+       .options = WDIOF_MAGICCLOSE | WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING |
+                       WDIOF_CARDRESET,
+       .identity = "ltq_wdt",
+};
+
+static long
+ltq_wdt_ioctl(struct file *file,
+               unsigned int cmd, unsigned long arg)
+{
+       int ret = -ENOTTY;
+
+       switch (cmd) {
+       case WDIOC_GETSUPPORT:
+               ret = copy_to_user((struct watchdog_info __user *)arg, &ident,
+                               sizeof(ident)) ? -EFAULT : 0;
+               break;
+
+       case WDIOC_GETBOOTSTATUS:
+               ret = put_user(ltq_wdt_bootstatus, (int __user *)arg);
+               break;
+
+       case WDIOC_GETSTATUS:
+               ret = put_user(0, (int __user *)arg);
+               break;
+
+       case WDIOC_SETTIMEOUT:
+               ret = get_user(ltq_wdt_timeout, (int __user *)arg);
+               if (!ret)
+                       ltq_wdt_enable();
+               /* intentional drop through */
+       case WDIOC_GETTIMEOUT:
+               ret = put_user(ltq_wdt_timeout, (int __user *)arg);
+               break;
+
+       case WDIOC_KEEPALIVE:
+               ltq_wdt_enable();
+               ret = 0;
+               break;
+       }
+       return ret;
+}
+
+static int
+ltq_wdt_open(struct inode *inode, struct file *file)
+{
+       if (test_and_set_bit(0, &ltq_wdt_in_use))
+               return -EBUSY;
+       ltq_wdt_in_use = 1;
+       ltq_wdt_enable();
+
+       return nonseekable_open(inode, file);
+}
+
+static int
+ltq_wdt_release(struct inode *inode, struct file *file)
+{
+       if (ltq_wdt_ok_to_close)
+               ltq_wdt_disable();
+       else
+               pr_err("ltq_wdt: watchdog closed without warning\n");
+       ltq_wdt_ok_to_close = 0;
+       clear_bit(0, &ltq_wdt_in_use);
+
+       return 0;
+}
+
+static const struct file_operations ltq_wdt_fops = {
+       .owner          = THIS_MODULE,
+       .write          = ltq_wdt_write,
+       .unlocked_ioctl = ltq_wdt_ioctl,
+       .open           = ltq_wdt_open,
+       .release        = ltq_wdt_release,
+       .llseek         = no_llseek,
+};
+
+static struct miscdevice ltq_wdt_miscdev = {
+       .minor  = WATCHDOG_MINOR,
+       .name   = "watchdog",
+       .fops   = &ltq_wdt_fops,
+};
+
+static int __init
+ltq_wdt_probe(struct platform_device *pdev)
+{
+       struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       struct clk *clk;
+
+       if (!res) {
+               dev_err(&pdev->dev, "cannot obtain I/O memory region");
+               return -ENOENT;
+       }
+       res = devm_request_mem_region(&pdev->dev, res->start,
+               resource_size(res), dev_name(&pdev->dev));
+       if (!res) {
+               dev_err(&pdev->dev, "cannot request I/O memory region");
+               return -EBUSY;
+       }
+       ltq_wdt_membase = devm_ioremap_nocache(&pdev->dev, res->start,
+               resource_size(res));
+       if (!ltq_wdt_membase) {
+               dev_err(&pdev->dev, "cannot remap I/O memory region\n");
+               return -ENOMEM;
+       }
+
+       /* we do not need to enable the clock as it is always running */
+       clk = clk_get(&pdev->dev, "io");
+       WARN_ON(!clk);
+       ltq_io_region_clk_rate = clk_get_rate(clk);
+       clk_put(clk);
+
+       if (ltq_reset_cause() == LTQ_RST_CAUSE_WDTRST)
+               ltq_wdt_bootstatus = WDIOF_CARDRESET;
+
+       return misc_register(&ltq_wdt_miscdev);
+}
+
+static int __devexit
+ltq_wdt_remove(struct platform_device *pdev)
+{
+       misc_deregister(&ltq_wdt_miscdev);
+
+       if (ltq_wdt_membase)
+               iounmap(ltq_wdt_membase);
+
+       return 0;
+}
+
+
+static struct platform_driver ltq_wdt_driver = {
+       .remove = __devexit_p(ltq_wdt_remove),
+       .driver = {
+               .name = "ltq_wdt",
+               .owner = THIS_MODULE,
+       },
+};
+
+static int __init
+init_ltq_wdt(void)
+{
+       return platform_driver_probe(&ltq_wdt_driver, ltq_wdt_probe);
+}
+
+static void __exit
+exit_ltq_wdt(void)
+{
+       return platform_driver_unregister(&ltq_wdt_driver);
+}
+
+module_init(init_ltq_wdt);
+module_exit(exit_ltq_wdt);
+
+module_param(nowayout, int, 0);
+MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started");
+
+MODULE_AUTHOR("John Crispin <blogic@openwrt.org>");
+MODULE_DESCRIPTION("Lantiq SoC Watchdog");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
index 528bceb..eed5436 100644 (file)
@@ -185,17 +185,20 @@ static struct miscdevice mpc8xxx_wdt_miscdev = {
        .fops   = &mpc8xxx_wdt_fops,
 };
 
+static const struct of_device_id mpc8xxx_wdt_match[];
 static int __devinit mpc8xxx_wdt_probe(struct platform_device *ofdev)
 {
        int ret;
+       const struct of_device_id *match;
        struct device_node *np = ofdev->dev.of_node;
        struct mpc8xxx_wdt_type *wdt_type;
        u32 freq = fsl_get_sys_freq();
        bool enabled;
 
-       if (!ofdev->dev.of_match)
+       match = of_match_device(mpc8xxx_wdt_match, &ofdev->dev);
+       if (!match)
                return -EINVAL;
-       wdt_type = ofdev->dev.of_match->data;
+       wdt_type = match->data;
 
        if (!freq || freq == -1)
                return -EINVAL;
index 5ec5ac1..1479dc4 100644 (file)
@@ -66,6 +66,7 @@ static struct {
        int default_ticks;
        unsigned long inuse;
        unsigned gpio;
+       int gstate;
 } mtx1_wdt_device;
 
 static void mtx1_wdt_trigger(unsigned long unused)
@@ -75,13 +76,13 @@ static void mtx1_wdt_trigger(unsigned long unused)
        spin_lock(&mtx1_wdt_device.lock);
        if (mtx1_wdt_device.running)
                ticks--;
-       /*
-        * toggle GPIO2_15
-        */
-       tmp = au_readl(GPIO2_DIR);
-       tmp = (tmp & ~(1 << mtx1_wdt_device.gpio)) |
-             ((~tmp) & (1 << mtx1_wdt_device.gpio));
-       au_writel(tmp, GPIO2_DIR);
+
+       /* toggle wdt gpio */
+       mtx1_wdt_device.gstate = ~mtx1_wdt_device.gstate;
+       if (mtx1_wdt_device.gstate)
+               gpio_direction_output(mtx1_wdt_device.gpio, 1);
+       else
+               gpio_direction_input(mtx1_wdt_device.gpio);
 
        if (mtx1_wdt_device.queue && ticks)
                mod_timer(&mtx1_wdt_device.timer, jiffies + MTX1_WDT_INTERVAL);
@@ -103,7 +104,8 @@ static void mtx1_wdt_start(void)
        spin_lock_irqsave(&mtx1_wdt_device.lock, flags);
        if (!mtx1_wdt_device.queue) {
                mtx1_wdt_device.queue = 1;
-               gpio_set_value(mtx1_wdt_device.gpio, 1);
+               mtx1_wdt_device.gstate = 1;
+               gpio_direction_output(mtx1_wdt_device.gpio, 1);
                mod_timer(&mtx1_wdt_device.timer, jiffies + MTX1_WDT_INTERVAL);
        }
        mtx1_wdt_device.running++;
@@ -117,7 +119,8 @@ static int mtx1_wdt_stop(void)
        spin_lock_irqsave(&mtx1_wdt_device.lock, flags);
        if (mtx1_wdt_device.queue) {
                mtx1_wdt_device.queue = 0;
-               gpio_set_value(mtx1_wdt_device.gpio, 0);
+               mtx1_wdt_device.gstate = 0;
+               gpio_direction_output(mtx1_wdt_device.gpio, 0);
        }
        ticks = mtx1_wdt_device.default_ticks;
        spin_unlock_irqrestore(&mtx1_wdt_device.lock, flags);
index f420f1f..4781f80 100644 (file)
@@ -4,21 +4,21 @@ obj-y += xenbus/
 nostackp := $(call cc-option, -fno-stack-protector)
 CFLAGS_features.o                      := $(nostackp)
 
-obj-$(CONFIG_BLOCK)            += biomerge.o
-obj-$(CONFIG_HOTPLUG_CPU)      += cpu_hotplug.o
-obj-$(CONFIG_XEN_XENCOMM)      += xencomm.o
-obj-$(CONFIG_XEN_BALLOON)      += xen-balloon.o
-obj-$(CONFIG_XEN_DEV_EVTCHN)   += xen-evtchn.o
-obj-$(CONFIG_XEN_GNTDEV)       += xen-gntdev.o
+obj-$(CONFIG_BLOCK)                    += biomerge.o
+obj-$(CONFIG_HOTPLUG_CPU)              += cpu_hotplug.o
+obj-$(CONFIG_XEN_XENCOMM)              += xencomm.o
+obj-$(CONFIG_XEN_BALLOON)              += xen-balloon.o
+obj-$(CONFIG_XEN_DEV_EVTCHN)           += xen-evtchn.o
+obj-$(CONFIG_XEN_GNTDEV)               += xen-gntdev.o
 obj-$(CONFIG_XEN_GRANT_DEV_ALLOC)      += xen-gntalloc.o
-obj-$(CONFIG_XENFS)            += xenfs/
+obj-$(CONFIG_XENFS)                    += xenfs/
 obj-$(CONFIG_XEN_SYS_HYPERVISOR)       += sys-hypervisor.o
-obj-$(CONFIG_XEN_PLATFORM_PCI) += xen-platform-pci.o
-obj-$(CONFIG_SWIOTLB_XEN)      += swiotlb-xen.o
-obj-$(CONFIG_XEN_DOM0)         += pci.o
+obj-$(CONFIG_XEN_PLATFORM_PCI)         += xen-platform-pci.o
+obj-$(CONFIG_SWIOTLB_XEN)              += swiotlb-xen.o
+obj-$(CONFIG_XEN_DOM0)                 += pci.o
 
-xen-evtchn-y                   := evtchn.o
+xen-evtchn-y                           := evtchn.o
 xen-gntdev-y                           := gntdev.o
 xen-gntalloc-y                         := gntalloc.o
 
-xen-platform-pci-y             := platform-pci.o
+xen-platform-pci-y                     := platform-pci.o
index 043af8a..f54290b 100644 (file)
@@ -114,7 +114,6 @@ static void __balloon_append(struct page *page)
        if (PageHighMem(page)) {
                list_add_tail(&page->lru, &ballooned_pages);
                balloon_stats.balloon_high++;
-               dec_totalhigh_pages();
        } else {
                list_add(&page->lru, &ballooned_pages);
                balloon_stats.balloon_low++;
@@ -124,6 +123,8 @@ static void __balloon_append(struct page *page)
 static void balloon_append(struct page *page)
 {
        __balloon_append(page);
+       if (PageHighMem(page))
+               dec_totalhigh_pages();
        totalram_pages--;
 }
 
@@ -193,7 +194,7 @@ static enum bp_state update_schedule(enum bp_state state)
        return BP_EAGAIN;
 }
 
-static unsigned long current_target(void)
+static long current_credit(void)
 {
        unsigned long target = balloon_stats.target_pages;
 
@@ -202,7 +203,7 @@ static unsigned long current_target(void)
                     balloon_stats.balloon_low +
                     balloon_stats.balloon_high);
 
-       return target;
+       return target - balloon_stats.current_pages;
 }
 
 static enum bp_state increase_reservation(unsigned long nr_pages)
@@ -246,7 +247,7 @@ static enum bp_state increase_reservation(unsigned long nr_pages)
                set_phys_to_machine(pfn, frame_list[i]);
 
                /* Link back into the page tables if not highmem. */
-               if (!xen_hvm_domain() && pfn < max_low_pfn) {
+               if (xen_pv_domain() && !PageHighMem(page)) {
                        int ret;
                        ret = HYPERVISOR_update_va_mapping(
                                (unsigned long)__va(pfn << PAGE_SHIFT),
@@ -293,7 +294,7 @@ static enum bp_state decrease_reservation(unsigned long nr_pages, gfp_t gfp)
 
                scrub_page(page);
 
-               if (!xen_hvm_domain() && !PageHighMem(page)) {
+               if (xen_pv_domain() && !PageHighMem(page)) {
                        ret = HYPERVISOR_update_va_mapping(
                                (unsigned long)__va(pfn << PAGE_SHIFT),
                                __pte_ma(0), 0);
@@ -337,7 +338,7 @@ static void balloon_process(struct work_struct *work)
        mutex_lock(&balloon_mutex);
 
        do {
-               credit = current_target() - balloon_stats.current_pages;
+               credit = current_credit();
 
                if (credit > 0)
                        state = increase_reservation(credit);
@@ -420,7 +421,7 @@ void free_xenballooned_pages(int nr_pages, struct page** pages)
        }
 
        /* The balloon may be too large now. Shrink it if needed. */
-       if (current_target() != balloon_stats.current_pages)
+       if (current_credit())
                schedule_delayed_work(&balloon_worker, 0);
 
        mutex_unlock(&balloon_mutex);
@@ -429,7 +430,7 @@ EXPORT_SYMBOL(free_xenballooned_pages);
 
 static int __init balloon_init(void)
 {
-       unsigned long pfn, nr_pages, extra_pfn_end;
+       unsigned long pfn, extra_pfn_end;
        struct page *page;
 
        if (!xen_domain())
@@ -437,11 +438,7 @@ static int __init balloon_init(void)
 
        pr_info("xen/balloon: Initialising balloon driver.\n");
 
-       if (xen_pv_domain())
-               nr_pages = xen_start_info->nr_pages;
-       else
-               nr_pages = max_pfn;
-       balloon_stats.current_pages = min(nr_pages, max_pfn);
+       balloon_stats.current_pages = xen_pv_domain() ? min(xen_start_info->nr_pages, max_pfn) : max_pfn;
        balloon_stats.target_pages  = balloon_stats.current_pages;
        balloon_stats.balloon_low   = 0;
        balloon_stats.balloon_high  = 0;
@@ -466,7 +463,7 @@ static int __init balloon_init(void)
             pfn < extra_pfn_end;
             pfn++) {
                page = pfn_to_page(pfn);
-               /* totalram_pages doesn't include the boot-time
+               /* totalram_pages and totalhigh_pages do not include the boot-time
                   balloon extension, so don't subtract from it. */
                __balloon_append(page);
        }
index 33167b4..3ff822b 100644 (file)
@@ -101,6 +101,7 @@ struct irq_info
                        unsigned short gsi;
                        unsigned char vector;
                        unsigned char flags;
+                       uint16_t domid;
                } pirq;
        } u;
 };
@@ -118,6 +119,8 @@ static DEFINE_PER_CPU(unsigned long [NR_EVENT_CHANNELS/BITS_PER_LONG],
 static struct irq_chip xen_dynamic_chip;
 static struct irq_chip xen_percpu_chip;
 static struct irq_chip xen_pirq_chip;
+static void enable_dynirq(struct irq_data *data);
+static void disable_dynirq(struct irq_data *data);
 
 /* Get info for IRQ */
 static struct irq_info *info_for_irq(unsigned irq)
@@ -184,6 +187,7 @@ static void xen_irq_info_pirq_init(unsigned irq,
                                   unsigned short pirq,
                                   unsigned short gsi,
                                   unsigned short vector,
+                                  uint16_t domid,
                                   unsigned char flags)
 {
        struct irq_info *info = info_for_irq(irq);
@@ -193,6 +197,7 @@ static void xen_irq_info_pirq_init(unsigned irq,
        info->u.pirq.pirq = pirq;
        info->u.pirq.gsi = gsi;
        info->u.pirq.vector = vector;
+       info->u.pirq.domid = domid;
        info->u.pirq.flags = flags;
 }
 
@@ -473,16 +478,6 @@ static void xen_free_irq(unsigned irq)
        irq_free_desc(irq);
 }
 
-static void pirq_unmask_notify(int irq)
-{
-       struct physdev_eoi eoi = { .irq = pirq_from_irq(irq) };
-
-       if (unlikely(pirq_needs_eoi(irq))) {
-               int rc = HYPERVISOR_physdev_op(PHYSDEVOP_eoi, &eoi);
-               WARN_ON(rc);
-       }
-}
-
 static void pirq_query_unmask(int irq)
 {
        struct physdev_irq_status_query irq_status;
@@ -506,6 +501,29 @@ static bool probing_irq(int irq)
        return desc && desc->action == NULL;
 }
 
+static void eoi_pirq(struct irq_data *data)
+{
+       int evtchn = evtchn_from_irq(data->irq);
+       struct physdev_eoi eoi = { .irq = pirq_from_irq(data->irq) };
+       int rc = 0;
+
+       irq_move_irq(data);
+
+       if (VALID_EVTCHN(evtchn))
+               clear_evtchn(evtchn);
+
+       if (pirq_needs_eoi(data->irq)) {
+               rc = HYPERVISOR_physdev_op(PHYSDEVOP_eoi, &eoi);
+               WARN_ON(rc);
+       }
+}
+
+static void mask_ack_pirq(struct irq_data *data)
+{
+       disable_dynirq(data);
+       eoi_pirq(data);
+}
+
 static unsigned int __startup_pirq(unsigned int irq)
 {
        struct evtchn_bind_pirq bind_pirq;
@@ -539,7 +557,7 @@ static unsigned int __startup_pirq(unsigned int irq)
 
 out:
        unmask_evtchn(evtchn);
-       pirq_unmask_notify(irq);
+       eoi_pirq(irq_get_irq_data(irq));
 
        return 0;
 }
@@ -579,18 +597,7 @@ static void enable_pirq(struct irq_data *data)
 
 static void disable_pirq(struct irq_data *data)
 {
-}
-
-static void ack_pirq(struct irq_data *data)
-{
-       int evtchn = evtchn_from_irq(data->irq);
-
-       irq_move_irq(data);
-
-       if (VALID_EVTCHN(evtchn)) {
-               mask_evtchn(evtchn);
-               clear_evtchn(evtchn);
-       }
+       disable_dynirq(data);
 }
 
 static int find_irq_by_gsi(unsigned gsi)
@@ -639,9 +646,6 @@ int xen_bind_pirq_gsi_to_irq(unsigned gsi,
        if (irq < 0)
                goto out;
 
-       irq_set_chip_and_handler_name(irq, &xen_pirq_chip, handle_level_irq,
-                                     name);
-
        irq_op.irq = irq;
        irq_op.vector = 0;
 
@@ -655,9 +659,35 @@ int xen_bind_pirq_gsi_to_irq(unsigned gsi,
                goto out;
        }
 
-       xen_irq_info_pirq_init(irq, 0, pirq, gsi, irq_op.vector,
+       xen_irq_info_pirq_init(irq, 0, pirq, gsi, irq_op.vector, DOMID_SELF,
                               shareable ? PIRQ_SHAREABLE : 0);
 
+       pirq_query_unmask(irq);
+       /* We try to use the handler with the appropriate semantic for the
+        * type of interrupt: if the interrupt doesn't need an eoi
+        * (pirq_needs_eoi returns false), we treat it like an edge
+        * triggered interrupt so we use handle_edge_irq.
+        * As a matter of fact this only happens when the corresponding
+        * physical interrupt is edge triggered or an msi.
+        *
+        * On the other hand if the interrupt needs an eoi (pirq_needs_eoi
+        * returns true) we treat it like a level triggered interrupt so we
+        * use handle_fasteoi_irq like the native code does for this kind of
+        * interrupts.
+        * Depending on the Xen version, pirq_needs_eoi might return true
+        * not only for level triggered interrupts but for edge triggered
+        * interrupts too. In any case Xen always honors the eoi mechanism,
+        * not injecting any more pirqs of the same kind if the first one
+        * hasn't received an eoi yet. Therefore using the fasteoi handler
+        * is the right choice either way.
+        */
+       if (pirq_needs_eoi(irq))
+               irq_set_chip_and_handler_name(irq, &xen_pirq_chip,
+                               handle_fasteoi_irq, name);
+       else
+               irq_set_chip_and_handler_name(irq, &xen_pirq_chip,
+                               handle_edge_irq, name);
+
 out:
        spin_unlock(&irq_mapping_update_lock);
 
@@ -680,7 +710,8 @@ int xen_allocate_pirq_msi(struct pci_dev *dev, struct msi_desc *msidesc)
 }
 
 int xen_bind_pirq_msi_to_irq(struct pci_dev *dev, struct msi_desc *msidesc,
-                            int pirq, int vector, const char *name)
+                            int pirq, int vector, const char *name,
+                            domid_t domid)
 {
        int irq, ret;
 
@@ -690,10 +721,10 @@ int xen_bind_pirq_msi_to_irq(struct pci_dev *dev, struct msi_desc *msidesc,
        if (irq == -1)
                goto out;
 
-       irq_set_chip_and_handler_name(irq, &xen_pirq_chip, handle_level_irq,
-                                     name);
+       irq_set_chip_and_handler_name(irq, &xen_pirq_chip, handle_edge_irq,
+                       name);
 
-       xen_irq_info_pirq_init(irq, 0, pirq, 0, vector, 0);
+       xen_irq_info_pirq_init(irq, 0, pirq, 0, vector, domid, 0);
        ret = irq_set_msi_desc(irq, msidesc);
        if (ret < 0)
                goto error_irq;
@@ -722,9 +753,16 @@ int xen_destroy_irq(int irq)
 
        if (xen_initial_domain()) {
                unmap_irq.pirq = info->u.pirq.pirq;
-               unmap_irq.domid = DOMID_SELF;
+               unmap_irq.domid = info->u.pirq.domid;
                rc = HYPERVISOR_physdev_op(PHYSDEVOP_unmap_pirq, &unmap_irq);
-               if (rc) {
+               /* If another domain quits without making the pci_disable_msix
+                * call, the Xen hypervisor takes care of freeing the PIRQs
+                * (free_domain_pirqs).
+                */
+               if ((rc == -ESRCH && info->u.pirq.domid != DOMID_SELF))
+                       printk(KERN_INFO "domain %d does not have %d anymore\n",
+                               info->u.pirq.domid, info->u.pirq.pirq);
+               else if (rc) {
                        printk(KERN_WARNING "unmap irq failed %d\n", rc);
                        goto out;
                }
@@ -759,6 +797,12 @@ out:
        return irq;
 }
 
+
+int xen_pirq_from_irq(unsigned irq)
+{
+       return pirq_from_irq(irq);
+}
+EXPORT_SYMBOL_GPL(xen_pirq_from_irq);
 int bind_evtchn_to_irq(unsigned int evtchn)
 {
        int irq;
@@ -773,7 +817,7 @@ int bind_evtchn_to_irq(unsigned int evtchn)
                        goto out;
 
                irq_set_chip_and_handler_name(irq, &xen_dynamic_chip,
-                                             handle_fasteoi_irq, "event");
+                                             handle_edge_irq, "event");
 
                xen_irq_info_evtchn_init(irq, evtchn);
        }
@@ -1179,9 +1223,6 @@ static void __xen_evtchn_do_upcall(void)
                                port = (word_idx * BITS_PER_LONG) + bit_idx;
                                irq = evtchn_to_irq[port];
 
-                               mask_evtchn(port);
-                               clear_evtchn(port);
-
                                if (irq != -1) {
                                        desc = irq_to_desc(irq);
                                        if (desc)
@@ -1337,10 +1378,16 @@ static void ack_dynirq(struct irq_data *data)
 {
        int evtchn = evtchn_from_irq(data->irq);
 
-       irq_move_masked_irq(data);
+       irq_move_irq(data);
 
        if (VALID_EVTCHN(evtchn))
-               unmask_evtchn(evtchn);
+               clear_evtchn(evtchn);
+}
+
+static void mask_ack_dynirq(struct irq_data *data)
+{
+       disable_dynirq(data);
+       ack_dynirq(data);
 }
 
 static int retrigger_dynirq(struct irq_data *data)
@@ -1502,6 +1549,18 @@ void xen_poll_irq(int irq)
        xen_poll_irq_timeout(irq, 0 /* no timeout */);
 }
 
+/* Check whether the IRQ line is shared with other guests. */
+int xen_test_irq_shared(int irq)
+{
+       struct irq_info *info = info_for_irq(irq);
+       struct physdev_irq_status_query irq_status = { .irq = info->u.pirq.pirq };
+
+       if (HYPERVISOR_physdev_op(PHYSDEVOP_irq_status_query, &irq_status))
+               return 0;
+       return !(irq_status.flags & XENIRQSTAT_shared);
+}
+EXPORT_SYMBOL_GPL(xen_test_irq_shared);
+
 void xen_irq_resume(void)
 {
        unsigned int cpu, evtchn;
@@ -1535,7 +1594,9 @@ static struct irq_chip xen_dynamic_chip __read_mostly = {
        .irq_mask               = disable_dynirq,
        .irq_unmask             = enable_dynirq,
 
-       .irq_eoi                = ack_dynirq,
+       .irq_ack                = ack_dynirq,
+       .irq_mask_ack           = mask_ack_dynirq,
+
        .irq_set_affinity       = set_affinity_irq,
        .irq_retrigger          = retrigger_dynirq,
 };
@@ -1545,14 +1606,15 @@ static struct irq_chip xen_pirq_chip __read_mostly = {
 
        .irq_startup            = startup_pirq,
        .irq_shutdown           = shutdown_pirq,
-
        .irq_enable             = enable_pirq,
-       .irq_unmask             = enable_pirq,
-
        .irq_disable            = disable_pirq,
-       .irq_mask               = disable_pirq,
 
-       .irq_ack                = ack_pirq,
+       .irq_mask               = disable_dynirq,
+       .irq_unmask             = enable_dynirq,
+
+       .irq_ack                = eoi_pirq,
+       .irq_eoi                = eoi_pirq,
+       .irq_mask_ack           = mask_ack_pirq,
 
        .irq_set_affinity       = set_affinity_irq,
 
index a7ffdfe..f6832f4 100644 (file)
@@ -427,6 +427,17 @@ static long gntalloc_ioctl(struct file *filp, unsigned int cmd,
        return 0;
 }
 
+static void gntalloc_vma_open(struct vm_area_struct *vma)
+{
+       struct gntalloc_gref *gref = vma->vm_private_data;
+       if (!gref)
+               return;
+
+       spin_lock(&gref_lock);
+       gref->users++;
+       spin_unlock(&gref_lock);
+}
+
 static void gntalloc_vma_close(struct vm_area_struct *vma)
 {
        struct gntalloc_gref *gref = vma->vm_private_data;
@@ -441,6 +452,7 @@ static void gntalloc_vma_close(struct vm_area_struct *vma)
 }
 
 static struct vm_operations_struct gntalloc_vmops = {
+       .open = gntalloc_vma_open,
        .close = gntalloc_vma_close,
 };
 
@@ -471,8 +483,6 @@ static int gntalloc_mmap(struct file *filp, struct vm_area_struct *vma)
        vma->vm_private_data = gref;
 
        vma->vm_flags |= VM_RESERVED;
-       vma->vm_flags |= VM_DONTCOPY;
-       vma->vm_flags |= VM_PFNMAP | VM_PFN_AT_MMAP;
 
        vma->vm_ops = &gntalloc_vmops;
 
index b0f9e8f..f914b26 100644 (file)
@@ -330,17 +330,26 @@ static int unmap_grant_pages(struct grant_map *map, int offset, int pages)
 
 /* ------------------------------------------------------------------ */
 
+static void gntdev_vma_open(struct vm_area_struct *vma)
+{
+       struct grant_map *map = vma->vm_private_data;
+
+       pr_debug("gntdev_vma_open %p\n", vma);
+       atomic_inc(&map->users);
+}
+
 static void gntdev_vma_close(struct vm_area_struct *vma)
 {
        struct grant_map *map = vma->vm_private_data;
 
-       pr_debug("close %p\n", vma);
+       pr_debug("gntdev_vma_close %p\n", vma);
        map->vma = NULL;
        vma->vm_private_data = NULL;
        gntdev_put_map(map);
 }
 
 static struct vm_operations_struct gntdev_vmops = {
+       .open = gntdev_vma_open,
        .close = gntdev_vma_close,
 };
 
@@ -652,7 +661,10 @@ static int gntdev_mmap(struct file *flip, struct vm_area_struct *vma)
 
        vma->vm_ops = &gntdev_vmops;
 
-       vma->vm_flags |= VM_RESERVED|VM_DONTCOPY|VM_DONTEXPAND|VM_PFNMAP;
+       vma->vm_flags |= VM_RESERVED|VM_DONTEXPAND;
+
+       if (use_ptemod)
+               vma->vm_flags |= VM_DONTCOPY|VM_PFNMAP;
 
        vma->vm_private_data = map;
 
index 3745a31..fd725cd 100644 (file)
@@ -466,13 +466,30 @@ int gnttab_map_refs(struct gnttab_map_grant_ref *map_ops,
                if (map_ops[i].status)
                        continue;
 
-               /* m2p override only supported for GNTMAP_contains_pte mappings */
-               if (!(map_ops[i].flags & GNTMAP_contains_pte))
-                       continue;
-               pte = (pte_t *) (mfn_to_virt(PFN_DOWN(map_ops[i].host_addr)) +
+               if (map_ops[i].flags & GNTMAP_contains_pte) {
+                       pte = (pte_t *) (mfn_to_virt(PFN_DOWN(map_ops[i].host_addr)) +
                                (map_ops[i].host_addr & ~PAGE_MASK));
-               mfn = pte_mfn(*pte);
-               ret = m2p_add_override(mfn, pages[i]);
+                       mfn = pte_mfn(*pte);
+               } else {
+                       /* If you really wanted to do this:
+                        * mfn = PFN_DOWN(map_ops[i].dev_bus_addr);
+                        *
+                        * The reason we do not implement it is b/c on the
+                        * unmap path (gnttab_unmap_refs) we have no means of
+                        * checking whether the page is !GNTMAP_contains_pte.
+                        *
+                        * That is without some extra data-structure to carry
+                        * the struct page, bool clear_pte, and list_head next
+                        * tuples and deal with allocation/delallocation, etc.
+                        *
+                        * The users of this API set the GNTMAP_contains_pte
+                        * flag so lets just return not supported until it
+                        * becomes neccessary to implement.
+                        */
+                       return -EOPNOTSUPP;
+               }
+               ret = m2p_add_override(mfn, pages[i],
+                                      map_ops[i].flags & GNTMAP_contains_pte);
                if (ret)
                        return ret;
        }
@@ -494,7 +511,7 @@ int gnttab_unmap_refs(struct gnttab_unmap_grant_ref *unmap_ops,
                return ret;
 
        for (i = 0; i < count; i++) {
-               ret = m2p_remove_override(pages[i]);
+               ret = m2p_remove_override(pages[i], true /* clear the PTE */);
                if (ret)
                        return ret;
        }
index a2eee57..0b5366b 100644 (file)
@@ -70,12 +70,7 @@ static int xen_suspend(void *data)
 
        BUG_ON(!irqs_disabled());
 
-       err = sysdev_suspend(PMSG_FREEZE);
-       if (!err) {
-               err = syscore_suspend();
-               if (err)
-                       sysdev_resume();
-       }
+       err = syscore_suspend();
        if (err) {
                printk(KERN_ERR "xen_suspend: system core suspend failed: %d\n",
                        err);
@@ -102,7 +97,6 @@ static int xen_suspend(void *data)
        }
 
        syscore_resume();
-       sysdev_resume();
 
        return 0;
 }
index 60f1827..1e0fe01 100644 (file)
@@ -215,7 +215,7 @@ static struct attribute_group xen_compilation_group = {
        .attrs = xen_compile_attrs,
 };
 
-int __init static xen_compilation_init(void)
+static int __init xen_compilation_init(void)
 {
        return sysfs_create_group(hypervisor_kobj, &xen_compilation_group);
 }
index 5147bdd..257b00e 100644 (file)
@@ -1102,6 +1102,7 @@ static int __blkdev_get(struct block_device *bdev, fmode_t mode, int for_part)
                        if (!bdev->bd_part)
                                goto out_clear;
 
+                       ret = 0;
                        if (disk->fops->open) {
                                ret = disk->fops->open(bdev, mode);
                                if (ret == -ERESTARTSYS) {
@@ -1118,9 +1119,18 @@ static int __blkdev_get(struct block_device *bdev, fmode_t mode, int for_part)
                                        put_disk(disk);
                                        goto restart;
                                }
-                               if (ret)
-                                       goto out_clear;
                        }
+                       /*
+                        * If the device is invalidated, rescan partition
+                        * if open succeeded or failed with -ENOMEDIUM.
+                        * The latter is necessary to prevent ghost
+                        * partitions on a removed medium.
+                        */
+                       if (bdev->bd_invalidated && (!ret || ret == -ENOMEDIUM))
+                               rescan_partitions(disk, bdev);
+                       if (ret)
+                               goto out_clear;
+
                        if (!bdev->bd_openers) {
                                bd_set_size(bdev,(loff_t)get_capacity(disk)<<9);
                                bdi = blk_get_backing_dev_info(bdev);
@@ -1128,8 +1138,6 @@ static int __blkdev_get(struct block_device *bdev, fmode_t mode, int for_part)
                                        bdi = &default_backing_dev_info;
                                bdev_inode_switch_bdi(bdev->bd_inode, bdi);
                        }
-                       if (bdev->bd_invalidated)
-                               rescan_partitions(disk, bdev);
                } else {
                        struct block_device *whole;
                        whole = bdget_disk(disk, 0);
@@ -1153,13 +1161,14 @@ static int __blkdev_get(struct block_device *bdev, fmode_t mode, int for_part)
                }
        } else {
                if (bdev->bd_contains == bdev) {
-                       if (bdev->bd_disk->fops->open) {
+                       ret = 0;
+                       if (bdev->bd_disk->fops->open)
                                ret = bdev->bd_disk->fops->open(bdev, mode);
-                               if (ret)
-                                       goto out_unlock_bdev;
-                       }
-                       if (bdev->bd_invalidated)
+                       /* the same as first opener case, read comment there */
+                       if (bdev->bd_invalidated && (!ret || ret == -ENOMEDIUM))
                                rescan_partitions(bdev->bd_disk, bdev);
+                       if (ret)
+                               goto out_unlock_bdev;
                }
                /* only one opener holds refs to the module and disk */
                module_put(disk->fops->owner);
index 5d505aa..44ea5b9 100644 (file)
@@ -178,12 +178,13 @@ static int btrfs_xattr_acl_set(struct dentry *dentry, const char *name,
 
        if (value) {
                acl = posix_acl_from_xattr(value, size);
+               if (IS_ERR(acl))
+                       return PTR_ERR(acl);
+
                if (acl) {
                        ret = posix_acl_valid(acl);
                        if (ret)
                                goto out;
-               } else if (IS_ERR(acl)) {
-                       return PTR_ERR(acl);
                }
        }
 
index cd52f7f..9ee6bd5 100644 (file)
@@ -8856,23 +8856,38 @@ out:
 int btrfs_init_space_info(struct btrfs_fs_info *fs_info)
 {
        struct btrfs_space_info *space_info;
+       struct btrfs_super_block *disk_super;
+       u64 features;
+       u64 flags;
+       int mixed = 0;
        int ret;
 
-       ret = update_space_info(fs_info, BTRFS_BLOCK_GROUP_SYSTEM, 0, 0,
-                                                                &space_info);
-       if (ret)
-               return ret;
+       disk_super = &fs_info->super_copy;
+       if (!btrfs_super_root(disk_super))
+               return 1;
 
-       ret = update_space_info(fs_info, BTRFS_BLOCK_GROUP_METADATA, 0, 0,
-                                                                &space_info);
-       if (ret)
-               return ret;
+       features = btrfs_super_incompat_flags(disk_super);
+       if (features & BTRFS_FEATURE_INCOMPAT_MIXED_GROUPS)
+               mixed = 1;
 
-       ret = update_space_info(fs_info, BTRFS_BLOCK_GROUP_DATA, 0, 0,
-                                                                &space_info);
+       flags = BTRFS_BLOCK_GROUP_SYSTEM;
+       ret = update_space_info(fs_info, flags, 0, 0, &space_info);
        if (ret)
-               return ret;
+               goto out;
 
+       if (mixed) {
+               flags = BTRFS_BLOCK_GROUP_METADATA | BTRFS_BLOCK_GROUP_DATA;
+               ret = update_space_info(fs_info, flags, 0, 0, &space_info);
+       } else {
+               flags = BTRFS_BLOCK_GROUP_METADATA;
+               ret = update_space_info(fs_info, flags, 0, 0, &space_info);
+               if (ret)
+                       goto out;
+
+               flags = BTRFS_BLOCK_GROUP_DATA;
+               ret = update_space_info(fs_info, flags, 0, 0, &space_info);
+       }
+out:
        return ret;
 }
 
index ffb48d6..2616f7e 100644 (file)
@@ -81,6 +81,13 @@ static unsigned int btrfs_flags_to_ioctl(unsigned int flags)
                iflags |= FS_NOATIME_FL;
        if (flags & BTRFS_INODE_DIRSYNC)
                iflags |= FS_DIRSYNC_FL;
+       if (flags & BTRFS_INODE_NODATACOW)
+               iflags |= FS_NOCOW_FL;
+
+       if ((flags & BTRFS_INODE_COMPRESS) && !(flags & BTRFS_INODE_NOCOMPRESS))
+               iflags |= FS_COMPR_FL;
+       else if (flags & BTRFS_INODE_NOCOMPRESS)
+               iflags |= FS_NOCOMP_FL;
 
        return iflags;
 }
@@ -144,16 +151,13 @@ static int check_flags(unsigned int flags)
        if (flags & ~(FS_IMMUTABLE_FL | FS_APPEND_FL | \
                      FS_NOATIME_FL | FS_NODUMP_FL | \
                      FS_SYNC_FL | FS_DIRSYNC_FL | \
-                     FS_NOCOMP_FL | FS_COMPR_FL | \
-                     FS_NOCOW_FL | FS_COW_FL))
+                     FS_NOCOMP_FL | FS_COMPR_FL |
+                     FS_NOCOW_FL))
                return -EOPNOTSUPP;
 
        if ((flags & FS_NOCOMP_FL) && (flags & FS_COMPR_FL))
                return -EINVAL;
 
-       if ((flags & FS_NOCOW_FL) && (flags & FS_COW_FL))
-               return -EINVAL;
-
        return 0;
 }
 
@@ -218,6 +222,10 @@ static int btrfs_ioctl_setflags(struct file *file, void __user *arg)
                ip->flags |= BTRFS_INODE_DIRSYNC;
        else
                ip->flags &= ~BTRFS_INODE_DIRSYNC;
+       if (flags & FS_NOCOW_FL)
+               ip->flags |= BTRFS_INODE_NODATACOW;
+       else
+               ip->flags &= ~BTRFS_INODE_NODATACOW;
 
        /*
         * The COMPRESS flag can only be changed by users, while the NOCOMPRESS
@@ -230,11 +238,9 @@ static int btrfs_ioctl_setflags(struct file *file, void __user *arg)
        } else if (flags & FS_COMPR_FL) {
                ip->flags |= BTRFS_INODE_COMPRESS;
                ip->flags &= ~BTRFS_INODE_NOCOMPRESS;
+       } else {
+               ip->flags &= ~(BTRFS_INODE_COMPRESS | BTRFS_INODE_NOCOMPRESS);
        }
-       if (flags & FS_NOCOW_FL)
-               ip->flags |= BTRFS_INODE_NODATACOW;
-       else if (flags & FS_COW_FL)
-               ip->flags &= ~BTRFS_INODE_NODATACOW;
 
        trans = btrfs_join_transaction(root, 1);
        BUG_ON(IS_ERR(trans));
index 9fa0866..2a5404c 100644 (file)
@@ -819,7 +819,7 @@ int __ceph_caps_used(struct ceph_inode_info *ci)
                used |= CEPH_CAP_FILE_CACHE;
        if (ci->i_wr_ref)
                used |= CEPH_CAP_FILE_WR;
-       if (ci->i_wrbuffer_ref)
+       if (ci->i_wb_ref || ci->i_wrbuffer_ref)
                used |= CEPH_CAP_FILE_BUFFER;
        return used;
 }
@@ -1990,11 +1990,11 @@ static void __take_cap_refs(struct ceph_inode_info *ci, int got)
        if (got & CEPH_CAP_FILE_WR)
                ci->i_wr_ref++;
        if (got & CEPH_CAP_FILE_BUFFER) {
-               if (ci->i_wrbuffer_ref == 0)
+               if (ci->i_wb_ref == 0)
                        ihold(&ci->vfs_inode);
-               ci->i_wrbuffer_ref++;
-               dout("__take_cap_refs %p wrbuffer %d -> %d (?)\n",
-                    &ci->vfs_inode, ci->i_wrbuffer_ref-1, ci->i_wrbuffer_ref);
+               ci->i_wb_ref++;
+               dout("__take_cap_refs %p wb %d -> %d (?)\n",
+                    &ci->vfs_inode, ci->i_wb_ref-1, ci->i_wb_ref);
        }
 }
 
@@ -2169,12 +2169,12 @@ void ceph_put_cap_refs(struct ceph_inode_info *ci, int had)
                if (--ci->i_rdcache_ref == 0)
                        last++;
        if (had & CEPH_CAP_FILE_BUFFER) {
-               if (--ci->i_wrbuffer_ref == 0) {
+               if (--ci->i_wb_ref == 0) {
                        last++;
                        put++;
                }
-               dout("put_cap_refs %p wrbuffer %d -> %d (?)\n",
-                    inode, ci->i_wrbuffer_ref+1, ci->i_wrbuffer_ref);
+               dout("put_cap_refs %p wb %d -> %d (?)\n",
+                    inode, ci->i_wb_ref+1, ci->i_wb_ref);
        }
        if (had & CEPH_CAP_FILE_WR)
                if (--ci->i_wr_ref == 0) {
index 03d6daf..70b6a48 100644 (file)
@@ -355,6 +355,7 @@ struct inode *ceph_alloc_inode(struct super_block *sb)
        ci->i_rd_ref = 0;
        ci->i_rdcache_ref = 0;
        ci->i_wr_ref = 0;
+       ci->i_wb_ref = 0;
        ci->i_wrbuffer_ref = 0;
        ci->i_wrbuffer_ref_head = 0;
        ci->i_shared_gen = 0;
index f60b07b..d0fae4c 100644 (file)
@@ -3304,8 +3304,8 @@ static void con_put(struct ceph_connection *con)
 {
        struct ceph_mds_session *s = con->private;
 
+       dout("mdsc con_put %p (%d)\n", s, atomic_read(&s->s_ref) - 1);
        ceph_put_mds_session(s);
-       dout("mdsc con_put %p (%d)\n", s, atomic_read(&s->s_ref));
 }
 
 /*
index e86ec11..24067d6 100644 (file)
@@ -206,7 +206,7 @@ void ceph_put_snap_realm(struct ceph_mds_client *mdsc,
                up_write(&mdsc->snap_rwsem);
        } else {
                spin_lock(&mdsc->snap_empty_lock);
-               list_add(&mdsc->snap_empty, &realm->empty_item);
+               list_add(&realm->empty_item, &mdsc->snap_empty);
                spin_unlock(&mdsc->snap_empty_lock);
        }
 }
index b1f1b8b..f5cabef 100644 (file)
@@ -293,7 +293,7 @@ struct ceph_inode_info {
 
        /* held references to caps */
        int i_pin_ref;
-       int i_rd_ref, i_rdcache_ref, i_wr_ref;
+       int i_rd_ref, i_rdcache_ref, i_wr_ref, i_wb_ref;
        int i_wrbuffer_ref, i_wrbuffer_ref_head;
        u32 i_shared_gen;       /* increment each time we get FILE_SHARED */
        u32 i_rdcache_gen;      /* incremented each time we get FILE_CACHE. */
index 23d43cd..1b2e180 100644 (file)
@@ -277,6 +277,7 @@ cifsConvertToUCS(__le16 *target, const char *source, int srclen,
 
        for (i = 0, j = 0; i < srclen; j++) {
                src_char = source[i];
+               charlen = 1;
                switch (src_char) {
                case 0:
                        put_unaligned(0, &target[j]);
@@ -316,16 +317,13 @@ cifsConvertToUCS(__le16 *target, const char *source, int srclen,
                                dst_char = cpu_to_le16(0x003f);
                                charlen = 1;
                        }
-                       /*
-                        * character may take more than one byte in the source
-                        * string, but will take exactly two bytes in the
-                        * target string
-                        */
-                       i += charlen;
-                       continue;
                }
+               /*
+                * character may take more than one byte in the source string,
+                * but will take exactly two bytes in the target string
+                */
+               i += charlen;
                put_unaligned(dst_char, &target[j]);
-               i++; /* move to next char in source string */
        }
 
 ctoUCS_out:
index 05f1dcf..277262a 100644 (file)
@@ -2673,6 +2673,11 @@ is_path_accessible(int xid, struct cifsTconInfo *tcon,
                              0 /* not legacy */, cifs_sb->local_nls,
                              cifs_sb->mnt_cifs_flags &
                                CIFS_MOUNT_MAP_SPECIAL_CHR);
+
+       if (rc == -EOPNOTSUPP || rc == -EINVAL)
+               rc = SMBQueryInformation(xid, tcon, full_path, pfile_info,
+                               cifs_sb->local_nls, cifs_sb->mnt_cifs_flags &
+                                 CIFS_MOUNT_MAP_SPECIAL_CHR);
        kfree(pfile_info);
        return rc;
 }
index 3313dd1..9a37a9b 100644 (file)
@@ -53,11 +53,14 @@ DEFINE_SPINLOCK(configfs_dirent_lock);
 static void configfs_d_iput(struct dentry * dentry,
                            struct inode * inode)
 {
-       struct configfs_dirent * sd = dentry->d_fsdata;
+       struct configfs_dirent *sd = dentry->d_fsdata;
 
        if (sd) {
                BUG_ON(sd->s_dentry != dentry);
+               /* Coordinate with configfs_readdir */
+               spin_lock(&configfs_dirent_lock);
                sd->s_dentry = NULL;
+               spin_unlock(&configfs_dirent_lock);
                configfs_put(sd);
        }
        iput(inode);
@@ -689,7 +692,8 @@ static int create_default_group(struct config_group *parent_group,
                        sd = child->d_fsdata;
                        sd->s_type |= CONFIGFS_USET_DEFAULT;
                } else {
-                       d_delete(child);
+                       BUG_ON(child->d_inode);
+                       d_drop(child);
                        dput(child);
                }
        }
@@ -1545,7 +1549,7 @@ static int configfs_readdir(struct file * filp, void * dirent, filldir_t filldir
        struct configfs_dirent * parent_sd = dentry->d_fsdata;
        struct configfs_dirent *cursor = filp->private_data;
        struct list_head *p, *q = &cursor->s_sibling;
-       ino_t ino;
+       ino_t ino = 0;
        int i = filp->f_pos;
 
        switch (i) {
@@ -1573,6 +1577,7 @@ static int configfs_readdir(struct file * filp, void * dirent, filldir_t filldir
                                struct configfs_dirent *next;
                                const char * name;
                                int len;
+                               struct inode *inode = NULL;
 
                                next = list_entry(p, struct configfs_dirent,
                                                   s_sibling);
@@ -1581,9 +1586,28 @@ static int configfs_readdir(struct file * filp, void * dirent, filldir_t filldir
 
                                name = configfs_get_name(next);
                                len = strlen(name);
-                               if (next->s_dentry)
-                                       ino = next->s_dentry->d_inode->i_ino;
-                               else
+
+                               /*
+                                * We'll have a dentry and an inode for
+                                * PINNED items and for open attribute
+                                * files.  We lock here to prevent a race
+                                * with configfs_d_iput() clearing
+                                * s_dentry before calling iput().
+                                *
+                                * Why do we go to the trouble?  If
+                                * someone has an attribute file open,
+                                * the inode number should match until
+                                * they close it.  Beyond that, we don't
+                                * care.
+                                */
+                               spin_lock(&configfs_dirent_lock);
+                               dentry = next->s_dentry;
+                               if (dentry)
+                                       inode = dentry->d_inode;
+                               if (inode)
+                                       ino = inode->i_ino;
+                               spin_unlock(&configfs_dirent_lock);
+                               if (!inode)
                                        ino = iunique(configfs_sb, 2);
 
                                if (filldir(dirent, name, len, filp->f_pos, ino,
@@ -1683,7 +1707,8 @@ int configfs_register_subsystem(struct configfs_subsystem *subsys)
                err = configfs_attach_group(sd->s_element, &group->cg_item,
                                            dentry);
                if (err) {
-                       d_delete(dentry);
+                       BUG_ON(dentry->d_inode);
+                       d_drop(dentry);
                        dput(dentry);
                } else {
                        spin_lock(&configfs_dirent_lock);
index 89d394d..90f7657 100644 (file)
@@ -428,26 +428,17 @@ static ssize_t write_file_bool(struct file *file, const char __user *user_buf,
                               size_t count, loff_t *ppos)
 {
        char buf[32];
-       int buf_size;
+       size_t buf_size;
+       bool bv;
        u32 *val = file->private_data;
 
        buf_size = min(count, (sizeof(buf)-1));
        if (copy_from_user(buf, user_buf, buf_size))
                return -EFAULT;
 
-       switch (buf[0]) {
-       case 'y':
-       case 'Y':
-       case '1':
-               *val = 1;
-               break;
-       case 'n':
-       case 'N':
-       case '0':
-               *val = 0;
-               break;
-       }
-       
+       if (strtobool(buf, &bv) == 0)
+               *val = bv;
+
        return count;
 }
 
index c6ba49b..b32eb29 100644 (file)
@@ -174,7 +174,7 @@ static int fuse_dentry_revalidate(struct dentry *entry, struct nameidata *nd)
                if (!inode)
                        return 0;
 
-               if (nd->flags & LOOKUP_RCU)
+               if (nd && (nd->flags & LOOKUP_RCU))
                        return -ECHILD;
 
                fc = get_fuse_conn(inode);
index 54fc993..e3c4f11 100644 (file)
@@ -179,7 +179,7 @@ EXPORT_SYMBOL(putname);
 static int acl_permission_check(struct inode *inode, int mask, unsigned int flags,
                int (*check_acl)(struct inode *inode, int mask, unsigned int flags))
 {
-       umode_t                 mode = inode->i_mode;
+       unsigned int mode = inode->i_mode;
 
        mask &= MAY_READ | MAY_WRITE | MAY_EXEC;
 
index 6f8192f..be79dc9 100644 (file)
@@ -117,6 +117,8 @@ static int filelayout_async_handle_error(struct rpc_task *task,
        case -EKEYEXPIRED:
                rpc_delay(task, FILELAYOUT_POLL_RETRY_MAX);
                break;
+       case -NFS4ERR_RETRY_UNCACHED_REP:
+               break;
        default:
                dprintk("%s DS error. Retry through MDS %d\n", __func__,
                        task->tk_status);
@@ -416,7 +418,8 @@ static int
 filelayout_check_layout(struct pnfs_layout_hdr *lo,
                        struct nfs4_filelayout_segment *fl,
                        struct nfs4_layoutget_res *lgr,
-                       struct nfs4_deviceid *id)
+                       struct nfs4_deviceid *id,
+                       gfp_t gfp_flags)
 {
        struct nfs4_file_layout_dsaddr *dsaddr;
        int status = -EINVAL;
@@ -439,7 +442,7 @@ filelayout_check_layout(struct pnfs_layout_hdr *lo,
        /* find and reference the deviceid */
        dsaddr = nfs4_fl_find_get_deviceid(id);
        if (dsaddr == NULL) {
-               dsaddr = get_device_info(lo->plh_inode, id);
+               dsaddr = get_device_info(lo->plh_inode, id, gfp_flags);
                if (dsaddr == NULL)
                        goto out;
        }
@@ -500,7 +503,8 @@ static int
 filelayout_decode_layout(struct pnfs_layout_hdr *flo,
                         struct nfs4_filelayout_segment *fl,
                         struct nfs4_layoutget_res *lgr,
-                        struct nfs4_deviceid *id)
+                        struct nfs4_deviceid *id,
+                        gfp_t gfp_flags)
 {
        struct xdr_stream stream;
        struct xdr_buf buf = {
@@ -516,7 +520,7 @@ filelayout_decode_layout(struct pnfs_layout_hdr *flo,
 
        dprintk("%s: set_layout_map Begin\n", __func__);
 
-       scratch = alloc_page(GFP_KERNEL);
+       scratch = alloc_page(gfp_flags);
        if (!scratch)
                return -ENOMEM;
 
@@ -554,13 +558,13 @@ filelayout_decode_layout(struct pnfs_layout_hdr *flo,
                goto out_err;
 
        fl->fh_array = kzalloc(fl->num_fh * sizeof(struct nfs_fh *),
-                              GFP_KERNEL);
+                              gfp_flags);
        if (!fl->fh_array)
                goto out_err;
 
        for (i = 0; i < fl->num_fh; i++) {
                /* Do we want to use a mempool here? */
-               fl->fh_array[i] = kmalloc(sizeof(struct nfs_fh), GFP_KERNEL);
+               fl->fh_array[i] = kmalloc(sizeof(struct nfs_fh), gfp_flags);
                if (!fl->fh_array[i])
                        goto out_err_free;
 
@@ -605,19 +609,20 @@ filelayout_free_lseg(struct pnfs_layout_segment *lseg)
 
 static struct pnfs_layout_segment *
 filelayout_alloc_lseg(struct pnfs_layout_hdr *layoutid,
-                     struct nfs4_layoutget_res *lgr)
+                     struct nfs4_layoutget_res *lgr,
+                     gfp_t gfp_flags)
 {
        struct nfs4_filelayout_segment *fl;
        int rc;
        struct nfs4_deviceid id;
 
        dprintk("--> %s\n", __func__);
-       fl = kzalloc(sizeof(*fl), GFP_KERNEL);
+       fl = kzalloc(sizeof(*fl), gfp_flags);
        if (!fl)
                return NULL;
 
-       rc = filelayout_decode_layout(layoutid, fl, lgr, &id);
-       if (rc != 0 || filelayout_check_layout(layoutid, fl, lgr, &id)) {
+       rc = filelayout_decode_layout(layoutid, fl, lgr, &id, gfp_flags);
+       if (rc != 0 || filelayout_check_layout(layoutid, fl, lgr, &id, gfp_flags)) {
                _filelayout_free_lseg(fl);
                return NULL;
        }
@@ -633,7 +638,7 @@ filelayout_alloc_lseg(struct pnfs_layout_hdr *layoutid,
                int size = (fl->stripe_type == STRIPE_SPARSE) ?
                        fl->dsaddr->ds_num : fl->dsaddr->stripe_count;
 
-               fl->commit_buckets = kcalloc(size, sizeof(struct list_head), GFP_KERNEL);
+               fl->commit_buckets = kcalloc(size, sizeof(struct list_head), gfp_flags);
                if (!fl->commit_buckets) {
                        filelayout_free_lseg(&fl->generic_hdr);
                        return NULL;
index 7c44579..2b461d7 100644 (file)
@@ -104,6 +104,6 @@ extern struct nfs4_file_layout_dsaddr *
 nfs4_fl_find_get_deviceid(struct nfs4_deviceid *dev_id);
 extern void nfs4_fl_put_deviceid(struct nfs4_file_layout_dsaddr *dsaddr);
 struct nfs4_file_layout_dsaddr *
-get_device_info(struct inode *inode, struct nfs4_deviceid *dev_id);
+get_device_info(struct inode *inode, struct nfs4_deviceid *dev_id, gfp_t gfp_flags);
 
 #endif /* FS_NFS_NFS4FILELAYOUT_H */
index de5350f..db07c7a 100644 (file)
@@ -225,11 +225,11 @@ nfs4_fl_free_deviceid(struct nfs4_file_layout_dsaddr *dsaddr)
 }
 
 static struct nfs4_pnfs_ds *
-nfs4_pnfs_ds_add(struct inode *inode, u32 ip_addr, u32 port)
+nfs4_pnfs_ds_add(struct inode *inode, u32 ip_addr, u32 port, gfp_t gfp_flags)
 {
        struct nfs4_pnfs_ds *tmp_ds, *ds;
 
-       ds = kzalloc(sizeof(*tmp_ds), GFP_KERNEL);
+       ds = kzalloc(sizeof(*tmp_ds), gfp_flags);
        if (!ds)
                goto out;
 
@@ -261,7 +261,7 @@ out:
  * Currently only support ipv4, and one multi-path address.
  */
 static struct nfs4_pnfs_ds *
-decode_and_add_ds(struct xdr_stream *streamp, struct inode *inode)
+decode_and_add_ds(struct xdr_stream *streamp, struct inode *inode, gfp_t gfp_flags)
 {
        struct nfs4_pnfs_ds *ds = NULL;
        char *buf;
@@ -303,7 +303,7 @@ decode_and_add_ds(struct xdr_stream *streamp, struct inode *inode)
                        rlen);
                goto out_err;
        }
-       buf = kmalloc(rlen + 1, GFP_KERNEL);
+       buf = kmalloc(rlen + 1, gfp_flags);
        if (!buf) {
                dprintk("%s: Not enough memory\n", __func__);
                goto out_err;
@@ -333,7 +333,7 @@ decode_and_add_ds(struct xdr_stream *streamp, struct inode *inode)
        sscanf(pstr, "-%d-%d", &tmp[0], &tmp[1]);
        port = htons((tmp[0] << 8) | (tmp[1]));
 
-       ds = nfs4_pnfs_ds_add(inode, ip_addr, port);
+       ds = nfs4_pnfs_ds_add(inode, ip_addr, port, gfp_flags);
        dprintk("%s: Decoded address and port %s\n", __func__, buf);
 out_free:
        kfree(buf);
@@ -343,7 +343,7 @@ out_err:
 
 /* Decode opaque device data and return the result */
 static struct nfs4_file_layout_dsaddr*
-decode_device(struct inode *ino, struct pnfs_device *pdev)
+decode_device(struct inode *ino, struct pnfs_device *pdev, gfp_t gfp_flags)
 {
        int i;
        u32 cnt, num;
@@ -362,7 +362,7 @@ decode_device(struct inode *ino, struct pnfs_device *pdev)
        struct page *scratch;
 
        /* set up xdr stream */
-       scratch = alloc_page(GFP_KERNEL);
+       scratch = alloc_page(gfp_flags);
        if (!scratch)
                goto out_err;
 
@@ -384,7 +384,7 @@ decode_device(struct inode *ino, struct pnfs_device *pdev)
        }
 
        /* read stripe indices */
-       stripe_indices = kcalloc(cnt, sizeof(u8), GFP_KERNEL);
+       stripe_indices = kcalloc(cnt, sizeof(u8), gfp_flags);
        if (!stripe_indices)
                goto out_err_free_scratch;
 
@@ -423,7 +423,7 @@ decode_device(struct inode *ino, struct pnfs_device *pdev)
 
        dsaddr = kzalloc(sizeof(*dsaddr) +
                        (sizeof(struct nfs4_pnfs_ds *) * (num - 1)),
-                       GFP_KERNEL);
+                       gfp_flags);
        if (!dsaddr)
                goto out_err_free_stripe_indices;
 
@@ -452,7 +452,7 @@ decode_device(struct inode *ino, struct pnfs_device *pdev)
                for (j = 0; j < mp_count; j++) {
                        if (j == 0) {
                                dsaddr->ds_list[i] = decode_and_add_ds(&stream,
-                                       ino);
+                                       ino, gfp_flags);
                                if (dsaddr->ds_list[i] == NULL)
                                        goto out_err_free_deviceid;
                        } else {
@@ -503,12 +503,12 @@ out_err:
  * available devices.
  */
 static struct nfs4_file_layout_dsaddr *
-decode_and_add_device(struct inode *inode, struct pnfs_device *dev)
+decode_and_add_device(struct inode *inode, struct pnfs_device *dev, gfp_t gfp_flags)
 {
        struct nfs4_file_layout_dsaddr *d, *new;
        long hash;
 
-       new = decode_device(inode, dev);
+       new = decode_device(inode, dev, gfp_flags);
        if (!new) {
                printk(KERN_WARNING "%s: Could not decode or add device\n",
                        __func__);
@@ -537,7 +537,7 @@ decode_and_add_device(struct inode *inode, struct pnfs_device *dev)
  * of available devices, and return it.
  */
 struct nfs4_file_layout_dsaddr *
-get_device_info(struct inode *inode, struct nfs4_deviceid *dev_id)
+get_device_info(struct inode *inode, struct nfs4_deviceid *dev_id, gfp_t gfp_flags)
 {
        struct pnfs_device *pdev = NULL;
        u32 max_resp_sz;
@@ -556,17 +556,17 @@ get_device_info(struct inode *inode, struct nfs4_deviceid *dev_id)
        dprintk("%s inode %p max_resp_sz %u max_pages %d\n",
                __func__, inode, max_resp_sz, max_pages);
 
-       pdev = kzalloc(sizeof(struct pnfs_device), GFP_KERNEL);
+       pdev = kzalloc(sizeof(struct pnfs_device), gfp_flags);
        if (pdev == NULL)
                return NULL;
 
-       pages = kzalloc(max_pages * sizeof(struct page *), GFP_KERNEL);
+       pages = kzalloc(max_pages * sizeof(struct page *), gfp_flags);
        if (pages == NULL) {
                kfree(pdev);
                return NULL;
        }
        for (i = 0; i < max_pages; i++) {
-               pages[i] = alloc_page(GFP_KERNEL);
+               pages[i] = alloc_page(gfp_flags);
                if (!pages[i])
                        goto out_free;
        }
@@ -587,7 +587,7 @@ get_device_info(struct inode *inode, struct nfs4_deviceid *dev_id)
         * Found new device, need to decode it and then add it to the
         * list of known devices for this mountpoint.
         */
-       dsaddr = decode_and_add_device(inode, pdev);
+       dsaddr = decode_and_add_device(inode, pdev, gfp_flags);
 out_free:
        for (i = 0; i < max_pages; i++)
                __free_page(pages[i]);
index 69c0f3c..cf1b339 100644 (file)
@@ -300,6 +300,7 @@ static int nfs4_handle_exception(struct nfs_server *server, int errorcode, struc
                        ret = nfs4_delay(server->client, &exception->timeout);
                        if (ret != 0)
                                break;
+               case -NFS4ERR_RETRY_UNCACHED_REP:
                case -NFS4ERR_OLD_STATEID:
                        exception->retry = 1;
                        break;
@@ -3695,6 +3696,7 @@ nfs4_async_handle_error(struct rpc_task *task, const struct nfs_server *server,
                        rpc_delay(task, NFS4_POLL_RETRY_MAX);
                        task->tk_status = 0;
                        return -EAGAIN;
+               case -NFS4ERR_RETRY_UNCACHED_REP:
                case -NFS4ERR_OLD_STATEID:
                        task->tk_status = 0;
                        return -EAGAIN;
@@ -4844,6 +4846,8 @@ static void nfs4_get_lease_time_done(struct rpc_task *task, void *calldata)
                dprintk("%s Retry: tk_status %d\n", __func__, task->tk_status);
                rpc_delay(task, NFS4_POLL_RETRY_MIN);
                task->tk_status = 0;
+               /* fall through */
+       case -NFS4ERR_RETRY_UNCACHED_REP:
                nfs_restart_rpc(task, data->clp);
                return;
        }
@@ -5479,6 +5483,8 @@ static int nfs41_reclaim_complete_handle_errors(struct rpc_task *task, struct nf
                break;
        case -NFS4ERR_DELAY:
                rpc_delay(task, NFS4_POLL_RETRY_MAX);
+               /* fall through */
+       case -NFS4ERR_RETRY_UNCACHED_REP:
                return -EAGAIN;
        default:
                nfs4_schedule_lease_recovery(clp);
index ff681ab..f57f528 100644 (file)
@@ -383,6 +383,7 @@ pnfs_destroy_all_layouts(struct nfs_client *clp)
                                plh_layouts);
                dprintk("%s freeing layout for inode %lu\n", __func__,
                        lo->plh_inode->i_ino);
+               list_del_init(&lo->plh_layouts);
                pnfs_destroy_layout(NFS_I(lo->plh_inode));
        }
 }
@@ -466,7 +467,8 @@ pnfs_choose_layoutget_stateid(nfs4_stateid *dst, struct pnfs_layout_hdr *lo,
 static struct pnfs_layout_segment *
 send_layoutget(struct pnfs_layout_hdr *lo,
           struct nfs_open_context *ctx,
-          u32 iomode)
+          u32 iomode,
+          gfp_t gfp_flags)
 {
        struct inode *ino = lo->plh_inode;
        struct nfs_server *server = NFS_SERVER(ino);
@@ -479,7 +481,7 @@ send_layoutget(struct pnfs_layout_hdr *lo,
        dprintk("--> %s\n", __func__);
 
        BUG_ON(ctx == NULL);
-       lgp = kzalloc(sizeof(*lgp), GFP_KERNEL);
+       lgp = kzalloc(sizeof(*lgp), gfp_flags);
        if (lgp == NULL)
                return NULL;
 
@@ -487,12 +489,12 @@ send_layoutget(struct pnfs_layout_hdr *lo,
        max_resp_sz = server->nfs_client->cl_session->fc_attrs.max_resp_sz;
        max_pages = max_resp_sz >> PAGE_SHIFT;
 
-       pages = kzalloc(max_pages * sizeof(struct page *), GFP_KERNEL);
+       pages = kzalloc(max_pages * sizeof(struct page *), gfp_flags);
        if (!pages)
                goto out_err_free;
 
        for (i = 0; i < max_pages; i++) {
-               pages[i] = alloc_page(GFP_KERNEL);
+               pages[i] = alloc_page(gfp_flags);
                if (!pages[i])
                        goto out_err_free;
        }
@@ -508,6 +510,7 @@ send_layoutget(struct pnfs_layout_hdr *lo,
        lgp->args.layout.pages = pages;
        lgp->args.layout.pglen = max_pages * PAGE_SIZE;
        lgp->lsegpp = &lseg;
+       lgp->gfp_flags = gfp_flags;
 
        /* Synchronously retrieve layout information from server and
         * store in lseg.
@@ -665,11 +668,11 @@ pnfs_insert_layout(struct pnfs_layout_hdr *lo,
 }
 
 static struct pnfs_layout_hdr *
-alloc_init_layout_hdr(struct inode *ino)
+alloc_init_layout_hdr(struct inode *ino, gfp_t gfp_flags)
 {
        struct pnfs_layout_hdr *lo;
 
-       lo = kzalloc(sizeof(struct pnfs_layout_hdr), GFP_KERNEL);
+       lo = kzalloc(sizeof(struct pnfs_layout_hdr), gfp_flags);
        if (!lo)
                return NULL;
        atomic_set(&lo->plh_refcount, 1);
@@ -681,7 +684,7 @@ alloc_init_layout_hdr(struct inode *ino)
 }
 
 static struct pnfs_layout_hdr *
-pnfs_find_alloc_layout(struct inode *ino)
+pnfs_find_alloc_layout(struct inode *ino, gfp_t gfp_flags)
 {
        struct nfs_inode *nfsi = NFS_I(ino);
        struct pnfs_layout_hdr *new = NULL;
@@ -696,7 +699,7 @@ pnfs_find_alloc_layout(struct inode *ino)
                        return nfsi->layout;
        }
        spin_unlock(&ino->i_lock);
-       new = alloc_init_layout_hdr(ino);
+       new = alloc_init_layout_hdr(ino, gfp_flags);
        spin_lock(&ino->i_lock);
 
        if (likely(nfsi->layout == NULL))       /* Won the race? */
@@ -756,7 +759,8 @@ pnfs_find_lseg(struct pnfs_layout_hdr *lo, u32 iomode)
 struct pnfs_layout_segment *
 pnfs_update_layout(struct inode *ino,
                   struct nfs_open_context *ctx,
-                  enum pnfs_iomode iomode)
+                  enum pnfs_iomode iomode,
+                  gfp_t gfp_flags)
 {
        struct nfs_inode *nfsi = NFS_I(ino);
        struct nfs_client *clp = NFS_SERVER(ino)->nfs_client;
@@ -767,7 +771,7 @@ pnfs_update_layout(struct inode *ino,
        if (!pnfs_enabled_sb(NFS_SERVER(ino)))
                return NULL;
        spin_lock(&ino->i_lock);
-       lo = pnfs_find_alloc_layout(ino);
+       lo = pnfs_find_alloc_layout(ino, gfp_flags);
        if (lo == NULL) {
                dprintk("%s ERROR: can't get pnfs_layout_hdr\n", __func__);
                goto out_unlock;
@@ -807,7 +811,7 @@ pnfs_update_layout(struct inode *ino,
                spin_unlock(&clp->cl_lock);
        }
 
-       lseg = send_layoutget(lo, ctx, iomode);
+       lseg = send_layoutget(lo, ctx, iomode, gfp_flags);
        if (!lseg && first) {
                spin_lock(&clp->cl_lock);
                list_del_init(&lo->plh_layouts);
@@ -846,7 +850,7 @@ pnfs_layout_process(struct nfs4_layoutget *lgp)
                goto out;
        }
        /* Inject layout blob into I/O device driver */
-       lseg = NFS_SERVER(ino)->pnfs_curr_ld->alloc_lseg(lo, res);
+       lseg = NFS_SERVER(ino)->pnfs_curr_ld->alloc_lseg(lo, res, lgp->gfp_flags);
        if (!lseg || IS_ERR(lseg)) {
                if (!lseg)
                        status = -ENOMEM;
@@ -899,7 +903,8 @@ static int pnfs_read_pg_test(struct nfs_pageio_descriptor *pgio,
                /* This is first coelesce call for a series of nfs_pages */
                pgio->pg_lseg = pnfs_update_layout(pgio->pg_inode,
                                                   prev->wb_context,
-                                                  IOMODE_READ);
+                                                  IOMODE_READ,
+                                                  GFP_KERNEL);
        }
        return NFS_SERVER(pgio->pg_inode)->pnfs_curr_ld->pg_test(pgio, prev, req);
 }
@@ -921,7 +926,8 @@ static int pnfs_write_pg_test(struct nfs_pageio_descriptor *pgio,
                /* This is first coelesce call for a series of nfs_pages */
                pgio->pg_lseg = pnfs_update_layout(pgio->pg_inode,
                                                   prev->wb_context,
-                                                  IOMODE_RW);
+                                                  IOMODE_RW,
+                                                  GFP_NOFS);
        }
        return NFS_SERVER(pgio->pg_inode)->pnfs_curr_ld->pg_test(pgio, prev, req);
 }
index bc48272..0c015ba 100644 (file)
@@ -70,7 +70,7 @@ struct pnfs_layoutdriver_type {
        const u32 id;
        const char *name;
        struct module *owner;
-       struct pnfs_layout_segment * (*alloc_lseg) (struct pnfs_layout_hdr *layoutid, struct nfs4_layoutget_res *lgr);
+       struct pnfs_layout_segment * (*alloc_lseg) (struct pnfs_layout_hdr *layoutid, struct nfs4_layoutget_res *lgr, gfp_t gfp_flags);
        void (*free_lseg) (struct pnfs_layout_segment *lseg);
 
        /* test for nfs page cache coalescing */
@@ -126,7 +126,7 @@ void get_layout_hdr(struct pnfs_layout_hdr *lo);
 void put_lseg(struct pnfs_layout_segment *lseg);
 struct pnfs_layout_segment *
 pnfs_update_layout(struct inode *ino, struct nfs_open_context *ctx,
-                  enum pnfs_iomode access_type);
+                  enum pnfs_iomode access_type, gfp_t gfp_flags);
 void set_pnfs_layoutdriver(struct nfs_server *, u32 id);
 void unset_pnfs_layoutdriver(struct nfs_server *);
 enum pnfs_try_status pnfs_try_to_write_data(struct nfs_write_data *,
@@ -245,7 +245,7 @@ static inline void put_lseg(struct pnfs_layout_segment *lseg)
 
 static inline struct pnfs_layout_segment *
 pnfs_update_layout(struct inode *ino, struct nfs_open_context *ctx,
-                  enum pnfs_iomode access_type)
+                  enum pnfs_iomode access_type, gfp_t gfp_flags)
 {
        return NULL;
 }
index 7cded2b..2bcf0dc 100644 (file)
@@ -288,7 +288,7 @@ static int nfs_pagein_multi(struct nfs_pageio_descriptor *desc)
        atomic_set(&req->wb_complete, requests);
 
        BUG_ON(desc->pg_lseg != NULL);
-       lseg = pnfs_update_layout(desc->pg_inode, req->wb_context, IOMODE_READ);
+       lseg = pnfs_update_layout(desc->pg_inode, req->wb_context, IOMODE_READ, GFP_KERNEL);
        ClearPageError(page);
        offset = 0;
        nbytes = desc->pg_count;
@@ -351,7 +351,7 @@ static int nfs_pagein_one(struct nfs_pageio_descriptor *desc)
        }
        req = nfs_list_entry(data->pages.next);
        if ((!lseg) && list_is_singular(&data->pages))
-               lseg = pnfs_update_layout(desc->pg_inode, req->wb_context, IOMODE_READ);
+               lseg = pnfs_update_layout(desc->pg_inode, req->wb_context, IOMODE_READ, GFP_KERNEL);
 
        ret = nfs_read_rpcsetup(req, data, &nfs_read_full_ops, desc->pg_count,
                                0, lseg);
index 3bd5d7e..49c715b 100644 (file)
@@ -939,7 +939,7 @@ static int nfs_flush_multi(struct nfs_pageio_descriptor *desc)
        atomic_set(&req->wb_complete, requests);
 
        BUG_ON(desc->pg_lseg);
-       lseg = pnfs_update_layout(desc->pg_inode, req->wb_context, IOMODE_RW);
+       lseg = pnfs_update_layout(desc->pg_inode, req->wb_context, IOMODE_RW, GFP_NOFS);
        ClearPageError(page);
        offset = 0;
        nbytes = desc->pg_count;
@@ -1013,7 +1013,7 @@ static int nfs_flush_one(struct nfs_pageio_descriptor *desc)
        }
        req = nfs_list_entry(data->pages.next);
        if ((!lseg) && list_is_singular(&data->pages))
-               lseg = pnfs_update_layout(desc->pg_inode, req->wb_context, IOMODE_RW);
+               lseg = pnfs_update_layout(desc->pg_inode, req->wb_context, IOMODE_RW, GFP_NOFS);
 
        if ((desc->pg_ioflags & FLUSH_COND_STABLE) &&
            (desc->pg_moreio || NFS_I(desc->pg_inode)->ncommit))
index 0a0a66d..f768448 100644 (file)
@@ -646,7 +646,7 @@ int nilfs_palloc_freev(struct inode *inode, __u64 *entry_nrs, size_t nitems)
        unsigned long group, group_offset;
        int i, j, n, ret;
 
-       for (i = 0; i < nitems; i += n) {
+       for (i = 0; i < nitems; i = j) {
                group = nilfs_palloc_group(inode, entry_nrs[i], &group_offset);
                ret = nilfs_palloc_get_desc_block(inode, group, 0, &desc_bh);
                if (ret < 0)
index 6437202..9a3e6bb 100644 (file)
@@ -539,25 +539,41 @@ static int o2hb_verify_crc(struct o2hb_region *reg,
 
 /* We want to make sure that nobody is heartbeating on top of us --
  * this will help detect an invalid configuration. */
-static int o2hb_check_last_timestamp(struct o2hb_region *reg)
+static void o2hb_check_last_timestamp(struct o2hb_region *reg)
 {
-       int node_num, ret;
        struct o2hb_disk_slot *slot;
        struct o2hb_disk_heartbeat_block *hb_block;
+       char *errstr;
 
-       node_num = o2nm_this_node();
-
-       ret = 1;
-       slot = &reg->hr_slots[node_num];
+       slot = &reg->hr_slots[o2nm_this_node()];
        /* Don't check on our 1st timestamp */
-       if (slot->ds_last_time) {
-               hb_block = slot->ds_raw_block;
+       if (!slot->ds_last_time)
+               return;
 
-               if (le64_to_cpu(hb_block->hb_seq) != slot->ds_last_time)
-                       ret = 0;
-       }
+       hb_block = slot->ds_raw_block;
+       if (le64_to_cpu(hb_block->hb_seq) == slot->ds_last_time &&
+           le64_to_cpu(hb_block->hb_generation) == slot->ds_last_generation &&
+           hb_block->hb_node == slot->ds_node_num)
+               return;
 
-       return ret;
+#define ERRSTR1                "Another node is heartbeating on device"
+#define ERRSTR2                "Heartbeat generation mismatch on device"
+#define ERRSTR3                "Heartbeat sequence mismatch on device"
+
+       if (hb_block->hb_node != slot->ds_node_num)
+               errstr = ERRSTR1;
+       else if (le64_to_cpu(hb_block->hb_generation) !=
+                slot->ds_last_generation)
+               errstr = ERRSTR2;
+       else
+               errstr = ERRSTR3;
+
+       mlog(ML_ERROR, "%s (%s): expected(%u:0x%llx, 0x%llx), "
+            "ondisk(%u:0x%llx, 0x%llx)\n", errstr, reg->hr_dev_name,
+            slot->ds_node_num, (unsigned long long)slot->ds_last_generation,
+            (unsigned long long)slot->ds_last_time, hb_block->hb_node,
+            (unsigned long long)le64_to_cpu(hb_block->hb_generation),
+            (unsigned long long)le64_to_cpu(hb_block->hb_seq));
 }
 
 static inline void o2hb_prepare_block(struct o2hb_region *reg,
@@ -983,9 +999,7 @@ static int o2hb_do_disk_heartbeat(struct o2hb_region *reg)
        /* With an up to date view of the slots, we can check that no
         * other node has been improperly configured to heartbeat in
         * our slot. */
-       if (!o2hb_check_last_timestamp(reg))
-               mlog(ML_ERROR, "Device \"%s\": another node is heartbeating "
-                    "in our slot!\n", reg->hr_dev_name);
+       o2hb_check_last_timestamp(reg);
 
        /* fill in the proper info for our next heartbeat */
        o2hb_prepare_block(reg, reg->hr_generation);
@@ -999,8 +1013,8 @@ static int o2hb_do_disk_heartbeat(struct o2hb_region *reg)
        }
 
        i = -1;
-       while((i = find_next_bit(configured_nodes, O2NM_MAX_NODES, i + 1)) < O2NM_MAX_NODES) {
-
+       while((i = find_next_bit(configured_nodes,
+                                O2NM_MAX_NODES, i + 1)) < O2NM_MAX_NODES) {
                change |= o2hb_check_slot(reg, &reg->hr_slots[i]);
        }
 
@@ -1690,6 +1704,7 @@ static ssize_t o2hb_region_dev_write(struct o2hb_region *reg,
        struct file *filp = NULL;
        struct inode *inode = NULL;
        ssize_t ret = -EINVAL;
+       int live_threshold;
 
        if (reg->hr_bdev)
                goto out;
@@ -1766,8 +1781,18 @@ static ssize_t o2hb_region_dev_write(struct o2hb_region *reg,
         * A node is considered live after it has beat LIVE_THRESHOLD
         * times.  We're not steady until we've given them a chance
         * _after_ our first read.
+        * The default threshold is bare minimum so as to limit the delay
+        * during mounts. For global heartbeat, the threshold doubled for the
+        * first region.
         */
-       atomic_set(&reg->hr_steady_iterations, O2HB_LIVE_THRESHOLD + 1);
+       live_threshold = O2HB_LIVE_THRESHOLD;
+       if (o2hb_global_heartbeat_active()) {
+               spin_lock(&o2hb_live_lock);
+               if (o2hb_pop_count(&o2hb_region_bitmap, O2NM_MAX_REGIONS) == 1)
+                       live_threshold <<= 1;
+               spin_unlock(&o2hb_live_lock);
+       }
+       atomic_set(&reg->hr_steady_iterations, live_threshold + 1);
 
        hb_task = kthread_run(o2hb_thread, reg, "o2hb-%s",
                              reg->hr_item.ci_name);
index 9fe5b8f..8582e3f 100644 (file)
@@ -2868,7 +2868,7 @@ static int ocfs2_expand_inline_dir(struct inode *dir, struct buffer_head *di_bh,
                bytes = blocks_wanted << sb->s_blocksize_bits;
        struct ocfs2_super *osb = OCFS2_SB(dir->i_sb);
        struct ocfs2_inode_info *oi = OCFS2_I(dir);
-       struct ocfs2_alloc_context *data_ac;
+       struct ocfs2_alloc_context *data_ac = NULL;
        struct ocfs2_alloc_context *meta_ac = NULL;
        struct buffer_head *dirdata_bh = NULL;
        struct buffer_head *dx_root_bh = NULL;
index 7540a49..3b179d6 100644 (file)
@@ -1614,7 +1614,8 @@ static int dlm_try_to_join_domain(struct dlm_ctxt *dlm)
        spin_unlock(&dlm->spinlock);
 
        /* Support for global heartbeat and node info was added in 1.1 */
-       if (dlm_protocol.pv_major > 1 || dlm_protocol.pv_minor > 0) {
+       if (dlm->dlm_locking_proto.pv_major > 1 ||
+           dlm->dlm_locking_proto.pv_minor > 0) {
                status = dlm_send_nodeinfo(dlm, ctxt->yes_resp_map);
                if (status) {
                        mlog_errno(status);
index fede57e..84d1663 100644 (file)
@@ -2574,6 +2574,9 @@ fail:
                res->state &= ~DLM_LOCK_RES_MIGRATING;
                wake = 1;
                spin_unlock(&res->spinlock);
+               if (dlm_is_host_down(ret))
+                       dlm_wait_for_node_death(dlm, target,
+                                               DLM_NODE_DEATH_WAIT_MAX);
                goto leave;
        }
 
index 41565ae..89659d6 100644 (file)
@@ -1607,6 +1607,9 @@ static void ocfs2_calc_trunc_pos(struct inode *inode,
        range = le32_to_cpu(rec->e_cpos) + ocfs2_rec_clusters(el, rec);
 
        if (le32_to_cpu(rec->e_cpos) >= trunc_start) {
+               /*
+                * remove an entire extent record.
+                */
                *trunc_cpos = le32_to_cpu(rec->e_cpos);
                /*
                 * Skip holes if any.
@@ -1617,7 +1620,16 @@ static void ocfs2_calc_trunc_pos(struct inode *inode,
                *blkno = le64_to_cpu(rec->e_blkno);
                *trunc_end = le32_to_cpu(rec->e_cpos);
        } else if (range > trunc_start) {
+               /*
+                * remove a partial extent record, which means we're
+                * removing the last extent record.
+                */
                *trunc_cpos = trunc_start;
+               /*
+                * skip hole if any.
+                */
+               if (range < *trunc_end)
+                       *trunc_end = range;
                *trunc_len = *trunc_end - trunc_start;
                coff = trunc_start - le32_to_cpu(rec->e_cpos);
                *blkno = le64_to_cpu(rec->e_blkno) +
index b141a44..295d564 100644 (file)
@@ -1260,6 +1260,9 @@ void ocfs2_complete_mount_recovery(struct ocfs2_super *osb)
 {
        struct ocfs2_journal *journal = osb->journal;
 
+       if (ocfs2_is_hard_readonly(osb))
+               return;
+
        /* No need to queue up our truncate_log as regular cleanup will catch
         * that */
        ocfs2_queue_recovery_completion(journal, osb->slot_num,
index da3fefe..1ad8c93 100644 (file)
 
 #include "sysfs.h"
 
-/* used in crash dumps to help with debugging */
-static char last_sysfs_file[PATH_MAX];
-void sysfs_printk_last_file(void)
-{
-       printk(KERN_EMERG "last sysfs file: %s\n", last_sysfs_file);
-}
-
 /*
  * There's one sysfs_buffer for each open file and one
  * sysfs_open_dirent for each sysfs_dirent with one or more open
@@ -337,11 +330,6 @@ static int sysfs_open_file(struct inode *inode, struct file *file)
        struct sysfs_buffer *buffer;
        const struct sysfs_ops *ops;
        int error = -EACCES;
-       char *p;
-
-       p = d_path(&file->f_path, last_sysfs_file, sizeof(last_sysfs_file));
-       if (!IS_ERR(p))
-               memmove(last_sysfs_file, p, strlen(p) + 1);
 
        /* need attr_sd for attr and ops, its parent for kobj */
        if (!sysfs_get_active(attr_sd))
index c8769dc..194414f 100644 (file)
@@ -101,9 +101,9 @@ int sysfs_create_group(struct kobject *kobj,
 }
 
 /**
- * sysfs_update_group - given a directory kobject, create an attribute group
- * @kobj:      The kobject to create the group on
- * @grp:       The attribute group to create
+ * sysfs_update_group - given a directory kobject, update an attribute group
+ * @kobj:      The kobject to update the group on
+ * @grp:       The attribute group to update
  *
  * This function updates an attribute group.  Unlike
  * sysfs_create_group(), it will explicitly not warn or error if any
index e4f9c1b..3e898a4 100644 (file)
@@ -926,6 +926,7 @@ restart:
                                        XFS_LOOKUP_BATCH,
                                        XFS_ICI_RECLAIM_TAG);
                        if (!nr_found) {
+                               done = 1;
                                rcu_read_unlock();
                                break;
                        }
index acdb92f..5fc2380 100644 (file)
@@ -346,20 +346,23 @@ xfs_ail_delete(
  */
 STATIC void
 xfs_ail_worker(
-       struct work_struct *work)
+       struct work_struct      *work)
 {
-       struct xfs_ail  *ailp = container_of(to_delayed_work(work),
+       struct xfs_ail          *ailp = container_of(to_delayed_work(work),
                                        struct xfs_ail, xa_work);
-       long            tout;
-       xfs_lsn_t       target =  ailp->xa_target;
-       xfs_lsn_t       lsn;
-       xfs_log_item_t  *lip;
-       int             flush_log, count, stuck;
-       xfs_mount_t     *mp = ailp->xa_mount;
+       xfs_mount_t             *mp = ailp->xa_mount;
        struct xfs_ail_cursor   *cur = &ailp->xa_cursors;
-       int             push_xfsbufd = 0;
+       xfs_log_item_t          *lip;
+       xfs_lsn_t               lsn;
+       xfs_lsn_t               target;
+       long                    tout = 10;
+       int                     flush_log = 0;
+       int                     stuck = 0;
+       int                     count = 0;
+       int                     push_xfsbufd = 0;
 
        spin_lock(&ailp->xa_lock);
+       target = ailp->xa_target;
        xfs_trans_ail_cursor_init(ailp, cur);
        lip = xfs_trans_ail_cursor_first(ailp, cur, ailp->xa_last_pushed_lsn);
        if (!lip || XFS_FORCED_SHUTDOWN(mp)) {
@@ -368,8 +371,7 @@ xfs_ail_worker(
                 */
                xfs_trans_ail_cursor_done(ailp, cur);
                spin_unlock(&ailp->xa_lock);
-               ailp->xa_last_pushed_lsn = 0;
-               return;
+               goto out_done;
        }
 
        XFS_STATS_INC(xs_push_ail);
@@ -386,8 +388,7 @@ xfs_ail_worker(
         * lots of contention on the AIL lists.
         */
        lsn = lip->li_lsn;
-       flush_log = stuck = count = 0;
-       while ((XFS_LSN_CMP(lip->li_lsn, target) < 0)) {
+       while ((XFS_LSN_CMP(lip->li_lsn, target) <= 0)) {
                int     lock_result;
                /*
                 * If we can lock the item without sleeping, unlock the AIL
@@ -480,21 +481,25 @@ xfs_ail_worker(
        }
 
        /* assume we have more work to do in a short while */
-       tout = 10;
+out_done:
        if (!count) {
                /* We're past our target or empty, so idle */
                ailp->xa_last_pushed_lsn = 0;
 
                /*
-                * Check for an updated push target before clearing the
-                * XFS_AIL_PUSHING_BIT. If the target changed, we've got more
-                * work to do. Wait a bit longer before starting that work.
+                * We clear the XFS_AIL_PUSHING_BIT first before checking
+                * whether the target has changed. If the target has changed,
+                * this pushes the requeue race directly onto the result of the
+                * atomic test/set bit, so we are guaranteed that either the
+                * the pusher that changed the target or ourselves will requeue
+                * the work (but not both).
                 */
+               clear_bit(XFS_AIL_PUSHING_BIT, &ailp->xa_flags);
                smp_rmb();
-               if (ailp->xa_target == target) {
-                       clear_bit(XFS_AIL_PUSHING_BIT, &ailp->xa_flags);
+               if (XFS_LSN_CMP(ailp->xa_target, target) == 0 ||
+                   test_and_set_bit(XFS_AIL_PUSHING_BIT, &ailp->xa_flags))
                        return;
-               }
+
                tout = 50;
        } else if (XFS_LSN_CMP(lsn, target) >= 0) {
                /*
@@ -553,7 +558,7 @@ xfs_ail_push(
         * the XFS_AIL_PUSHING_BIT.
         */
        smp_wmb();
-       ailp->xa_target = threshold_lsn;
+       xfs_trans_ail_copy_lsn(ailp, &ailp->xa_target, &threshold_lsn);
        if (!test_and_set_bit(XFS_AIL_PUSHING_BIT, &ailp->xa_flags))
                queue_delayed_work(xfs_syncd_wq, &ailp->xa_work, 0);
 }
index 75a8692..077c00d 100644 (file)
        /* Kernel symbol table: Normal symbols */                       \
        __ksymtab         : AT(ADDR(__ksymtab) - LOAD_OFFSET) {         \
                VMLINUX_SYMBOL(__start___ksymtab) = .;                  \
-               *(__ksymtab)                                            \
+               *(SORT(___ksymtab+*))                                   \
                VMLINUX_SYMBOL(__stop___ksymtab) = .;                   \
        }                                                               \
                                                                        \
        /* Kernel symbol table: GPL-only symbols */                     \
        __ksymtab_gpl     : AT(ADDR(__ksymtab_gpl) - LOAD_OFFSET) {     \
                VMLINUX_SYMBOL(__start___ksymtab_gpl) = .;              \
-               *(__ksymtab_gpl)                                        \
+               *(SORT(___ksymtab_gpl+*))                               \
                VMLINUX_SYMBOL(__stop___ksymtab_gpl) = .;               \
        }                                                               \
                                                                        \
        /* Kernel symbol table: Normal unused symbols */                \
        __ksymtab_unused  : AT(ADDR(__ksymtab_unused) - LOAD_OFFSET) {  \
                VMLINUX_SYMBOL(__start___ksymtab_unused) = .;           \
-               *(__ksymtab_unused)                                     \
+               *(SORT(___ksymtab_unused+*))                            \
                VMLINUX_SYMBOL(__stop___ksymtab_unused) = .;            \
        }                                                               \
                                                                        \
        /* Kernel symbol table: GPL-only unused symbols */              \
        __ksymtab_unused_gpl : AT(ADDR(__ksymtab_unused_gpl) - LOAD_OFFSET) { \
                VMLINUX_SYMBOL(__start___ksymtab_unused_gpl) = .;       \
-               *(__ksymtab_unused_gpl)                                 \
+               *(SORT(___ksymtab_unused_gpl+*))                        \
                VMLINUX_SYMBOL(__stop___ksymtab_unused_gpl) = .;        \
        }                                                               \
                                                                        \
        /* Kernel symbol table: GPL-future-only symbols */              \
        __ksymtab_gpl_future : AT(ADDR(__ksymtab_gpl_future) - LOAD_OFFSET) { \
                VMLINUX_SYMBOL(__start___ksymtab_gpl_future) = .;       \
-               *(__ksymtab_gpl_future)                                 \
+               *(SORT(___ksymtab_gpl_future+*))                        \
                VMLINUX_SYMBOL(__stop___ksymtab_gpl_future) = .;        \
        }                                                               \
                                                                        \
        /* Kernel symbol table: Normal symbols */                       \
        __kcrctab         : AT(ADDR(__kcrctab) - LOAD_OFFSET) {         \
                VMLINUX_SYMBOL(__start___kcrctab) = .;                  \
-               *(__kcrctab)                                            \
+               *(SORT(___kcrctab+*))                                   \
                VMLINUX_SYMBOL(__stop___kcrctab) = .;                   \
        }                                                               \
                                                                        \
        /* Kernel symbol table: GPL-only symbols */                     \
        __kcrctab_gpl     : AT(ADDR(__kcrctab_gpl) - LOAD_OFFSET) {     \
                VMLINUX_SYMBOL(__start___kcrctab_gpl) = .;              \
-               *(__kcrctab_gpl)                                        \
+               *(SORT(___kcrctab_gpl+*))                               \
                VMLINUX_SYMBOL(__stop___kcrctab_gpl) = .;               \
        }                                                               \
                                                                        \
        /* Kernel symbol table: Normal unused symbols */                \
        __kcrctab_unused  : AT(ADDR(__kcrctab_unused) - LOAD_OFFSET) {  \
                VMLINUX_SYMBOL(__start___kcrctab_unused) = .;           \
-               *(__kcrctab_unused)                                     \
+               *(SORT(___kcrctab_unused+*))                            \
                VMLINUX_SYMBOL(__stop___kcrctab_unused) = .;            \
        }                                                               \
                                                                        \
        /* Kernel symbol table: GPL-only unused symbols */              \
        __kcrctab_unused_gpl : AT(ADDR(__kcrctab_unused_gpl) - LOAD_OFFSET) { \
                VMLINUX_SYMBOL(__start___kcrctab_unused_gpl) = .;       \
-               *(__kcrctab_unused_gpl)                                 \
+               *(SORT(___kcrctab_unused_gpl+*))                        \
                VMLINUX_SYMBOL(__stop___kcrctab_unused_gpl) = .;        \
        }                                                               \
                                                                        \
        /* Kernel symbol table: GPL-future-only symbols */              \
        __kcrctab_gpl_future : AT(ADDR(__kcrctab_gpl_future) - LOAD_OFFSET) { \
                VMLINUX_SYMBOL(__start___kcrctab_gpl_future) = .;       \
-               *(__kcrctab_gpl_future)                                 \
+               *(SORT(___kcrctab_gpl_future+*))                        \
                VMLINUX_SYMBOL(__stop___kcrctab_gpl_future) = .;        \
        }                                                               \
                                                                        \
index ade09d7..c99c3d3 100644 (file)
@@ -127,7 +127,7 @@ void drm_fb_helper_fill_fix(struct fb_info *info, uint32_t pitch,
 
 int drm_fb_helper_setcmap(struct fb_cmap *cmap, struct fb_info *info);
 
-bool drm_fb_helper_hotplug_event(struct drm_fb_helper *fb_helper);
+int drm_fb_helper_hotplug_event(struct drm_fb_helper *fb_helper);
 bool drm_fb_helper_initial_config(struct drm_fb_helper *fb_helper, int bpp_sel);
 int drm_fb_helper_single_add_all_connectors(struct drm_fb_helper *fb_helper);
 int drm_fb_helper_debug_enter(struct fb_info *info);
diff --git a/include/linux/alarmtimer.h b/include/linux/alarmtimer.h
new file mode 100644 (file)
index 0000000..c5d6095
--- /dev/null
@@ -0,0 +1,40 @@
+#ifndef _LINUX_ALARMTIMER_H
+#define _LINUX_ALARMTIMER_H
+
+#include <linux/time.h>
+#include <linux/hrtimer.h>
+#include <linux/timerqueue.h>
+#include <linux/rtc.h>
+
+enum alarmtimer_type {
+       ALARM_REALTIME,
+       ALARM_BOOTTIME,
+
+       ALARM_NUMTYPE,
+};
+
+/**
+ * struct alarm - Alarm timer structure
+ * @node:      timerqueue node for adding to the event list this value
+ *             also includes the expiration time.
+ * @period:    Period for recuring alarms
+ * @function:  Function pointer to be executed when the timer fires.
+ * @type:      Alarm type (BOOTTIME/REALTIME)
+ * @enabled:   Flag that represents if the alarm is set to fire or not
+ * @data:      Internal data value.
+ */
+struct alarm {
+       struct timerqueue_node  node;
+       ktime_t                 period;
+       void                    (*function)(struct alarm *);
+       enum alarmtimer_type    type;
+       bool                    enabled;
+       void                    *data;
+};
+
+void alarm_init(struct alarm *alarm, enum alarmtimer_type type,
+               void (*function)(struct alarm *));
+void alarm_start(struct alarm *alarm, ktime_t start, ktime_t period);
+void alarm_cancel(struct alarm *alarm);
+
+#endif
index b8613e8..01eca17 100644 (file)
@@ -111,6 +111,8 @@ extern void *__alloc_bootmem_low_node(pg_data_t *pgdat,
        __alloc_bootmem_nopanic(x, PAGE_SIZE, __pa(MAX_DMA_ADDRESS))
 #define alloc_bootmem_node(pgdat, x) \
        __alloc_bootmem_node(pgdat, x, SMP_CACHE_BYTES, __pa(MAX_DMA_ADDRESS))
+#define alloc_bootmem_node_nopanic(pgdat, x) \
+       __alloc_bootmem_node_nopanic(pgdat, x, SMP_CACHE_BYTES, __pa(MAX_DMA_ADDRESS))
 #define alloc_bootmem_pages_node(pgdat, x) \
        __alloc_bootmem_node(pgdat, x, PAGE_SIZE, __pa(MAX_DMA_ADDRESS))
 #define alloc_bootmem_pages_node_nopanic(pgdat, x) \
diff --git a/include/linux/bsearch.h b/include/linux/bsearch.h
new file mode 100644 (file)
index 0000000..90b1aa8
--- /dev/null
@@ -0,0 +1,9 @@
+#ifndef _LINUX_BSEARCH_H
+#define _LINUX_BSEARCH_H
+
+#include <linux/types.h>
+
+void *bsearch(const void *key, const void *base, size_t num, size_t size,
+             int (*cmp)(const void *key, const void *elt));
+
+#endif /* _LINUX_BSEARCH_H */
index 16ee8b4..4554db0 100644 (file)
@@ -355,7 +355,12 @@ struct cpu_vfs_cap_data {
 
 #define CAP_SYSLOG           34
 
-#define CAP_LAST_CAP         CAP_SYSLOG
+/* Allow triggering something that will wake the system */
+
+#define CAP_WAKE_ALARM            35
+
+
+#define CAP_LAST_CAP         CAP_WAKE_ALARM
 
 #define cap_valid(x) ((x) >= 0 && (x) <= CAP_LAST_CAP)
 
@@ -546,18 +551,7 @@ extern bool has_capability_noaudit(struct task_struct *t, int cap);
 extern bool capable(int cap);
 extern bool ns_capable(struct user_namespace *ns, int cap);
 extern bool task_ns_capable(struct task_struct *t, int cap);
-
-/**
- * nsown_capable - Check superior capability to one's own user_ns
- * @cap: The capability in question
- *
- * Return true if the current task has the given superior capability
- * targeted at its own user namespace.
- */
-static inline bool nsown_capable(int cap)
-{
-       return ns_capable(current_user_ns(), cap);
-}
+extern bool nsown_capable(int cap);
 
 /* audit system wants to get cap info from files as well */
 extern int get_vfs_caps_from_disk(const struct dentry *dentry, struct cpu_vfs_cap_data *cpu_caps);
index fc53492..d6733e2 100644 (file)
@@ -56,46 +56,52 @@ enum clock_event_nofitiers {
 
 /**
  * struct clock_event_device - clock event device descriptor
- * @name:              ptr to clock event name
- * @features:          features
+ * @event_handler:     Assigned by the framework to be called by the low
+ *                     level handler of the event source
+ * @set_next_event:    set next event function
+ * @next_event:                local storage for the next event in oneshot mode
  * @max_delta_ns:      maximum delta value in ns
  * @min_delta_ns:      minimum delta value in ns
  * @mult:              nanosecond to cycles multiplier
  * @shift:             nanoseconds to cycles divisor (power of two)
+ * @mode:              operating mode assigned by the management code
+ * @features:          features
+ * @retries:           number of forced programming retries
+ * @set_mode:          set mode function
+ * @broadcast:         function to broadcast events
+ * @min_delta_ticks:   minimum delta value in ticks stored for reconfiguration
+ * @max_delta_ticks:   maximum delta value in ticks stored for reconfiguration
+ * @name:              ptr to clock event name
  * @rating:            variable to rate clock event devices
  * @irq:               IRQ number (only for non CPU local devices)
  * @cpumask:           cpumask to indicate for which CPUs this device works
- * @set_next_event:    set next event function
- * @set_mode:          set mode function
- * @event_handler:     Assigned by the framework to be called by the low
- *                     level handler of the event source
- * @broadcast:         function to broadcast events
  * @list:              list head for the management code
- * @mode:              operating mode assigned by the management code
- * @next_event:                local storage for the next event in oneshot mode
- * @retries:           number of forced programming retries
  */
 struct clock_event_device {
-       const char              *name;
-       unsigned int            features;
+       void                    (*event_handler)(struct clock_event_device *);
+       int                     (*set_next_event)(unsigned long evt,
+                                                 struct clock_event_device *);
+       ktime_t                 next_event;
        u64                     max_delta_ns;
        u64                     min_delta_ns;
        u32                     mult;
        u32                     shift;
+       enum clock_event_mode   mode;
+       unsigned int            features;
+       unsigned long           retries;
+
+       void                    (*broadcast)(const struct cpumask *mask);
+       void                    (*set_mode)(enum clock_event_mode mode,
+                                           struct clock_event_device *);
+       unsigned long           min_delta_ticks;
+       unsigned long           max_delta_ticks;
+
+       const char              *name;
        int                     rating;
        int                     irq;
        const struct cpumask    *cpumask;
-       int                     (*set_next_event)(unsigned long evt,
-                                                 struct clock_event_device *);
-       void                    (*set_mode)(enum clock_event_mode mode,
-                                           struct clock_event_device *);
-       void                    (*event_handler)(struct clock_event_device *);
-       void                    (*broadcast)(const struct cpumask *mask);
        struct list_head        list;
-       enum clock_event_mode   mode;
-       ktime_t                 next_event;
-       unsigned long           retries;
-};
+} ____cacheline_aligned;
 
 /*
  * Calculate a multiplication factor for scaled math, which is used to convert
@@ -122,6 +128,12 @@ extern u64 clockevent_delta2ns(unsigned long latch,
                               struct clock_event_device *evt);
 extern void clockevents_register_device(struct clock_event_device *dev);
 
+extern void clockevents_config_and_register(struct clock_event_device *dev,
+                                           u32 freq, unsigned long min_delta,
+                                           unsigned long max_delta);
+
+extern int clockevents_update_freq(struct clock_event_device *ce, u32 freq);
+
 extern void clockevents_exchange_device(struct clock_event_device *old,
                                        struct clock_event_device *new);
 extern void clockevents_set_mode(struct clock_event_device *dev,
index c37b21a..c918fbd 100644 (file)
@@ -159,42 +159,38 @@ extern u64 timecounter_cyc2time(struct timecounter *tc,
  */
 struct clocksource {
        /*
-        * First part of structure is read mostly
+        * Hotpath data, fits in a single cache line when the
+        * clocksource itself is cacheline aligned.
         */
-       char *name;
-       struct list_head list;
-       int rating;
        cycle_t (*read)(struct clocksource *cs);
-       int (*enable)(struct clocksource *cs);
-       void (*disable)(struct clocksource *cs);
+       cycle_t cycle_last;
        cycle_t mask;
        u32 mult;
        u32 shift;
        u64 max_idle_ns;
-       unsigned long flags;
-       cycle_t (*vread)(void);
-       void (*suspend)(struct clocksource *cs);
-       void (*resume)(struct clocksource *cs);
+
 #ifdef CONFIG_IA64
        void *fsys_mmio;        /* used by fsyscall asm code */
 #define CLKSRC_FSYS_MMIO_SET(mmio, addr)      ((mmio) = (addr))
 #else
 #define CLKSRC_FSYS_MMIO_SET(mmio, addr)      do { } while (0)
 #endif
-
-       /*
-        * Second part is written at each timer interrupt
-        * Keep it in a different cache line to dirty no
-        * more than one cache line.
-        */
-       cycle_t cycle_last ____cacheline_aligned_in_smp;
+       const char *name;
+       struct list_head list;
+       int rating;
+       cycle_t (*vread)(void);
+       int (*enable)(struct clocksource *cs);
+       void (*disable)(struct clocksource *cs);
+       unsigned long flags;
+       void (*suspend)(struct clocksource *cs);
+       void (*resume)(struct clocksource *cs);
 
 #ifdef CONFIG_CLOCKSOURCE_WATCHDOG
        /* Watchdog related data, used by the framework */
        struct list_head wd_list;
        cycle_t wd_last;
 #endif
-};
+} ____cacheline_aligned;
 
 /*
  * Clock source flags bits::
@@ -341,4 +337,6 @@ static inline void update_vsyscall_tz(void)
 
 extern void timekeeping_notify(struct clocksource *clock);
 
+extern int clocksource_i8253_init(void);
+
 #endif /* _LINUX_CLOCKSOURCE_H */
index 9343dd3..11be48e 100644 (file)
@@ -3,7 +3,7 @@
  *
  *  Copyright (C) 2001 Russell King
  *            (C) 2002 - 2003 Dominik Brodowski <linux@brodo.de>
- *            
+ *
  * 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.
@@ -56,9 +56,9 @@ static inline int cpufreq_unregister_notifier(struct notifier_block *nb,
 #define CPUFREQ_POLICY_POWERSAVE       (1)
 #define CPUFREQ_POLICY_PERFORMANCE     (2)
 
-/* Frequency values here are CPU kHz so that hardware which doesn't run 
- * with some frequencies can complain without having to guess what per 
- * cent / per mille means. 
+/* Frequency values here are CPU kHz so that hardware which doesn't run
+ * with some frequencies can complain without having to guess what per
+ * cent / per mille means.
  * Maximum transition latency is in nanoseconds - if it's unknown,
  * CPUFREQ_ETERNAL shall be used.
  */
@@ -72,13 +72,15 @@ extern struct kobject *cpufreq_global_kobject;
 struct cpufreq_cpuinfo {
        unsigned int            max_freq;
        unsigned int            min_freq;
-       unsigned int            transition_latency; /* in 10^(-9) s = nanoseconds */
+
+       /* in 10^(-9) s = nanoseconds */
+       unsigned int            transition_latency;
 };
 
 struct cpufreq_real_policy {
        unsigned int            min;    /* in kHz */
        unsigned int            max;    /* in kHz */
-        unsigned int           policy; /* see above */
+       unsigned int            policy; /* see above */
        struct cpufreq_governor *governor; /* see below */
 };
 
@@ -94,7 +96,7 @@ struct cpufreq_policy {
        unsigned int            max;    /* in kHz */
        unsigned int            cur;    /* in kHz, only needed if cpufreq
                                         * governors are used */
-        unsigned int           policy; /* see above */
+       unsigned int            policy; /* see above */
        struct cpufreq_governor *governor; /* see below */
 
        struct work_struct      update; /* if update_policy() needs to be
@@ -167,11 +169,11 @@ static inline unsigned long cpufreq_scale(unsigned long old, u_int div, u_int mu
 
 struct cpufreq_governor {
        char    name[CPUFREQ_NAME_LEN];
-       int     (*governor)     (struct cpufreq_policy *policy,
+       int     (*governor)     (struct cpufreq_policy *policy,
                                 unsigned int event);
        ssize_t (*show_setspeed)        (struct cpufreq_policy *policy,
                                         char *buf);
-       int     (*store_setspeed)       (struct cpufreq_policy *policy,
+       int     (*store_setspeed)       (struct cpufreq_policy *policy,
                                         unsigned int freq);
        unsigned int max_transition_latency; /* HW must be able to switch to
                        next freq faster than this value in nano secs or we
@@ -180,7 +182,8 @@ struct cpufreq_governor {
        struct module           *owner;
 };
 
-/* pass a target to the cpufreq driver 
+/*
+ * Pass a target to the cpufreq driver.
  */
 extern int cpufreq_driver_target(struct cpufreq_policy *policy,
                                 unsigned int target_freq,
@@ -237,9 +240,9 @@ struct cpufreq_driver {
 
 /* flags */
 
-#define CPUFREQ_STICKY         0x01    /* the driver isn't removed even if 
+#define CPUFREQ_STICKY         0x01    /* the driver isn't removed even if
                                         * all ->init() calls failed */
-#define CPUFREQ_CONST_LOOPS    0x02    /* loops_per_jiffy or other kernel
+#define CPUFREQ_CONST_LOOPS    0x02    /* loops_per_jiffy or other kernel
                                         * "constants" aren't affected by
                                         * frequency transitions */
 #define CPUFREQ_PM_NO_WARN     0x04    /* don't warn on suspend/resume speed
@@ -252,7 +255,7 @@ int cpufreq_unregister_driver(struct cpufreq_driver *driver_data);
 void cpufreq_notify_transition(struct cpufreq_freqs *freqs, unsigned int state);
 
 
-static inline void cpufreq_verify_within_limits(struct cpufreq_policy *policy, unsigned int min, unsigned int max) 
+static inline void cpufreq_verify_within_limits(struct cpufreq_policy *policy, unsigned int min, unsigned int max)
 {
        if (policy->min < min)
                policy->min = min;
@@ -386,34 +389,15 @@ int cpufreq_frequency_table_target(struct cpufreq_policy *policy,
 /* the following 3 funtions are for cpufreq core use only */
 struct cpufreq_frequency_table *cpufreq_frequency_get_table(unsigned int cpu);
 struct cpufreq_policy *cpufreq_cpu_get(unsigned int cpu);
-void   cpufreq_cpu_put (struct cpufreq_policy *data);
+void   cpufreq_cpu_put(struct cpufreq_policy *data);
 
 /* the following are really really optional */
 extern struct freq_attr cpufreq_freq_attr_scaling_available_freqs;
 
-void cpufreq_frequency_table_get_attr(struct cpufreq_frequency_table *table, 
+void cpufreq_frequency_table_get_attr(struct cpufreq_frequency_table *table,
                                      unsigned int cpu);
 
 void cpufreq_frequency_table_put_attr(unsigned int cpu);
 
 
-/*********************************************************************
- *                     UNIFIED DEBUG HELPERS                         *
- *********************************************************************/
-
-#define CPUFREQ_DEBUG_CORE     1
-#define CPUFREQ_DEBUG_DRIVER   2
-#define CPUFREQ_DEBUG_GOVERNOR 4
-
-#ifdef CONFIG_CPU_FREQ_DEBUG
-
-extern void cpufreq_debug_printk(unsigned int type, const char *prefix, 
-                                const char *fmt, ...);
-
-#else
-
-#define cpufreq_debug_printk(msg...) do { } while(0)
-
-#endif /* CONFIG_CPU_FREQ_DEBUG */
-
 #endif /* _LINUX_CPUFREQ_H */
index 9aeeb0b..be16b61 100644 (file)
@@ -146,6 +146,7 @@ struct cred {
        void            *security;      /* subjective LSM security */
 #endif
        struct user_struct *user;       /* real user ID subscription */
+       struct user_namespace *user_ns; /* cached user->user_ns */
        struct group_info *group_info;  /* supplementary groups for euid/fsgid */
        struct rcu_head rcu;            /* RCU deletion hook */
 };
@@ -354,10 +355,15 @@ static inline void put_cred(const struct cred *_cred)
 #define current_fsgid()        (current_cred_xxx(fsgid))
 #define current_cap()          (current_cred_xxx(cap_effective))
 #define current_user()         (current_cred_xxx(user))
-#define _current_user_ns()     (current_cred_xxx(user)->user_ns)
 #define current_security()     (current_cred_xxx(security))
 
-extern struct user_namespace *current_user_ns(void);
+#ifdef CONFIG_USER_NS
+#define current_user_ns() (current_cred_xxx(user_ns))
+#else
+extern struct user_namespace init_user_ns;
+#define current_user_ns() (&init_user_ns)
+#endif
+
 
 #define current_uid_gid(_uid, _gid)            \
 do {                                           \
index ab8dfc0..c66111a 100644 (file)
@@ -47,6 +47,38 @@ extern int __must_check bus_create_file(struct bus_type *,
                                        struct bus_attribute *);
 extern void bus_remove_file(struct bus_type *, struct bus_attribute *);
 
+/**
+ * struct bus_type - The bus type of the device
+ *
+ * @name:      The name of the bus.
+ * @bus_attrs: Default attributes of the bus.
+ * @dev_attrs: Default attributes of the devices on the bus.
+ * @drv_attrs: Default attributes of the device drivers on the bus.
+ * @match:     Called, perhaps multiple times, whenever a new device or driver
+ *             is added for this bus. It should return a nonzero value if the
+ *             given device can be handled by the given driver.
+ * @uevent:    Called when a device is added, removed, or a few other things
+ *             that generate uevents to add the environment variables.
+ * @probe:     Called when a new device or driver add to this bus, and callback
+ *             the specific driver's probe to initial the matched device.
+ * @remove:    Called when a device removed from this bus.
+ * @shutdown:  Called at shut-down time to quiesce the device.
+ * @suspend:   Called when a device on this bus wants to go to sleep mode.
+ * @resume:    Called to bring a device on this bus out of sleep mode.
+ * @pm:                Power management operations of this bus, callback the specific
+ *             device driver's pm-ops.
+ * @p:         The private data of the driver core, only the driver core can
+ *             touch this.
+ *
+ * A bus is a channel between the processor and one or more devices. For the
+ * purposes of the device model, all devices are connected via a bus, even if
+ * it is an internal, virtual, "platform" bus. Buses can plug into each other.
+ * A USB controller is usually a PCI device, for example. The device model
+ * represents the actual connections between buses and the devices they control.
+ * A bus is represented by the bus_type structure. It contains the name, the
+ * default attributes, the bus' methods, PM operations, and the driver core's
+ * private data.
+ */
 struct bus_type {
        const char              *name;
        struct bus_attribute    *bus_attrs;
@@ -119,6 +151,37 @@ extern int bus_unregister_notifier(struct bus_type *bus,
 extern struct kset *bus_get_kset(struct bus_type *bus);
 extern struct klist *bus_get_device_klist(struct bus_type *bus);
 
+/**
+ * struct device_driver - The basic device driver structure
+ * @name:      Name of the device driver.
+ * @bus:       The bus which the device of this driver belongs to.
+ * @owner:     The module owner.
+ * @mod_name:  Used for built-in modules.
+ * @suppress_bind_attrs: Disables bind/unbind via sysfs.
+ * @of_match_table: The open firmware table.
+ * @probe:     Called to query the existence of a specific device,
+ *             whether this driver can work with it, and bind the driver
+ *             to a specific device.
+ * @remove:    Called when the device is removed from the system to
+ *             unbind a device from this driver.
+ * @shutdown:  Called at shut-down time to quiesce the device.
+ * @suspend:   Called to put the device to sleep mode. Usually to a
+ *             low power state.
+ * @resume:    Called to bring a device from sleep mode.
+ * @groups:    Default attributes that get created by the driver core
+ *             automatically.
+ * @pm:                Power management operations of the device which matched
+ *             this driver.
+ * @p:         Driver core's private data, no one other than the driver
+ *             core can touch this.
+ *
+ * The device driver-model tracks all of the drivers known to the system.
+ * The main reason for this tracking is to enable the driver core to match
+ * up drivers with new devices. Once drivers are known objects within the
+ * system, however, a number of other things become possible. Device drivers
+ * can export information and configuration variables that are independent
+ * of any specific device.
+ */
 struct device_driver {
        const char              *name;
        struct bus_type         *bus;
@@ -185,8 +248,34 @@ struct device *driver_find_device(struct device_driver *drv,
                                  struct device *start, void *data,
                                  int (*match)(struct device *dev, void *data));
 
-/*
- * device classes
+/**
+ * struct class - device classes
+ * @name:      Name of the class.
+ * @owner:     The module owner.
+ * @class_attrs: Default attributes of this class.
+ * @dev_attrs: Default attributes of the devices belong to the class.
+ * @dev_bin_attrs: Default binary attributes of the devices belong to the class.
+ * @dev_kobj:  The kobject that represents this class and links it into the hierarchy.
+ * @dev_uevent:        Called when a device is added, removed from this class, or a
+ *             few other things that generate uevents to add the environment
+ *             variables.
+ * @devnode:   Callback to provide the devtmpfs.
+ * @class_release: Called to release this class.
+ * @dev_release: Called to release the device.
+ * @suspend:   Used to put the device to sleep mode, usually to a low power
+ *             state.
+ * @resume:    Used to bring the device from the sleep mode.
+ * @ns_type:   Callbacks so sysfs can detemine namespaces.
+ * @namespace: Namespace of the device belongs to this class.
+ * @pm:                The default device power management operations of this class.
+ * @p:         The private data of the driver core, no one other than the
+ *             driver core can touch this.
+ *
+ * A class is a higher-level view of a device that abstracts out low-level
+ * implementation details. Drivers may see a SCSI disk or an ATA disk, but,
+ * at the class level, they are all simply disks. Classes allow user space
+ * to work with devices based on what they do, rather than how they are
+ * connected or how they work.
  */
 struct class {
        const char              *name;
@@ -401,6 +490,65 @@ struct device_dma_parameters {
        unsigned long segment_boundary_mask;
 };
 
+/**
+ * struct device - The basic device structure
+ * @parent:    The device's "parent" device, the device to which it is attached.
+ *             In most cases, a parent device is some sort of bus or host
+ *             controller. If parent is NULL, the device, is a top-level device,
+ *             which is not usually what you want.
+ * @p:         Holds the private data of the driver core portions of the device.
+ *             See the comment of the struct device_private for detail.
+ * @kobj:      A top-level, abstract class from which other classes are derived.
+ * @init_name: Initial name of the device.
+ * @type:      The type of device.
+ *             This identifies the device type and carries type-specific
+ *             information.
+ * @mutex:     Mutex to synchronize calls to its driver.
+ * @bus:       Type of bus device is on.
+ * @driver:    Which driver has allocated this
+ * @platform_data: Platform data specific to the device.
+ *             Example: For devices on custom boards, as typical of embedded
+ *             and SOC based hardware, Linux often uses platform_data to point
+ *             to board-specific structures describing devices and how they
+ *             are wired.  That can include what ports are available, chip
+ *             variants, which GPIO pins act in what additional roles, and so
+ *             on.  This shrinks the "Board Support Packages" (BSPs) and
+ *             minimizes board-specific #ifdefs in drivers.
+ * @power:     For device power management.
+ *             See Documentation/power/devices.txt for details.
+ * @pwr_domain:        Provide callbacks that are executed during system suspend,
+ *             hibernation, system resume and during runtime PM transitions
+ *             along with subsystem-level and driver-level callbacks.
+ * @numa_node: NUMA node this device is close to.
+ * @dma_mask:  Dma mask (if dma'ble device).
+ * @coherent_dma_mask: Like dma_mask, but for alloc_coherent mapping as not all
+ *             hardware supports 64-bit addresses for consistent allocations
+ *             such descriptors.
+ * @dma_parms: A low level driver may set these to teach IOMMU code about
+ *             segment limitations.
+ * @dma_pools: Dma pools (if dma'ble device).
+ * @dma_mem:   Internal for coherent mem override.
+ * @archdata:  For arch-specific additions.
+ * @of_node:   Associated device tree node.
+ * @of_match:  Matching of_device_id from driver.
+ * @devt:      For creating the sysfs "dev".
+ * @devres_lock: Spinlock to protect the resource of the device.
+ * @devres_head: The resources list of the device.
+ * @knode_class: The node used to add the device to the class list.
+ * @class:     The class of the device.
+ * @groups:    Optional attribute groups.
+ * @release:   Callback to free the device after all references have
+ *             gone away. This should be set by the allocator of the
+ *             device (i.e. the bus driver that discovered the device).
+ *
+ * At the lowest level, every device in a Linux system is represented by an
+ * instance of struct device. The device structure contains the information
+ * that the device model core needs to model the system. Most subsystems,
+ * however, track additional information about the devices they host. As a
+ * result, it is rare for devices to be represented by bare device structures;
+ * instead, that structure, like kobject structures, is usually embedded within
+ * a higher-level representation of the device.
+ */
 struct device {
        struct device           *parent;
 
@@ -408,7 +556,7 @@ struct device {
 
        struct kobject kobj;
        const char              *init_name; /* initial name of the device */
-       struct device_type      *type;
+       const struct device_type *type;
 
        struct mutex            mutex;  /* mutex to synchronize calls to
                                         * its driver.
@@ -442,7 +590,6 @@ struct device {
        struct dev_archdata     archdata;
 
        struct device_node      *of_node; /* associated device tree node */
-       const struct of_device_id *of_match; /* matching of_device_id from driver */
 
        dev_t                   devt;   /* dev_t, creates the sysfs "dev" */
 
@@ -557,7 +704,7 @@ extern int device_move(struct device *dev, struct device *new_parent,
 extern const char *device_get_devnode(struct device *dev,
                                      mode_t *mode, const char **tmp);
 extern void *dev_get_drvdata(const struct device *dev);
-extern void dev_set_drvdata(struct device *dev, void *data);
+extern int dev_set_drvdata(struct device *dev, void *data);
 
 /*
  * Root device objects for grouping under /sys/devices
@@ -611,7 +758,7 @@ extern int (*platform_notify)(struct device *dev);
 extern int (*platform_notify_remove)(struct device *dev);
 
 
-/**
+/*
  * get_device - atomically increment the reference count for the device.
  *
  */
@@ -633,13 +780,6 @@ static inline int devtmpfs_mount(const char *mountpoint) { return 0; }
 /* drivers/base/power/shutdown.c */
 extern void device_shutdown(void);
 
-#ifndef CONFIG_ARCH_NO_SYSDEV_OPS
-/* drivers/base/sys.c */
-extern void sysdev_shutdown(void);
-#else
-static inline void sysdev_shutdown(void) { }
-#endif
-
 /* debugging and troubleshooting/diagnostic helpers. */
 extern const char *dev_driver_string(const struct device *dev);
 
@@ -742,13 +882,17 @@ do {                                                   \
 #endif
 
 /*
- * dev_WARN() acts like dev_printk(), but with the key difference
+ * dev_WARN*() acts like dev_printk(), but with the key difference
  * of using a WARN/WARN_ON to get the message out, including the
  * file/line information and a backtrace.
  */
 #define dev_WARN(dev, format, arg...) \
        WARN(1, "Device: %s\n" format, dev_driver_string(dev), ## arg);
 
+#define dev_WARN_ONCE(dev, condition, format, arg...) \
+       WARN_ONCE(condition, "Device %s\n" format, \
+                       dev_driver_string(dev), ## arg)
+
 /* Create alias, so I can be autoloaded. */
 #define MODULE_ALIAS_CHARDEV(major,minor) \
        MODULE_ALIAS("char-major-" __stringify(major) "-" __stringify(minor))
index df728c1..6a82748 100644 (file)
@@ -832,6 +832,7 @@ struct fb_tile_ops {
 #define FBINFO_CAN_FORCE_OUTPUT     0x200000
 
 struct fb_info {
+       atomic_t count;
        int node;
        int flags;
        struct mutex lock;              /* Lock for open/release/ioctl funcs */
index dbd860a..cdf9495 100644 (file)
@@ -358,7 +358,6 @@ struct inodes_stat_t {
 #define FS_EXTENT_FL                   0x00080000 /* Extents */
 #define FS_DIRECTIO_FL                 0x00100000 /* Use direct i/o */
 #define FS_NOCOW_FL                    0x00800000 /* Do not cow file */
-#define FS_COW_FL                      0x02000000 /* Cow file */
 #define FS_RESERVED_FL                 0x80000000 /* reserved for ext2 lib */
 
 #define FS_FL_USER_VISIBLE             0x0003DFFF /* User visible flags */
index bfb8f93..56d8fc8 100644 (file)
@@ -353,6 +353,8 @@ extern unsigned long get_zeroed_page(gfp_t gfp_mask);
 
 void *alloc_pages_exact(size_t size, gfp_t gfp_mask);
 void free_pages_exact(void *virt, size_t size);
+/* This is different from alloc_pages_exact_node !!! */
+void *alloc_pages_exact_nid(int nid, size_t size, gfp_t gfp_mask);
 
 #define __get_free_page(gfp_mask) \
                __get_free_pages((gfp_mask), 0)
index caa151f..689496b 100644 (file)
@@ -134,7 +134,6 @@ extern struct cred init_cred;
        .stack          = &init_thread_info,                            \
        .usage          = ATOMIC_INIT(2),                               \
        .flags          = PF_KTHREAD,                                   \
-       .lock_depth     = -1,                                           \
        .prio           = MAX_PRIO-20,                                  \
        .static_prio    = MAX_PRIO-20,                                  \
        .normal_prio    = MAX_PRIO-20,                                  \
index bea0ac7..6c12989 100644 (file)
@@ -414,7 +414,6 @@ enum
        TASKLET_SOFTIRQ,
        SCHED_SOFTIRQ,
        HRTIMER_SOFTIRQ,
-       RCU_SOFTIRQ,    /* Preferable RCU should always be the last softirq */
 
        NR_SOFTIRQS
 };
index 09a3080..8b45384 100644 (file)
@@ -53,12 +53,13 @@ typedef     void (*irq_preflow_handler_t)(struct irq_data *data);
  * Bits which can be modified via irq_set/clear/modify_status_flags()
  * IRQ_LEVEL                   - Interrupt is level type. Will be also
  *                               updated in the code when the above trigger
- *                               bits are modified via set_irq_type()
+ *                               bits are modified via irq_set_irq_type()
  * IRQ_PER_CPU                 - Mark an interrupt PER_CPU. Will protect
  *                               it from affinity setting
  * IRQ_NOPROBE                 - Interrupt cannot be probed by autoprobing
  * IRQ_NOREQUEST               - Interrupt cannot be requested via
  *                               request_irq()
+ * IRQ_NOTHREAD                        - Interrupt cannot be threaded
  * IRQ_NOAUTOEN                        - Interrupt is not automatically enabled in
  *                               request/setup_irq()
  * IRQ_NO_BALANCING            - Interrupt cannot be balanced (affinity set)
@@ -85,6 +86,7 @@ enum {
        IRQ_NO_BALANCING        = (1 << 13),
        IRQ_MOVE_PCNTXT         = (1 << 14),
        IRQ_NESTED_THREAD       = (1 << 15),
+       IRQ_NOTHREAD            = (1 << 16),
 };
 
 #define IRQF_MODIFY_MASK       \
@@ -261,23 +263,6 @@ static inline void irqd_clr_chained_irq_inprogress(struct irq_data *d)
  * struct irq_chip - hardware interrupt chip descriptor
  *
  * @name:              name for /proc/interrupts
- * @startup:           deprecated, replaced by irq_startup
- * @shutdown:          deprecated, replaced by irq_shutdown
- * @enable:            deprecated, replaced by irq_enable
- * @disable:           deprecated, replaced by irq_disable
- * @ack:               deprecated, replaced by irq_ack
- * @mask:              deprecated, replaced by irq_mask
- * @mask_ack:          deprecated, replaced by irq_mask_ack
- * @unmask:            deprecated, replaced by irq_unmask
- * @eoi:               deprecated, replaced by irq_eoi
- * @end:               deprecated, will go away with __do_IRQ()
- * @set_affinity:      deprecated, replaced by irq_set_affinity
- * @retrigger:         deprecated, replaced by irq_retrigger
- * @set_type:          deprecated, replaced by irq_set_type
- * @set_wake:          deprecated, replaced by irq_wake
- * @bus_lock:          deprecated, replaced by irq_bus_lock
- * @bus_sync_unlock:   deprecated, replaced by irq_bus_sync_unlock
- *
  * @irq_startup:       start up the interrupt (defaults to ->enable if NULL)
  * @irq_shutdown:      shut down the interrupt (defaults to ->disable if NULL)
  * @irq_enable:                enable the interrupt (defaults to chip->unmask if NULL)
@@ -295,6 +280,9 @@ static inline void irqd_clr_chained_irq_inprogress(struct irq_data *d)
  * @irq_bus_sync_unlock:function to sync and unlock slow bus (i2c) chips
  * @irq_cpu_online:    configure an interrupt source for a secondary CPU
  * @irq_cpu_offline:   un-configure an interrupt source for a secondary CPU
+ * @irq_suspend:       function called from core code on suspend once per chip
+ * @irq_resume:                function called from core code on resume once per chip
+ * @irq_pm_shutdown:   function called from core code on shutdown once per chip
  * @irq_print_chip:    optional to print special chip info in show_interrupts
  * @flags:             chip specific flags
  *
@@ -324,6 +312,10 @@ struct irq_chip {
        void            (*irq_cpu_online)(struct irq_data *data);
        void            (*irq_cpu_offline)(struct irq_data *data);
 
+       void            (*irq_suspend)(struct irq_data *data);
+       void            (*irq_resume)(struct irq_data *data);
+       void            (*irq_pm_shutdown)(struct irq_data *data);
+
        void            (*irq_print_chip)(struct irq_data *data, struct seq_file *p);
 
        unsigned long   flags;
@@ -439,7 +431,7 @@ irq_set_handler(unsigned int irq, irq_flow_handler_t handle)
 /*
  * Set a highlevel chained flow handler for a given IRQ.
  * (a chained handler is automatically enabled and set to
- *  IRQ_NOREQUEST and IRQ_NOPROBE)
+ *  IRQ_NOREQUEST, IRQ_NOPROBE, and IRQ_NOTHREAD)
  */
 static inline void
 irq_set_chained_handler(unsigned int irq, irq_flow_handler_t handle)
@@ -469,6 +461,16 @@ static inline void irq_set_probe(unsigned int irq)
        irq_modify_status(irq, IRQ_NOPROBE, 0);
 }
 
+static inline void irq_set_nothread(unsigned int irq)
+{
+       irq_modify_status(irq, 0, IRQ_NOTHREAD);
+}
+
+static inline void irq_set_thread(unsigned int irq)
+{
+       irq_modify_status(irq, IRQ_NOTHREAD, 0);
+}
+
 static inline void irq_set_nested_thread(unsigned int irq, bool nest)
 {
        if (nest)
@@ -573,6 +575,145 @@ static inline int irq_reserve_irq(unsigned int irq)
        return irq_reserve_irqs(irq, 1);
 }
 
+#ifndef irq_reg_writel
+# define irq_reg_writel(val, addr)     writel(val, addr)
+#endif
+#ifndef irq_reg_readl
+# define irq_reg_readl(addr)           readl(addr)
+#endif
+
+/**
+ * struct irq_chip_regs - register offsets for struct irq_gci
+ * @enable:    Enable register offset to reg_base
+ * @disable:   Disable register offset to reg_base
+ * @mask:      Mask register offset to reg_base
+ * @ack:       Ack register offset to reg_base
+ * @eoi:       Eoi register offset to reg_base
+ * @type:      Type configuration register offset to reg_base
+ * @polarity:  Polarity configuration register offset to reg_base
+ */
+struct irq_chip_regs {
+       unsigned long           enable;
+       unsigned long           disable;
+       unsigned long           mask;
+       unsigned long           ack;
+       unsigned long           eoi;
+       unsigned long           type;
+       unsigned long           polarity;
+};
+
+/**
+ * struct irq_chip_type - Generic interrupt chip instance for a flow type
+ * @chip:              The real interrupt chip which provides the callbacks
+ * @regs:              Register offsets for this chip
+ * @handler:           Flow handler associated with this chip
+ * @type:              Chip can handle these flow types
+ *
+ * A irq_generic_chip can have several instances of irq_chip_type when
+ * it requires different functions and register offsets for different
+ * flow types.
+ */
+struct irq_chip_type {
+       struct irq_chip         chip;
+       struct irq_chip_regs    regs;
+       irq_flow_handler_t      handler;
+       u32                     type;
+};
+
+/**
+ * struct irq_chip_generic - Generic irq chip data structure
+ * @lock:              Lock to protect register and cache data access
+ * @reg_base:          Register base address (virtual)
+ * @irq_base:          Interrupt base nr for this chip
+ * @irq_cnt:           Number of interrupts handled by this chip
+ * @mask_cache:                Cached mask register
+ * @type_cache:                Cached type register
+ * @polarity_cache:    Cached polarity register
+ * @wake_enabled:      Interrupt can wakeup from suspend
+ * @wake_active:       Interrupt is marked as an wakeup from suspend source
+ * @num_ct:            Number of available irq_chip_type instances (usually 1)
+ * @private:           Private data for non generic chip callbacks
+ * @list:              List head for keeping track of instances
+ * @chip_types:                Array of interrupt irq_chip_types
+ *
+ * Note, that irq_chip_generic can have multiple irq_chip_type
+ * implementations which can be associated to a particular irq line of
+ * an irq_chip_generic instance. That allows to share and protect
+ * state in an irq_chip_generic instance when we need to implement
+ * different flow mechanisms (level/edge) for it.
+ */
+struct irq_chip_generic {
+       raw_spinlock_t          lock;
+       void __iomem            *reg_base;
+       unsigned int            irq_base;
+       unsigned int            irq_cnt;
+       u32                     mask_cache;
+       u32                     type_cache;
+       u32                     polarity_cache;
+       u32                     wake_enabled;
+       u32                     wake_active;
+       unsigned int            num_ct;
+       void                    *private;
+       struct list_head        list;
+       struct irq_chip_type    chip_types[0];
+};
+
+/**
+ * enum irq_gc_flags - Initialization flags for generic irq chips
+ * @IRQ_GC_INIT_MASK_CACHE:    Initialize the mask_cache by reading mask reg
+ * @IRQ_GC_INIT_NESTED_LOCK:   Set the lock class of the irqs to nested for
+ *                             irq chips which need to call irq_set_wake() on
+ *                             the parent irq. Usually GPIO implementations
+ */
+enum irq_gc_flags {
+       IRQ_GC_INIT_MASK_CACHE          = 1 << 0,
+       IRQ_GC_INIT_NESTED_LOCK         = 1 << 1,
+};
+
+/* Generic chip callback functions */
+void irq_gc_noop(struct irq_data *d);
+void irq_gc_mask_disable_reg(struct irq_data *d);
+void irq_gc_mask_set_bit(struct irq_data *d);
+void irq_gc_mask_clr_bit(struct irq_data *d);
+void irq_gc_unmask_enable_reg(struct irq_data *d);
+void irq_gc_ack(struct irq_data *d);
+void irq_gc_mask_disable_reg_and_ack(struct irq_data *d);
+void irq_gc_eoi(struct irq_data *d);
+int irq_gc_set_wake(struct irq_data *d, unsigned int on);
+
+/* Setup functions for irq_chip_generic */
+struct irq_chip_generic *
+irq_alloc_generic_chip(const char *name, int nr_ct, unsigned int irq_base,
+                      void __iomem *reg_base, irq_flow_handler_t handler);
+void irq_setup_generic_chip(struct irq_chip_generic *gc, u32 msk,
+                           enum irq_gc_flags flags, unsigned int clr,
+                           unsigned int set);
+int irq_setup_alt_chip(struct irq_data *d, unsigned int type);
+void irq_remove_generic_chip(struct irq_chip_generic *gc, u32 msk,
+                            unsigned int clr, unsigned int set);
+
+static inline struct irq_chip_type *irq_data_get_chip_type(struct irq_data *d)
+{
+       return container_of(d->chip, struct irq_chip_type, chip);
+}
+
+#define IRQ_MSK(n) (u32)((n) < 32 ? ((1 << (n)) - 1) : UINT_MAX)
+
+#ifdef CONFIG_SMP
+static inline void irq_gc_lock(struct irq_chip_generic *gc)
+{
+       raw_spin_lock(&gc->lock);
+}
+
+static inline void irq_gc_unlock(struct irq_chip_generic *gc)
+{
+       raw_spin_unlock(&gc->lock);
+}
+#else
+static inline void irq_gc_lock(struct irq_chip_generic *gc) { }
+static inline void irq_gc_unlock(struct irq_chip_generic *gc) { }
+#endif
+
 #endif /* CONFIG_GENERIC_HARDIRQS */
 
 #endif /* !CONFIG_S390 */
index a082905..2d921b3 100644 (file)
@@ -16,16 +16,18 @@ struct timer_rand_state;
  * @irq_data:          per irq and chip data passed down to chip functions
  * @timer_rand_state:  pointer to timer rand state struct
  * @kstat_irqs:                irq stats per cpu
- * @handle_irq:                highlevel irq-events handler [if NULL, __do_IRQ()]
+ * @handle_irq:                highlevel irq-events handler
+ * @preflow_handler:   handler called before the flow handler (currently used by sparc)
  * @action:            the irq action chain
  * @status:            status information
  * @core_internal_state__do_not_mess_with_it: core internal status information
  * @depth:             disable-depth, for nested irq_disable() calls
- * @wake_depth:                enable depth, for multiple set_irq_wake() callers
+ * @wake_depth:                enable depth, for multiple irq_set_irq_wake() callers
  * @irq_count:         stats field to detect stalled irqs
  * @last_unhandled:    aging timer for unhandled count
  * @irqs_unhandled:    stats field for spurious unhandled interrupts
  * @lock:              locking for SMP
+ * @affinity_hint:     hint to user space for preferred irq affinity
  * @affinity_notify:   context for notification of affinity changes
  * @pending_mask:      pending rebalanced interrupts
  * @threads_oneshot:   bitfield to handle shared oneshot threads
@@ -109,10 +111,7 @@ static inline void generic_handle_irq_desc(unsigned int irq, struct irq_desc *de
        desc->handle_irq(irq, desc);
 }
 
-static inline void generic_handle_irq(unsigned int irq)
-{
-       generic_handle_irq_desc(irq, irq_to_desc(irq));
-}
+int generic_handle_irq(unsigned int irq);
 
 /* Test to see if a driver has successfully requested an irq */
 static inline int irq_has_action(unsigned int irq)
index 6efd7a7..3102318 100644 (file)
@@ -113,5 +113,6 @@ extern void usermodehelper_init(void);
 
 extern int usermodehelper_disable(void);
 extern void usermodehelper_enable(void);
+extern bool usermodehelper_is_disabled(void);
 
 #endif /* __LINUX_KMOD_H__ */
index 3a54266..cc6d2aa 100644 (file)
@@ -4,7 +4,7 @@
 #include <linux/types.h>
 #include <linux/stddef.h>
 #include <linux/poison.h>
-#include <linux/prefetch.h>
+#include <linux/const.h>
 
 /*
  * Simple doubly linked list implementation.
@@ -367,18 +367,15 @@ static inline void list_splice_tail_init(struct list_head *list,
  * @head:      the head for your list.
  */
 #define list_for_each(pos, head) \
-       for (pos = (head)->next; prefetch(pos->next), pos != (head); \
-               pos = pos->next)
+       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.
+ * This variant doesn't differ from list_for_each() any more.
+ * We don't do prefetching in either case.
  */
 #define __list_for_each(pos, head) \
        for (pos = (head)->next; pos != (head); pos = pos->next)
@@ -389,8 +386,7 @@ static inline void list_splice_tail_init(struct list_head *list,
  * @head:      the head for your list.
  */
 #define list_for_each_prev(pos, head) \
-       for (pos = (head)->prev; prefetch(pos->prev), pos != (head); \
-               pos = pos->prev)
+       for (pos = (head)->prev; pos != (head); pos = pos->prev)
 
 /**
  * list_for_each_safe - iterate over a list safe against removal of list entry
@@ -410,7 +406,7 @@ static inline void list_splice_tail_init(struct list_head *list,
  */
 #define list_for_each_prev_safe(pos, n, head) \
        for (pos = (head)->prev, n = pos->prev; \
-            prefetch(pos->prev), pos != (head); \
+            pos != (head); \
             pos = n, n = pos->prev)
 
 /**
@@ -421,7 +417,7 @@ static inline void list_splice_tail_init(struct list_head *list,
  */
 #define list_for_each_entry(pos, head, member)                         \
        for (pos = list_entry((head)->next, typeof(*pos), member);      \
-            prefetch(pos->member.next), &pos->member != (head);        \
+            &pos->member != (head);    \
             pos = list_entry(pos->member.next, typeof(*pos), member))
 
 /**
@@ -432,7 +428,7 @@ static inline void list_splice_tail_init(struct list_head *list,
  */
 #define list_for_each_entry_reverse(pos, head, member)                 \
        for (pos = list_entry((head)->prev, typeof(*pos), member);      \
-            prefetch(pos->member.prev), &pos->member != (head);        \
+            &pos->member != (head);    \
             pos = list_entry(pos->member.prev, typeof(*pos), member))
 
 /**
@@ -457,7 +453,7 @@ static inline void list_splice_tail_init(struct list_head *list,
  */
 #define list_for_each_entry_continue(pos, head, member)                \
        for (pos = list_entry(pos->member.next, typeof(*pos), member);  \
-            prefetch(pos->member.next), &pos->member != (head);        \
+            &pos->member != (head);    \
             pos = list_entry(pos->member.next, typeof(*pos), member))
 
 /**
@@ -471,7 +467,7 @@ static inline void list_splice_tail_init(struct list_head *list,
  */
 #define list_for_each_entry_continue_reverse(pos, head, member)                \
        for (pos = list_entry(pos->member.prev, typeof(*pos), member);  \
-            prefetch(pos->member.prev), &pos->member != (head);        \
+            &pos->member != (head);    \
             pos = list_entry(pos->member.prev, typeof(*pos), member))
 
 /**
@@ -483,7 +479,7 @@ static inline void list_splice_tail_init(struct list_head *list,
  * Iterate over list of given type, continuing from current position.
  */
 #define list_for_each_entry_from(pos, head, member)                    \
-       for (; prefetch(pos->member.next), &pos->member != (head);      \
+       for (; &pos->member != (head);  \
             pos = list_entry(pos->member.next, typeof(*pos), member))
 
 /**
@@ -664,8 +660,7 @@ static inline void hlist_move_list(struct hlist_head *old,
 #define hlist_entry(ptr, type, member) container_of(ptr,type,member)
 
 #define hlist_for_each(pos, head) \
-       for (pos = (head)->first; pos && ({ prefetch(pos->next); 1; }); \
-            pos = pos->next)
+       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; }); \
@@ -680,7 +675,7 @@ static inline void hlist_move_list(struct hlist_head *old,
  */
 #define hlist_for_each_entry(tpos, pos, head, member)                   \
        for (pos = (head)->first;                                        \
-            pos && ({ prefetch(pos->next); 1;}) &&                      \
+            pos &&                                                      \
                ({ tpos = hlist_entry(pos, typeof(*tpos), member); 1;}); \
             pos = pos->next)
 
@@ -692,7 +687,7 @@ static inline void hlist_move_list(struct hlist_head *old,
  */
 #define hlist_for_each_entry_continue(tpos, pos, member)                \
        for (pos = (pos)->next;                                          \
-            pos && ({ prefetch(pos->next); 1;}) &&                      \
+            pos &&                                                      \
                ({ tpos = hlist_entry(pos, typeof(*tpos), member); 1;}); \
             pos = pos->next)
 
@@ -703,7 +698,7 @@ static inline void hlist_move_list(struct hlist_head *old,
  * @member:    the name of the hlist_node within the struct.
  */
 #define hlist_for_each_entry_from(tpos, pos, member)                    \
-       for (; pos && ({ prefetch(pos->next); 1;}) &&                    \
+       for (; pos &&                                                    \
                ({ tpos = hlist_entry(pos, typeof(*tpos), member); 1;}); \
             pos = pos->next)
 
index eb792cb..bcb793e 100644 (file)
@@ -183,6 +183,7 @@ struct mmc_host {
        struct work_struct      clk_gate_work; /* delayed clock gate */
        unsigned int            clk_old;        /* old clock value cache */
        spinlock_t              clk_lock;       /* lock for clk fields */
+       struct mutex            clk_gate_mutex; /* mutex for clock gating */
 #endif
 
        /* host specific block data */
index 5de4204..d9ca2d5 100644 (file)
@@ -64,6 +64,9 @@ struct module_version_attribute {
        const char *version;
 } __attribute__ ((__aligned__(sizeof(void *))));
 
+extern ssize_t __modver_version_show(struct module_attribute *,
+                                    struct module *, char *);
+
 struct module_kobject
 {
        struct kobject kobj;
@@ -172,12 +175,7 @@ extern struct module __this_module;
 #define MODULE_VERSION(_version) MODULE_INFO(version, _version)
 #else
 #define MODULE_VERSION(_version)                                       \
-       extern ssize_t __modver_version_show(struct module_attribute *, \
-                                            struct module *, char *);  \
-       static struct module_version_attribute __modver_version_attr    \
-       __used                                                          \
-    __attribute__ ((__section__ ("__modver"),aligned(sizeof(void *)))) \
-       = {                                                             \
+       static struct module_version_attribute ___modver_attr = {       \
                .mattr  = {                                             \
                        .attr   = {                                     \
                                .name   = "version",                    \
@@ -187,7 +185,10 @@ extern struct module __this_module;
                },                                                      \
                .module_name    = KBUILD_MODNAME,                       \
                .version        = _version,                             \
-       }
+       };                                                              \
+       static const struct module_version_attribute                    \
+       __used __attribute__ ((__section__ ("__modver")))               \
+       * __moduleparam_const __modver_attr = &___modver_attr
 #endif
 
 /* Optional firmware file (or files) needed by the module
@@ -223,7 +224,7 @@ struct module_use {
        extern void *__crc_##sym __attribute__((weak));         \
        static const unsigned long __kcrctab_##sym              \
        __used                                                  \
-       __attribute__((section("__kcrctab" sec), unused))       \
+       __attribute__((section("___kcrctab" sec "+" #sym), unused))     \
        = (unsigned long) &__crc_##sym;
 #else
 #define __CRC_SYMBOL(sym, sec)
@@ -238,7 +239,7 @@ struct module_use {
        = MODULE_SYMBOL_PREFIX #sym;                            \
        static const struct kernel_symbol __ksymtab_##sym       \
        __used                                                  \
-       __attribute__((section("__ksymtab" sec), unused))       \
+       __attribute__((section("___ksymtab" sec "+" #sym), unused))     \
        = { (unsigned long)&sym, __kstrtab_##sym }
 
 #define EXPORT_SYMBOL(sym)                                     \
@@ -367,34 +368,35 @@ struct module
        struct module_notes_attrs *notes_attrs;
 #endif
 
+       /* The command line arguments (may be mangled).  People like
+          keeping pointers to this stuff */
+       char *args;
+
 #ifdef CONFIG_SMP
        /* Per-cpu data. */
        void __percpu *percpu;
        unsigned int percpu_size;
 #endif
 
-       /* The command line arguments (may be mangled).  People like
-          keeping pointers to this stuff */
-       char *args;
 #ifdef CONFIG_TRACEPOINTS
-       struct tracepoint * const *tracepoints_ptrs;
        unsigned int num_tracepoints;
+       struct tracepoint * const *tracepoints_ptrs;
 #endif
 #ifdef HAVE_JUMP_LABEL
        struct jump_entry *jump_entries;
        unsigned int num_jump_entries;
 #endif
 #ifdef CONFIG_TRACING
-       const char **trace_bprintk_fmt_start;
        unsigned int num_trace_bprintk_fmt;
+       const char **trace_bprintk_fmt_start;
 #endif
 #ifdef CONFIG_EVENT_TRACING
        struct ftrace_event_call **trace_events;
        unsigned int num_trace_events;
 #endif
 #ifdef CONFIG_FTRACE_MCOUNT_RECORD
-       unsigned long *ftrace_callsites;
        unsigned int num_ftrace_callsites;
+       unsigned long *ftrace_callsites;
 #endif
 
 #ifdef CONFIG_MODULE_UNLOAD
@@ -475,8 +477,9 @@ const struct kernel_symbol *find_symbol(const char *name,
                                        bool warn);
 
 /* Walk the exported symbol table */
-bool each_symbol(bool (*fn)(const struct symsearch *arr, struct module *owner,
-                           unsigned int symnum, void *data), void *data);
+bool each_symbol_section(bool (*fn)(const struct symsearch *arr,
+                                   struct module *owner,
+                                   void *data), void *data);
 
 /* Returns 0 and fills in value, defined and namebuf, or -ERANGE if
    symnum out of range. */
index 07b4195..ddaae98 100644 (file)
@@ -67,9 +67,9 @@ struct kparam_string {
 struct kparam_array
 {
        unsigned int max;
+       unsigned int elemsize;
        unsigned int *num;
        const struct kernel_param_ops *ops;
-       unsigned int elemsize;
        void *elem;
 };
 
@@ -371,8 +371,9 @@ extern int param_get_invbool(char *buffer, const struct kernel_param *kp);
  */
 #define module_param_array_named(name, array, type, nump, perm)                \
        static const struct kparam_array __param_arr_##name             \
-       = { ARRAY_SIZE(array), nump, &param_ops_##type,                 \
-           sizeof(array[0]), array };                                  \
+       = { .max = ARRAY_SIZE(array), .num = nump,                      \
+           .ops = &param_ops_##type,                                   \
+           .elemsize = sizeof(array[0]), .elem = array };              \
        __module_param_call(MODULE_PARAM_PREFIX, name,                  \
                            &param_array_ops,                           \
                            .arr = &__param_arr_##name,                 \
index 94b48bd..c75471d 100644 (file)
@@ -51,7 +51,7 @@ struct mutex {
        spinlock_t              wait_lock;
        struct list_head        wait_list;
 #if defined(CONFIG_DEBUG_MUTEXES) || defined(CONFIG_SMP)
-       struct thread_info      *owner;
+       struct task_struct      *owner;
 #endif
 #ifdef CONFIG_DEBUG_MUTEXES
        const char              *name;
index 890dce2..7e371f7 100644 (file)
@@ -233,6 +233,7 @@ struct nfs4_layoutget {
        struct nfs4_layoutget_args args;
        struct nfs4_layoutget_res res;
        struct pnfs_layout_segment **lsegpp;
+       gfp_t gfp_flags;
 };
 
 struct nfs4_getdeviceinfo_args {
index 8bfe6c1..ae56384 100644 (file)
@@ -21,8 +21,7 @@ extern void of_device_make_bus_id(struct device *dev);
 static inline int of_driver_match_device(struct device *dev,
                                         const struct device_driver *drv)
 {
-       dev->of_match = of_match_device(drv->of_match_table, dev);
-       return dev->of_match != NULL;
+       return of_match_device(drv->of_match_table, dev) != NULL;
 }
 
 extern struct platform_device *of_dev_get(struct platform_device *dev);
@@ -58,6 +57,11 @@ static inline int of_device_uevent(struct device *dev,
 
 static inline void of_device_node_put(struct device *dev) { }
 
+static inline const struct of_device_id *of_match_device(
+               const struct of_device_id *matches, const struct device *dev)
+{
+       return NULL;
+}
 #endif /* CONFIG_OF_DEVICE */
 
 #endif /* _LINUX_OF_DEVICE_H */
diff --git a/include/linux/pci-ats.h b/include/linux/pci-ats.h
new file mode 100644 (file)
index 0000000..655824f
--- /dev/null
@@ -0,0 +1,52 @@
+#ifndef LINUX_PCI_ATS_H
+#define LINUX_PCI_ATS_H
+
+/* Address Translation Service */
+struct pci_ats {
+       int pos;        /* capability position */
+       int stu;        /* Smallest Translation Unit */
+       int qdep;       /* Invalidate Queue Depth */
+       int ref_cnt;    /* Physical Function reference count */
+       unsigned int is_enabled:1;      /* Enable bit is set */
+};
+
+#ifdef CONFIG_PCI_IOV
+
+extern int pci_enable_ats(struct pci_dev *dev, int ps);
+extern void pci_disable_ats(struct pci_dev *dev);
+extern int pci_ats_queue_depth(struct pci_dev *dev);
+/**
+ * pci_ats_enabled - query the ATS status
+ * @dev: the PCI device
+ *
+ * Returns 1 if ATS capability is enabled, or 0 if not.
+ */
+static inline int pci_ats_enabled(struct pci_dev *dev)
+{
+       return dev->ats && dev->ats->is_enabled;
+}
+
+#else /* CONFIG_PCI_IOV */
+
+static inline int pci_enable_ats(struct pci_dev *dev, int ps)
+{
+       return -ENODEV;
+}
+
+static inline void pci_disable_ats(struct pci_dev *dev)
+{
+}
+
+static inline int pci_ats_queue_depth(struct pci_dev *dev)
+{
+       return -ENODEV;
+}
+
+static inline int pci_ats_enabled(struct pci_dev *dev)
+{
+       return 0;
+}
+
+#endif /* CONFIG_PCI_IOV */
+
+#endif /* LINUX_PCI_ATS_H*/
index 744942c..ede1a80 100644 (file)
@@ -150,9 +150,6 @@ extern struct platform_device *platform_create_bundle(struct platform_driver *dr
                                        struct resource *res, unsigned int n_res,
                                        const void *data, size_t size);
 
-extern const struct dev_pm_ops * platform_bus_get_pm_ops(void);
-extern void platform_bus_set_pm_ops(const struct dev_pm_ops *pm);
-
 /* early platform driver interface */
 struct early_platform_driver {
        const char *class_str;
@@ -205,4 +202,64 @@ static inline char *early_platform_driver_setup_func(void)         \
 }
 #endif /* MODULE */
 
+#ifdef CONFIG_PM_SLEEP
+extern int platform_pm_prepare(struct device *dev);
+extern void platform_pm_complete(struct device *dev);
+#else
+#define platform_pm_prepare    NULL
+#define platform_pm_complete   NULL
+#endif
+
+#ifdef CONFIG_SUSPEND
+extern int platform_pm_suspend(struct device *dev);
+extern int platform_pm_suspend_noirq(struct device *dev);
+extern int platform_pm_resume(struct device *dev);
+extern int platform_pm_resume_noirq(struct device *dev);
+#else
+#define platform_pm_suspend            NULL
+#define platform_pm_resume             NULL
+#define platform_pm_suspend_noirq      NULL
+#define platform_pm_resume_noirq       NULL
+#endif
+
+#ifdef CONFIG_HIBERNATE_CALLBACKS
+extern int platform_pm_freeze(struct device *dev);
+extern int platform_pm_freeze_noirq(struct device *dev);
+extern int platform_pm_thaw(struct device *dev);
+extern int platform_pm_thaw_noirq(struct device *dev);
+extern int platform_pm_poweroff(struct device *dev);
+extern int platform_pm_poweroff_noirq(struct device *dev);
+extern int platform_pm_restore(struct device *dev);
+extern int platform_pm_restore_noirq(struct device *dev);
+#else
+#define platform_pm_freeze             NULL
+#define platform_pm_thaw               NULL
+#define platform_pm_poweroff           NULL
+#define platform_pm_restore            NULL
+#define platform_pm_freeze_noirq       NULL
+#define platform_pm_thaw_noirq         NULL
+#define platform_pm_poweroff_noirq     NULL
+#define platform_pm_restore_noirq      NULL
+#endif
+
+#ifdef CONFIG_PM_SLEEP
+#define USE_PLATFORM_PM_SLEEP_OPS \
+       .prepare = platform_pm_prepare, \
+       .complete = platform_pm_complete, \
+       .suspend = platform_pm_suspend, \
+       .resume = platform_pm_resume, \
+       .freeze = platform_pm_freeze, \
+       .thaw = platform_pm_thaw, \
+       .poweroff = platform_pm_poweroff, \
+       .restore = platform_pm_restore, \
+       .suspend_noirq = platform_pm_suspend_noirq, \
+       .resume_noirq = platform_pm_resume_noirq, \
+       .freeze_noirq = platform_pm_freeze_noirq, \
+       .thaw_noirq = platform_pm_thaw_noirq, \
+       .poweroff_noirq = platform_pm_poweroff_noirq, \
+       .restore_noirq = platform_pm_restore_noirq,
+#else
+#define USE_PLATFORM_PM_SLEEP_OPS
+#endif
+
 #endif /* _PLATFORM_DEVICE_H_ */
index 512e091..3160648 100644 (file)
@@ -460,6 +460,7 @@ struct dev_pm_info {
        unsigned long           active_jiffies;
        unsigned long           suspended_jiffies;
        unsigned long           accounting_timestamp;
+       void                    *subsys_data;  /* Owned by the subsystem. */
 #endif
 };
 
@@ -529,21 +530,17 @@ struct dev_power_domain {
  */
 
 #ifdef CONFIG_PM_SLEEP
-#ifndef CONFIG_ARCH_NO_SYSDEV_OPS
-extern int sysdev_suspend(pm_message_t state);
-extern int sysdev_resume(void);
-#else
-static inline int sysdev_suspend(pm_message_t state) { return 0; }
-static inline int sysdev_resume(void) { return 0; }
-#endif
-
 extern void device_pm_lock(void);
 extern void dpm_resume_noirq(pm_message_t state);
 extern void dpm_resume_end(pm_message_t state);
+extern void dpm_resume(pm_message_t state);
+extern void dpm_complete(pm_message_t state);
 
 extern void device_pm_unlock(void);
 extern int dpm_suspend_noirq(pm_message_t state);
 extern int dpm_suspend_start(pm_message_t state);
+extern int dpm_suspend(pm_message_t state);
+extern int dpm_prepare(pm_message_t state);
 
 extern void __suspend_report_result(const char *function, void *fn, int ret);
 
@@ -553,6 +550,16 @@ extern void __suspend_report_result(const char *function, void *fn, int ret);
        } while (0)
 
 extern int device_pm_wait_for_dev(struct device *sub, struct device *dev);
+
+extern int pm_generic_prepare(struct device *dev);
+extern int pm_generic_suspend(struct device *dev);
+extern int pm_generic_resume(struct device *dev);
+extern int pm_generic_freeze(struct device *dev);
+extern int pm_generic_thaw(struct device *dev);
+extern int pm_generic_restore(struct device *dev);
+extern int pm_generic_poweroff(struct device *dev);
+extern void pm_generic_complete(struct device *dev);
+
 #else /* !CONFIG_PM_SLEEP */
 
 #define device_pm_lock() do {} while (0)
@@ -569,6 +576,15 @@ static inline int device_pm_wait_for_dev(struct device *a, struct device *b)
 {
        return 0;
 }
+
+#define pm_generic_prepare     NULL
+#define pm_generic_suspend     NULL
+#define pm_generic_resume      NULL
+#define pm_generic_freeze      NULL
+#define pm_generic_thaw                NULL
+#define pm_generic_restore     NULL
+#define pm_generic_poweroff    NULL
+#define pm_generic_complete    NULL
 #endif /* !CONFIG_PM_SLEEP */
 
 /* How to reorder dpm_list after device_move() */
@@ -579,11 +595,4 @@ enum dpm_order {
        DPM_ORDER_DEV_LAST,
 };
 
-extern int pm_generic_suspend(struct device *dev);
-extern int pm_generic_resume(struct device *dev);
-extern int pm_generic_freeze(struct device *dev);
-extern int pm_generic_thaw(struct device *dev);
-extern int pm_generic_restore(struct device *dev);
-extern int pm_generic_poweroff(struct device *dev);
-
 #endif /* _LINUX_PM_H */
index 8de9aa6..878cf84 100644 (file)
@@ -245,4 +245,46 @@ static inline void pm_runtime_dont_use_autosuspend(struct device *dev)
        __pm_runtime_use_autosuspend(dev, false);
 }
 
+struct pm_clk_notifier_block {
+       struct notifier_block nb;
+       struct dev_power_domain *pwr_domain;
+       char *con_ids[];
+};
+
+#ifdef CONFIG_PM_RUNTIME_CLK
+extern int pm_runtime_clk_init(struct device *dev);
+extern void pm_runtime_clk_destroy(struct device *dev);
+extern int pm_runtime_clk_add(struct device *dev, const char *con_id);
+extern void pm_runtime_clk_remove(struct device *dev, const char *con_id);
+extern int pm_runtime_clk_suspend(struct device *dev);
+extern int pm_runtime_clk_resume(struct device *dev);
+#else
+static inline int pm_runtime_clk_init(struct device *dev)
+{
+       return -EINVAL;
+}
+static inline void pm_runtime_clk_destroy(struct device *dev)
+{
+}
+static inline int pm_runtime_clk_add(struct device *dev, const char *con_id)
+{
+       return -EINVAL;
+}
+static inline void pm_runtime_clk_remove(struct device *dev, const char *con_id)
+{
+}
+#define pm_runtime_clock_suspend       NULL
+#define pm_runtime_clock_resume                NULL
+#endif
+
+#ifdef CONFIG_HAVE_CLK
+extern void pm_runtime_clk_add_notifier(struct bus_type *bus,
+                                       struct pm_clk_notifier_block *clknb);
+#else
+static inline void pm_runtime_clk_add_notifier(struct bus_type *bus,
+                                       struct pm_clk_notifier_block *clknb)
+{
+}
+#endif
+
 #endif
index d51243a..808227d 100644 (file)
@@ -5,6 +5,7 @@
 #include <linux/list.h>
 #include <linux/sched.h>
 #include <linux/timex.h>
+#include <linux/alarmtimer.h>
 
 union cpu_time_count {
        cputime_t cpu;
@@ -80,6 +81,7 @@ struct k_itimer {
                        unsigned long incr;
                        unsigned long expires;
                } mmtimer;
+               struct alarm alarmtimer;
        } it;
 };
 
index 838c114..eaf4350 100644 (file)
@@ -208,6 +208,8 @@ static inline struct proc_dir_entry *proc_symlink(const char *name,
                struct proc_dir_entry *parent,const char *dest) {return NULL;}
 static inline struct proc_dir_entry *proc_mkdir(const char *name,
        struct proc_dir_entry *parent) {return NULL;}
+static inline struct proc_dir_entry *proc_mkdir_mode(const char *name,
+       mode_t mode, struct proc_dir_entry *parent) { return NULL; }
 
 static inline struct proc_dir_entry *create_proc_read_entry(const char *name,
        mode_t mode, struct proc_dir_entry *base, 
index 7066acb..033b507 100644 (file)
@@ -136,6 +136,14 @@ static inline void rb_set_color(struct rb_node *rb, int color)
 #define RB_EMPTY_NODE(node)    (rb_parent(node) == node)
 #define RB_CLEAR_NODE(node)    (rb_set_parent(node, node))
 
+static inline void rb_init_node(struct rb_node *rb)
+{
+       rb->rb_parent_color = 0;
+       rb->rb_right = NULL;
+       rb->rb_left = NULL;
+       RB_CLEAR_NODE(rb);
+}
+
 extern void rb_insert_color(struct rb_node *, struct rb_root *);
 extern void rb_erase(struct rb_node *, struct rb_root *);
 
index 2dea94f..e3beb31 100644 (file)
@@ -253,7 +253,7 @@ static inline void list_splice_init_rcu(struct list_head *list,
  */
 #define list_for_each_entry_rcu(pos, head, member) \
        for (pos = list_entry_rcu((head)->next, typeof(*pos), member); \
-               prefetch(pos->member.next), &pos->member != (head); \
+               &pos->member != (head); \
                pos = list_entry_rcu(pos->member.next, typeof(*pos), member))
 
 
@@ -270,7 +270,7 @@ static inline void list_splice_init_rcu(struct list_head *list,
  */
 #define list_for_each_continue_rcu(pos, head) \
        for ((pos) = rcu_dereference_raw(list_next_rcu(pos)); \
-               prefetch((pos)->next), (pos) != (head); \
+               (pos) != (head); \
                (pos) = rcu_dereference_raw(list_next_rcu(pos)))
 
 /**
@@ -284,7 +284,7 @@ static inline void list_splice_init_rcu(struct list_head *list,
  */
 #define list_for_each_entry_continue_rcu(pos, head, member)            \
        for (pos = list_entry_rcu(pos->member.next, typeof(*pos), member); \
-            prefetch(pos->member.next), &pos->member != (head);        \
+            &pos->member != (head);    \
             pos = list_entry_rcu(pos->member.next, typeof(*pos), member))
 
 /**
@@ -427,7 +427,7 @@ static inline void hlist_add_after_rcu(struct hlist_node *prev,
 
 #define __hlist_for_each_rcu(pos, head)                                \
        for (pos = rcu_dereference(hlist_first_rcu(head));      \
-            pos && ({ prefetch(pos->next); 1; });              \
+            pos;                                               \
             pos = rcu_dereference(hlist_next_rcu(pos)))
 
 /**
@@ -443,7 +443,7 @@ static inline void hlist_add_after_rcu(struct hlist_node *prev,
  */
 #define hlist_for_each_entry_rcu(tpos, pos, head, member)              \
        for (pos = rcu_dereference_raw(hlist_first_rcu(head));          \
-               pos && ({ prefetch(pos->next); 1; }) &&                  \
+               pos &&                                                   \
                ({ tpos = hlist_entry(pos, typeof(*tpos), member); 1; }); \
                pos = rcu_dereference_raw(hlist_next_rcu(pos)))
 
@@ -460,7 +460,7 @@ static inline void hlist_add_after_rcu(struct hlist_node *prev,
  */
 #define hlist_for_each_entry_rcu_bh(tpos, pos, head, member)            \
        for (pos = rcu_dereference_bh((head)->first);                    \
-               pos && ({ prefetch(pos->next); 1; }) &&                  \
+               pos &&                                                   \
                ({ tpos = hlist_entry(pos, typeof(*tpos), member); 1; }); \
                pos = rcu_dereference_bh(pos->next))
 
@@ -472,7 +472,7 @@ static inline void hlist_add_after_rcu(struct hlist_node *prev,
  */
 #define hlist_for_each_entry_continue_rcu(tpos, pos, member)           \
        for (pos = rcu_dereference((pos)->next);                        \
-            pos && ({ prefetch(pos->next); 1; }) &&                    \
+            pos &&                                                     \
             ({ tpos = hlist_entry(pos, typeof(*tpos), member); 1; });  \
             pos = rcu_dereference(pos->next))
 
@@ -484,7 +484,7 @@ static inline void hlist_add_after_rcu(struct hlist_node *prev,
  */
 #define hlist_for_each_entry_continue_rcu_bh(tpos, pos, member)                \
        for (pos = rcu_dereference_bh((pos)->next);                     \
-            pos && ({ prefetch(pos->next); 1; }) &&                    \
+            pos &&                                                     \
             ({ tpos = hlist_entry(pos, typeof(*tpos), member); 1; });  \
             pos = rcu_dereference_bh(pos->next))
 
index ff422d2..99f9aa7 100644 (file)
 extern int rcutorture_runnable; /* for sysctl */
 #endif /* #ifdef CONFIG_RCU_TORTURE_TEST */
 
+#if defined(CONFIG_TREE_RCU) || defined(CONFIG_TREE_PREEMPT_RCU)
+extern void rcutorture_record_test_transition(void);
+extern void rcutorture_record_progress(unsigned long vernum);
+#else
+static inline void rcutorture_record_test_transition(void)
+{
+}
+static inline void rcutorture_record_progress(unsigned long vernum)
+{
+}
+#endif
+
 #define UINT_CMP_GE(a, b)      (UINT_MAX / 2 >= (a) - (b))
 #define UINT_CMP_LT(a, b)      (UINT_MAX / 2 < (a) - (b))
 #define ULONG_CMP_GE(a, b)     (ULONG_MAX / 2 >= (a) - (b))
@@ -68,7 +80,6 @@ extern void call_rcu_sched(struct rcu_head *head,
 extern void synchronize_sched(void);
 extern void rcu_barrier_bh(void);
 extern void rcu_barrier_sched(void);
-extern int sched_expedited_torture_stats(char *page);
 
 static inline void __rcu_read_lock_bh(void)
 {
@@ -774,6 +785,7 @@ extern struct debug_obj_descr rcuhead_debug_descr;
 
 static inline void debug_rcu_head_queue(struct rcu_head *head)
 {
+       WARN_ON_ONCE((unsigned long)head & 0x3);
        debug_object_activate(head, &rcuhead_debug_descr);
        debug_object_active_state(head, &rcuhead_debug_descr,
                                  STATE_RCU_HEAD_READY,
@@ -797,4 +809,60 @@ static inline void debug_rcu_head_unqueue(struct rcu_head *head)
 }
 #endif /* #else !CONFIG_DEBUG_OBJECTS_RCU_HEAD */
 
+static __always_inline bool __is_kfree_rcu_offset(unsigned long offset)
+{
+       return offset < 4096;
+}
+
+static __always_inline
+void __kfree_rcu(struct rcu_head *head, unsigned long offset)
+{
+       typedef void (*rcu_callback)(struct rcu_head *);
+
+       BUILD_BUG_ON(!__builtin_constant_p(offset));
+
+       /* See the kfree_rcu() header comment. */
+       BUILD_BUG_ON(!__is_kfree_rcu_offset(offset));
+
+       call_rcu(head, (rcu_callback)offset);
+}
+
+extern void kfree(const void *);
+
+static inline void __rcu_reclaim(struct rcu_head *head)
+{
+       unsigned long offset = (unsigned long)head->func;
+
+       if (__is_kfree_rcu_offset(offset))
+               kfree((void *)head - offset);
+       else
+               head->func(head);
+}
+
+/**
+ * kfree_rcu() - kfree an object after a grace period.
+ * @ptr:       pointer to kfree
+ * @rcu_head:  the name of the struct rcu_head within the type of @ptr.
+ *
+ * Many rcu callbacks functions just call kfree() on the base structure.
+ * These functions are trivial, but their size adds up, and furthermore
+ * when they are used in a kernel module, that module must invoke the
+ * high-latency rcu_barrier() function at module-unload time.
+ *
+ * The kfree_rcu() function handles this issue.  Rather than encoding a
+ * function address in the embedded rcu_head structure, kfree_rcu() instead
+ * encodes the offset of the rcu_head structure within the base structure.
+ * Because the functions are not allowed in the low-order 4096 bytes of
+ * kernel virtual memory, offsets up to 4095 bytes can be accommodated.
+ * If the offset is larger than 4095 bytes, a compile-time error will
+ * be generated in __kfree_rcu().  If this error is triggered, you can
+ * either fall back to use of call_rcu() or rearrange the structure to
+ * position the rcu_head structure into the first 4096 bytes.
+ *
+ * Note that the allowable offset might decrease in the future, for example,
+ * to allow something like kmem_cache_free_rcu().
+ */
+#define kfree_rcu(ptr, rcu_head)                                       \
+       __kfree_rcu(&((ptr)->rcu_head), offsetof(typeof(*(ptr)), rcu_head))
+
 #endif /* __LINUX_RCUPDATE_H */
index 30ebd7c..52b3e02 100644 (file)
@@ -100,6 +100,14 @@ static inline void rcu_note_context_switch(int cpu)
 }
 
 /*
+ * Take advantage of the fact that there is only one CPU, which
+ * allows us to ignore virtualization-based context switches.
+ */
+static inline void rcu_virt_note_context_switch(int cpu)
+{
+}
+
+/*
  * Return the number of grace periods.
  */
 static inline long rcu_batches_completed(void)
index 3a93348..e65d066 100644 (file)
@@ -35,6 +35,16 @@ extern void rcu_note_context_switch(int cpu);
 extern int rcu_needs_cpu(int cpu);
 extern void rcu_cpu_stall_reset(void);
 
+/*
+ * Note a virtualization-based context switch.  This is simply a
+ * wrapper around rcu_note_context_switch(), which allows TINY_RCU
+ * to save a few bytes.
+ */
+static inline void rcu_virt_note_context_switch(int cpu)
+{
+       rcu_note_context_switch(cpu);
+}
+
 #ifdef CONFIG_TREE_PREEMPT_RCU
 
 extern void exit_rcu(void);
@@ -58,9 +68,12 @@ static inline void synchronize_rcu_bh_expedited(void)
 
 extern void rcu_barrier(void);
 
+extern unsigned long rcutorture_testseq;
+extern unsigned long rcutorture_vernum;
 extern long rcu_batches_completed(void);
 extern long rcu_batches_completed_bh(void);
 extern long rcu_batches_completed_sched(void);
+
 extern void rcu_force_quiescent_state(void);
 extern void rcu_bh_force_quiescent_state(void);
 extern void rcu_sched_force_quiescent_state(void);
index 781abd1..12211e1 100644 (file)
@@ -360,7 +360,7 @@ extern signed long schedule_timeout_interruptible(signed long timeout);
 extern signed long schedule_timeout_killable(signed long timeout);
 extern signed long schedule_timeout_uninterruptible(signed long timeout);
 asmlinkage void schedule(void);
-extern int mutex_spin_on_owner(struct mutex *lock, struct thread_info *owner);
+extern int mutex_spin_on_owner(struct mutex *lock, struct task_struct *owner);
 
 struct nsproxy;
 struct user_namespace;
@@ -731,10 +731,6 @@ struct sched_info {
        /* timestamps */
        unsigned long long last_arrival,/* when we last ran on a cpu */
                           last_queued; /* when we were last queued to run */
-#ifdef CONFIG_SCHEDSTATS
-       /* BKL stats */
-       unsigned int bkl_count;
-#endif
 };
 #endif /* defined(CONFIG_SCHEDSTATS) || defined(CONFIG_TASK_DELAY_ACCT) */
 
@@ -868,6 +864,7 @@ static inline int sd_power_saving_flags(void)
 
 struct sched_group {
        struct sched_group *next;       /* Must be a circular list */
+       atomic_t ref;
 
        /*
         * CPU power of this group, SCHED_LOAD_SCALE being max power for a
@@ -882,9 +879,6 @@ struct sched_group {
         * NOTE: this field is variable length. (Allocated dynamically
         * by attaching extra space to the end of the structure,
         * depending on how many CPUs the kernel has booted up with)
-        *
-        * It is also be embedded into static data structures at build
-        * time. (See 'struct static_sched_group' in kernel/sched.c)
         */
        unsigned long cpumask[0];
 };
@@ -894,17 +888,6 @@ static inline struct cpumask *sched_group_cpus(struct sched_group *sg)
        return to_cpumask(sg->cpumask);
 }
 
-enum sched_domain_level {
-       SD_LV_NONE = 0,
-       SD_LV_SIBLING,
-       SD_LV_MC,
-       SD_LV_BOOK,
-       SD_LV_CPU,
-       SD_LV_NODE,
-       SD_LV_ALLNODES,
-       SD_LV_MAX
-};
-
 struct sched_domain_attr {
        int relax_domain_level;
 };
@@ -913,6 +896,8 @@ struct sched_domain_attr {
        .relax_domain_level = -1,                       \
 }
 
+extern int sched_domain_level_max;
+
 struct sched_domain {
        /* These fields must be setup */
        struct sched_domain *parent;    /* top domain must be null terminated */
@@ -930,7 +915,7 @@ struct sched_domain {
        unsigned int forkexec_idx;
        unsigned int smt_gain;
        int flags;                      /* See SD_* */
-       enum sched_domain_level level;
+       int level;
 
        /* Runtime fields. */
        unsigned long last_balance;     /* init to jiffies. units in jiffies */
@@ -973,6 +958,10 @@ struct sched_domain {
 #ifdef CONFIG_SCHED_DEBUG
        char *name;
 #endif
+       union {
+               void *private;          /* used during construction */
+               struct rcu_head rcu;    /* used during destruction */
+       };
 
        unsigned int span_weight;
        /*
@@ -981,9 +970,6 @@ struct sched_domain {
         * NOTE: this field is variable length. (Allocated dynamically
         * by attaching extra space to the end of the structure,
         * depending on how many CPUs the kernel has booted up with)
-        *
-        * It is also be embedded into static data structures at build
-        * time. (See 'struct static_sched_domain' in kernel/sched.c)
         */
        unsigned long span[0];
 };
@@ -1048,8 +1034,12 @@ struct sched_domain;
 #define WF_FORK                0x02            /* child wakeup after fork */
 
 #define ENQUEUE_WAKEUP         1
-#define ENQUEUE_WAKING         2
-#define ENQUEUE_HEAD           4
+#define ENQUEUE_HEAD           2
+#ifdef CONFIG_SMP
+#define ENQUEUE_WAKING         4       /* sched_class::task_waking was called */
+#else
+#define ENQUEUE_WAKING         0
+#endif
 
 #define DEQUEUE_SLEEP          1
 
@@ -1067,12 +1057,11 @@ struct sched_class {
        void (*put_prev_task) (struct rq *rq, struct task_struct *p);
 
 #ifdef CONFIG_SMP
-       int  (*select_task_rq)(struct rq *rq, struct task_struct *p,
-                              int sd_flag, int flags);
+       int  (*select_task_rq)(struct task_struct *p, int sd_flag, int flags);
 
        void (*pre_schedule) (struct rq *this_rq, struct task_struct *task);
        void (*post_schedule) (struct rq *this_rq);
-       void (*task_waking) (struct rq *this_rq, struct task_struct *task);
+       void (*task_waking) (struct task_struct *task);
        void (*task_woken) (struct rq *this_rq, struct task_struct *task);
 
        void (*set_cpus_allowed)(struct task_struct *p,
@@ -1197,13 +1186,11 @@ struct task_struct {
        unsigned int flags;     /* per process flags, defined below */
        unsigned int ptrace;
 
-       int lock_depth;         /* BKL lock depth */
-
 #ifdef CONFIG_SMP
-#ifdef __ARCH_WANT_UNLOCKED_CTXSW
-       int oncpu;
-#endif
+       struct task_struct *wake_entry;
+       int on_cpu;
 #endif
+       int on_rq;
 
        int prio, static_prio, normal_prio;
        unsigned int rt_priority;
@@ -1274,6 +1261,7 @@ struct task_struct {
 
        /* Revert to default priority/policy when forking */
        unsigned sched_reset_on_fork:1;
+       unsigned sched_contributes_to_load:1;
 
        pid_t pid;
        pid_t tgid;
@@ -2063,14 +2051,13 @@ extern void xtime_update(unsigned long ticks);
 
 extern int wake_up_state(struct task_struct *tsk, unsigned int state);
 extern int wake_up_process(struct task_struct *tsk);
-extern void wake_up_new_task(struct task_struct *tsk,
-                               unsigned long clone_flags);
+extern void wake_up_new_task(struct task_struct *tsk);
 #ifdef CONFIG_SMP
  extern void kick_process(struct task_struct *tsk);
 #else
  static inline void kick_process(struct task_struct *tsk) { }
 #endif
-extern void sched_fork(struct task_struct *p, int clone_flags);
+extern void sched_fork(struct task_struct *p);
 extern void sched_dead(struct task_struct *p);
 
 extern void proc_caches_init(void);
@@ -2195,8 +2182,10 @@ extern void set_task_comm(struct task_struct *tsk, char *from);
 extern char *get_task_comm(char *to, struct task_struct *tsk);
 
 #ifdef CONFIG_SMP
+void scheduler_ipi(void);
 extern unsigned long wait_task_inactive(struct task_struct *, long match_state);
 #else
+static inline void scheduler_ipi(void) { }
 static inline unsigned long wait_task_inactive(struct task_struct *p,
                                               long match_state)
 {
index e98cd2e..06d6964 100644 (file)
@@ -88,12 +88,12 @@ static __always_inline unsigned read_seqbegin(const seqlock_t *sl)
        unsigned ret;
 
 repeat:
-       ret = sl->sequence;
-       smp_rmb();
+       ret = ACCESS_ONCE(sl->sequence);
        if (unlikely(ret & 1)) {
                cpu_relax();
                goto repeat;
        }
+       smp_rmb();
 
        return ret;
 }
index fcd2b14..29a68ac 100644 (file)
@@ -7,6 +7,8 @@
 #ifdef __KERNEL__
 #include <linux/list.h>
 
+struct task_struct;
+
 /* for sysctl */
 extern int print_fatal_signals;
 /*
index 9659eff..045f72a 100644 (file)
@@ -404,7 +404,9 @@ extern bool ssb_is_sprom_available(struct ssb_bus *bus);
 
 /* Set a fallback SPROM.
  * See kdoc at the function definition for complete documentation. */
-extern int ssb_arch_set_fallback_sprom(const struct ssb_sprom *sprom);
+extern int ssb_arch_register_fallback_sprom(
+               int (*sprom_callback)(struct ssb_bus *bus,
+               struct ssb_sprom *out));
 
 /* Suspend a SSB bus.
  * Call this from the parent bus suspend routine. */
index a716ee2..a176db2 100644 (file)
@@ -123,6 +123,7 @@ extern char **argv_split(gfp_t gfp, const char *str, int *argcp);
 extern void argv_free(char **argv);
 
 extern bool sysfs_streq(const char *s1, const char *s2);
+extern int strtobool(const char *s, bool *res);
 
 #ifdef CONFIG_BINARY_PRINTF
 int vbin_printf(u32 *bin_buf, size_t size, const char *fmt, va_list args);
index dfb078d..d35e783 100644 (file)
@@ -34,12 +34,6 @@ struct sysdev_class {
        struct list_head        drivers;
        struct sysdev_class_attribute **attrs;
        struct kset             kset;
-#ifndef CONFIG_ARCH_NO_SYSDEV_OPS
-       /* Default operations for these types of devices */
-       int     (*shutdown)(struct sys_device *);
-       int     (*suspend)(struct sys_device *, pm_message_t state);
-       int     (*resume)(struct sys_device *);
-#endif
 };
 
 struct sysdev_class_attribute {
@@ -77,11 +71,6 @@ struct sysdev_driver {
        struct list_head        entry;
        int     (*add)(struct sys_device *);
        int     (*remove)(struct sys_device *);
-#ifndef CONFIG_ARCH_NO_SYSDEV_OPS
-       int     (*shutdown)(struct sys_device *);
-       int     (*suspend)(struct sys_device *, pm_message_t state);
-       int     (*resume)(struct sys_device *);
-#endif
 };
 
 
index 30b8815..c3acda6 100644 (file)
@@ -176,7 +176,6 @@ struct sysfs_dirent *sysfs_get_dirent(struct sysfs_dirent *parent_sd,
                                      const unsigned char *name);
 struct sysfs_dirent *sysfs_get(struct sysfs_dirent *sd);
 void sysfs_put(struct sysfs_dirent *sd);
-void sysfs_printk_last_file(void);
 
 /* Called to clear a ns tag when it is no longer valid */
 void sysfs_exit_ns(enum kobj_ns_type type, const void *tag);
@@ -348,10 +347,6 @@ static inline int __must_check sysfs_init(void)
        return 0;
 }
 
-static inline void sysfs_printk_last_file(void)
-{
-}
-
 #endif /* CONFIG_SYSFS */
 
 #endif /* _SYSFS_H_ */
index 7071ec5..b004e55 100644 (file)
@@ -140,12 +140,12 @@ extern long st_unregister(struct st_proto_s *);
  */
 struct st_data_s {
        unsigned long st_state;
-       struct tty_struct *tty;
        struct sk_buff *tx_skb;
 #define ST_TX_SENDING  1
 #define ST_TX_WAKEUP   2
        unsigned long tx_state;
        struct st_proto_s *list[ST_MAX_CHANNELS];
+       bool is_registered[ST_MAX_CHANNELS];
        unsigned long rx_state;
        unsigned long rx_count;
        struct sk_buff *rx_skb;
@@ -155,6 +155,7 @@ struct st_data_s {
        unsigned char   protos_registered;
        unsigned long ll_state;
        void *kim_data;
+       struct tty_struct *tty;
 };
 
 /*
index 454a262..b306178 100644 (file)
@@ -126,6 +126,7 @@ struct timespec __current_kernel_time(void); /* does not take xtime_lock */
 struct timespec get_monotonic_coarse(void);
 void get_xtime_and_monotonic_and_sleep_offset(struct timespec *xtim,
                                struct timespec *wtom, struct timespec *sleep);
+void timekeeping_inject_sleeptime(struct timespec *delta);
 
 #define CURRENT_TIME           (current_kernel_time())
 #define CURRENT_TIME_SEC       ((struct timespec) { get_seconds(), 0 })
@@ -294,6 +295,8 @@ struct itimerval {
 #define CLOCK_REALTIME_COARSE          5
 #define CLOCK_MONOTONIC_COARSE         6
 #define CLOCK_BOOTTIME                 7
+#define CLOCK_REALTIME_ALARM           8
+#define CLOCK_BOOTTIME_ALARM           9
 
 /*
  * The IDs of various hardware clocks:
index a520fd7..5088727 100644 (file)
@@ -39,7 +39,7 @@ struct timerqueue_node *timerqueue_getnext(struct timerqueue_head *head)
 
 static inline void timerqueue_init(struct timerqueue_node *node)
 {
-       RB_CLEAR_NODE(&node->node);
+       rb_init_node(&node->node);
 }
 
 static inline void timerqueue_init_head(struct timerqueue_head *head)
index 88bdd01..2fa8d13 100644 (file)
@@ -38,9 +38,19 @@ static inline __u8 INET_ECN_encapsulate(__u8 outer, __u8 inner)
        return outer;
 }
 
-#define        INET_ECN_xmit(sk) do { inet_sk(sk)->tos |= INET_ECN_ECT_0; } while (0)
-#define        INET_ECN_dontxmit(sk) \
-       do { inet_sk(sk)->tos &= ~INET_ECN_MASK; } while (0)
+static inline void INET_ECN_xmit(struct sock *sk)
+{
+       inet_sk(sk)->tos |= INET_ECN_ECT_0;
+       if (inet6_sk(sk) != NULL)
+               inet6_sk(sk)->tclass |= INET_ECN_ECT_0;
+}
+
+static inline void INET_ECN_dontxmit(struct sock *sk)
+{
+       inet_sk(sk)->tos &= ~INET_ECN_MASK;
+       if (inet6_sk(sk) != NULL)
+               inet6_sk(sk)->tclass &= ~INET_ECN_MASK;
+}
 
 #define IP6_ECN_flow_init(label) do {          \
       (label) &= ~htonl(INET_ECN_MASK << 20);  \
index d516f00..86aefed 100644 (file)
@@ -791,6 +791,7 @@ struct ip_vs_app {
 /* IPVS in network namespace */
 struct netns_ipvs {
        int                     gen;            /* Generation */
+       int                     enable;         /* enable like nf_hooks do */
        /*
         *      Hash table: for real service lookups
         */
@@ -1089,6 +1090,22 @@ ip_vs_control_add(struct ip_vs_conn *cp, struct ip_vs_conn *ctl_cp)
        atomic_inc(&ctl_cp->n_control);
 }
 
+/*
+ * IPVS netns init & cleanup functions
+ */
+extern int __ip_vs_estimator_init(struct net *net);
+extern int __ip_vs_control_init(struct net *net);
+extern int __ip_vs_protocol_init(struct net *net);
+extern int __ip_vs_app_init(struct net *net);
+extern int __ip_vs_conn_init(struct net *net);
+extern int __ip_vs_sync_init(struct net *net);
+extern void __ip_vs_conn_cleanup(struct net *net);
+extern void __ip_vs_app_cleanup(struct net *net);
+extern void __ip_vs_protocol_cleanup(struct net *net);
+extern void __ip_vs_control_cleanup(struct net *net);
+extern void __ip_vs_estimator_cleanup(struct net *net);
+extern void __ip_vs_sync_cleanup(struct net *net);
+extern void __ip_vs_service_cleanup(struct net *net);
 
 /*
  *      IPVS application functions
index 75b8e29..f57e7d4 100644 (file)
@@ -199,7 +199,7 @@ struct llc_pdu_sn {
        u8 ssap;
        u8 ctrl_1;
        u8 ctrl_2;
-};
+} __packed;
 
 static inline struct llc_pdu_sn *llc_pdu_sn_hdr(struct sk_buff *skb)
 {
@@ -211,7 +211,7 @@ struct llc_pdu_un {
        u8 dsap;
        u8 ssap;
        u8 ctrl_1;
-};
+} __packed;
 
 static inline struct llc_pdu_un *llc_pdu_un_hdr(struct sk_buff *skb)
 {
@@ -359,7 +359,7 @@ struct llc_xid_info {
        u8 fmt_id;      /* always 0x81 for LLC */
        u8 type;        /* different if NULL/non-NULL LSAP */
        u8 rw;          /* sender receive window */
-};
+} __packed;
 
 /**
  *     llc_pdu_init_as_xid_cmd - sets bytes 3, 4 & 5 of LLC header as XID
@@ -415,7 +415,7 @@ struct llc_frmr_info {
        u8  curr_ssv;           /* current send state variable val */
        u8  curr_rsv;           /* current receive state variable */
        u8  ind_bits;           /* indicator bits set with macro */
-};
+} __packed;
 
 extern void llc_pdu_set_cmd_rsp(struct sk_buff *skb, u8 type);
 extern void llc_pdu_set_pf_bit(struct sk_buff *skb, u8 bit_value);
index 505845d..01e094c 100644 (file)
  * sctp/protocol.c
  */
 extern struct sock *sctp_get_ctl_sock(void);
-extern void sctp_local_addr_free(struct rcu_head *head);
 extern int sctp_copy_local_addr_list(struct sctp_bind_addr *,
                                     sctp_scope_t, gfp_t gfp,
                                     int flags);
index 6ae4bc5..20afeaa 100644 (file)
@@ -324,6 +324,7 @@ struct xfrm_state_afinfo {
        int                     (*tmpl_sort)(struct xfrm_tmpl **dst, struct xfrm_tmpl **src, int n);
        int                     (*state_sort)(struct xfrm_state **dst, struct xfrm_state **src, int n);
        int                     (*output)(struct sk_buff *skb);
+       int                     (*output_finish)(struct sk_buff *skb);
        int                     (*extract_input)(struct xfrm_state *x,
                                                 struct sk_buff *skb);
        int                     (*extract_output)(struct xfrm_state *x,
@@ -1454,6 +1455,7 @@ static inline int xfrm4_rcv_spi(struct sk_buff *skb, int nexthdr, __be32 spi)
 extern int xfrm4_extract_output(struct xfrm_state *x, struct sk_buff *skb);
 extern int xfrm4_prepare_output(struct xfrm_state *x, struct sk_buff *skb);
 extern int xfrm4_output(struct sk_buff *skb);
+extern int xfrm4_output_finish(struct sk_buff *skb);
 extern int xfrm4_tunnel_register(struct xfrm_tunnel *handler, unsigned short family);
 extern int xfrm4_tunnel_deregister(struct xfrm_tunnel *handler, unsigned short family);
 extern int xfrm6_extract_header(struct sk_buff *skb);
@@ -1470,6 +1472,7 @@ extern __be32 xfrm6_tunnel_spi_lookup(struct net *net, xfrm_address_t *saddr);
 extern int xfrm6_extract_output(struct xfrm_state *x, struct sk_buff *skb);
 extern int xfrm6_prepare_output(struct xfrm_state *x, struct sk_buff *skb);
 extern int xfrm6_output(struct sk_buff *skb);
+extern int xfrm6_output_finish(struct sk_buff *skb);
 extern int xfrm6_find_1stfragopt(struct xfrm_state *x, struct sk_buff *skb,
                                 u8 **prevhdr);
 
index cbb822e..2d0191c 100644 (file)
@@ -46,18 +46,9 @@ enum iw_cm_event_type {
        IW_CM_EVENT_CLOSE                /* close complete */
 };
 
-enum iw_cm_event_status {
-       IW_CM_EVENT_STATUS_OK = 0,       /* request successful */
-       IW_CM_EVENT_STATUS_ACCEPTED = 0, /* connect request accepted */
-       IW_CM_EVENT_STATUS_REJECTED,     /* connect request rejected */
-       IW_CM_EVENT_STATUS_TIMEOUT,      /* the operation timed out */
-       IW_CM_EVENT_STATUS_RESET,        /* reset from remote peer */
-       IW_CM_EVENT_STATUS_EINVAL,       /* asynchronous failure for bad parm */
-};
-
 struct iw_cm_event {
        enum iw_cm_event_type event;
-       enum iw_cm_event_status status;
+       int                      status;
        struct sockaddr_in local_addr;
        struct sockaddr_in remote_addr;
        void *private_data;
index 4fae903..169f7a5 100644 (file)
@@ -329,4 +329,14 @@ void rdma_leave_multicast(struct rdma_cm_id *id, struct sockaddr *addr);
  */
 void rdma_set_service_type(struct rdma_cm_id *id, int tos);
 
+/**
+ * rdma_set_reuseaddr - Allow the reuse of local addresses when binding
+ *    the rdma_cm_id.
+ * @id: Communication identifier to configure.
+ * @reuse: Value indicating if the bound address is reusable.
+ *
+ * Reuse must be set before an address is bound to the id.
+ */
+int rdma_set_reuseaddr(struct rdma_cm_id *id, int reuse);
+
 #endif /* RDMA_CM_H */
index 1d16502..fc82c18 100644 (file)
@@ -221,8 +221,9 @@ enum {
 
 /* Option details */
 enum {
-       RDMA_OPTION_ID_TOS      = 0,
-       RDMA_OPTION_IB_PATH     = 1
+       RDMA_OPTION_ID_TOS       = 0,
+       RDMA_OPTION_ID_REUSEADDR = 1,
+       RDMA_OPTION_IB_PATH      = 1
 };
 
 struct rdma_ucm_set_option {
index 2d3ec50..dd82e02 100644 (file)
@@ -169,6 +169,7 @@ struct scsi_device {
                                sdev_dev;
 
        struct execute_work     ew; /* used to get process context on put */
+       struct work_struct      requeue_work;
 
        struct scsi_dh_data     *scsi_dh_data;
        enum scsi_device_state sdev_state;
index e3615c0..9fe3a36 100644 (file)
@@ -10,6 +10,7 @@
  */
 #define show_gfp_flags(flags)                                          \
        (flags) ? __print_flags(flags, "|",                             \
+       {(unsigned long)GFP_TRANSHUGE,          "GFP_TRANSHUGE"},       \
        {(unsigned long)GFP_HIGHUSER_MOVABLE,   "GFP_HIGHUSER_MOVABLE"}, \
        {(unsigned long)GFP_HIGHUSER,           "GFP_HIGHUSER"},        \
        {(unsigned long)GFP_USER,               "GFP_USER"},            \
@@ -32,6 +33,9 @@
        {(unsigned long)__GFP_HARDWALL,         "GFP_HARDWALL"},        \
        {(unsigned long)__GFP_THISNODE,         "GFP_THISNODE"},        \
        {(unsigned long)__GFP_RECLAIMABLE,      "GFP_RECLAIMABLE"},     \
-       {(unsigned long)__GFP_MOVABLE,          "GFP_MOVABLE"}          \
+       {(unsigned long)__GFP_MOVABLE,          "GFP_MOVABLE"},         \
+       {(unsigned long)__GFP_NOTRACK,          "GFP_NOTRACK"},         \
+       {(unsigned long)__GFP_NO_KSWAPD,        "GFP_NO_KSWAPD"},       \
+       {(unsigned long)__GFP_OTHER_NODE,       "GFP_OTHER_NODE"}       \
        ) : "GFP_NOWAIT"
 
index 1c09820..ae045ca 100644 (file)
@@ -20,8 +20,7 @@ struct softirq_action;
                         softirq_name(BLOCK_IOPOLL),    \
                         softirq_name(TASKLET),         \
                         softirq_name(SCHED),           \
-                        softirq_name(HRTIMER),         \
-                        softirq_name(RCU))
+                        softirq_name(HRTIMER))
 
 /**
  * irq_handler_entry - called immediately before the irq action handler
index f1b87ad..9af21e1 100644 (file)
@@ -85,7 +85,8 @@ int xen_bind_pirq_gsi_to_irq(unsigned gsi,
 int xen_allocate_pirq_msi(struct pci_dev *dev, struct msi_desc *msidesc);
 /* Bind an PSI pirq to an irq. */
 int xen_bind_pirq_msi_to_irq(struct pci_dev *dev, struct msi_desc *msidesc,
-                            int pirq, int vector, const char *name);
+                            int pirq, int vector, const char *name,
+                            domid_t domid);
 #endif
 
 /* De-allocates the above mentioned physical interrupt. */
@@ -94,4 +95,10 @@ int xen_destroy_irq(int irq);
 /* Return irq from pirq */
 int xen_irq_from_pirq(unsigned pirq);
 
+/* Return the pirq allocated to the irq. */
+int xen_pirq_from_irq(unsigned irq);
+
+/* Determine whether to ignore this IRQ if it is passed to a guest. */
+int xen_test_irq_shared(int irq);
+
 #endif /* _XEN_EVENTS_H */
index d886b1e..4986ecc 100644 (file)
@@ -485,7 +485,7 @@ config TREE_RCU_TRACE
 
 config RCU_BOOST
        bool "Enable RCU priority boosting"
-       depends on RT_MUTEXES && TINY_PREEMPT_RCU
+       depends on RT_MUTEXES && PREEMPT_RCU
        default n
        help
          This option boosts the priority of preempted RCU readers that
@@ -827,6 +827,11 @@ config SCHED_AUTOGROUP
          desktop applications.  Task group autogeneration is currently based
          upon task session.
 
+config SCHED_TTWU_QUEUE
+       bool
+       depends on !SPARC32
+       default y
+
 config MM_OWNER
        bool
 
@@ -1226,7 +1231,6 @@ config SLAB
          per cpu and per node queues.
 
 config SLUB
-       depends on BROKEN || NUMA || !DISCONTIGMEM
        bool "SLUB (Unqueued Allocator)"
        help
           SLUB is a slab allocator that minimizes cache line usage
index 4a9479e..48df882 100644 (file)
@@ -580,8 +580,8 @@ asmlinkage void __init start_kernel(void)
 #endif
        page_cgroup_init();
        enable_debug_pagealloc();
-       kmemleak_init();
        debug_objects_mem_init();
+       kmemleak_init();
        setup_per_cpu_pageset();
        numa_policy_init();
        if (late_time_init)
index bf0c734..32a80e0 100644 (file)
@@ -399,3 +399,15 @@ bool task_ns_capable(struct task_struct *t, int cap)
        return ns_capable(task_cred_xxx(t, user)->user_ns, cap);
 }
 EXPORT_SYMBOL(task_ns_capable);
+
+/**
+ * nsown_capable - Check superior capability to one's own user_ns
+ * @cap: The capability in question
+ *
+ * Return true if the current task has the given superior capability
+ * targeted at its own user namespace.
+ */
+bool nsown_capable(int cap)
+{
+       return ns_capable(current_user_ns(), cap);
+}
index 25c7eb5..909a355 100644 (file)
@@ -326,12 +326,6 @@ static struct hlist_head *css_set_hash(struct cgroup_subsys_state *css[])
        return &css_set_table[index];
 }
 
-static void free_css_set_rcu(struct rcu_head *obj)
-{
-       struct css_set *cg = container_of(obj, struct css_set, rcu_head);
-       kfree(cg);
-}
-
 /* We don't maintain the lists running through each css_set to its
  * task until after the first call to cgroup_iter_start(). This
  * reduces the fork()/exit() overhead for people who have cgroups
@@ -375,7 +369,7 @@ static void __put_css_set(struct css_set *cg, int taskexit)
        }
 
        write_unlock(&css_set_lock);
-       call_rcu(&cg->rcu_head, free_css_set_rcu);
+       kfree_rcu(cg, rcu_head);
 }
 
 /*
@@ -812,13 +806,6 @@ static int cgroup_call_pre_destroy(struct cgroup *cgrp)
        return ret;
 }
 
-static void free_cgroup_rcu(struct rcu_head *obj)
-{
-       struct cgroup *cgrp = container_of(obj, struct cgroup, rcu_head);
-
-       kfree(cgrp);
-}
-
 static void cgroup_diput(struct dentry *dentry, struct inode *inode)
 {
        /* is dentry a directory ? if so, kfree() associated cgroup */
@@ -856,7 +843,7 @@ static void cgroup_diput(struct dentry *dentry, struct inode *inode)
                 */
                BUG_ON(!list_empty(&cgrp->pidlists));
 
-               call_rcu(&cgrp->rcu_head, free_cgroup_rcu);
+               kfree_rcu(cgrp, rcu_head);
        }
        iput(inode);
 }
@@ -4623,14 +4610,6 @@ bool css_is_ancestor(struct cgroup_subsys_state *child,
        return ret;
 }
 
-static void __free_css_id_cb(struct rcu_head *head)
-{
-       struct css_id *id;
-
-       id = container_of(head, struct css_id, rcu_head);
-       kfree(id);
-}
-
 void free_css_id(struct cgroup_subsys *ss, struct cgroup_subsys_state *css)
 {
        struct css_id *id = css->id;
@@ -4645,7 +4624,7 @@ void free_css_id(struct cgroup_subsys *ss, struct cgroup_subsys_state *css)
        spin_lock(&ss->id_lock);
        idr_remove(&ss->idr, id->id);
        spin_unlock(&ss->id_lock);
-       call_rcu(&id->rcu_head, __free_css_id_cb);
+       kfree_rcu(id, rcu_head);
 }
 EXPORT_SYMBOL_GPL(free_css_id);
 
index 33eee16..2bb8c2e 100644 (file)
@@ -1159,7 +1159,7 @@ int current_cpuset_is_being_rebound(void)
 static int update_relax_domain_level(struct cpuset *cs, s64 val)
 {
 #ifdef CONFIG_SMP
-       if (val < -1 || val >= SD_LV_MAX)
+       if (val < -1 || val >= sched_domain_level_max)
                return -EINVAL;
 #endif
 
index 5557b55..8093c16 100644 (file)
@@ -54,6 +54,7 @@ struct cred init_cred = {
        .cap_effective          = CAP_INIT_EFF_SET,
        .cap_bset               = CAP_INIT_BSET,
        .user                   = INIT_USER,
+       .user_ns                = &init_user_ns,
        .group_info             = &init_groups,
 #ifdef CONFIG_KEYS
        .tgcred                 = &init_tgcred,
@@ -410,6 +411,11 @@ int copy_creds(struct task_struct *p, unsigned long clone_flags)
                        goto error_put;
        }
 
+       /* cache user_ns in cred.  Doesn't need a refcount because it will
+        * stay pinned by cred->user
+        */
+       new->user_ns = new->user->user_ns;
+
 #ifdef CONFIG_KEYS
        /* new threads get their own thread keyrings if their parent already
         * had one */
@@ -741,12 +747,6 @@ int set_create_files_as(struct cred *new, struct inode *inode)
 }
 EXPORT_SYMBOL(set_create_files_as);
 
-struct user_namespace *current_user_ns(void)
-{
-       return _current_user_ns();
-}
-EXPORT_SYMBOL(current_user_ns);
-
 #ifdef CONFIG_DEBUG_CREDENTIALS
 
 bool creds_are_invalid(const struct cred *cred)
index 0fc34a3..c09767f 100644 (file)
@@ -586,14 +586,6 @@ static void get_ctx(struct perf_event_context *ctx)
        WARN_ON(!atomic_inc_not_zero(&ctx->refcount));
 }
 
-static void free_ctx(struct rcu_head *head)
-{
-       struct perf_event_context *ctx;
-
-       ctx = container_of(head, struct perf_event_context, rcu_head);
-       kfree(ctx);
-}
-
 static void put_ctx(struct perf_event_context *ctx)
 {
        if (atomic_dec_and_test(&ctx->refcount)) {
@@ -601,7 +593,7 @@ static void put_ctx(struct perf_event_context *ctx)
                        put_ctx(ctx->parent_ctx);
                if (ctx->task)
                        put_task_struct(ctx->task);
-               call_rcu(&ctx->rcu_head, free_ctx);
+               kfree_rcu(ctx, rcu_head);
        }
 }
 
@@ -5331,14 +5323,6 @@ swevent_hlist_deref(struct swevent_htable *swhash)
                                         lockdep_is_held(&swhash->hlist_mutex));
 }
 
-static void swevent_hlist_release_rcu(struct rcu_head *rcu_head)
-{
-       struct swevent_hlist *hlist;
-
-       hlist = container_of(rcu_head, struct swevent_hlist, rcu_head);
-       kfree(hlist);
-}
-
 static void swevent_hlist_release(struct swevent_htable *swhash)
 {
        struct swevent_hlist *hlist = swevent_hlist_deref(swhash);
@@ -5347,7 +5331,7 @@ static void swevent_hlist_release(struct swevent_htable *swhash)
                return;
 
        rcu_assign_pointer(swhash->swevent_hlist, NULL);
-       call_rcu(&hlist->rcu_head, swevent_hlist_release_rcu);
+       kfree_rcu(hlist, rcu_head);
 }
 
 static void swevent_hlist_put_cpu(struct perf_event *event, int cpu)
index d44aac0..5339705 100644 (file)
@@ -72,9 +72,19 @@ int core_kernel_text(unsigned long addr)
        return 0;
 }
 
+/**
+ * core_kernel_data - tell if addr points to kernel data
+ * @addr: address to test
+ *
+ * Returns true if @addr passed in is from the core kernel data
+ * section.
+ *
+ * Note: On some archs it may return true for core RODATA, and false
+ *  for others. But will always be true for core RW data.
+ */
 int core_kernel_data(unsigned long addr)
 {
-       if (addr >= (unsigned long)_stext &&
+       if (addr >= (unsigned long)_sdata &&
            addr < (unsigned long)_edata)
                return 1;
        return 0;
index e7548de..2b44d82 100644 (file)
@@ -1103,7 +1103,6 @@ static struct task_struct *copy_process(unsigned long clone_flags,
 
        posix_cpu_timers_init(p);
 
-       p->lock_depth = -1;             /* -1 = no lock */
        do_posix_clock_monotonic_gettime(&p->start_time);
        p->real_start_time = p->start_time;
        monotonic_to_bootbased(&p->real_start_time);
@@ -1153,7 +1152,7 @@ static struct task_struct *copy_process(unsigned long clone_flags,
 #endif
 
        /* Perform scheduler related setup. Assign this task to a CPU. */
-       sched_fork(p, clone_flags);
+       sched_fork(p);
 
        retval = perf_event_init_task(p);
        if (retval)
@@ -1464,7 +1463,7 @@ long do_fork(unsigned long clone_flags,
                 */
                p->flags &= ~PF_STARTING;
 
-               wake_up_new_task(p, clone_flags);
+               wake_up_new_task(p);
 
                tracehook_report_clone_complete(trace, regs,
                                                clone_flags, nr, p);
index 66ecd2e..7b01de9 100644 (file)
@@ -17,7 +17,7 @@ static inline void frozen_process(void)
 {
        if (!unlikely(current->flags & PF_NOFREEZE)) {
                current->flags |= PF_FROZEN;
-               wmb();
+               smp_wmb();
        }
        clear_freeze_flag(current);
 }
@@ -93,7 +93,7 @@ bool freeze_task(struct task_struct *p, bool sig_only)
         * the task as frozen and next clears its TIF_FREEZE.
         */
        if (!freezing(p)) {
-               rmb();
+               smp_rmb();
                if (frozen(p))
                        return false;
 
index 87fdb3f..dbbbf7d 100644 (file)
@@ -81,7 +81,7 @@ DEFINE_PER_CPU(struct hrtimer_cpu_base, hrtimer_bases) =
        }
 };
 
-static int hrtimer_clock_to_base_table[MAX_CLOCKS] = {
+static const int hrtimer_clock_to_base_table[MAX_CLOCKS] = {
        [CLOCK_REALTIME]        = HRTIMER_BASE_REALTIME,
        [CLOCK_MONOTONIC]       = HRTIMER_BASE_MONOTONIC,
        [CLOCK_BOOTTIME]        = HRTIMER_BASE_BOOTTIME,
index 53ead17..ea64012 100644 (file)
@@ -33,7 +33,7 @@ unsigned long __read_mostly sysctl_hung_task_check_count = PID_MAX_LIMIT;
 /*
  * Zero means infinite timeout - no checking done:
  */
-unsigned long __read_mostly sysctl_hung_task_timeout_secs = 120;
+unsigned long __read_mostly sysctl_hung_task_timeout_secs = CONFIG_DEFAULT_HUNG_TASK_TIMEOUT;
 
 unsigned long __read_mostly sysctl_hung_task_warnings = 10;
 
index c574f9a..d1d051b 100644 (file)
@@ -48,6 +48,10 @@ config IRQ_PREFLOW_FASTEOI
 config IRQ_EDGE_EOI_HANDLER
        bool
 
+# Generic configurable interrupt chip implementation
+config GENERIC_IRQ_CHIP
+       bool
+
 # Support forced irq threading
 config IRQ_FORCED_THREADING
        bool
index 54329cd..7329005 100644 (file)
@@ -1,5 +1,6 @@
 
 obj-y := irqdesc.o handle.o manage.o spurious.o resend.o chip.o dummychip.o devres.o
+obj-$(CONFIG_GENERIC_IRQ_CHIP) += generic-chip.o
 obj-$(CONFIG_GENERIC_IRQ_PROBE) += autoprobe.o
 obj-$(CONFIG_PROC_FS) += proc.o
 obj-$(CONFIG_GENERIC_PENDING_IRQ) += migration.o
index 4af1e2b..d5a3009 100644 (file)
@@ -310,6 +310,7 @@ handle_simple_irq(unsigned int irq, struct irq_desc *desc)
 out_unlock:
        raw_spin_unlock(&desc->lock);
 }
+EXPORT_SYMBOL_GPL(handle_simple_irq);
 
 /**
  *     handle_level_irq - Level type irq handler
@@ -573,6 +574,7 @@ __irq_set_handler(unsigned int irq, irq_flow_handler_t handle, int is_chained,
        if (handle != handle_bad_irq && is_chained) {
                irq_settings_set_noprobe(desc);
                irq_settings_set_norequest(desc);
+               irq_settings_set_nothread(desc);
                irq_startup(desc);
        }
 out:
@@ -612,6 +614,7 @@ void irq_modify_status(unsigned int irq, unsigned long clr, unsigned long set)
 
        irq_put_desc_unlock(desc, flags);
 }
+EXPORT_SYMBOL_GPL(irq_modify_status);
 
 /**
  *     irq_cpu_online - Invoke all irq_cpu_online functions.
index 306cba3..97a8bfa 100644 (file)
@@ -27,6 +27,7 @@ static inline void print_irq_desc(unsigned int irq, struct irq_desc *desc)
        P(IRQ_PER_CPU);
        P(IRQ_NOPROBE);
        P(IRQ_NOREQUEST);
+       P(IRQ_NOTHREAD);
        P(IRQ_NOAUTOEN);
 
        PS(IRQS_AUTODETECT);
diff --git a/kernel/irq/generic-chip.c b/kernel/irq/generic-chip.c
new file mode 100644 (file)
index 0000000..31a9db7
--- /dev/null
@@ -0,0 +1,354 @@
+/*
+ * Library implementing the most common irq chip callback functions
+ *
+ * Copyright (C) 2011, Thomas Gleixner
+ */
+#include <linux/io.h>
+#include <linux/irq.h>
+#include <linux/slab.h>
+#include <linux/interrupt.h>
+#include <linux/kernel_stat.h>
+#include <linux/syscore_ops.h>
+
+#include "internals.h"
+
+static LIST_HEAD(gc_list);
+static DEFINE_RAW_SPINLOCK(gc_lock);
+
+static inline struct irq_chip_regs *cur_regs(struct irq_data *d)
+{
+       return &container_of(d->chip, struct irq_chip_type, chip)->regs;
+}
+
+/**
+ * irq_gc_noop - NOOP function
+ * @d: irq_data
+ */
+void irq_gc_noop(struct irq_data *d)
+{
+}
+
+/**
+ * irq_gc_mask_disable_reg - Mask chip via disable register
+ * @d: irq_data
+ *
+ * Chip has separate enable/disable registers instead of a single mask
+ * register.
+ */
+void irq_gc_mask_disable_reg(struct irq_data *d)
+{
+       struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d);
+       u32 mask = 1 << (d->irq - gc->irq_base);
+
+       irq_gc_lock(gc);
+       irq_reg_writel(mask, gc->reg_base + cur_regs(d)->disable);
+       gc->mask_cache &= ~mask;
+       irq_gc_unlock(gc);
+}
+
+/**
+ * irq_gc_mask_set_mask_bit - Mask chip via setting bit in mask register
+ * @d: irq_data
+ *
+ * Chip has a single mask register. Values of this register are cached
+ * and protected by gc->lock
+ */
+void irq_gc_mask_set_bit(struct irq_data *d)
+{
+       struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d);
+       u32 mask = 1 << (d->irq - gc->irq_base);
+
+       irq_gc_lock(gc);
+       gc->mask_cache |= mask;
+       irq_reg_writel(gc->mask_cache, gc->reg_base + cur_regs(d)->mask);
+       irq_gc_unlock(gc);
+}
+
+/**
+ * irq_gc_mask_set_mask_bit - Mask chip via clearing bit in mask register
+ * @d: irq_data
+ *
+ * Chip has a single mask register. Values of this register are cached
+ * and protected by gc->lock
+ */
+void irq_gc_mask_clr_bit(struct irq_data *d)
+{
+       struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d);
+       u32 mask = 1 << (d->irq - gc->irq_base);
+
+       irq_gc_lock(gc);
+       gc->mask_cache &= ~mask;
+       irq_reg_writel(gc->mask_cache, gc->reg_base + cur_regs(d)->mask);
+       irq_gc_unlock(gc);
+}
+
+/**
+ * irq_gc_unmask_enable_reg - Unmask chip via enable register
+ * @d: irq_data
+ *
+ * Chip has separate enable/disable registers instead of a single mask
+ * register.
+ */
+void irq_gc_unmask_enable_reg(struct irq_data *d)
+{
+       struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d);
+       u32 mask = 1 << (d->irq - gc->irq_base);
+
+       irq_gc_lock(gc);
+       irq_reg_writel(mask, gc->reg_base + cur_regs(d)->enable);
+       gc->mask_cache |= mask;
+       irq_gc_unlock(gc);
+}
+
+/**
+ * irq_gc_ack - Ack pending interrupt
+ * @d: irq_data
+ */
+void irq_gc_ack(struct irq_data *d)
+{
+       struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d);
+       u32 mask = 1 << (d->irq - gc->irq_base);
+
+       irq_gc_lock(gc);
+       irq_reg_writel(mask, gc->reg_base + cur_regs(d)->ack);
+       irq_gc_unlock(gc);
+}
+
+/**
+ * irq_gc_mask_disable_reg_and_ack- Mask and ack pending interrupt
+ * @d: irq_data
+ */
+void irq_gc_mask_disable_reg_and_ack(struct irq_data *d)
+{
+       struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d);
+       u32 mask = 1 << (d->irq - gc->irq_base);
+
+       irq_gc_lock(gc);
+       irq_reg_writel(mask, gc->reg_base + cur_regs(d)->mask);
+       irq_reg_writel(mask, gc->reg_base + cur_regs(d)->ack);
+       irq_gc_unlock(gc);
+}
+
+/**
+ * irq_gc_eoi - EOI interrupt
+ * @d: irq_data
+ */
+void irq_gc_eoi(struct irq_data *d)
+{
+       struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d);
+       u32 mask = 1 << (d->irq - gc->irq_base);
+
+       irq_gc_lock(gc);
+       irq_reg_writel(mask, gc->reg_base + cur_regs(d)->eoi);
+       irq_gc_unlock(gc);
+}
+
+/**
+ * irq_gc_set_wake - Set/clr wake bit for an interrupt
+ * @d: irq_data
+ *
+ * For chips where the wake from suspend functionality is not
+ * configured in a separate register and the wakeup active state is
+ * just stored in a bitmask.
+ */
+int irq_gc_set_wake(struct irq_data *d, unsigned int on)
+{
+       struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d);
+       u32 mask = 1 << (d->irq - gc->irq_base);
+
+       if (!(mask & gc->wake_enabled))
+               return -EINVAL;
+
+       irq_gc_lock(gc);
+       if (on)
+               gc->wake_active |= mask;
+       else
+               gc->wake_active &= ~mask;
+       irq_gc_unlock(gc);
+       return 0;
+}
+
+/**
+ * irq_alloc_generic_chip - Allocate a generic chip and initialize it
+ * @name:      Name of the irq chip
+ * @num_ct:    Number of irq_chip_type instances associated with this
+ * @irq_base:  Interrupt base nr for this chip
+ * @reg_base:  Register base address (virtual)
+ * @handler:   Default flow handler associated with this chip
+ *
+ * Returns an initialized irq_chip_generic structure. The chip defaults
+ * to the primary (index 0) irq_chip_type and @handler
+ */
+struct irq_chip_generic *
+irq_alloc_generic_chip(const char *name, int num_ct, unsigned int irq_base,
+                      void __iomem *reg_base, irq_flow_handler_t handler)
+{
+       struct irq_chip_generic *gc;
+       unsigned long sz = sizeof(*gc) + num_ct * sizeof(struct irq_chip_type);
+
+       gc = kzalloc(sz, GFP_KERNEL);
+       if (gc) {
+               raw_spin_lock_init(&gc->lock);
+               gc->num_ct = num_ct;
+               gc->irq_base = irq_base;
+               gc->reg_base = reg_base;
+               gc->chip_types->chip.name = name;
+               gc->chip_types->handler = handler;
+       }
+       return gc;
+}
+
+/*
+ * Separate lockdep class for interrupt chip which can nest irq_desc
+ * lock.
+ */
+static struct lock_class_key irq_nested_lock_class;
+
+/**
+ * irq_setup_generic_chip - Setup a range of interrupts with a generic chip
+ * @gc:                Generic irq chip holding all data
+ * @msk:       Bitmask holding the irqs to initialize relative to gc->irq_base
+ * @flags:     Flags for initialization
+ * @clr:       IRQ_* bits to clear
+ * @set:       IRQ_* bits to set
+ *
+ * Set up max. 32 interrupts starting from gc->irq_base. Note, this
+ * initializes all interrupts to the primary irq_chip_type and its
+ * associated handler.
+ */
+void irq_setup_generic_chip(struct irq_chip_generic *gc, u32 msk,
+                           enum irq_gc_flags flags, unsigned int clr,
+                           unsigned int set)
+{
+       struct irq_chip_type *ct = gc->chip_types;
+       unsigned int i;
+
+       raw_spin_lock(&gc_lock);
+       list_add_tail(&gc->list, &gc_list);
+       raw_spin_unlock(&gc_lock);
+
+       /* Init mask cache ? */
+       if (flags & IRQ_GC_INIT_MASK_CACHE)
+               gc->mask_cache = irq_reg_readl(gc->reg_base + ct->regs.mask);
+
+       for (i = gc->irq_base; msk; msk >>= 1, i++) {
+               if (!msk & 0x01)
+                       continue;
+
+               if (flags & IRQ_GC_INIT_NESTED_LOCK)
+                       irq_set_lockdep_class(i, &irq_nested_lock_class);
+
+               irq_set_chip_and_handler(i, &ct->chip, ct->handler);
+               irq_set_chip_data(i, gc);
+               irq_modify_status(i, clr, set);
+       }
+       gc->irq_cnt = i - gc->irq_base;
+}
+
+/**
+ * irq_setup_alt_chip - Switch to alternative chip
+ * @d:         irq_data for this interrupt
+ * @type       Flow type to be initialized
+ *
+ * Only to be called from chip->irq_set_type() callbacks.
+ */
+int irq_setup_alt_chip(struct irq_data *d, unsigned int type)
+{
+       struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d);
+       struct irq_chip_type *ct = gc->chip_types;
+       unsigned int i;
+
+       for (i = 0; i < gc->num_ct; i++, ct++) {
+               if (ct->type & type) {
+                       d->chip = &ct->chip;
+                       irq_data_to_desc(d)->handle_irq = ct->handler;
+                       return 0;
+               }
+       }
+       return -EINVAL;
+}
+
+/**
+ * irq_remove_generic_chip - Remove a chip
+ * @gc:                Generic irq chip holding all data
+ * @msk:       Bitmask holding the irqs to initialize relative to gc->irq_base
+ * @clr:       IRQ_* bits to clear
+ * @set:       IRQ_* bits to set
+ *
+ * Remove up to 32 interrupts starting from gc->irq_base.
+ */
+void irq_remove_generic_chip(struct irq_chip_generic *gc, u32 msk,
+                            unsigned int clr, unsigned int set)
+{
+       unsigned int i = gc->irq_base;
+
+       raw_spin_lock(&gc_lock);
+       list_del(&gc->list);
+       raw_spin_unlock(&gc_lock);
+
+       for (; msk; msk >>= 1, i++) {
+               if (!msk & 0x01)
+                       continue;
+
+               /* Remove handler first. That will mask the irq line */
+               irq_set_handler(i, NULL);
+               irq_set_chip(i, &no_irq_chip);
+               irq_set_chip_data(i, NULL);
+               irq_modify_status(i, clr, set);
+       }
+}
+
+#ifdef CONFIG_PM
+static int irq_gc_suspend(void)
+{
+       struct irq_chip_generic *gc;
+
+       list_for_each_entry(gc, &gc_list, list) {
+               struct irq_chip_type *ct = gc->chip_types;
+
+               if (ct->chip.irq_suspend)
+                       ct->chip.irq_suspend(irq_get_irq_data(gc->irq_base));
+       }
+       return 0;
+}
+
+static void irq_gc_resume(void)
+{
+       struct irq_chip_generic *gc;
+
+       list_for_each_entry(gc, &gc_list, list) {
+               struct irq_chip_type *ct = gc->chip_types;
+
+               if (ct->chip.irq_resume)
+                       ct->chip.irq_resume(irq_get_irq_data(gc->irq_base));
+       }
+}
+#else
+#define irq_gc_suspend NULL
+#define irq_gc_resume NULL
+#endif
+
+static void irq_gc_shutdown(void)
+{
+       struct irq_chip_generic *gc;
+
+       list_for_each_entry(gc, &gc_list, list) {
+               struct irq_chip_type *ct = gc->chip_types;
+
+               if (ct->chip.irq_pm_shutdown)
+                       ct->chip.irq_pm_shutdown(irq_get_irq_data(gc->irq_base));
+       }
+}
+
+static struct syscore_ops irq_gc_syscore_ops = {
+       .suspend = irq_gc_suspend,
+       .resume = irq_gc_resume,
+       .shutdown = irq_gc_shutdown,
+};
+
+static int __init irq_gc_init_ops(void)
+{
+       register_syscore_ops(&irq_gc_syscore_ops);
+       return 0;
+}
+device_initcall(irq_gc_init_ops);
index 2c039c9..886e803 100644 (file)
@@ -22,7 +22,7 @@
  */
 static struct lock_class_key irq_desc_lock_class;
 
-#if defined(CONFIG_SMP) && defined(CONFIG_GENERIC_HARDIRQS)
+#if defined(CONFIG_SMP)
 static void __init init_irq_default_affinity(void)
 {
        alloc_cpumask_var(&irq_default_affinity, GFP_NOWAIT);
@@ -290,6 +290,22 @@ static int irq_expand_nr_irqs(unsigned int nr)
 
 #endif /* !CONFIG_SPARSE_IRQ */
 
+/**
+ * generic_handle_irq - Invoke the handler for a particular irq
+ * @irq:       The irq number to handle
+ *
+ */
+int generic_handle_irq(unsigned int irq)
+{
+       struct irq_desc *desc = irq_to_desc(irq);
+
+       if (!desc)
+               return -EINVAL;
+       generic_handle_irq_desc(irq, desc);
+       return 0;
+}
+EXPORT_SYMBOL_GPL(generic_handle_irq);
+
 /* Dynamic interrupt handling */
 
 /**
@@ -311,6 +327,7 @@ void irq_free_descs(unsigned int from, unsigned int cnt)
        bitmap_clear(allocated_irqs, from, cnt);
        mutex_unlock(&sparse_irq_lock);
 }
+EXPORT_SYMBOL_GPL(irq_free_descs);
 
 /**
  * irq_alloc_descs - allocate and initialize a range of irq descriptors
@@ -351,6 +368,7 @@ err:
        mutex_unlock(&sparse_irq_lock);
        return ret;
 }
+EXPORT_SYMBOL_GPL(irq_alloc_descs);
 
 /**
  * irq_reserve_irqs - mark irqs allocated
@@ -430,7 +448,6 @@ unsigned int kstat_irqs_cpu(unsigned int irq, int cpu)
                        *per_cpu_ptr(desc->kstat_irqs, cpu) : 0;
 }
 
-#ifdef CONFIG_GENERIC_HARDIRQS
 unsigned int kstat_irqs(unsigned int irq)
 {
        struct irq_desc *desc = irq_to_desc(irq);
@@ -443,4 +460,3 @@ unsigned int kstat_irqs(unsigned int irq)
                sum += *per_cpu_ptr(desc->kstat_irqs, cpu);
        return sum;
 }
-#endif /* CONFIG_GENERIC_HARDIRQS */
index 07c1611..f7ce002 100644 (file)
@@ -900,7 +900,8 @@ __setup_irq(unsigned int irq, struct irq_desc *desc, struct irqaction *new)
                 */
                new->handler = irq_nested_primary_handler;
        } else {
-               irq_setup_forced_threading(new);
+               if (irq_settings_can_thread(desc))
+                       irq_setup_forced_threading(new);
        }
 
        /*
index 0d91730..f166783 100644 (file)
@@ -8,6 +8,7 @@ enum {
        _IRQ_LEVEL              = IRQ_LEVEL,
        _IRQ_NOPROBE            = IRQ_NOPROBE,
        _IRQ_NOREQUEST          = IRQ_NOREQUEST,
+       _IRQ_NOTHREAD           = IRQ_NOTHREAD,
        _IRQ_NOAUTOEN           = IRQ_NOAUTOEN,
        _IRQ_MOVE_PCNTXT        = IRQ_MOVE_PCNTXT,
        _IRQ_NO_BALANCING       = IRQ_NO_BALANCING,
@@ -20,6 +21,7 @@ enum {
 #define IRQ_LEVEL              GOT_YOU_MORON
 #define IRQ_NOPROBE            GOT_YOU_MORON
 #define IRQ_NOREQUEST          GOT_YOU_MORON
+#define IRQ_NOTHREAD           GOT_YOU_MORON
 #define IRQ_NOAUTOEN           GOT_YOU_MORON
 #define IRQ_NESTED_THREAD      GOT_YOU_MORON
 #undef IRQF_MODIFY_MASK
@@ -94,6 +96,21 @@ static inline void irq_settings_set_norequest(struct irq_desc *desc)
        desc->status_use_accessors |= _IRQ_NOREQUEST;
 }
 
+static inline bool irq_settings_can_thread(struct irq_desc *desc)
+{
+       return !(desc->status_use_accessors & _IRQ_NOTHREAD);
+}
+
+static inline void irq_settings_clr_nothread(struct irq_desc *desc)
+{
+       desc->status_use_accessors &= ~_IRQ_NOTHREAD;
+}
+
+static inline void irq_settings_set_nothread(struct irq_desc *desc)
+{
+       desc->status_use_accessors |= _IRQ_NOTHREAD;
+}
+
 static inline bool irq_settings_can_probe(struct irq_desc *desc)
 {
        return !(desc->status_use_accessors & _IRQ_NOPROBE);
index 87b77de..8d814cb 100644 (file)
@@ -1531,13 +1531,7 @@ int kernel_kexec(void)
                if (error)
                        goto Enable_cpus;
                local_irq_disable();
-               /* Suspend system devices */
-               error = sysdev_suspend(PMSG_FREEZE);
-               if (!error) {
-                       error = syscore_suspend();
-                       if (error)
-                               sysdev_resume();
-               }
+               error = syscore_suspend();
                if (error)
                        goto Enable_irqs;
        } else
@@ -1553,7 +1547,6 @@ int kernel_kexec(void)
 #ifdef CONFIG_KEXEC_JUMP
        if (kexec_image->preserve_context) {
                syscore_resume();
-               sysdev_resume();
  Enable_irqs:
                local_irq_enable();
  Enable_cpus:
index 9cd0591..5ae0ff3 100644 (file)
@@ -245,7 +245,6 @@ static void __call_usermodehelper(struct work_struct *work)
        }
 }
 
-#ifdef CONFIG_PM_SLEEP
 /*
  * If set, call_usermodehelper_exec() will exit immediately returning -EBUSY
  * (used for preventing user land processes from being created after the user
@@ -301,6 +300,15 @@ void usermodehelper_enable(void)
        usermodehelper_disabled = 0;
 }
 
+/**
+ * usermodehelper_is_disabled - check if new helpers are allowed to be started
+ */
+bool usermodehelper_is_disabled(void)
+{
+       return usermodehelper_disabled;
+}
+EXPORT_SYMBOL_GPL(usermodehelper_is_disabled);
+
 static void helper_lock(void)
 {
        atomic_inc(&running_helpers);
@@ -312,12 +320,6 @@ static void helper_unlock(void)
        if (atomic_dec_and_test(&running_helpers))
                wake_up(&running_helpers_waitq);
 }
-#else /* CONFIG_PM_SLEEP */
-#define usermodehelper_disabled        0
-
-static inline void helper_lock(void) {}
-static inline void helper_unlock(void) {}
-#endif /* CONFIG_PM_SLEEP */
 
 /**
  * call_usermodehelper_setup - prepare to call a usermode helper
index 0b624e7..3b053c0 100644 (file)
@@ -16,6 +16,7 @@
 #include <linux/kexec.h>
 #include <linux/profile.h>
 #include <linux/sched.h>
+#include <linux/capability.h>
 
 #define KERNEL_ATTR_RO(_name) \
 static struct kobj_attribute _name##_attr = __ATTR_RO(_name)
@@ -131,6 +132,14 @@ KERNEL_ATTR_RO(vmcoreinfo);
 
 #endif /* CONFIG_KEXEC */
 
+/* whether file capabilities are enabled */
+static ssize_t fscaps_show(struct kobject *kobj,
+                                 struct kobj_attribute *attr, char *buf)
+{
+       return sprintf(buf, "%d\n", file_caps_enabled);
+}
+KERNEL_ATTR_RO(fscaps);
+
 /*
  * Make /sys/kernel/notes give the raw contents of our kernel .notes section.
  */
@@ -158,6 +167,7 @@ struct kobject *kernel_kobj;
 EXPORT_SYMBOL_GPL(kernel_kobj);
 
 static struct attribute * kernel_attrs[] = {
+       &fscaps_attr.attr,
 #if defined(CONFIG_HOTPLUG)
        &uevent_seqnum_attr.attr,
        &uevent_helper_attr.attr,
index 53a6895..63437d0 100644 (file)
@@ -490,6 +490,18 @@ void get_usage_chars(struct lock_class *class, char usage[LOCK_USAGE_CHARS])
        usage[i] = '\0';
 }
 
+static int __print_lock_name(struct lock_class *class)
+{
+       char str[KSYM_NAME_LEN];
+       const char *name;
+
+       name = class->name;
+       if (!name)
+               name = __get_key_name(class->key, str);
+
+       return printk("%s", name);
+}
+
 static void print_lock_name(struct lock_class *class)
 {
        char str[KSYM_NAME_LEN], usage[LOCK_USAGE_CHARS];
@@ -1053,6 +1065,56 @@ print_circular_bug_entry(struct lock_list *target, int depth)
        return 0;
 }
 
+static void
+print_circular_lock_scenario(struct held_lock *src,
+                            struct held_lock *tgt,
+                            struct lock_list *prt)
+{
+       struct lock_class *source = hlock_class(src);
+       struct lock_class *target = hlock_class(tgt);
+       struct lock_class *parent = prt->class;
+
+       /*
+        * A direct locking problem where unsafe_class lock is taken
+        * directly by safe_class lock, then all we need to show
+        * is the deadlock scenario, as it is obvious that the
+        * unsafe lock is taken under the safe lock.
+        *
+        * But if there is a chain instead, where the safe lock takes
+        * an intermediate lock (middle_class) where this lock is
+        * not the same as the safe lock, then the lock chain is
+        * used to describe the problem. Otherwise we would need
+        * to show a different CPU case for each link in the chain
+        * from the safe_class lock to the unsafe_class lock.
+        */
+       if (parent != source) {
+               printk("Chain exists of:\n  ");
+               __print_lock_name(source);
+               printk(" --> ");
+               __print_lock_name(parent);
+               printk(" --> ");
+               __print_lock_name(target);
+               printk("\n\n");
+       }
+
+       printk(" Possible unsafe locking scenario:\n\n");
+       printk("       CPU0                    CPU1\n");
+       printk("       ----                    ----\n");
+       printk("  lock(");
+       __print_lock_name(target);
+       printk(");\n");
+       printk("                               lock(");
+       __print_lock_name(parent);
+       printk(");\n");
+       printk("                               lock(");
+       __print_lock_name(target);
+       printk(");\n");
+       printk("  lock(");
+       __print_lock_name(source);
+       printk(");\n");
+       printk("\n *** DEADLOCK ***\n\n");
+}
+
 /*
  * When a circular dependency is detected, print the
  * header first:
@@ -1096,6 +1158,7 @@ static noinline int print_circular_bug(struct lock_list *this,
 {
        struct task_struct *curr = current;
        struct lock_list *parent;
+       struct lock_list *first_parent;
        int depth;
 
        if (!debug_locks_off_graph_unlock() || debug_locks_silent)
@@ -1109,6 +1172,7 @@ static noinline int print_circular_bug(struct lock_list *this,
        print_circular_bug_header(target, depth, check_src, check_tgt);
 
        parent = get_lock_parent(target);
+       first_parent = parent;
 
        while (parent) {
                print_circular_bug_entry(parent, --depth);
@@ -1116,6 +1180,9 @@ static noinline int print_circular_bug(struct lock_list *this,
        }
 
        printk("\nother info that might help us debug this:\n\n");
+       print_circular_lock_scenario(check_src, check_tgt,
+                                    first_parent);
+
        lockdep_print_held_locks(curr);
 
        printk("\nstack backtrace:\n");
@@ -1314,7 +1381,7 @@ print_shortest_lock_dependencies(struct lock_list *leaf,
                printk("\n");
 
                if (depth == 0 && (entry != root)) {
-                       printk("lockdep:%s bad BFS generated tree\n", __func__);
+                       printk("lockdep:%s bad path found in chain graph\n", __func__);
                        break;
                }
 
@@ -1325,6 +1392,62 @@ print_shortest_lock_dependencies(struct lock_list *leaf,
        return;
 }
 
+static void
+print_irq_lock_scenario(struct lock_list *safe_entry,
+                       struct lock_list *unsafe_entry,
+                       struct lock_class *prev_class,
+                       struct lock_class *next_class)
+{
+       struct lock_class *safe_class = safe_entry->class;
+       struct lock_class *unsafe_class = unsafe_entry->class;
+       struct lock_class *middle_class = prev_class;
+
+       if (middle_class == safe_class)
+               middle_class = next_class;
+
+       /*
+        * A direct locking problem where unsafe_class lock is taken
+        * directly by safe_class lock, then all we need to show
+        * is the deadlock scenario, as it is obvious that the
+        * unsafe lock is taken under the safe lock.
+        *
+        * But if there is a chain instead, where the safe lock takes
+        * an intermediate lock (middle_class) where this lock is
+        * not the same as the safe lock, then the lock chain is
+        * used to describe the problem. Otherwise we would need
+        * to show a different CPU case for each link in the chain
+        * from the safe_class lock to the unsafe_class lock.
+        */
+       if (middle_class != unsafe_class) {
+               printk("Chain exists of:\n  ");
+               __print_lock_name(safe_class);
+               printk(" --> ");
+               __print_lock_name(middle_class);
+               printk(" --> ");
+               __print_lock_name(unsafe_class);
+               printk("\n\n");
+       }
+
+       printk(" Possible interrupt unsafe locking scenario:\n\n");
+       printk("       CPU0                    CPU1\n");
+       printk("       ----                    ----\n");
+       printk("  lock(");
+       __print_lock_name(unsafe_class);
+       printk(");\n");
+       printk("                               local_irq_disable();\n");
+       printk("                               lock(");
+       __print_lock_name(safe_class);
+       printk(");\n");
+       printk("                               lock(");
+       __print_lock_name(middle_class);
+       printk(");\n");
+       printk("  <Interrupt>\n");
+       printk("    lock(");
+       __print_lock_name(safe_class);
+       printk(");\n");
+       printk("\n *** DEADLOCK ***\n\n");
+}
+
 static int
 print_bad_irq_dependency(struct task_struct *curr,
                         struct lock_list *prev_root,
@@ -1376,6 +1499,9 @@ print_bad_irq_dependency(struct task_struct *curr,
        print_stack_trace(forwards_entry->class->usage_traces + bit2, 1);
 
        printk("\nother info that might help us debug this:\n\n");
+       print_irq_lock_scenario(backwards_entry, forwards_entry,
+                               hlock_class(prev), hlock_class(next));
+
        lockdep_print_held_locks(curr);
 
        printk("\nthe dependencies between %s-irq-safe lock", irqclass);
@@ -1539,6 +1665,26 @@ static inline void inc_chains(void)
 
 #endif
 
+static void
+print_deadlock_scenario(struct held_lock *nxt,
+                            struct held_lock *prv)
+{
+       struct lock_class *next = hlock_class(nxt);
+       struct lock_class *prev = hlock_class(prv);
+
+       printk(" Possible unsafe locking scenario:\n\n");
+       printk("       CPU0\n");
+       printk("       ----\n");
+       printk("  lock(");
+       __print_lock_name(prev);
+       printk(");\n");
+       printk("  lock(");
+       __print_lock_name(next);
+       printk(");\n");
+       printk("\n *** DEADLOCK ***\n\n");
+       printk(" May be due to missing lock nesting notation\n\n");
+}
+
 static int
 print_deadlock_bug(struct task_struct *curr, struct held_lock *prev,
                   struct held_lock *next)
@@ -1557,6 +1703,7 @@ print_deadlock_bug(struct task_struct *curr, struct held_lock *prev,
        print_lock(prev);
 
        printk("\nother info that might help us debug this:\n");
+       print_deadlock_scenario(next, prev);
        lockdep_print_held_locks(curr);
 
        printk("\nstack backtrace:\n");
@@ -1826,7 +1973,7 @@ static inline int lookup_chain_cache(struct task_struct *curr,
        struct list_head *hash_head = chainhashentry(chain_key);
        struct lock_chain *chain;
        struct held_lock *hlock_curr, *hlock_next;
-       int i, j, n, cn;
+       int i, j;
 
        if (DEBUG_LOCKS_WARN_ON(!irqs_disabled()))
                return 0;
@@ -1886,15 +2033,9 @@ cache_hit:
        }
        i++;
        chain->depth = curr->lockdep_depth + 1 - i;
-       cn = nr_chain_hlocks;
-       while (cn + chain->depth <= MAX_LOCKDEP_CHAIN_HLOCKS) {
-               n = cmpxchg(&nr_chain_hlocks, cn, cn + chain->depth);
-               if (n == cn)
-                       break;
-               cn = n;
-       }
-       if (likely(cn + chain->depth <= MAX_LOCKDEP_CHAIN_HLOCKS)) {
-               chain->base = cn;
+       if (likely(nr_chain_hlocks + chain->depth <= MAX_LOCKDEP_CHAIN_HLOCKS)) {
+               chain->base = nr_chain_hlocks;
+               nr_chain_hlocks += chain->depth;
                for (j = 0; j < chain->depth - 1; j++, i++) {
                        int lock_id = curr->held_locks[i].class_idx - 1;
                        chain_hlocks[chain->base + j] = lock_id;
@@ -2011,6 +2152,24 @@ static void check_chain_key(struct task_struct *curr)
 #endif
 }
 
+static void
+print_usage_bug_scenario(struct held_lock *lock)
+{
+       struct lock_class *class = hlock_class(lock);
+
+       printk(" Possible unsafe locking scenario:\n\n");
+       printk("       CPU0\n");
+       printk("       ----\n");
+       printk("  lock(");
+       __print_lock_name(class);
+       printk(");\n");
+       printk("  <Interrupt>\n");
+       printk("    lock(");
+       __print_lock_name(class);
+       printk(");\n");
+       printk("\n *** DEADLOCK ***\n\n");
+}
+
 static int
 print_usage_bug(struct task_struct *curr, struct held_lock *this,
                enum lock_usage_bit prev_bit, enum lock_usage_bit new_bit)
@@ -2039,6 +2198,8 @@ print_usage_bug(struct task_struct *curr, struct held_lock *this,
 
        print_irqtrace_events(curr);
        printk("\nother info that might help us debug this:\n");
+       print_usage_bug_scenario(this);
+
        lockdep_print_held_locks(curr);
 
        printk("\nstack backtrace:\n");
@@ -2073,6 +2234,10 @@ print_irq_inversion_bug(struct task_struct *curr,
                        struct held_lock *this, int forwards,
                        const char *irqclass)
 {
+       struct lock_list *entry = other;
+       struct lock_list *middle = NULL;
+       int depth;
+
        if (!debug_locks_off_graph_unlock() || debug_locks_silent)
                return 0;
 
@@ -2091,6 +2256,25 @@ print_irq_inversion_bug(struct task_struct *curr,
        printk("\n\nand interrupts could create inverse lock ordering between them.\n\n");
 
        printk("\nother info that might help us debug this:\n");
+
+       /* Find a middle lock (if one exists) */
+       depth = get_lock_depth(other);
+       do {
+               if (depth == 0 && (entry != root)) {
+                       printk("lockdep:%s bad path found in chain graph\n", __func__);
+                       break;
+               }
+               middle = entry;
+               entry = get_lock_parent(entry);
+               depth--;
+       } while (entry && entry != root && (depth >= 0));
+       if (forwards)
+               print_irq_lock_scenario(root, other,
+                       middle ? middle->class : root->class, other->class);
+       else
+               print_irq_lock_scenario(other, root,
+                       middle ? middle->class : other->class, root->class);
+
        lockdep_print_held_locks(curr);
 
        printk("\nthe shortest dependencies between 2nd lock and 1st lock:\n");
index d5938a5..2287972 100644 (file)
@@ -57,6 +57,7 @@
 #include <linux/kmemleak.h>
 #include <linux/jump_label.h>
 #include <linux/pfn.h>
+#include <linux/bsearch.h>
 
 #define CREATE_TRACE_POINTS
 #include <trace/events/module.h>
@@ -240,23 +241,24 @@ static bool each_symbol_in_section(const struct symsearch *arr,
                                   struct module *owner,
                                   bool (*fn)(const struct symsearch *syms,
                                              struct module *owner,
-                                             unsigned int symnum, void *data),
+                                             void *data),
                                   void *data)
 {
-       unsigned int i, j;
+       unsigned int j;
 
        for (j = 0; j < arrsize; j++) {
-               for (i = 0; i < arr[j].stop - arr[j].start; i++)
-                       if (fn(&arr[j], owner, i, data))
-                               return true;
+               if (fn(&arr[j], owner, data))
+                       return true;
        }
 
        return false;
 }
 
 /* Returns true as soon as fn returns true, otherwise false. */
-bool each_symbol(bool (*fn)(const struct symsearch *arr, struct module *owner,
-                           unsigned int symnum, void *data), void *data)
+bool each_symbol_section(bool (*fn)(const struct symsearch *arr,
+                                   struct module *owner,
+                                   void *data),
+                        void *data)
 {
        struct module *mod;
        static const struct symsearch arr[] = {
@@ -309,7 +311,7 @@ bool each_symbol(bool (*fn)(const struct symsearch *arr, struct module *owner,
        }
        return false;
 }
-EXPORT_SYMBOL_GPL(each_symbol);
+EXPORT_SYMBOL_GPL(each_symbol_section);
 
 struct find_symbol_arg {
        /* Input */
@@ -323,15 +325,12 @@ struct find_symbol_arg {
        const struct kernel_symbol *sym;
 };
 
-static bool find_symbol_in_section(const struct symsearch *syms,
-                                  struct module *owner,
-                                  unsigned int symnum, void *data)
+static bool check_symbol(const struct symsearch *syms,
+                                struct module *owner,
+                                unsigned int symnum, void *data)
 {
        struct find_symbol_arg *fsa = data;
 
-       if (strcmp(syms->start[symnum].name, fsa->name) != 0)
-               return false;
-
        if (!fsa->gplok) {
                if (syms->licence == GPL_ONLY)
                        return false;
@@ -365,6 +364,30 @@ static bool find_symbol_in_section(const struct symsearch *syms,
        return true;
 }
 
+static int cmp_name(const void *va, const void *vb)
+{
+       const char *a;
+       const struct kernel_symbol *b;
+       a = va; b = vb;
+       return strcmp(a, b->name);
+}
+
+static bool find_symbol_in_section(const struct symsearch *syms,
+                                  struct module *owner,
+                                  void *data)
+{
+       struct find_symbol_arg *fsa = data;
+       struct kernel_symbol *sym;
+
+       sym = bsearch(fsa->name, syms->start, syms->stop - syms->start,
+                       sizeof(struct kernel_symbol), cmp_name);
+
+       if (sym != NULL && check_symbol(syms, owner, sym - syms->start, data))
+               return true;
+
+       return false;
+}
+
 /* Find a symbol and return it, along with, (optional) crc and
  * (optional) module which owns it.  Needs preempt disabled or module_mutex. */
 const struct kernel_symbol *find_symbol(const char *name,
@@ -379,7 +402,7 @@ const struct kernel_symbol *find_symbol(const char *name,
        fsa.gplok = gplok;
        fsa.warn = warn;
 
-       if (each_symbol(find_symbol_in_section, &fsa)) {
+       if (each_symbol_section(find_symbol_in_section, &fsa)) {
                if (owner)
                        *owner = fsa.owner;
                if (crc)
@@ -1607,27 +1630,28 @@ static void set_section_ro_nx(void *base,
        }
 }
 
-/* Setting memory back to RW+NX before releasing it */
-void unset_section_ro_nx(struct module *mod, void *module_region)
+static void unset_module_core_ro_nx(struct module *mod)
 {
-       unsigned long total_pages;
-
-       if (mod->module_core == module_region) {
-               /* Set core as NX+RW */
-               total_pages = MOD_NUMBER_OF_PAGES(mod->module_core, mod->core_size);
-               set_memory_nx((unsigned long)mod->module_core, total_pages);
-               set_memory_rw((unsigned long)mod->module_core, total_pages);
+       set_page_attributes(mod->module_core + mod->core_text_size,
+               mod->module_core + mod->core_size,
+               set_memory_x);
+       set_page_attributes(mod->module_core,
+               mod->module_core + mod->core_ro_size,
+               set_memory_rw);
+}
 
-       } else if (mod->module_init == module_region) {
-               /* Set init as NX+RW */
-               total_pages = MOD_NUMBER_OF_PAGES(mod->module_init, mod->init_size);
-               set_memory_nx((unsigned long)mod->module_init, total_pages);
-               set_memory_rw((unsigned long)mod->module_init, total_pages);
-       }
+static void unset_module_init_ro_nx(struct module *mod)
+{
+       set_page_attributes(mod->module_init + mod->init_text_size,
+               mod->module_init + mod->init_size,
+               set_memory_x);
+       set_page_attributes(mod->module_init,
+               mod->module_init + mod->init_ro_size,
+               set_memory_rw);
 }
 
 /* Iterate through all modules and set each module's text as RW */
-void set_all_modules_text_rw()
+void set_all_modules_text_rw(void)
 {
        struct module *mod;
 
@@ -1648,7 +1672,7 @@ void set_all_modules_text_rw()
 }
 
 /* Iterate through all modules and set each module's text as RO */
-void set_all_modules_text_ro()
+void set_all_modules_text_ro(void)
 {
        struct module *mod;
 
@@ -1669,7 +1693,8 @@ void set_all_modules_text_ro()
 }
 #else
 static inline void set_section_ro_nx(void *base, unsigned long text_size, unsigned long ro_size, unsigned long total_size) { }
-static inline void unset_section_ro_nx(struct module *mod, void *module_region) { }
+static void unset_module_core_ro_nx(struct module *mod) { }
+static void unset_module_init_ro_nx(struct module *mod) { }
 #endif
 
 /* Free a module, remove from lists, etc. */
@@ -1696,7 +1721,7 @@ static void free_module(struct module *mod)
        destroy_params(mod->kp, mod->num_kp);
 
        /* This may be NULL, but that's OK */
-       unset_section_ro_nx(mod, mod->module_init);
+       unset_module_init_ro_nx(mod);
        module_free(mod, mod->module_init);
        kfree(mod->args);
        percpu_modfree(mod);
@@ -1705,7 +1730,7 @@ static void free_module(struct module *mod)
        lockdep_free_key_range(mod->module_core, mod->core_size);
 
        /* Finally, free the core (containing the module structure) */
-       unset_section_ro_nx(mod, mod->module_core);
+       unset_module_core_ro_nx(mod);
        module_free(mod, mod->module_core);
 
 #ifdef CONFIG_MPU
@@ -2030,11 +2055,8 @@ static const struct kernel_symbol *lookup_symbol(const char *name,
        const struct kernel_symbol *start,
        const struct kernel_symbol *stop)
 {
-       const struct kernel_symbol *ks = start;
-       for (; ks < stop; ks++)
-               if (strcmp(ks->name, name) == 0)
-                       return ks;
-       return NULL;
+       return bsearch(name, start, stop - start,
+                       sizeof(struct kernel_symbol), cmp_name);
 }
 
 static int is_exported(const char *name, unsigned long value,
@@ -2931,10 +2953,11 @@ SYSCALL_DEFINE3(init_module, void __user *, umod,
        mod->symtab = mod->core_symtab;
        mod->strtab = mod->core_strtab;
 #endif
-       unset_section_ro_nx(mod, mod->module_init);
+       unset_module_init_ro_nx(mod);
        module_free(mod, mod->module_init);
        mod->module_init = NULL;
        mod->init_size = 0;
+       mod->init_ro_size = 0;
        mod->init_text_size = 0;
        mutex_unlock(&module_mutex);
 
index ec815a9..73da83a 100644 (file)
@@ -75,7 +75,7 @@ void debug_mutex_unlock(struct mutex *lock)
                return;
 
        DEBUG_LOCKS_WARN_ON(lock->magic != lock);
-       DEBUG_LOCKS_WARN_ON(lock->owner != current_thread_info());
+       DEBUG_LOCKS_WARN_ON(lock->owner != current);
        DEBUG_LOCKS_WARN_ON(!lock->wait_list.prev && !lock->wait_list.next);
        mutex_clear_owner(lock);
 }
index 57d527a..0799fd3 100644 (file)
@@ -29,7 +29,7 @@ extern void debug_mutex_init(struct mutex *lock, const char *name,
 
 static inline void mutex_set_owner(struct mutex *lock)
 {
-       lock->owner = current_thread_info();
+       lock->owner = current;
 }
 
 static inline void mutex_clear_owner(struct mutex *lock)
index c4195fa..2c938e2 100644 (file)
@@ -160,14 +160,7 @@ __mutex_lock_common(struct mutex *lock, long state, unsigned int subclass,
         */
 
        for (;;) {
-               struct thread_info *owner;
-
-               /*
-                * If we own the BKL, then don't spin. The owner of
-                * the mutex might be waiting on us to release the BKL.
-                */
-               if (unlikely(current->lock_depth >= 0))
-                       break;
+               struct task_struct *owner;
 
                /*
                 * If there's an owner, wait for it to either
index 67578ca..4115fbf 100644 (file)
@@ -19,7 +19,7 @@
 #ifdef CONFIG_SMP
 static inline void mutex_set_owner(struct mutex *lock)
 {
-       lock->owner = current_thread_info();
+       lock->owner = current;
 }
 
 static inline void mutex_clear_owner(struct mutex *lock)
index 7ab388a..ed72e13 100644 (file)
@@ -297,21 +297,15 @@ EXPORT_SYMBOL(param_ops_charp);
 int param_set_bool(const char *val, const struct kernel_param *kp)
 {
        bool v;
+       int ret;
 
        /* No equals means "set"... */
        if (!val) val = "1";
 
        /* One of =[yYnN01] */
-       switch (val[0]) {
-       case 'y': case 'Y': case '1':
-               v = true;
-               break;
-       case 'n': case 'N': case '0':
-               v = false;
-               break;
-       default:
-               return -EINVAL;
-       }
+       ret = strtobool(val, &v);
+       if (ret)
+               return ret;
 
        if (kp->flags & KPARAM_ISBOOL)
                *(bool *)kp->arg = v;
@@ -821,15 +815,18 @@ ssize_t __modver_version_show(struct module_attribute *mattr,
        return sprintf(buf, "%s\n", vattr->version);
 }
 
-extern struct module_version_attribute __start___modver[], __stop___modver[];
+extern const struct module_version_attribute *__start___modver[];
+extern const struct module_version_attribute *__stop___modver[];
 
 static void __init version_sysfs_builtin(void)
 {
-       const struct module_version_attribute *vattr;
+       const struct module_version_attribute **p;
        struct module_kobject *mk;
        int err;
 
-       for (vattr = __start___modver; vattr < __stop___modver; vattr++) {
+       for (p = __start___modver; p < __stop___modver; p++) {
+               const struct module_version_attribute *vattr = *p;
+
                mk = locate_module_kobject(vattr->module_name);
                if (mk) {
                        err = sysfs_create_file(&mk->kobj, &vattr->mattr.attr);
index 6de9a8f..87f4d24 100644 (file)
@@ -125,12 +125,6 @@ config PM_DEBUG
        code. This is helpful when debugging and reporting PM bugs, like
        suspend support.
 
-config PM_VERBOSE
-       bool "Verbose Power Management debugging"
-       depends on PM_DEBUG
-       ---help---
-       This option enables verbose messages from the Power Management code.
-
 config PM_ADVANCED_DEBUG
        bool "Extra PM attributes in sysfs for low-level debugging/testing"
        depends on PM_DEBUG
@@ -229,3 +223,7 @@ config PM_OPP
          representing individual voltage domains and provides SOC
          implementations a ready to use framework to manage OPPs.
          For more information, read <file:Documentation/power/opp.txt>
+
+config PM_RUNTIME_CLK
+       def_bool y
+       depends on PM_RUNTIME && HAVE_CLK
index 50aae66..f9bec56 100644 (file)
@@ -272,12 +272,7 @@ static int create_image(int platform_mode)
 
        local_irq_disable();
 
-       error = sysdev_suspend(PMSG_FREEZE);
-       if (!error) {
-               error = syscore_suspend();
-               if (error)
-                       sysdev_resume();
-       }
+       error = syscore_suspend();
        if (error) {
                printk(KERN_ERR "PM: Some system devices failed to power down, "
                        "aborting hibernation\n");
@@ -302,7 +297,6 @@ static int create_image(int platform_mode)
 
  Power_up:
        syscore_resume();
-       sysdev_resume();
        /* NOTE:  dpm_resume_noirq() is just a resume() for devices
         * that suspended with irqs off ... no overall powerup.
         */
@@ -333,20 +327,25 @@ static int create_image(int platform_mode)
 
 int hibernation_snapshot(int platform_mode)
 {
+       pm_message_t msg = PMSG_RECOVER;
        int error;
 
        error = platform_begin(platform_mode);
        if (error)
                goto Close;
 
+       error = dpm_prepare(PMSG_FREEZE);
+       if (error)
+               goto Complete_devices;
+
        /* Preallocate image memory before shutting down devices. */
        error = hibernate_preallocate_memory();
        if (error)
-               goto Close;
+               goto Complete_devices;
 
        suspend_console();
        pm_restrict_gfp_mask();
-       error = dpm_suspend_start(PMSG_FREEZE);
+       error = dpm_suspend(PMSG_FREEZE);
        if (error)
                goto Recover_platform;
 
@@ -364,13 +363,17 @@ int hibernation_snapshot(int platform_mode)
        if (error || !in_suspend)
                swsusp_free();
 
-       dpm_resume_end(in_suspend ?
-               (error ? PMSG_RECOVER : PMSG_THAW) : PMSG_RESTORE);
+       msg = in_suspend ? (error ? PMSG_RECOVER : PMSG_THAW) : PMSG_RESTORE;
+       dpm_resume(msg);
 
        if (error || !in_suspend)
                pm_restore_gfp_mask();
 
        resume_console();
+
+ Complete_devices:
+       dpm_complete(msg);
+
  Close:
        platform_end(platform_mode);
        return error;
@@ -409,12 +412,7 @@ static int resume_target_kernel(bool platform_mode)
 
        local_irq_disable();
 
-       error = sysdev_suspend(PMSG_QUIESCE);
-       if (!error) {
-               error = syscore_suspend();
-               if (error)
-                       sysdev_resume();
-       }
+       error = syscore_suspend();
        if (error)
                goto Enable_irqs;
 
@@ -442,7 +440,6 @@ static int resume_target_kernel(bool platform_mode)
        touch_softlockup_watchdog();
 
        syscore_resume();
-       sysdev_resume();
 
  Enable_irqs:
        local_irq_enable();
@@ -528,7 +525,6 @@ int hibernation_platform_enter(void)
                goto Platform_finish;
 
        local_irq_disable();
-       sysdev_suspend(PMSG_HIBERNATE);
        syscore_suspend();
        if (pm_wakeup_pending()) {
                error = -EAGAIN;
@@ -541,7 +537,6 @@ int hibernation_platform_enter(void)
 
  Power_up:
        syscore_resume();
-       sysdev_resume();
        local_irq_enable();
        enable_nonboot_cpus();
 
@@ -982,10 +977,33 @@ static ssize_t image_size_store(struct kobject *kobj, struct kobj_attribute *att
 
 power_attr(image_size);
 
+static ssize_t reserved_size_show(struct kobject *kobj,
+                                 struct kobj_attribute *attr, char *buf)
+{
+       return sprintf(buf, "%lu\n", reserved_size);
+}
+
+static ssize_t reserved_size_store(struct kobject *kobj,
+                                  struct kobj_attribute *attr,
+                                  const char *buf, size_t n)
+{
+       unsigned long size;
+
+       if (sscanf(buf, "%lu", &size) == 1) {
+               reserved_size = size;
+               return n;
+       }
+
+       return -EINVAL;
+}
+
+power_attr(reserved_size);
+
 static struct attribute * g[] = {
        &disk_attr.attr,
        &resume_attr.attr,
        &image_size_attr.attr,
+       &reserved_size_attr.attr,
        NULL,
 };
 
index de9aef8..2981af4 100644 (file)
@@ -337,6 +337,7 @@ static int __init pm_init(void)
        if (error)
                return error;
        hibernate_image_size_init();
+       hibernate_reserved_size_init();
        power_kobj = kobject_create_and_add("power", NULL);
        if (!power_kobj)
                return -ENOMEM;
index 03634be..9a00a0a 100644 (file)
@@ -15,6 +15,7 @@ struct swsusp_info {
 
 #ifdef CONFIG_HIBERNATION
 /* kernel/power/snapshot.c */
+extern void __init hibernate_reserved_size_init(void);
 extern void __init hibernate_image_size_init(void);
 
 #ifdef CONFIG_ARCH_HIBERNATION_HEADER
@@ -55,6 +56,7 @@ extern int hibernation_platform_enter(void);
 
 #else /* !CONFIG_HIBERNATION */
 
+static inline void hibernate_reserved_size_init(void) {}
 static inline void hibernate_image_size_init(void) {}
 #endif /* !CONFIG_HIBERNATION */
 
@@ -72,6 +74,8 @@ static struct kobj_attribute _name##_attr = { \
 
 /* Preferred image size in bytes (default 500 MB) */
 extern unsigned long image_size;
+/* Size of memory reserved for drivers (default SPARE_PAGES x PAGE_SIZE) */
+extern unsigned long reserved_size;
 extern int in_suspend;
 extern dev_t swsusp_resume_device;
 extern sector_t swsusp_resume_block;
index ca0aacc..ace5588 100644 (file)
@@ -41,16 +41,28 @@ static void swsusp_set_page_forbidden(struct page *);
 static void swsusp_unset_page_forbidden(struct page *);
 
 /*
+ * Number of bytes to reserve for memory allocations made by device drivers
+ * from their ->freeze() and ->freeze_noirq() callbacks so that they don't
+ * cause image creation to fail (tunable via /sys/power/reserved_size).
+ */
+unsigned long reserved_size;
+
+void __init hibernate_reserved_size_init(void)
+{
+       reserved_size = SPARE_PAGES * PAGE_SIZE;
+}
+
+/*
  * Preferred image size in bytes (tunable via /sys/power/image_size).
- * When it is set to N, the image creating code will do its best to
- * ensure the image size will not exceed N bytes, but if that is
- * impossible, it will try to create the smallest image possible.
+ * When it is set to N, swsusp will do its best to ensure the image
+ * size will not exceed N bytes, but if that is impossible, it will
+ * try to create the smallest image possible.
  */
 unsigned long image_size;
 
 void __init hibernate_image_size_init(void)
 {
-       image_size = (totalram_pages / 3) * PAGE_SIZE;
+       image_size = ((totalram_pages * 2) / 5) * PAGE_SIZE;
 }
 
 /* List of PBEs needed for restoring the pages that were allocated before
@@ -1263,11 +1275,13 @@ static unsigned long minimum_image_size(unsigned long saveable)
  * frame in use.  We also need a number of page frames to be free during
  * hibernation for allocations made while saving the image and for device
  * drivers, in case they need to allocate memory from their hibernation
- * callbacks (these two numbers are given by PAGES_FOR_IO and SPARE_PAGES,
- * respectively, both of which are rough estimates).  To make this happen, we
- * compute the total number of available page frames and allocate at least
+ * callbacks (these two numbers are given by PAGES_FOR_IO (which is a rough
+ * estimate) and reserverd_size divided by PAGE_SIZE (which is tunable through
+ * /sys/power/reserved_size, respectively).  To make this happen, we compute the
+ * total number of available page frames and allocate at least
  *
- * ([page frames total] + PAGES_FOR_IO + [metadata pages]) / 2 + 2 * SPARE_PAGES
+ * ([page frames total] + PAGES_FOR_IO + [metadata pages]) / 2
+ *  + 2 * DIV_ROUND_UP(reserved_size, PAGE_SIZE)
  *
  * of them, which corresponds to the maximum size of a hibernation image.
  *
@@ -1322,7 +1336,8 @@ int hibernate_preallocate_memory(void)
        count -= totalreserve_pages;
 
        /* Compute the maximum number of saveable pages to leave in memory. */
-       max_size = (count - (size + PAGES_FOR_IO)) / 2 - 2 * SPARE_PAGES;
+       max_size = (count - (size + PAGES_FOR_IO)) / 2
+                       - 2 * DIV_ROUND_UP(reserved_size, PAGE_SIZE);
        /* Compute the desired number of image pages specified by image_size. */
        size = DIV_ROUND_UP(image_size, PAGE_SIZE);
        if (size > max_size)
index 8935369..1c41ba2 100644 (file)
@@ -163,19 +163,13 @@ static int suspend_enter(suspend_state_t state)
        arch_suspend_disable_irqs();
        BUG_ON(!irqs_disabled());
 
-       error = sysdev_suspend(PMSG_SUSPEND);
-       if (!error) {
-               error = syscore_suspend();
-               if (error)
-                       sysdev_resume();
-       }
+       error = syscore_suspend();
        if (!error) {
                if (!(suspend_test(TEST_CORE) || pm_wakeup_pending())) {
                        error = suspend_ops->enter(state);
                        events_check_enabled = false;
                }
                syscore_resume();
-               sysdev_resume();
        }
 
        arch_suspend_enable_irqs();
@@ -216,7 +210,6 @@ int suspend_devices_and_enter(suspend_state_t state)
                        goto Close;
        }
        suspend_console();
-       pm_restrict_gfp_mask();
        suspend_test_start();
        error = dpm_suspend_start(PMSG_SUSPEND);
        if (error) {
@@ -227,13 +220,12 @@ int suspend_devices_and_enter(suspend_state_t state)
        if (suspend_test(TEST_DEVICES))
                goto Recover_platform;
 
-       suspend_enter(state);
+       error = suspend_enter(state);
 
  Resume_devices:
        suspend_test_start();
        dpm_resume_end(PMSG_RESUME);
        suspend_test_finish("resume devices");
-       pm_restore_gfp_mask();
        resume_console();
  Close:
        if (suspend_ops->end)
@@ -294,7 +286,9 @@ int enter_state(suspend_state_t state)
                goto Finish;
 
        pr_debug("PM: Entering %s sleep\n", pm_states[state]);
+       pm_restrict_gfp_mask();
        error = suspend_devices_and_enter(state);
+       pm_restore_gfp_mask();
 
  Finish:
        pr_debug("PM: Finishing wakeup.\n");
index c36c3b9..7d02d33 100644 (file)
@@ -135,8 +135,10 @@ static int snapshot_release(struct inode *inode, struct file *filp)
        free_basic_memory_bitmaps();
        data = filp->private_data;
        free_all_swap_pages(data->swap);
-       if (data->frozen)
+       if (data->frozen) {
+               pm_restore_gfp_mask();
                thaw_processes();
+       }
        pm_notifier_call_chain(data->mode == O_RDONLY ?
                        PM_POST_HIBERNATION : PM_POST_RESTORE);
        atomic_inc(&snapshot_device_available);
@@ -379,6 +381,7 @@ static long snapshot_ioctl(struct file *filp, unsigned int cmd,
                 * PM_HIBERNATION_PREPARE
                 */
                error = suspend_devices_and_enter(PM_SUSPEND_MEM);
+               data->ready = 0;
                break;
 
        case SNAPSHOT_PLATFORM_SUPPORT:
index f3240e9..7784bd2 100644 (file)
@@ -142,10 +142,17 @@ static int rcuhead_fixup_init(void *addr, enum debug_obj_state state)
                 * Ensure that queued callbacks are all executed.
                 * If we detect that we are nested in a RCU read-side critical
                 * section, we should simply fail, otherwise we would deadlock.
+                * In !PREEMPT configurations, there is no way to tell if we are
+                * in a RCU read-side critical section or not, so we never
+                * attempt any fixup and just print a warning.
                 */
+#ifndef CONFIG_PREEMPT
+               WARN_ON_ONCE(1);
+               return 0;
+#endif
                if (rcu_preempt_depth() != 0 || preempt_count() != 0 ||
                    irqs_disabled()) {
-                       WARN_ON(1);
+                       WARN_ON_ONCE(1);
                        return 0;
                }
                rcu_barrier();
@@ -184,10 +191,17 @@ static int rcuhead_fixup_activate(void *addr, enum debug_obj_state state)
                 * Ensure that queued callbacks are all executed.
                 * If we detect that we are nested in a RCU read-side critical
                 * section, we should simply fail, otherwise we would deadlock.
+                * In !PREEMPT configurations, there is no way to tell if we are
+                * in a RCU read-side critical section or not, so we never
+                * attempt any fixup and just print a warning.
                 */
+#ifndef CONFIG_PREEMPT
+               WARN_ON_ONCE(1);
+               return 0;
+#endif
                if (rcu_preempt_depth() != 0 || preempt_count() != 0 ||
                    irqs_disabled()) {
-                       WARN_ON(1);
+                       WARN_ON_ONCE(1);
                        return 0;
                }
                rcu_barrier();
@@ -214,15 +228,17 @@ static int rcuhead_fixup_free(void *addr, enum debug_obj_state state)
                 * Ensure that queued callbacks are all executed.
                 * If we detect that we are nested in a RCU read-side critical
                 * section, we should simply fail, otherwise we would deadlock.
-                * Note that the machinery to reliably determine whether
-                * or not we are in an RCU read-side critical section
-                * exists only in the preemptible RCU implementations
-                * (TINY_PREEMPT_RCU and TREE_PREEMPT_RCU), which is why
-                * DEBUG_OBJECTS_RCU_HEAD is disallowed if !PREEMPT.
+                * In !PREEMPT configurations, there is no way to tell if we are
+                * in a RCU read-side critical section or not, so we never
+                * attempt any fixup and just print a warning.
                 */
+#ifndef CONFIG_PREEMPT
+               WARN_ON_ONCE(1);
+               return 0;
+#endif
                if (rcu_preempt_depth() != 0 || preempt_count() != 0 ||
                    irqs_disabled()) {
-                       WARN_ON(1);
+                       WARN_ON_ONCE(1);
                        return 0;
                }
                rcu_barrier();
index 0c343b9..421abfd 100644 (file)
 static struct task_struct *rcu_kthread_task;
 static DECLARE_WAIT_QUEUE_HEAD(rcu_kthread_wq);
 static unsigned long have_rcu_kthread_work;
-static void invoke_rcu_kthread(void);
 
 /* Forward declarations for rcutiny_plugin.h. */
 struct rcu_ctrlblk;
+static void invoke_rcu_kthread(void);
 static void rcu_process_callbacks(struct rcu_ctrlblk *rcp);
 static int rcu_kthread(void *arg);
 static void __call_rcu(struct rcu_head *head,
@@ -79,36 +79,45 @@ void rcu_exit_nohz(void)
 #endif /* #ifdef CONFIG_NO_HZ */
 
 /*
- * Helper function for rcu_qsctr_inc() and rcu_bh_qsctr_inc().
- * Also disable irqs to avoid confusion due to interrupt handlers
+ * Helper function for rcu_sched_qs() and rcu_bh_qs().
+ * Also irqs are disabled to avoid confusion due to interrupt handlers
  * invoking call_rcu().
  */
 static int rcu_qsctr_help(struct rcu_ctrlblk *rcp)
 {
-       unsigned long flags;
-
-       local_irq_save(flags);
        if (rcp->rcucblist != NULL &&
            rcp->donetail != rcp->curtail) {
                rcp->donetail = rcp->curtail;
-               local_irq_restore(flags);
                return 1;
        }
-       local_irq_restore(flags);
 
        return 0;
 }
 
 /*
+ * Wake up rcu_kthread() to process callbacks now eligible for invocation
+ * or to boost readers.
+ */
+static void invoke_rcu_kthread(void)
+{
+       have_rcu_kthread_work = 1;
+       wake_up(&rcu_kthread_wq);
+}
+
+/*
  * Record an rcu quiescent state.  And an rcu_bh quiescent state while we
  * are at it, given that any rcu quiescent state is also an rcu_bh
  * quiescent state.  Use "+" instead of "||" to defeat short circuiting.
  */
 void rcu_sched_qs(int cpu)
 {
+       unsigned long flags;
+
+       local_irq_save(flags);
        if (rcu_qsctr_help(&rcu_sched_ctrlblk) +
            rcu_qsctr_help(&rcu_bh_ctrlblk))
                invoke_rcu_kthread();
+       local_irq_restore(flags);
 }
 
 /*
@@ -116,8 +125,12 @@ void rcu_sched_qs(int cpu)
  */
 void rcu_bh_qs(int cpu)
 {
+       unsigned long flags;
+
+       local_irq_save(flags);
        if (rcu_qsctr_help(&rcu_bh_ctrlblk))
                invoke_rcu_kthread();
+       local_irq_restore(flags);
 }
 
 /*
@@ -167,7 +180,7 @@ static void rcu_process_callbacks(struct rcu_ctrlblk *rcp)
                prefetch(next);
                debug_rcu_head_unqueue(list);
                local_bh_disable();
-               list->func(list);
+               __rcu_reclaim(list);
                local_bh_enable();
                list = next;
                RCU_TRACE(cb_count++);
@@ -208,20 +221,6 @@ static int rcu_kthread(void *arg)
 }
 
 /*
- * Wake up rcu_kthread() to process callbacks now eligible for invocation
- * or to boost readers.
- */
-static void invoke_rcu_kthread(void)
-{
-       unsigned long flags;
-
-       local_irq_save(flags);
-       have_rcu_kthread_work = 1;
-       wake_up(&rcu_kthread_wq);
-       local_irq_restore(flags);
-}
-
-/*
  * Wait for a grace period to elapse.  But it is illegal to invoke
  * synchronize_sched() from within an RCU read-side critical section.
  * Therefore, any legal call to synchronize_sched() is a quiescent
index 3cb8e36..f259c67 100644 (file)
@@ -100,23 +100,28 @@ struct rcu_preempt_ctrlblk {
        u8 completed;           /* Last grace period completed. */
                                /*  If all three are equal, RCU is idle. */
 #ifdef CONFIG_RCU_BOOST
-       s8 boosted_this_gp;     /* Has boosting already happened? */
        unsigned long boost_time; /* When to start boosting (jiffies) */
 #endif /* #ifdef CONFIG_RCU_BOOST */
 #ifdef CONFIG_RCU_TRACE
        unsigned long n_grace_periods;
 #ifdef CONFIG_RCU_BOOST
        unsigned long n_tasks_boosted;
+                               /* Total number of tasks boosted. */
        unsigned long n_exp_boosts;
+                               /* Number of tasks boosted for expedited GP. */
        unsigned long n_normal_boosts;
-       unsigned long n_normal_balk_blkd_tasks;
-       unsigned long n_normal_balk_gp_tasks;
-       unsigned long n_normal_balk_boost_tasks;
-       unsigned long n_normal_balk_boosted;
-       unsigned long n_normal_balk_notyet;
-       unsigned long n_normal_balk_nos;
-       unsigned long n_exp_balk_blkd_tasks;
-       unsigned long n_exp_balk_nos;
+                               /* Number of tasks boosted for normal GP. */
+       unsigned long n_balk_blkd_tasks;
+                               /* Refused to boost: no blocked tasks. */
+       unsigned long n_balk_exp_gp_tasks;
+                               /* Refused to boost: nothing blocking GP. */
+       unsigned long n_balk_boost_tasks;
+                               /* Refused to boost: already boosting. */
+       unsigned long n_balk_notyet;
+                               /* Refused to boost: not yet time. */
+       unsigned long n_balk_nos;
+                               /* Refused to boost: not sure why, though. */
+                               /*  This can happen due to race conditions. */
 #endif /* #ifdef CONFIG_RCU_BOOST */
 #endif /* #ifdef CONFIG_RCU_TRACE */
 };
@@ -201,7 +206,6 @@ static struct list_head *rcu_next_node_entry(struct task_struct *t)
 
 #ifdef CONFIG_RCU_BOOST
 static void rcu_initiate_boost_trace(void);
-static void rcu_initiate_exp_boost_trace(void);
 #endif /* #ifdef CONFIG_RCU_BOOST */
 
 /*
@@ -219,41 +223,21 @@ static void show_tiny_preempt_stats(struct seq_file *m)
                   "N."[!rcu_preempt_ctrlblk.gp_tasks],
                   "E."[!rcu_preempt_ctrlblk.exp_tasks]);
 #ifdef CONFIG_RCU_BOOST
-       seq_printf(m, "             ttb=%c btg=",
-                  "B."[!rcu_preempt_ctrlblk.boost_tasks]);
-       switch (rcu_preempt_ctrlblk.boosted_this_gp) {
-       case -1:
-               seq_puts(m, "exp");
-               break;
-       case 0:
-               seq_puts(m, "no");
-               break;
-       case 1:
-               seq_puts(m, "begun");
-               break;
-       case 2:
-               seq_puts(m, "done");
-               break;
-       default:
-               seq_printf(m, "?%d?", rcu_preempt_ctrlblk.boosted_this_gp);
-       }
-       seq_printf(m, " ntb=%lu neb=%lu nnb=%lu j=%04x bt=%04x\n",
+       seq_printf(m, "%sttb=%c ntb=%lu neb=%lu nnb=%lu j=%04x bt=%04x\n",
+                  "             ",
+                  "B."[!rcu_preempt_ctrlblk.boost_tasks],
                   rcu_preempt_ctrlblk.n_tasks_boosted,
                   rcu_preempt_ctrlblk.n_exp_boosts,
                   rcu_preempt_ctrlblk.n_normal_boosts,
                   (int)(jiffies & 0xffff),
                   (int)(rcu_preempt_ctrlblk.boost_time & 0xffff));
-       seq_printf(m, "             %s: nt=%lu gt=%lu bt=%lu b=%lu ny=%lu nos=%lu\n",
-                  "normal balk",
-                  rcu_preempt_ctrlblk.n_normal_balk_blkd_tasks,
-                  rcu_preempt_ctrlblk.n_normal_balk_gp_tasks,
-                  rcu_preempt_ctrlblk.n_normal_balk_boost_tasks,
-                  rcu_preempt_ctrlblk.n_normal_balk_boosted,
-                  rcu_preempt_ctrlblk.n_normal_balk_notyet,
-                  rcu_preempt_ctrlblk.n_normal_balk_nos);
-       seq_printf(m, "             exp balk: bt=%lu nos=%lu\n",
-                  rcu_preempt_ctrlblk.n_exp_balk_blkd_tasks,
-                  rcu_preempt_ctrlblk.n_exp_balk_nos);
+       seq_printf(m, "%s: nt=%lu egt=%lu bt=%lu ny=%lu nos=%lu\n",
+                  "             balk",
+                  rcu_preempt_ctrlblk.n_balk_blkd_tasks,
+                  rcu_preempt_ctrlblk.n_balk_exp_gp_tasks,
+                  rcu_preempt_ctrlblk.n_balk_boost_tasks,
+                  rcu_preempt_ctrlblk.n_balk_notyet,
+                  rcu_preempt_ctrlblk.n_balk_nos);
 #endif /* #ifdef CONFIG_RCU_BOOST */
 }
 
@@ -271,25 +255,59 @@ static int rcu_boost(void)
 {
        unsigned long flags;
        struct rt_mutex mtx;
-       struct list_head *np;
        struct task_struct *t;
+       struct list_head *tb;
 
-       if (rcu_preempt_ctrlblk.boost_tasks == NULL)
+       if (rcu_preempt_ctrlblk.boost_tasks == NULL &&
+           rcu_preempt_ctrlblk.exp_tasks == NULL)
                return 0;  /* Nothing to boost. */
+
        raw_local_irq_save(flags);
-       rcu_preempt_ctrlblk.boosted_this_gp++;
-       t = container_of(rcu_preempt_ctrlblk.boost_tasks, struct task_struct,
-                        rcu_node_entry);
-       np = rcu_next_node_entry(t);
+
+       /*
+        * Recheck with irqs disabled: all tasks in need of boosting
+        * might exit their RCU read-side critical sections on their own
+        * if we are preempted just before disabling irqs.
+        */
+       if (rcu_preempt_ctrlblk.boost_tasks == NULL &&
+           rcu_preempt_ctrlblk.exp_tasks == NULL) {
+               raw_local_irq_restore(flags);
+               return 0;
+       }
+
+       /*
+        * Preferentially boost tasks blocking expedited grace periods.
+        * This cannot starve the normal grace periods because a second
+        * expedited grace period must boost all blocked tasks, including
+        * those blocking the pre-existing normal grace period.
+        */
+       if (rcu_preempt_ctrlblk.exp_tasks != NULL) {
+               tb = rcu_preempt_ctrlblk.exp_tasks;
+               RCU_TRACE(rcu_preempt_ctrlblk.n_exp_boosts++);
+       } else {
+               tb = rcu_preempt_ctrlblk.boost_tasks;
+               RCU_TRACE(rcu_preempt_ctrlblk.n_normal_boosts++);
+       }
+       RCU_TRACE(rcu_preempt_ctrlblk.n_tasks_boosted++);
+
+       /*
+        * We boost task t by manufacturing an rt_mutex that appears to
+        * be held by task t.  We leave a pointer to that rt_mutex where
+        * task t can find it, and task t will release the mutex when it
+        * exits its outermost RCU read-side critical section.  Then
+        * simply acquiring this artificial rt_mutex will boost task
+        * t's priority.  (Thanks to tglx for suggesting this approach!)
+        */
+       t = container_of(tb, struct task_struct, rcu_node_entry);
        rt_mutex_init_proxy_locked(&mtx, t);
        t->rcu_boost_mutex = &mtx;
        t->rcu_read_unlock_special |= RCU_READ_UNLOCK_BOOSTED;
        raw_local_irq_restore(flags);
        rt_mutex_lock(&mtx);
-       RCU_TRACE(rcu_preempt_ctrlblk.n_tasks_boosted++);
-       rcu_preempt_ctrlblk.boosted_this_gp++;
-       rt_mutex_unlock(&mtx);
-       return rcu_preempt_ctrlblk.boost_tasks != NULL;
+       rt_mutex_unlock(&mtx);  /* Keep lockdep happy. */
+
+       return rcu_preempt_ctrlblk.boost_tasks != NULL ||
+              rcu_preempt_ctrlblk.exp_tasks != NULL;
 }
 
 /*
@@ -304,42 +322,25 @@ static int rcu_boost(void)
  */
 static int rcu_initiate_boost(void)
 {
-       if (!rcu_preempt_blocked_readers_cgp()) {
-               RCU_TRACE(rcu_preempt_ctrlblk.n_normal_balk_blkd_tasks++);
+       if (!rcu_preempt_blocked_readers_cgp() &&
+           rcu_preempt_ctrlblk.exp_tasks == NULL) {
+               RCU_TRACE(rcu_preempt_ctrlblk.n_balk_exp_gp_tasks++);
                return 0;
        }
-       if (rcu_preempt_ctrlblk.gp_tasks != NULL &&
-           rcu_preempt_ctrlblk.boost_tasks == NULL &&
-           rcu_preempt_ctrlblk.boosted_this_gp == 0 &&
-           ULONG_CMP_GE(jiffies, rcu_preempt_ctrlblk.boost_time)) {
-               rcu_preempt_ctrlblk.boost_tasks = rcu_preempt_ctrlblk.gp_tasks;
+       if (rcu_preempt_ctrlblk.exp_tasks != NULL ||
+           (rcu_preempt_ctrlblk.gp_tasks != NULL &&
+            rcu_preempt_ctrlblk.boost_tasks == NULL &&
+            ULONG_CMP_GE(jiffies, rcu_preempt_ctrlblk.boost_time))) {
+               if (rcu_preempt_ctrlblk.exp_tasks == NULL)
+                       rcu_preempt_ctrlblk.boost_tasks =
+                               rcu_preempt_ctrlblk.gp_tasks;
                invoke_rcu_kthread();
-               RCU_TRACE(rcu_preempt_ctrlblk.n_normal_boosts++);
        } else
                RCU_TRACE(rcu_initiate_boost_trace());
        return 1;
 }
 
-/*
- * Initiate boosting for an expedited grace period.
- */
-static void rcu_initiate_expedited_boost(void)
-{
-       unsigned long flags;
-
-       raw_local_irq_save(flags);
-       if (!list_empty(&rcu_preempt_ctrlblk.blkd_tasks)) {
-               rcu_preempt_ctrlblk.boost_tasks =
-                       rcu_preempt_ctrlblk.blkd_tasks.next;
-               rcu_preempt_ctrlblk.boosted_this_gp = -1;
-               invoke_rcu_kthread();
-               RCU_TRACE(rcu_preempt_ctrlblk.n_exp_boosts++);
-       } else
-               RCU_TRACE(rcu_initiate_exp_boost_trace());
-       raw_local_irq_restore(flags);
-}
-
-#define RCU_BOOST_DELAY_JIFFIES DIV_ROUND_UP(CONFIG_RCU_BOOST_DELAY * HZ, 1000);
+#define RCU_BOOST_DELAY_JIFFIES DIV_ROUND_UP(CONFIG_RCU_BOOST_DELAY * HZ, 1000)
 
 /*
  * Do priority-boost accounting for the start of a new grace period.
@@ -347,8 +348,6 @@ static void rcu_initiate_expedited_boost(void)
 static void rcu_preempt_boost_start_gp(void)
 {
        rcu_preempt_ctrlblk.boost_time = jiffies + RCU_BOOST_DELAY_JIFFIES;
-       if (rcu_preempt_ctrlblk.boosted_this_gp > 0)
-               rcu_preempt_ctrlblk.boosted_this_gp = 0;
 }
 
 #else /* #ifdef CONFIG_RCU_BOOST */
@@ -372,13 +371,6 @@ static int rcu_initiate_boost(void)
 }
 
 /*
- * If there is no RCU priority boosting, we don't initiate expedited boosting.
- */
-static void rcu_initiate_expedited_boost(void)
-{
-}
-
-/*
  * If there is no RCU priority boosting, nothing to do at grace-period start.
  */
 static void rcu_preempt_boost_start_gp(void)
@@ -418,7 +410,7 @@ static void rcu_preempt_cpu_qs(void)
        if (!rcu_preempt_gp_in_progress())
                return;
        /*
-        * Check up on boosting.  If there are no readers blocking the
+        * Check up on boosting.  If there are readers blocking the
         * current grace period, leave.
         */
        if (rcu_initiate_boost())
@@ -578,7 +570,7 @@ static void rcu_read_unlock_special(struct task_struct *t)
                empty = !rcu_preempt_blocked_readers_cgp();
                empty_exp = rcu_preempt_ctrlblk.exp_tasks == NULL;
                np = rcu_next_node_entry(t);
-               list_del(&t->rcu_node_entry);
+               list_del_init(&t->rcu_node_entry);
                if (&t->rcu_node_entry == rcu_preempt_ctrlblk.gp_tasks)
                        rcu_preempt_ctrlblk.gp_tasks = np;
                if (&t->rcu_node_entry == rcu_preempt_ctrlblk.exp_tasks)
@@ -587,7 +579,6 @@ static void rcu_read_unlock_special(struct task_struct *t)
                if (&t->rcu_node_entry == rcu_preempt_ctrlblk.boost_tasks)
                        rcu_preempt_ctrlblk.boost_tasks = np;
 #endif /* #ifdef CONFIG_RCU_BOOST */
-               INIT_LIST_HEAD(&t->rcu_node_entry);
 
                /*
                 * If this was the last task on the current list, and if
@@ -812,13 +803,16 @@ void synchronize_rcu_expedited(void)
        rpcp->exp_tasks = rpcp->blkd_tasks.next;
        if (rpcp->exp_tasks == &rpcp->blkd_tasks)
                rpcp->exp_tasks = NULL;
-       local_irq_restore(flags);
 
        /* Wait for tail of ->blkd_tasks list to drain. */
-       if (rcu_preempted_readers_exp())
-               rcu_initiate_expedited_boost();
+       if (!rcu_preempted_readers_exp())
+               local_irq_restore(flags);
+       else {
+               rcu_initiate_boost();
+               local_irq_restore(flags);
                wait_event(sync_rcu_preempt_exp_wq,
                           !rcu_preempted_readers_exp());
+       }
 
        /* Clean up and exit. */
        barrier(); /* ensure expedited GP seen before counter increment. */
@@ -931,24 +925,17 @@ void __init rcu_scheduler_starting(void)
 
 static void rcu_initiate_boost_trace(void)
 {
-       if (rcu_preempt_ctrlblk.gp_tasks == NULL)
-               rcu_preempt_ctrlblk.n_normal_balk_gp_tasks++;
+       if (list_empty(&rcu_preempt_ctrlblk.blkd_tasks))
+               rcu_preempt_ctrlblk.n_balk_blkd_tasks++;
+       else if (rcu_preempt_ctrlblk.gp_tasks == NULL &&
+                rcu_preempt_ctrlblk.exp_tasks == NULL)
+               rcu_preempt_ctrlblk.n_balk_exp_gp_tasks++;
        else if (rcu_preempt_ctrlblk.boost_tasks != NULL)
-               rcu_preempt_ctrlblk.n_normal_balk_boost_tasks++;
-       else if (rcu_preempt_ctrlblk.boosted_this_gp != 0)
-               rcu_preempt_ctrlblk.n_normal_balk_boosted++;
+               rcu_preempt_ctrlblk.n_balk_boost_tasks++;
        else if (!ULONG_CMP_GE(jiffies, rcu_preempt_ctrlblk.boost_time))
-               rcu_preempt_ctrlblk.n_normal_balk_notyet++;
-       else
-               rcu_preempt_ctrlblk.n_normal_balk_nos++;
-}
-
-static void rcu_initiate_exp_boost_trace(void)
-{
-       if (list_empty(&rcu_preempt_ctrlblk.blkd_tasks))
-               rcu_preempt_ctrlblk.n_exp_balk_blkd_tasks++;
+               rcu_preempt_ctrlblk.n_balk_notyet++;
        else
-               rcu_preempt_ctrlblk.n_exp_balk_nos++;
+               rcu_preempt_ctrlblk.n_balk_nos++;
 }
 
 #endif /* #ifdef CONFIG_RCU_BOOST */
index c224da4..2e138db 100644 (file)
@@ -131,7 +131,7 @@ struct rcu_torture {
 
 static LIST_HEAD(rcu_torture_freelist);
 static struct rcu_torture __rcu *rcu_torture_current;
-static long rcu_torture_current_version;
+static unsigned long rcu_torture_current_version;
 static struct rcu_torture rcu_tortures[10 * RCU_TORTURE_PIPE_LEN];
 static DEFINE_SPINLOCK(rcu_torture_lock);
 static DEFINE_PER_CPU(long [RCU_TORTURE_PIPE_LEN + 1], rcu_torture_count) =
@@ -146,8 +146,6 @@ static atomic_t n_rcu_torture_mberror;
 static atomic_t n_rcu_torture_error;
 static long n_rcu_torture_boost_ktrerror;
 static long n_rcu_torture_boost_rterror;
-static long n_rcu_torture_boost_allocerror;
-static long n_rcu_torture_boost_afferror;
 static long n_rcu_torture_boost_failure;
 static long n_rcu_torture_boosts;
 static long n_rcu_torture_timers;
@@ -163,11 +161,11 @@ static int stutter_pause_test;
 #endif
 int rcutorture_runnable = RCUTORTURE_RUNNABLE_INIT;
 
-#ifdef CONFIG_RCU_BOOST
+#if defined(CONFIG_RCU_BOOST) && !defined(CONFIG_HOTPLUG_CPU)
 #define rcu_can_boost() 1
-#else /* #ifdef CONFIG_RCU_BOOST */
+#else /* #if defined(CONFIG_RCU_BOOST) && !defined(CONFIG_HOTPLUG_CPU) */
 #define rcu_can_boost() 0
-#endif /* #else #ifdef CONFIG_RCU_BOOST */
+#endif /* #else #if defined(CONFIG_RCU_BOOST) && !defined(CONFIG_HOTPLUG_CPU) */
 
 static unsigned long boost_starttime;  /* jiffies of next boost test start. */
 DEFINE_MUTEX(boost_mutex);             /* protect setting boost_starttime */
@@ -751,6 +749,7 @@ static int rcu_torture_boost(void *arg)
                n_rcu_torture_boost_rterror++;
        }
 
+       init_rcu_head_on_stack(&rbi.rcu);
        /* Each pass through the following loop does one boost-test cycle. */
        do {
                /* Wait for the next test interval. */
@@ -810,6 +809,7 @@ checkwait:  rcu_stutter_wait("rcu_torture_boost");
 
        /* Clean up and exit. */
        VERBOSE_PRINTK_STRING("rcu_torture_boost task stopping");
+       destroy_rcu_head_on_stack(&rbi.rcu);
        rcutorture_shutdown_absorb("rcu_torture_boost");
        while (!kthread_should_stop() || rbi.inflight)
                schedule_timeout_uninterruptible(1);
@@ -886,7 +886,7 @@ rcu_torture_writer(void *arg)
                        old_rp->rtort_pipe_count++;
                        cur_ops->deferred_free(old_rp);
                }
-               rcu_torture_current_version++;
+               rcutorture_record_progress(++rcu_torture_current_version);
                oldbatch = cur_ops->completed();
                rcu_stutter_wait("rcu_torture_writer");
        } while (!kthread_should_stop() && fullstop == FULLSTOP_DONTSTOP);
@@ -1066,8 +1066,8 @@ rcu_torture_printk(char *page)
        }
        cnt += sprintf(&page[cnt], "%s%s ", torture_type, TORTURE_FLAG);
        cnt += sprintf(&page[cnt],
-                      "rtc: %p ver: %ld tfle: %d rta: %d rtaf: %d rtf: %d "
-                      "rtmbe: %d rtbke: %ld rtbre: %ld rtbae: %ld rtbafe: %ld "
+                      "rtc: %p ver: %lu tfle: %d rta: %d rtaf: %d rtf: %d "
+                      "rtmbe: %d rtbke: %ld rtbre: %ld "
                       "rtbf: %ld rtb: %ld nt: %ld",
                       rcu_torture_current,
                       rcu_torture_current_version,
@@ -1078,16 +1078,12 @@ rcu_torture_printk(char *page)
                       atomic_read(&n_rcu_torture_mberror),
                       n_rcu_torture_boost_ktrerror,
                       n_rcu_torture_boost_rterror,
-                      n_rcu_torture_boost_allocerror,
-                      n_rcu_torture_boost_afferror,
                       n_rcu_torture_boost_failure,
                       n_rcu_torture_boosts,
                       n_rcu_torture_timers);
        if (atomic_read(&n_rcu_torture_mberror) != 0 ||
            n_rcu_torture_boost_ktrerror != 0 ||
            n_rcu_torture_boost_rterror != 0 ||
-           n_rcu_torture_boost_allocerror != 0 ||
-           n_rcu_torture_boost_afferror != 0 ||
            n_rcu_torture_boost_failure != 0)
                cnt += sprintf(&page[cnt], " !!!");
        cnt += sprintf(&page[cnt], "\n%s%s ", torture_type, TORTURE_FLAG);
@@ -1331,6 +1327,7 @@ rcu_torture_cleanup(void)
        int i;
 
        mutex_lock(&fullstop_mutex);
+       rcutorture_record_test_transition();
        if (fullstop == FULLSTOP_SHUTDOWN) {
                printk(KERN_WARNING /* but going down anyway, so... */
                       "Concurrent 'rmmod rcutorture' and shutdown illegal!\n");
@@ -1486,8 +1483,6 @@ rcu_torture_init(void)
        atomic_set(&n_rcu_torture_error, 0);
        n_rcu_torture_boost_ktrerror = 0;
        n_rcu_torture_boost_rterror = 0;
-       n_rcu_torture_boost_allocerror = 0;
-       n_rcu_torture_boost_afferror = 0;
        n_rcu_torture_boost_failure = 0;
        n_rcu_torture_boosts = 0;
        for (i = 0; i < RCU_TORTURE_PIPE_LEN + 1; i++)
@@ -1624,6 +1619,7 @@ rcu_torture_init(void)
                }
        }
        register_reboot_notifier(&rcutorture_shutdown_nb);
+       rcutorture_record_test_transition();
        mutex_unlock(&fullstop_mutex);
        return 0;
 
index dd4aea8..e486f7c 100644 (file)
@@ -47,6 +47,8 @@
 #include <linux/mutex.h>
 #include <linux/time.h>
 #include <linux/kernel_stat.h>
+#include <linux/wait.h>
+#include <linux/kthread.h>
 
 #include "rcutree.h"
 
@@ -79,10 +81,41 @@ DEFINE_PER_CPU(struct rcu_data, rcu_sched_data);
 struct rcu_state rcu_bh_state = RCU_STATE_INITIALIZER(rcu_bh_state);
 DEFINE_PER_CPU(struct rcu_data, rcu_bh_data);
 
+static struct rcu_state *rcu_state;
+
 int rcu_scheduler_active __read_mostly;
 EXPORT_SYMBOL_GPL(rcu_scheduler_active);
 
 /*
+ * Control variables for per-CPU and per-rcu_node kthreads.  These
+ * handle all flavors of RCU.
+ */
+static DEFINE_PER_CPU(struct task_struct *, rcu_cpu_kthread_task);
+DEFINE_PER_CPU(unsigned int, rcu_cpu_kthread_status);
+DEFINE_PER_CPU(int, rcu_cpu_kthread_cpu);
+DEFINE_PER_CPU(unsigned int, rcu_cpu_kthread_loops);
+static DEFINE_PER_CPU(wait_queue_head_t, rcu_cpu_wq);
+DEFINE_PER_CPU(char, rcu_cpu_has_work);
+static char rcu_kthreads_spawnable;
+
+static void rcu_node_kthread_setaffinity(struct rcu_node *rnp, int outgoingcpu);
+static void invoke_rcu_cpu_kthread(void);
+
+#define RCU_KTHREAD_PRIO 1     /* RT priority for per-CPU kthreads. */
+
+/*
+ * Track the rcutorture test sequence number and the update version
+ * number within a given test.  The rcutorture_testseq is incremented
+ * on every rcutorture module load and unload, so has an odd value
+ * when a test is running.  The rcutorture_vernum is set to zero
+ * when rcutorture starts and is incremented on each rcutorture update.
+ * These variables enable correlating rcutorture output with the
+ * RCU tracing information.
+ */
+unsigned long rcutorture_testseq;
+unsigned long rcutorture_vernum;
+
+/*
  * Return true if an RCU grace period is in progress.  The ACCESS_ONCE()s
  * permit this function to be invoked without holding the root rcu_node
  * structure's ->lock, but of course results can be subject to change.
@@ -124,6 +157,7 @@ void rcu_note_context_switch(int cpu)
        rcu_sched_qs(cpu);
        rcu_preempt_note_context_switch(cpu);
 }
+EXPORT_SYMBOL_GPL(rcu_note_context_switch);
 
 #ifdef CONFIG_NO_HZ
 DEFINE_PER_CPU(struct rcu_dynticks, rcu_dynticks) = {
@@ -140,10 +174,8 @@ module_param(blimit, int, 0);
 module_param(qhimark, int, 0);
 module_param(qlowmark, int, 0);
 
-#ifdef CONFIG_RCU_CPU_STALL_DETECTOR
-int rcu_cpu_stall_suppress __read_mostly = RCU_CPU_STALL_SUPPRESS_INIT;
+int rcu_cpu_stall_suppress __read_mostly;
 module_param(rcu_cpu_stall_suppress, int, 0644);
-#endif /* #ifdef CONFIG_RCU_CPU_STALL_DETECTOR */
 
 static void force_quiescent_state(struct rcu_state *rsp, int relaxed);
 static int rcu_pending(int cpu);
@@ -176,6 +208,31 @@ void rcu_bh_force_quiescent_state(void)
 EXPORT_SYMBOL_GPL(rcu_bh_force_quiescent_state);
 
 /*
+ * Record the number of times rcutorture tests have been initiated and
+ * terminated.  This information allows the debugfs tracing stats to be
+ * correlated to the rcutorture messages, even when the rcutorture module
+ * is being repeatedly loaded and unloaded.  In other words, we cannot
+ * store this state in rcutorture itself.
+ */
+void rcutorture_record_test_transition(void)
+{
+       rcutorture_testseq++;
+       rcutorture_vernum = 0;
+}
+EXPORT_SYMBOL_GPL(rcutorture_record_test_transition);
+
+/*
+ * Record the number of writer passes through the current rcutorture test.
+ * This is also used to correlate debugfs tracing stats with the rcutorture
+ * messages.
+ */
+void rcutorture_record_progress(unsigned long vernum)
+{
+       rcutorture_vernum++;
+}
+EXPORT_SYMBOL_GPL(rcutorture_record_progress);
+
+/*
  * Force a quiescent state for RCU-sched.
  */
 void rcu_sched_force_quiescent_state(void)
@@ -234,8 +291,8 @@ static int rcu_implicit_offline_qs(struct rcu_data *rdp)
                return 1;
        }
 
-       /* If preemptable RCU, no point in sending reschedule IPI. */
-       if (rdp->preemptable)
+       /* If preemptible RCU, no point in sending reschedule IPI. */
+       if (rdp->preemptible)
                return 0;
 
        /* The CPU is online, so send it a reschedule IPI. */
@@ -450,8 +507,6 @@ static int rcu_implicit_dynticks_qs(struct rcu_data *rdp)
 
 #endif /* #else #ifdef CONFIG_NO_HZ */
 
-#ifdef CONFIG_RCU_CPU_STALL_DETECTOR
-
 int rcu_cpu_stall_suppress __read_mostly;
 
 static void record_gp_stall_check_time(struct rcu_state *rsp)
@@ -537,21 +592,24 @@ static void print_cpu_stall(struct rcu_state *rsp)
 
 static void check_cpu_stall(struct rcu_state *rsp, struct rcu_data *rdp)
 {
-       long delta;
+       unsigned long j;
+       unsigned long js;
        struct rcu_node *rnp;
 
        if (rcu_cpu_stall_suppress)
                return;
-       delta = jiffies - ACCESS_ONCE(rsp->jiffies_stall);
+       j = ACCESS_ONCE(jiffies);
+       js = ACCESS_ONCE(rsp->jiffies_stall);
        rnp = rdp->mynode;
-       if ((ACCESS_ONCE(rnp->qsmask) & rdp->grpmask) && delta >= 0) {
+       if ((ACCESS_ONCE(rnp->qsmask) & rdp->grpmask) && ULONG_CMP_GE(j, js)) {
 
                /* We haven't checked in, so go dump stack. */
                print_cpu_stall(rsp);
 
-       } else if (rcu_gp_in_progress(rsp) && delta >= RCU_STALL_RAT_DELAY) {
+       } else if (rcu_gp_in_progress(rsp) &&
+                  ULONG_CMP_GE(j, js + RCU_STALL_RAT_DELAY)) {
 
-               /* They had two time units to dump stack, so complain. */
+               /* They had a few time units to dump stack, so complain. */
                print_other_cpu_stall(rsp);
        }
 }
@@ -587,26 +645,6 @@ static void __init check_cpu_stall_init(void)
        atomic_notifier_chain_register(&panic_notifier_list, &rcu_panic_block);
 }
 
-#else /* #ifdef CONFIG_RCU_CPU_STALL_DETECTOR */
-
-static void record_gp_stall_check_time(struct rcu_state *rsp)
-{
-}
-
-static void check_cpu_stall(struct rcu_state *rsp, struct rcu_data *rdp)
-{
-}
-
-void rcu_cpu_stall_reset(void)
-{
-}
-
-static void __init check_cpu_stall_init(void)
-{
-}
-
-#endif /* #else #ifdef CONFIG_RCU_CPU_STALL_DETECTOR */
-
 /*
  * Update CPU-local rcu_data state to record the newly noticed grace period.
  * This is used both when we started the grace period and when we notice
@@ -809,6 +847,7 @@ rcu_start_gp(struct rcu_state *rsp, unsigned long flags)
                rnp->completed = rsp->completed;
                rsp->signaled = RCU_SIGNAL_INIT; /* force_quiescent_state OK. */
                rcu_start_gp_per_cpu(rsp, rnp, rdp);
+               rcu_preempt_boost_start_gp(rnp);
                raw_spin_unlock_irqrestore(&rnp->lock, flags);
                return;
        }
@@ -844,6 +883,7 @@ rcu_start_gp(struct rcu_state *rsp, unsigned long flags)
                rnp->completed = rsp->completed;
                if (rnp == rdp->mynode)
                        rcu_start_gp_per_cpu(rsp, rnp, rdp);
+               rcu_preempt_boost_start_gp(rnp);
                raw_spin_unlock(&rnp->lock);    /* irqs remain disabled. */
        }
 
@@ -864,7 +904,12 @@ rcu_start_gp(struct rcu_state *rsp, unsigned long flags)
 static void rcu_report_qs_rsp(struct rcu_state *rsp, unsigned long flags)
        __releases(rcu_get_root(rsp)->lock)
 {
+       unsigned long gp_duration;
+
        WARN_ON_ONCE(!rcu_gp_in_progress(rsp));
+       gp_duration = jiffies - rsp->gp_start;
+       if (gp_duration > rsp->gp_max)
+               rsp->gp_max = gp_duration;
        rsp->completed = rsp->gpnum;
        rsp->signaled = RCU_GP_IDLE;
        rcu_start_gp(rsp, flags);  /* releases root node's rnp->lock. */
@@ -894,7 +939,7 @@ rcu_report_qs_rnp(unsigned long mask, struct rcu_state *rsp,
                        return;
                }
                rnp->qsmask &= ~mask;
-               if (rnp->qsmask != 0 || rcu_preempted_readers(rnp)) {
+               if (rnp->qsmask != 0 || rcu_preempt_blocked_readers_cgp(rnp)) {
 
                        /* Other bits still set at this level, so done. */
                        raw_spin_unlock_irqrestore(&rnp->lock, flags);
@@ -1037,6 +1082,8 @@ static void rcu_send_cbs_to_online(struct rcu_state *rsp)
 /*
  * Remove the outgoing CPU from the bitmasks in the rcu_node hierarchy
  * and move all callbacks from the outgoing CPU to the current one.
+ * There can only be one CPU hotplug operation at a time, so no other
+ * CPU can be attempting to update rcu_cpu_kthread_task.
  */
 static void __rcu_offline_cpu(int cpu, struct rcu_state *rsp)
 {
@@ -1045,6 +1092,14 @@ static void __rcu_offline_cpu(int cpu, struct rcu_state *rsp)
        int need_report = 0;
        struct rcu_data *rdp = per_cpu_ptr(rsp->rda, cpu);
        struct rcu_node *rnp;
+       struct task_struct *t;
+
+       /* Stop the CPU's kthread. */
+       t = per_cpu(rcu_cpu_kthread_task, cpu);
+       if (t != NULL) {
+               per_cpu(rcu_cpu_kthread_task, cpu) = NULL;
+               kthread_stop(t);
+       }
 
        /* Exclude any attempts to start a new grace period. */
        raw_spin_lock_irqsave(&rsp->onofflock, flags);
@@ -1082,6 +1137,7 @@ static void __rcu_offline_cpu(int cpu, struct rcu_state *rsp)
                raw_spin_unlock_irqrestore(&rnp->lock, flags);
        if (need_report & RCU_OFL_TASKS_EXP_GP)
                rcu_report_exp_rnp(rsp, rnp);
+       rcu_node_kthread_setaffinity(rnp, -1);
 }
 
 /*
@@ -1143,7 +1199,7 @@ static void rcu_do_batch(struct rcu_state *rsp, struct rcu_data *rdp)
                next = list->next;
                prefetch(next);
                debug_rcu_head_unqueue(list);
-               list->func(list);
+               __rcu_reclaim(list);
                list = next;
                if (++count >= rdp->blimit)
                        break;
@@ -1179,7 +1235,7 @@ static void rcu_do_batch(struct rcu_state *rsp, struct rcu_data *rdp)
 
        /* Re-raise the RCU softirq if there are callbacks remaining. */
        if (cpu_has_callbacks_ready_to_invoke(rdp))
-               raise_softirq(RCU_SOFTIRQ);
+               invoke_rcu_cpu_kthread();
 }
 
 /*
@@ -1225,7 +1281,7 @@ void rcu_check_callbacks(int cpu, int user)
        }
        rcu_preempt_check_callbacks(cpu);
        if (rcu_pending(cpu))
-               raise_softirq(RCU_SOFTIRQ);
+               invoke_rcu_cpu_kthread();
 }
 
 #ifdef CONFIG_SMP
@@ -1233,6 +1289,8 @@ void rcu_check_callbacks(int cpu, int user)
 /*
  * Scan the leaf rcu_node structures, processing dyntick state for any that
  * have not yet encountered a quiescent state, using the function specified.
+ * Also initiate boosting for any threads blocked on the root rcu_node.
+ *
  * The caller must have suppressed start of new grace periods.
  */
 static void force_qs_rnp(struct rcu_state *rsp, int (*f)(struct rcu_data *))
@@ -1251,7 +1309,7 @@ static void force_qs_rnp(struct rcu_state *rsp, int (*f)(struct rcu_data *))
                        return;
                }
                if (rnp->qsmask == 0) {
-                       raw_spin_unlock_irqrestore(&rnp->lock, flags);
+                       rcu_initiate_boost(rnp, flags); /* releases rnp->lock */
                        continue;
                }
                cpu = rnp->grplo;
@@ -1269,6 +1327,11 @@ static void force_qs_rnp(struct rcu_state *rsp, int (*f)(struct rcu_data *))
                }
                raw_spin_unlock_irqrestore(&rnp->lock, flags);
        }
+       rnp = rcu_get_root(rsp);
+       if (rnp->qsmask == 0) {
+               raw_spin_lock_irqsave(&rnp->lock, flags);
+               rcu_initiate_boost(rnp, flags); /* releases rnp->lock. */
+       }
 }
 
 /*
@@ -1389,7 +1452,7 @@ __rcu_process_callbacks(struct rcu_state *rsp, struct rcu_data *rdp)
 /*
  * Do softirq processing for the current CPU.
  */
-static void rcu_process_callbacks(struct softirq_action *unused)
+static void rcu_process_callbacks(void)
 {
        /*
         * Memory references from any prior RCU read-side critical sections
@@ -1414,6 +1477,347 @@ static void rcu_process_callbacks(struct softirq_action *unused)
        rcu_needs_cpu_flush();
 }
 
+/*
+ * Wake up the current CPU's kthread.  This replaces raise_softirq()
+ * in earlier versions of RCU.  Note that because we are running on
+ * the current CPU with interrupts disabled, the rcu_cpu_kthread_task
+ * cannot disappear out from under us.
+ */
+static void invoke_rcu_cpu_kthread(void)
+{
+       unsigned long flags;
+
+       local_irq_save(flags);
+       __this_cpu_write(rcu_cpu_has_work, 1);
+       if (__this_cpu_read(rcu_cpu_kthread_task) == NULL) {
+               local_irq_restore(flags);
+               return;
+       }
+       wake_up(&__get_cpu_var(rcu_cpu_wq));
+       local_irq_restore(flags);
+}
+
+/*
+ * Wake up the specified per-rcu_node-structure kthread.
+ * Because the per-rcu_node kthreads are immortal, we don't need
+ * to do anything to keep them alive.
+ */
+static void invoke_rcu_node_kthread(struct rcu_node *rnp)
+{
+       struct task_struct *t;
+
+       t = rnp->node_kthread_task;
+       if (t != NULL)
+               wake_up_process(t);
+}
+
+/*
+ * Set the specified CPU's kthread to run RT or not, as specified by
+ * the to_rt argument.  The CPU-hotplug locks are held, so the task
+ * is not going away.
+ */
+static void rcu_cpu_kthread_setrt(int cpu, int to_rt)
+{
+       int policy;
+       struct sched_param sp;
+       struct task_struct *t;
+
+       t = per_cpu(rcu_cpu_kthread_task, cpu);
+       if (t == NULL)
+               return;
+       if (to_rt) {
+               policy = SCHED_FIFO;
+               sp.sched_priority = RCU_KTHREAD_PRIO;
+       } else {
+               policy = SCHED_NORMAL;
+               sp.sched_priority = 0;
+       }
+       sched_setscheduler_nocheck(t, policy, &sp);
+}
+
+/*
+ * Timer handler to initiate the waking up of per-CPU kthreads that
+ * have yielded the CPU due to excess numbers of RCU callbacks.
+ * We wake up the per-rcu_node kthread, which in turn will wake up
+ * the booster kthread.
+ */
+static void rcu_cpu_kthread_timer(unsigned long arg)
+{
+       unsigned long flags;
+       struct rcu_data *rdp = per_cpu_ptr(rcu_state->rda, arg);
+       struct rcu_node *rnp = rdp->mynode;
+
+       raw_spin_lock_irqsave(&rnp->lock, flags);
+       rnp->wakemask |= rdp->grpmask;
+       raw_spin_unlock_irqrestore(&rnp->lock, flags);
+       invoke_rcu_node_kthread(rnp);
+}
+
+/*
+ * Drop to non-real-time priority and yield, but only after posting a
+ * timer that will cause us to regain our real-time priority if we
+ * remain preempted.  Either way, we restore our real-time priority
+ * before returning.
+ */
+static void rcu_yield(void (*f)(unsigned long), unsigned long arg)
+{
+       struct sched_param sp;
+       struct timer_list yield_timer;
+
+       setup_timer_on_stack(&yield_timer, f, arg);
+       mod_timer(&yield_timer, jiffies + 2);
+       sp.sched_priority = 0;
+       sched_setscheduler_nocheck(current, SCHED_NORMAL, &sp);
+       set_user_nice(current, 19);
+       schedule();
+       sp.sched_priority = RCU_KTHREAD_PRIO;
+       sched_setscheduler_nocheck(current, SCHED_FIFO, &sp);
+       del_timer(&yield_timer);
+}
+
+/*
+ * Handle cases where the rcu_cpu_kthread() ends up on the wrong CPU.
+ * This can happen while the corresponding CPU is either coming online
+ * or going offline.  We cannot wait until the CPU is fully online
+ * before starting the kthread, because the various notifier functions
+ * can wait for RCU grace periods.  So we park rcu_cpu_kthread() until
+ * the corresponding CPU is online.
+ *
+ * Return 1 if the kthread needs to stop, 0 otherwise.
+ *
+ * Caller must disable bh.  This function can momentarily enable it.
+ */
+static int rcu_cpu_kthread_should_stop(int cpu)
+{
+       while (cpu_is_offline(cpu) ||
+              !cpumask_equal(&current->cpus_allowed, cpumask_of(cpu)) ||
+              smp_processor_id() != cpu) {
+               if (kthread_should_stop())
+                       return 1;
+               per_cpu(rcu_cpu_kthread_status, cpu) = RCU_KTHREAD_OFFCPU;
+               per_cpu(rcu_cpu_kthread_cpu, cpu) = raw_smp_processor_id();
+               local_bh_enable();
+               schedule_timeout_uninterruptible(1);
+               if (!cpumask_equal(&current->cpus_allowed, cpumask_of(cpu)))
+                       set_cpus_allowed_ptr(current, cpumask_of(cpu));
+               local_bh_disable();
+       }
+       per_cpu(rcu_cpu_kthread_cpu, cpu) = cpu;
+       return 0;
+}
+
+/*
+ * Per-CPU kernel thread that invokes RCU callbacks.  This replaces the
+ * earlier RCU softirq.
+ */
+static int rcu_cpu_kthread(void *arg)
+{
+       int cpu = (int)(long)arg;
+       unsigned long flags;
+       int spincnt = 0;
+       unsigned int *statusp = &per_cpu(rcu_cpu_kthread_status, cpu);
+       wait_queue_head_t *wqp = &per_cpu(rcu_cpu_wq, cpu);
+       char work;
+       char *workp = &per_cpu(rcu_cpu_has_work, cpu);
+
+       for (;;) {
+               *statusp = RCU_KTHREAD_WAITING;
+               wait_event_interruptible(*wqp,
+                                        *workp != 0 || kthread_should_stop());
+               local_bh_disable();
+               if (rcu_cpu_kthread_should_stop(cpu)) {
+                       local_bh_enable();
+                       break;
+               }
+               *statusp = RCU_KTHREAD_RUNNING;
+               per_cpu(rcu_cpu_kthread_loops, cpu)++;
+               local_irq_save(flags);
+               work = *workp;
+               *workp = 0;
+               local_irq_restore(flags);
+               if (work)
+                       rcu_process_callbacks();
+               local_bh_enable();
+               if (*workp != 0)
+                       spincnt++;
+               else
+                       spincnt = 0;
+               if (spincnt > 10) {
+                       *statusp = RCU_KTHREAD_YIELDING;
+                       rcu_yield(rcu_cpu_kthread_timer, (unsigned long)cpu);
+                       spincnt = 0;
+               }
+       }
+       *statusp = RCU_KTHREAD_STOPPED;
+       return 0;
+}
+
+/*
+ * Spawn a per-CPU kthread, setting up affinity and priority.
+ * Because the CPU hotplug lock is held, no other CPU will be attempting
+ * to manipulate rcu_cpu_kthread_task.  There might be another CPU
+ * attempting to access it during boot, but the locking in kthread_bind()
+ * will enforce sufficient ordering.
+ */
+static int __cpuinit rcu_spawn_one_cpu_kthread(int cpu)
+{
+       struct sched_param sp;
+       struct task_struct *t;
+
+       if (!rcu_kthreads_spawnable ||
+           per_cpu(rcu_cpu_kthread_task, cpu) != NULL)
+               return 0;
+       t = kthread_create(rcu_cpu_kthread, (void *)(long)cpu, "rcuc%d", cpu);
+       if (IS_ERR(t))
+               return PTR_ERR(t);
+       kthread_bind(t, cpu);
+       per_cpu(rcu_cpu_kthread_cpu, cpu) = cpu;
+       WARN_ON_ONCE(per_cpu(rcu_cpu_kthread_task, cpu) != NULL);
+       per_cpu(rcu_cpu_kthread_task, cpu) = t;
+       wake_up_process(t);
+       sp.sched_priority = RCU_KTHREAD_PRIO;
+       sched_setscheduler_nocheck(t, SCHED_FIFO, &sp);
+       return 0;
+}
+
+/*
+ * Per-rcu_node kthread, which is in charge of waking up the per-CPU
+ * kthreads when needed.  We ignore requests to wake up kthreads
+ * for offline CPUs, which is OK because force_quiescent_state()
+ * takes care of this case.
+ */
+static int rcu_node_kthread(void *arg)
+{
+       int cpu;
+       unsigned long flags;
+       unsigned long mask;
+       struct rcu_node *rnp = (struct rcu_node *)arg;
+       struct sched_param sp;
+       struct task_struct *t;
+
+       for (;;) {
+               rnp->node_kthread_status = RCU_KTHREAD_WAITING;
+               wait_event_interruptible(rnp->node_wq, rnp->wakemask != 0);
+               rnp->node_kthread_status = RCU_KTHREAD_RUNNING;
+               raw_spin_lock_irqsave(&rnp->lock, flags);
+               mask = rnp->wakemask;
+               rnp->wakemask = 0;
+               rcu_initiate_boost(rnp, flags); /* releases rnp->lock. */
+               for (cpu = rnp->grplo; cpu <= rnp->grphi; cpu++, mask >>= 1) {
+                       if ((mask & 0x1) == 0)
+                               continue;
+                       preempt_disable();
+                       t = per_cpu(rcu_cpu_kthread_task, cpu);
+                       if (!cpu_online(cpu) || t == NULL) {
+                               preempt_enable();
+                               continue;
+                       }
+                       per_cpu(rcu_cpu_has_work, cpu) = 1;
+                       sp.sched_priority = RCU_KTHREAD_PRIO;
+                       sched_setscheduler_nocheck(t, SCHED_FIFO, &sp);
+                       preempt_enable();
+               }
+       }
+       /* NOTREACHED */
+       rnp->node_kthread_status = RCU_KTHREAD_STOPPED;
+       return 0;
+}
+
+/*
+ * Set the per-rcu_node kthread's affinity to cover all CPUs that are
+ * served by the rcu_node in question.  The CPU hotplug lock is still
+ * held, so the value of rnp->qsmaskinit will be stable.
+ *
+ * We don't include outgoingcpu in the affinity set, use -1 if there is
+ * no outgoing CPU.  If there are no CPUs left in the affinity set,
+ * this function allows the kthread to execute on any CPU.
+ */
+static void rcu_node_kthread_setaffinity(struct rcu_node *rnp, int outgoingcpu)
+{
+       cpumask_var_t cm;
+       int cpu;
+       unsigned long mask = rnp->qsmaskinit;
+
+       if (rnp->node_kthread_task == NULL)
+               return;
+       if (!alloc_cpumask_var(&cm, GFP_KERNEL))
+               return;
+       cpumask_clear(cm);
+       for (cpu = rnp->grplo; cpu <= rnp->grphi; cpu++, mask >>= 1)
+               if ((mask & 0x1) && cpu != outgoingcpu)
+                       cpumask_set_cpu(cpu, cm);
+       if (cpumask_weight(cm) == 0) {
+               cpumask_setall(cm);
+               for (cpu = rnp->grplo; cpu <= rnp->grphi; cpu++)
+                       cpumask_clear_cpu(cpu, cm);
+               WARN_ON_ONCE(cpumask_weight(cm) == 0);
+       }
+       set_cpus_allowed_ptr(rnp->node_kthread_task, cm);
+       rcu_boost_kthread_setaffinity(rnp, cm);
+       free_cpumask_var(cm);
+}
+
+/*
+ * Spawn a per-rcu_node kthread, setting priority and affinity.
+ * Called during boot before online/offline can happen, or, if
+ * during runtime, with the main CPU-hotplug locks held.  So only
+ * one of these can be executing at a time.
+ */
+static int __cpuinit rcu_spawn_one_node_kthread(struct rcu_state *rsp,
+                                               struct rcu_node *rnp)
+{
+       unsigned long flags;
+       int rnp_index = rnp - &rsp->node[0];
+       struct sched_param sp;
+       struct task_struct *t;
+
+       if (!rcu_kthreads_spawnable ||
+           rnp->qsmaskinit == 0)
+               return 0;
+       if (rnp->node_kthread_task == NULL) {
+               t = kthread_create(rcu_node_kthread, (void *)rnp,
+                                  "rcun%d", rnp_index);
+               if (IS_ERR(t))
+                       return PTR_ERR(t);
+               raw_spin_lock_irqsave(&rnp->lock, flags);
+               rnp->node_kthread_task = t;
+               raw_spin_unlock_irqrestore(&rnp->lock, flags);
+               wake_up_process(t);
+               sp.sched_priority = 99;
+               sched_setscheduler_nocheck(t, SCHED_FIFO, &sp);
+       }
+       return rcu_spawn_one_boost_kthread(rsp, rnp, rnp_index);
+}
+
+/*
+ * Spawn all kthreads -- called as soon as the scheduler is running.
+ */
+static int __init rcu_spawn_kthreads(void)
+{
+       int cpu;
+       struct rcu_node *rnp;
+
+       rcu_kthreads_spawnable = 1;
+       for_each_possible_cpu(cpu) {
+               init_waitqueue_head(&per_cpu(rcu_cpu_wq, cpu));
+               per_cpu(rcu_cpu_has_work, cpu) = 0;
+               if (cpu_online(cpu))
+                       (void)rcu_spawn_one_cpu_kthread(cpu);
+       }
+       rnp = rcu_get_root(rcu_state);
+       init_waitqueue_head(&rnp->node_wq);
+       rcu_init_boost_waitqueue(rnp);
+       (void)rcu_spawn_one_node_kthread(rcu_state, rnp);
+       if (NUM_RCU_NODES > 1)
+               rcu_for_each_leaf_node(rcu_state, rnp) {
+                       init_waitqueue_head(&rnp->node_wq);
+                       rcu_init_boost_waitqueue(rnp);
+                       (void)rcu_spawn_one_node_kthread(rcu_state, rnp);
+               }
+       return 0;
+}
+early_initcall(rcu_spawn_kthreads);
+
 static void
 __call_rcu(struct rcu_head *head, void (*func)(struct rcu_head *rcu),
           struct rcu_state *rsp)
@@ -1439,6 +1843,13 @@ __call_rcu(struct rcu_head *head, void (*func)(struct rcu_head *rcu),
        /* Add the callback to our list. */
        *rdp->nxttail[RCU_NEXT_TAIL] = head;
        rdp->nxttail[RCU_NEXT_TAIL] = &head->next;
+       rdp->qlen++;
+
+       /* If interrupts were disabled, don't dive into RCU core. */
+       if (irqs_disabled_flags(flags)) {
+               local_irq_restore(flags);
+               return;
+       }
 
        /*
         * Force the grace period if too many callbacks or too long waiting.
@@ -1447,7 +1858,7 @@ __call_rcu(struct rcu_head *head, void (*func)(struct rcu_head *rcu),
         * invoking force_quiescent_state() if the newly enqueued callback
         * is the only one waiting for a grace period to complete.
         */
-       if (unlikely(++rdp->qlen > rdp->qlen_last_fqs_check + qhimark)) {
+       if (unlikely(rdp->qlen > rdp->qlen_last_fqs_check + qhimark)) {
 
                /* Are we ignoring a completed grace period? */
                rcu_process_gp_end(rsp, rdp);
@@ -1583,7 +1994,7 @@ static int __rcu_pending(struct rcu_state *rsp, struct rcu_data *rdp)
                 * or RCU-bh, force a local reschedule.
                 */
                rdp->n_rp_qs_pending++;
-               if (!rdp->preemptable &&
+               if (!rdp->preemptible &&
                    ULONG_CMP_LT(ACCESS_ONCE(rsp->jiffies_force_qs) - 1,
                                 jiffies))
                        set_need_resched();
@@ -1760,7 +2171,7 @@ rcu_boot_init_percpu_data(int cpu, struct rcu_state *rsp)
  * that this CPU cannot possibly have any RCU callbacks in flight yet.
  */
 static void __cpuinit
-rcu_init_percpu_data(int cpu, struct rcu_state *rsp, int preemptable)
+rcu_init_percpu_data(int cpu, struct rcu_state *rsp, int preemptible)
 {
        unsigned long flags;
        unsigned long mask;
@@ -1772,7 +2183,7 @@ rcu_init_percpu_data(int cpu, struct rcu_state *rsp, int preemptable)
        rdp->passed_quiesc = 0;  /* We could be racing with new GP, */
        rdp->qs_pending = 1;     /*  so set up to respond to current GP. */
        rdp->beenonline = 1;     /* We have now been online. */
-       rdp->preemptable = preemptable;
+       rdp->preemptible = preemptible;
        rdp->qlen_last_fqs_check = 0;
        rdp->n_force_qs_snap = rsp->n_force_qs;
        rdp->blimit = blimit;
@@ -1813,6 +2224,19 @@ static void __cpuinit rcu_online_cpu(int cpu)
        rcu_preempt_init_percpu_data(cpu);
 }
 
+static void __cpuinit rcu_online_kthreads(int cpu)
+{
+       struct rcu_data *rdp = per_cpu_ptr(rcu_state->rda, cpu);
+       struct rcu_node *rnp = rdp->mynode;
+
+       /* Fire up the incoming CPU's kthread and leaf rcu_node kthread. */
+       if (rcu_kthreads_spawnable) {
+               (void)rcu_spawn_one_cpu_kthread(cpu);
+               if (rnp->node_kthread_task == NULL)
+                       (void)rcu_spawn_one_node_kthread(rcu_state, rnp);
+       }
+}
+
 /*
  * Handle CPU online/offline notification events.
  */
@@ -1820,11 +2244,23 @@ static int __cpuinit rcu_cpu_notify(struct notifier_block *self,
                                    unsigned long action, void *hcpu)
 {
        long cpu = (long)hcpu;
+       struct rcu_data *rdp = per_cpu_ptr(rcu_state->rda, cpu);
+       struct rcu_node *rnp = rdp->mynode;
 
        switch (action) {
        case CPU_UP_PREPARE:
        case CPU_UP_PREPARE_FROZEN:
                rcu_online_cpu(cpu);
+               rcu_online_kthreads(cpu);
+               break;
+       case CPU_ONLINE:
+       case CPU_DOWN_FAILED:
+               rcu_node_kthread_setaffinity(rnp, -1);
+               rcu_cpu_kthread_setrt(cpu, 1);
+               break;
+       case CPU_DOWN_PREPARE:
+               rcu_node_kthread_setaffinity(rnp, cpu);
+               rcu_cpu_kthread_setrt(cpu, 0);
                break;
        case CPU_DYING:
        case CPU_DYING_FROZEN:
@@ -1943,10 +2379,7 @@ static void __init rcu_init_one(struct rcu_state *rsp,
                                              j / rsp->levelspread[i - 1];
                        }
                        rnp->level = i;
-                       INIT_LIST_HEAD(&rnp->blocked_tasks[0]);
-                       INIT_LIST_HEAD(&rnp->blocked_tasks[1]);
-                       INIT_LIST_HEAD(&rnp->blocked_tasks[2]);
-                       INIT_LIST_HEAD(&rnp->blocked_tasks[3]);
+                       INIT_LIST_HEAD(&rnp->blkd_tasks);
                }
        }
 
@@ -1968,7 +2401,6 @@ void __init rcu_init(void)
        rcu_init_one(&rcu_sched_state, &rcu_sched_data);
        rcu_init_one(&rcu_bh_state, &rcu_bh_data);
        __rcu_init_preempt();
-       open_softirq(RCU_SOFTIRQ, rcu_process_callbacks);
 
        /*
         * We don't need protection against CPU-hotplug here because
index e8f057e..2576648 100644 (file)
@@ -91,6 +91,14 @@ struct rcu_dynticks {
                                /*  remains even for nmi from irq handler. */
 };
 
+/* RCU's kthread states for tracing. */
+#define RCU_KTHREAD_STOPPED  0
+#define RCU_KTHREAD_RUNNING  1
+#define RCU_KTHREAD_WAITING  2
+#define RCU_KTHREAD_OFFCPU   3
+#define RCU_KTHREAD_YIELDING 4
+#define RCU_KTHREAD_MAX      4
+
 /*
  * Definition for node within the RCU grace-period-detection hierarchy.
  */
@@ -109,10 +117,11 @@ struct rcu_node {
                                /*  an rcu_data structure, otherwise, each */
                                /*  bit corresponds to a child rcu_node */
                                /*  structure. */
-       unsigned long expmask;  /* Groups that have ->blocked_tasks[] */
+       unsigned long expmask;  /* Groups that have ->blkd_tasks */
                                /*  elements that need to drain to allow the */
                                /*  current expedited grace period to */
                                /*  complete (only for TREE_PREEMPT_RCU). */
+       unsigned long wakemask; /* CPUs whose kthread needs to be awakened. */
        unsigned long qsmaskinit;
                                /* Per-GP initial value for qsmask & expmask. */
        unsigned long grpmask;  /* Mask to apply to parent qsmask. */
@@ -122,11 +131,68 @@ struct rcu_node {
        u8      grpnum;         /* CPU/group number for next level up. */
        u8      level;          /* root is at level 0. */
        struct rcu_node *parent;
-       struct list_head blocked_tasks[4];
-                               /* Tasks blocked in RCU read-side critsect. */
-                               /*  Grace period number (->gpnum) x blocked */
-                               /*  by tasks on the (x & 0x1) element of the */
-                               /*  blocked_tasks[] array. */
+       struct list_head blkd_tasks;
+                               /* Tasks blocked in RCU read-side critical */
+                               /*  section.  Tasks are placed at the head */
+                               /*  of this list and age towards the tail. */
+       struct list_head *gp_tasks;
+                               /* Pointer to the first task blocking the */
+                               /*  current grace period, or NULL if there */
+                               /*  is no such task. */
+       struct list_head *exp_tasks;
+                               /* Pointer to the first task blocking the */
+                               /*  current expedited grace period, or NULL */
+                               /*  if there is no such task.  If there */
+                               /*  is no current expedited grace period, */
+                               /*  then there can cannot be any such task. */
+#ifdef CONFIG_RCU_BOOST
+       struct list_head *boost_tasks;
+                               /* Pointer to first task that needs to be */
+                               /*  priority boosted, or NULL if no priority */
+                               /*  boosting is needed for this rcu_node */
+                               /*  structure.  If there are no tasks */
+                               /*  queued on this rcu_node structure that */
+                               /*  are blocking the current grace period, */
+                               /*  there can be no such task. */
+       unsigned long boost_time;
+                               /* When to start boosting (jiffies). */
+       struct task_struct *boost_kthread_task;
+                               /* kthread that takes care of priority */
+                               /*  boosting for this rcu_node structure. */
+       wait_queue_head_t boost_wq;
+                               /* Wait queue on which to park the boost */
+                               /*  kthread. */
+       unsigned int boost_kthread_status;
+                               /* State of boost_kthread_task for tracing. */
+       unsigned long n_tasks_boosted;
+                               /* Total number of tasks boosted. */
+       unsigned long n_exp_boosts;
+                               /* Number of tasks boosted for expedited GP. */
+       unsigned long n_normal_boosts;
+                               /* Number of tasks boosted for normal GP. */
+       unsigned long n_balk_blkd_tasks;
+                               /* Refused to boost: no blocked tasks. */
+       unsigned long n_balk_exp_gp_tasks;
+                               /* Refused to boost: nothing blocking GP. */
+       unsigned long n_balk_boost_tasks;
+                               /* Refused to boost: already boosting. */
+       unsigned long n_balk_notblocked;
+                               /* Refused to boost: RCU RS CS still running. */
+       unsigned long n_balk_notyet;
+                               /* Refused to boost: not yet time. */
+       unsigned long n_balk_nos;
+                               /* Refused to boost: not sure why, though. */
+                               /*  This can happen due to race conditions. */
+#endif /* #ifdef CONFIG_RCU_BOOST */
+       struct task_struct *node_kthread_task;
+                               /* kthread that takes care of this rcu_node */
+                               /*  structure, for example, awakening the */
+                               /*  per-CPU kthreads as needed. */
+       wait_queue_head_t node_wq;
+                               /* Wait queue on which to park the per-node */
+                               /*  kthread. */
+       unsigned int node_kthread_status;
+                               /* State of node_kthread_task for tracing. */
 } ____cacheline_internodealigned_in_smp;
 
 /*
@@ -175,7 +241,7 @@ struct rcu_data {
        bool            passed_quiesc;  /* User-mode/idle loop etc. */
        bool            qs_pending;     /* Core waits for quiesc state. */
        bool            beenonline;     /* CPU online at least once. */
-       bool            preemptable;    /* Preemptable RCU? */
+       bool            preemptible;    /* Preemptible RCU? */
        struct rcu_node *mynode;        /* This CPU's leaf of hierarchy */
        unsigned long grpmask;          /* Mask to apply to leaf qsmask. */
 
@@ -254,7 +320,6 @@ struct rcu_data {
 #endif /* #else #ifdef CONFIG_NO_HZ */
 
 #define RCU_JIFFIES_TILL_FORCE_QS       3      /* for rsp->jiffies_force_qs */
-#ifdef CONFIG_RCU_CPU_STALL_DETECTOR
 
 #ifdef CONFIG_PROVE_RCU
 #define RCU_STALL_DELAY_DELTA         (5 * HZ)
@@ -272,13 +337,6 @@ struct rcu_data {
                                                /*  scheduling clock irq */
                                                /*  before ratting on them. */
 
-#ifdef CONFIG_RCU_CPU_STALL_DETECTOR_RUNNABLE
-#define RCU_CPU_STALL_SUPPRESS_INIT 0
-#else
-#define RCU_CPU_STALL_SUPPRESS_INIT 1
-#endif
-
-#endif /* #ifdef CONFIG_RCU_CPU_STALL_DETECTOR */
 
 /*
  * RCU global state, including node hierarchy.  This hierarchy is
@@ -325,12 +383,12 @@ struct rcu_state {
                                                /*  due to lock unavailable. */
        unsigned long n_force_qs_ngp;           /* Number of calls leaving */
                                                /*  due to no GP active. */
-#ifdef CONFIG_RCU_CPU_STALL_DETECTOR
        unsigned long gp_start;                 /* Time at which GP started, */
                                                /*  but in jiffies. */
        unsigned long jiffies_stall;            /* Time at which to check */
                                                /*  for CPU stalls. */
-#endif /* #ifdef CONFIG_RCU_CPU_STALL_DETECTOR */
+       unsigned long gp_max;                   /* Maximum GP duration in */
+                                               /*  jiffies. */
        char *name;                             /* Name of structure. */
 };
 
@@ -361,16 +419,14 @@ DECLARE_PER_CPU(struct rcu_data, rcu_preempt_data);
 static void rcu_bootup_announce(void);
 long rcu_batches_completed(void);
 static void rcu_preempt_note_context_switch(int cpu);
-static int rcu_preempted_readers(struct rcu_node *rnp);
+static int rcu_preempt_blocked_readers_cgp(struct rcu_node *rnp);
 #ifdef CONFIG_HOTPLUG_CPU
 static void rcu_report_unblock_qs_rnp(struct rcu_node *rnp,
                                      unsigned long flags);
 #endif /* #ifdef CONFIG_HOTPLUG_CPU */
-#ifdef CONFIG_RCU_CPU_STALL_DETECTOR
 static void rcu_print_detail_task_stall(struct rcu_state *rsp);
 static void rcu_print_task_stall(struct rcu_node *rnp);
 static void rcu_preempt_stall_reset(void);
-#endif /* #ifdef CONFIG_RCU_CPU_STALL_DETECTOR */
 static void rcu_preempt_check_blocked_tasks(struct rcu_node *rnp);
 #ifdef CONFIG_HOTPLUG_CPU
 static int rcu_preempt_offline_tasks(struct rcu_state *rsp,
@@ -390,5 +446,13 @@ static void __cpuinit rcu_preempt_init_percpu_data(int cpu);
 static void rcu_preempt_send_cbs_to_online(void);
 static void __init __rcu_init_preempt(void);
 static void rcu_needs_cpu_flush(void);
+static void __init rcu_init_boost_waitqueue(struct rcu_node *rnp);
+static void rcu_initiate_boost(struct rcu_node *rnp, unsigned long flags);
+static void rcu_boost_kthread_setaffinity(struct rcu_node *rnp,
+                                         cpumask_var_t cm);
+static void rcu_preempt_boost_start_gp(struct rcu_node *rnp);
+static int __cpuinit rcu_spawn_one_boost_kthread(struct rcu_state *rsp,
+                                                struct rcu_node *rnp,
+                                                int rnp_index);
 
 #endif /* #ifndef RCU_TREE_NONCORE */
index a363871..3f6559a 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * Read-Copy Update mechanism for mutual exclusion (tree-based version)
  * Internal non-public definitions that provide either classic
- * or preemptable semantics.
+ * or preemptible semantics.
  *
  * 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
@@ -54,10 +54,6 @@ static void __init rcu_bootup_announce_oddness(void)
 #ifdef CONFIG_RCU_TORTURE_TEST_RUNNABLE
        printk(KERN_INFO "\tRCU torture testing starts during boot.\n");
 #endif
-#ifndef CONFIG_RCU_CPU_STALL_DETECTOR
-       printk(KERN_INFO
-              "\tRCU-based detection of stalled CPUs is disabled.\n");
-#endif
 #if defined(CONFIG_TREE_PREEMPT_RCU) && !defined(CONFIG_RCU_CPU_STALL_VERBOSE)
        printk(KERN_INFO "\tVerbose stalled-CPUs detection is disabled.\n");
 #endif
@@ -70,6 +66,7 @@ static void __init rcu_bootup_announce_oddness(void)
 
 struct rcu_state rcu_preempt_state = RCU_STATE_INITIALIZER(rcu_preempt_state);
 DEFINE_PER_CPU(struct rcu_data, rcu_preempt_data);
+static struct rcu_state *rcu_state = &rcu_preempt_state;
 
 static int rcu_preempted_readers_exp(struct rcu_node *rnp);
 
@@ -78,7 +75,7 @@ static int rcu_preempted_readers_exp(struct rcu_node *rnp);
  */
 static void __init rcu_bootup_announce(void)
 {
-       printk(KERN_INFO "Preemptable hierarchical RCU implementation.\n");
+       printk(KERN_INFO "Preemptible hierarchical RCU implementation.\n");
        rcu_bootup_announce_oddness();
 }
 
@@ -111,7 +108,7 @@ void rcu_force_quiescent_state(void)
 EXPORT_SYMBOL_GPL(rcu_force_quiescent_state);
 
 /*
- * Record a preemptable-RCU quiescent state for the specified CPU.  Note
+ * Record a preemptible-RCU quiescent state for the specified CPU.  Note
  * that this just means that the task currently running on the CPU is
  * not in a quiescent state.  There might be any number of tasks blocked
  * while in an RCU read-side critical section.
@@ -134,12 +131,12 @@ static void rcu_preempt_qs(int cpu)
  * We have entered the scheduler, and the current task might soon be
  * context-switched away from.  If this task is in an RCU read-side
  * critical section, we will no longer be able to rely on the CPU to
- * record that fact, so we enqueue the task on the appropriate entry
- * of the blocked_tasks[] array.  The task will dequeue itself when
- * it exits the outermost enclosing RCU read-side critical section.
- * Therefore, the current grace period cannot be permitted to complete
- * until the blocked_tasks[] entry indexed by the low-order bit of
- * rnp->gpnum empties.
+ * record that fact, so we enqueue the task on the blkd_tasks list.
+ * The task will dequeue itself when it exits the outermost enclosing
+ * RCU read-side critical section.  Therefore, the current grace period
+ * cannot be permitted to complete until the blkd_tasks list entries
+ * predating the current grace period drain, in other words, until
+ * rnp->gp_tasks becomes NULL.
  *
  * Caller must disable preemption.
  */
@@ -147,7 +144,6 @@ static void rcu_preempt_note_context_switch(int cpu)
 {
        struct task_struct *t = current;
        unsigned long flags;
-       int phase;
        struct rcu_data *rdp;
        struct rcu_node *rnp;
 
@@ -169,15 +165,30 @@ static void rcu_preempt_note_context_switch(int cpu)
                 * (i.e., this CPU has not yet passed through a quiescent
                 * state for the current grace period), then as long
                 * as that task remains queued, the current grace period
-                * cannot end.
+                * cannot end.  Note that there is some uncertainty as
+                * to exactly when the current grace period started.
+                * We take a conservative approach, which can result
+                * in unnecessarily waiting on tasks that started very
+                * slightly after the current grace period began.  C'est
+                * la vie!!!
                 *
                 * But first, note that the current CPU must still be
                 * on line!
                 */
                WARN_ON_ONCE((rdp->grpmask & rnp->qsmaskinit) == 0);
                WARN_ON_ONCE(!list_empty(&t->rcu_node_entry));
-               phase = (rnp->gpnum + !(rnp->qsmask & rdp->grpmask)) & 0x1;
-               list_add(&t->rcu_node_entry, &rnp->blocked_tasks[phase]);
+               if ((rnp->qsmask & rdp->grpmask) && rnp->gp_tasks != NULL) {
+                       list_add(&t->rcu_node_entry, rnp->gp_tasks->prev);
+                       rnp->gp_tasks = &t->rcu_node_entry;
+#ifdef CONFIG_RCU_BOOST
+                       if (rnp->boost_tasks != NULL)
+                               rnp->boost_tasks = rnp->gp_tasks;
+#endif /* #ifdef CONFIG_RCU_BOOST */
+               } else {
+                       list_add(&t->rcu_node_entry, &rnp->blkd_tasks);
+                       if (rnp->qsmask & rdp->grpmask)
+                               rnp->gp_tasks = &t->rcu_node_entry;
+               }
                raw_spin_unlock_irqrestore(&rnp->lock, flags);
        }
 
@@ -196,7 +207,7 @@ static void rcu_preempt_note_context_switch(int cpu)
 }
 
 /*
- * Tree-preemptable RCU implementation for rcu_read_lock().
+ * Tree-preemptible RCU implementation for rcu_read_lock().
  * Just increment ->rcu_read_lock_nesting, shared state will be updated
  * if we block.
  */
@@ -212,12 +223,9 @@ EXPORT_SYMBOL_GPL(__rcu_read_lock);
  * for the specified rcu_node structure.  If the caller needs a reliable
  * answer, it must hold the rcu_node's ->lock.
  */
-static int rcu_preempted_readers(struct rcu_node *rnp)
+static int rcu_preempt_blocked_readers_cgp(struct rcu_node *rnp)
 {
-       int phase = rnp->gpnum & 0x1;
-
-       return !list_empty(&rnp->blocked_tasks[phase]) ||
-              !list_empty(&rnp->blocked_tasks[phase + 2]);
+       return rnp->gp_tasks != NULL;
 }
 
 /*
@@ -233,7 +241,7 @@ static void rcu_report_unblock_qs_rnp(struct rcu_node *rnp, unsigned long flags)
        unsigned long mask;
        struct rcu_node *rnp_p;
 
-       if (rnp->qsmask != 0 || rcu_preempted_readers(rnp)) {
+       if (rnp->qsmask != 0 || rcu_preempt_blocked_readers_cgp(rnp)) {
                raw_spin_unlock_irqrestore(&rnp->lock, flags);
                return;  /* Still need more quiescent states! */
        }
@@ -257,6 +265,21 @@ static void rcu_report_unblock_qs_rnp(struct rcu_node *rnp, unsigned long flags)
 }
 
 /*
+ * Advance a ->blkd_tasks-list pointer to the next entry, instead
+ * returning NULL if at the end of the list.
+ */
+static struct list_head *rcu_next_node_entry(struct task_struct *t,
+                                            struct rcu_node *rnp)
+{
+       struct list_head *np;
+
+       np = t->rcu_node_entry.next;
+       if (np == &rnp->blkd_tasks)
+               np = NULL;
+       return np;
+}
+
+/*
  * Handle special cases during rcu_read_unlock(), such as needing to
  * notify RCU core processing or task having blocked during the RCU
  * read-side critical section.
@@ -266,6 +289,7 @@ static void rcu_read_unlock_special(struct task_struct *t)
        int empty;
        int empty_exp;
        unsigned long flags;
+       struct list_head *np;
        struct rcu_node *rnp;
        int special;
 
@@ -306,10 +330,19 @@ static void rcu_read_unlock_special(struct task_struct *t)
                                break;
                        raw_spin_unlock(&rnp->lock); /* irqs remain disabled. */
                }
-               empty = !rcu_preempted_readers(rnp);
+               empty = !rcu_preempt_blocked_readers_cgp(rnp);
                empty_exp = !rcu_preempted_readers_exp(rnp);
                smp_mb(); /* ensure expedited fastpath sees end of RCU c-s. */
+               np = rcu_next_node_entry(t, rnp);
                list_del_init(&t->rcu_node_entry);
+               if (&t->rcu_node_entry == rnp->gp_tasks)
+                       rnp->gp_tasks = np;
+               if (&t->rcu_node_entry == rnp->exp_tasks)
+                       rnp->exp_tasks = np;
+#ifdef CONFIG_RCU_BOOST
+               if (&t->rcu_node_entry == rnp->boost_tasks)
+                       rnp->boost_tasks = np;
+#endif /* #ifdef CONFIG_RCU_BOOST */
                t->rcu_blocked_node = NULL;
 
                /*
@@ -322,6 +355,15 @@ static void rcu_read_unlock_special(struct task_struct *t)
                else
                        rcu_report_unblock_qs_rnp(rnp, flags);
 
+#ifdef CONFIG_RCU_BOOST
+               /* Unboost if we were boosted. */
+               if (special & RCU_READ_UNLOCK_BOOSTED) {
+                       t->rcu_read_unlock_special &= ~RCU_READ_UNLOCK_BOOSTED;
+                       rt_mutex_unlock(t->rcu_boost_mutex);
+                       t->rcu_boost_mutex = NULL;
+               }
+#endif /* #ifdef CONFIG_RCU_BOOST */
+
                /*
                 * If this was the last task on the expedited lists,
                 * then we need to report up the rcu_node hierarchy.
@@ -334,7 +376,7 @@ static void rcu_read_unlock_special(struct task_struct *t)
 }
 
 /*
- * Tree-preemptable RCU implementation for rcu_read_unlock().
+ * Tree-preemptible RCU implementation for rcu_read_unlock().
  * Decrement ->rcu_read_lock_nesting.  If the result is zero (outermost
  * rcu_read_unlock()) and ->rcu_read_unlock_special is non-zero, then
  * invoke rcu_read_unlock_special() to clean up after a context switch
@@ -356,8 +398,6 @@ void __rcu_read_unlock(void)
 }
 EXPORT_SYMBOL_GPL(__rcu_read_unlock);
 
-#ifdef CONFIG_RCU_CPU_STALL_DETECTOR
-
 #ifdef CONFIG_RCU_CPU_STALL_VERBOSE
 
 /*
@@ -367,18 +407,16 @@ EXPORT_SYMBOL_GPL(__rcu_read_unlock);
 static void rcu_print_detail_task_stall_rnp(struct rcu_node *rnp)
 {
        unsigned long flags;
-       struct list_head *lp;
-       int phase;
        struct task_struct *t;
 
-       if (rcu_preempted_readers(rnp)) {
-               raw_spin_lock_irqsave(&rnp->lock, flags);
-               phase = rnp->gpnum & 0x1;
-               lp = &rnp->blocked_tasks[phase];
-               list_for_each_entry(t, lp, rcu_node_entry)
-                       sched_show_task(t);
-               raw_spin_unlock_irqrestore(&rnp->lock, flags);
-       }
+       if (!rcu_preempt_blocked_readers_cgp(rnp))
+               return;
+       raw_spin_lock_irqsave(&rnp->lock, flags);
+       t = list_entry(rnp->gp_tasks,
+                      struct task_struct, rcu_node_entry);
+       list_for_each_entry_continue(t, &rnp->blkd_tasks, rcu_node_entry)
+               sched_show_task(t);
+       raw_spin_unlock_irqrestore(&rnp->lock, flags);
 }
 
 /*
@@ -408,16 +446,14 @@ static void rcu_print_detail_task_stall(struct rcu_state *rsp)
  */
 static void rcu_print_task_stall(struct rcu_node *rnp)
 {
-       struct list_head *lp;
-       int phase;
        struct task_struct *t;
 
-       if (rcu_preempted_readers(rnp)) {
-               phase = rnp->gpnum & 0x1;
-               lp = &rnp->blocked_tasks[phase];
-               list_for_each_entry(t, lp, rcu_node_entry)
-                       printk(" P%d", t->pid);
-       }
+       if (!rcu_preempt_blocked_readers_cgp(rnp))
+               return;
+       t = list_entry(rnp->gp_tasks,
+                      struct task_struct, rcu_node_entry);
+       list_for_each_entry_continue(t, &rnp->blkd_tasks, rcu_node_entry)
+               printk(" P%d", t->pid);
 }
 
 /*
@@ -430,18 +466,21 @@ static void rcu_preempt_stall_reset(void)
        rcu_preempt_state.jiffies_stall = jiffies + ULONG_MAX / 2;
 }
 
-#endif /* #ifdef CONFIG_RCU_CPU_STALL_DETECTOR */
-
 /*
  * Check that the list of blocked tasks for the newly completed grace
  * period is in fact empty.  It is a serious bug to complete a grace
  * period that still has RCU readers blocked!  This function must be
  * invoked -before- updating this rnp's ->gpnum, and the rnp's ->lock
  * must be held by the caller.
+ *
+ * Also, if there are blocked tasks on the list, they automatically
+ * block the newly created grace period, so set up ->gp_tasks accordingly.
  */
 static void rcu_preempt_check_blocked_tasks(struct rcu_node *rnp)
 {
-       WARN_ON_ONCE(rcu_preempted_readers(rnp));
+       WARN_ON_ONCE(rcu_preempt_blocked_readers_cgp(rnp));
+       if (!list_empty(&rnp->blkd_tasks))
+               rnp->gp_tasks = rnp->blkd_tasks.next;
        WARN_ON_ONCE(rnp->qsmask);
 }
 
@@ -465,50 +504,68 @@ static int rcu_preempt_offline_tasks(struct rcu_state *rsp,
                                     struct rcu_node *rnp,
                                     struct rcu_data *rdp)
 {
-       int i;
        struct list_head *lp;
        struct list_head *lp_root;
        int retval = 0;
        struct rcu_node *rnp_root = rcu_get_root(rsp);
-       struct task_struct *tp;
+       struct task_struct *t;
 
        if (rnp == rnp_root) {
                WARN_ONCE(1, "Last CPU thought to be offlined?");
                return 0;  /* Shouldn't happen: at least one CPU online. */
        }
-       WARN_ON_ONCE(rnp != rdp->mynode &&
-                    (!list_empty(&rnp->blocked_tasks[0]) ||
-                     !list_empty(&rnp->blocked_tasks[1]) ||
-                     !list_empty(&rnp->blocked_tasks[2]) ||
-                     !list_empty(&rnp->blocked_tasks[3])));
+
+       /* If we are on an internal node, complain bitterly. */
+       WARN_ON_ONCE(rnp != rdp->mynode);
 
        /*
-        * Move tasks up to root rcu_node.  Rely on the fact that the
-        * root rcu_node can be at most one ahead of the rest of the
-        * rcu_nodes in terms of gp_num value.  This fact allows us to
-        * move the blocked_tasks[] array directly, element by element.
+        * Move tasks up to root rcu_node.  Don't try to get fancy for
+        * this corner-case operation -- just put this node's tasks
+        * at the head of the root node's list, and update the root node's
+        * ->gp_tasks and ->exp_tasks pointers to those of this node's,
+        * if non-NULL.  This might result in waiting for more tasks than
+        * absolutely necessary, but this is a good performance/complexity
+        * tradeoff.
         */
-       if (rcu_preempted_readers(rnp))
+       if (rcu_preempt_blocked_readers_cgp(rnp))
                retval |= RCU_OFL_TASKS_NORM_GP;
        if (rcu_preempted_readers_exp(rnp))
                retval |= RCU_OFL_TASKS_EXP_GP;
-       for (i = 0; i < 4; i++) {
-               lp = &rnp->blocked_tasks[i];
-               lp_root = &rnp_root->blocked_tasks[i];
-               while (!list_empty(lp)) {
-                       tp = list_entry(lp->next, typeof(*tp), rcu_node_entry);
-                       raw_spin_lock(&rnp_root->lock); /* irqs already disabled */
-                       list_del(&tp->rcu_node_entry);
-                       tp->rcu_blocked_node = rnp_root;
-                       list_add(&tp->rcu_node_entry, lp_root);
-                       raw_spin_unlock(&rnp_root->lock); /* irqs remain disabled */
-               }
+       lp = &rnp->blkd_tasks;
+       lp_root = &rnp_root->blkd_tasks;
+       while (!list_empty(lp)) {
+               t = list_entry(lp->next, typeof(*t), rcu_node_entry);
+               raw_spin_lock(&rnp_root->lock); /* irqs already disabled */
+               list_del(&t->rcu_node_entry);
+               t->rcu_blocked_node = rnp_root;
+               list_add(&t->rcu_node_entry, lp_root);
+               if (&t->rcu_node_entry == rnp->gp_tasks)
+                       rnp_root->gp_tasks = rnp->gp_tasks;
+               if (&t->rcu_node_entry == rnp->exp_tasks)
+                       rnp_root->exp_tasks = rnp->exp_tasks;
+#ifdef CONFIG_RCU_BOOST
+               if (&t->rcu_node_entry == rnp->boost_tasks)
+                       rnp_root->boost_tasks = rnp->boost_tasks;
+#endif /* #ifdef CONFIG_RCU_BOOST */
+               raw_spin_unlock(&rnp_root->lock); /* irqs still disabled */
        }
+
+#ifdef CONFIG_RCU_BOOST
+       /* In case root is being boosted and leaf is not. */
+       raw_spin_lock(&rnp_root->lock); /* irqs already disabled */
+       if (rnp_root->boost_tasks != NULL &&
+           rnp_root->boost_tasks != rnp_root->gp_tasks)
+               rnp_root->boost_tasks = rnp_root->gp_tasks;
+       raw_spin_unlock(&rnp_root->lock); /* irqs still disabled */
+#endif /* #ifdef CONFIG_RCU_BOOST */
+
+       rnp->gp_tasks = NULL;
+       rnp->exp_tasks = NULL;
        return retval;
 }
 
 /*
- * Do CPU-offline processing for preemptable RCU.
+ * Do CPU-offline processing for preemptible RCU.
  */
 static void rcu_preempt_offline_cpu(int cpu)
 {
@@ -537,7 +594,7 @@ static void rcu_preempt_check_callbacks(int cpu)
 }
 
 /*
- * Process callbacks for preemptable RCU.
+ * Process callbacks for preemptible RCU.
  */
 static void rcu_preempt_process_callbacks(void)
 {
@@ -546,7 +603,7 @@ static void rcu_preempt_process_callbacks(void)
 }
 
 /*
- * Queue a preemptable-RCU callback for invocation after a grace period.
+ * Queue a preemptible-RCU callback for invocation after a grace period.
  */
 void call_rcu(struct rcu_head *head, void (*func)(struct rcu_head *rcu))
 {
@@ -594,8 +651,7 @@ static DEFINE_MUTEX(sync_rcu_preempt_exp_mutex);
  */
 static int rcu_preempted_readers_exp(struct rcu_node *rnp)
 {
-       return !list_empty(&rnp->blocked_tasks[2]) ||
-              !list_empty(&rnp->blocked_tasks[3]);
+       return rnp->exp_tasks != NULL;
 }
 
 /*
@@ -655,13 +711,17 @@ static void rcu_report_exp_rnp(struct rcu_state *rsp, struct rcu_node *rnp)
 static void
 sync_rcu_preempt_exp_init(struct rcu_state *rsp, struct rcu_node *rnp)
 {
-       int must_wait;
+       unsigned long flags;
+       int must_wait = 0;
 
-       raw_spin_lock(&rnp->lock); /* irqs already disabled */
-       list_splice_init(&rnp->blocked_tasks[0], &rnp->blocked_tasks[2]);
-       list_splice_init(&rnp->blocked_tasks[1], &rnp->blocked_tasks[3]);
-       must_wait = rcu_preempted_readers_exp(rnp);
-       raw_spin_unlock(&rnp->lock); /* irqs remain disabled */
+       raw_spin_lock_irqsave(&rnp->lock, flags);
+       if (list_empty(&rnp->blkd_tasks))
+               raw_spin_unlock_irqrestore(&rnp->lock, flags);
+       else {
+               rnp->exp_tasks = rnp->blkd_tasks.next;
+               rcu_initiate_boost(rnp, flags);  /* releases rnp->lock */
+               must_wait = 1;
+       }
        if (!must_wait)
                rcu_report_exp_rnp(rsp, rnp);
 }
@@ -669,9 +729,7 @@ sync_rcu_preempt_exp_init(struct rcu_state *rsp, struct rcu_node *rnp)
 /*
  * Wait for an rcu-preempt grace period, but expedite it.  The basic idea
  * is to invoke synchronize_sched_expedited() to push all the tasks to
- * the ->blocked_tasks[] lists, move all entries from the first set of
- * ->blocked_tasks[] lists to the second set, and finally wait for this
- * second set to drain.
+ * the ->blkd_tasks lists and wait for this list to drain.
  */
 void synchronize_rcu_expedited(void)
 {
@@ -703,7 +761,7 @@ void synchronize_rcu_expedited(void)
        if ((ACCESS_ONCE(sync_rcu_preempt_exp_count) - snap) > 0)
                goto unlock_mb_ret; /* Others did our work for us. */
 
-       /* force all RCU readers onto blocked_tasks[]. */
+       /* force all RCU readers onto ->blkd_tasks lists. */
        synchronize_sched_expedited();
 
        raw_spin_lock_irqsave(&rsp->onofflock, flags);
@@ -715,7 +773,7 @@ void synchronize_rcu_expedited(void)
                raw_spin_unlock(&rnp->lock); /* irqs remain disabled. */
        }
 
-       /* Snapshot current state of ->blocked_tasks[] lists. */
+       /* Snapshot current state of ->blkd_tasks lists. */
        rcu_for_each_leaf_node(rsp, rnp)
                sync_rcu_preempt_exp_init(rsp, rnp);
        if (NUM_RCU_NODES > 1)
@@ -723,7 +781,7 @@ void synchronize_rcu_expedited(void)
 
        raw_spin_unlock_irqrestore(&rsp->onofflock, flags);
 
-       /* Wait for snapshotted ->blocked_tasks[] lists to drain. */
+       /* Wait for snapshotted ->blkd_tasks lists to drain. */
        rnp = rcu_get_root(rsp);
        wait_event(sync_rcu_preempt_exp_wq,
                   sync_rcu_preempt_exp_done(rnp));
@@ -739,7 +797,7 @@ mb_ret:
 EXPORT_SYMBOL_GPL(synchronize_rcu_expedited);
 
 /*
- * Check to see if there is any immediate preemptable-RCU-related work
+ * Check to see if there is any immediate preemptible-RCU-related work
  * to be done.
  */
 static int rcu_preempt_pending(int cpu)
@@ -749,7 +807,7 @@ static int rcu_preempt_pending(int cpu)
 }
 
 /*
- * Does preemptable RCU need the CPU to stay out of dynticks mode?
+ * Does preemptible RCU need the CPU to stay out of dynticks mode?
  */
 static int rcu_preempt_needs_cpu(int cpu)
 {
@@ -766,7 +824,7 @@ void rcu_barrier(void)
 EXPORT_SYMBOL_GPL(rcu_barrier);
 
 /*
- * Initialize preemptable RCU's per-CPU data.
+ * Initialize preemptible RCU's per-CPU data.
  */
 static void __cpuinit rcu_preempt_init_percpu_data(int cpu)
 {
@@ -774,7 +832,7 @@ static void __cpuinit rcu_preempt_init_percpu_data(int cpu)
 }
 
 /*
- * Move preemptable RCU's callbacks from dying CPU to other online CPU.
+ * Move preemptible RCU's callbacks from dying CPU to other online CPU.
  */
 static void rcu_preempt_send_cbs_to_online(void)
 {
@@ -782,7 +840,7 @@ static void rcu_preempt_send_cbs_to_online(void)
 }
 
 /*
- * Initialize preemptable RCU's state structures.
+ * Initialize preemptible RCU's state structures.
  */
 static void __init __rcu_init_preempt(void)
 {
@@ -790,7 +848,7 @@ static void __init __rcu_init_preempt(void)
 }
 
 /*
- * Check for a task exiting while in a preemptable-RCU read-side
+ * Check for a task exiting while in a preemptible-RCU read-side
  * critical section, clean up if so.  No need to issue warnings,
  * as debug_check_no_locks_held() already does this if lockdep
  * is enabled.
@@ -802,11 +860,13 @@ void exit_rcu(void)
        if (t->rcu_read_lock_nesting == 0)
                return;
        t->rcu_read_lock_nesting = 1;
-       rcu_read_unlock();
+       __rcu_read_unlock();
 }
 
 #else /* #ifdef CONFIG_TREE_PREEMPT_RCU */
 
+static struct rcu_state *rcu_state = &rcu_sched_state;
+
 /*
  * Tell them what RCU they are running.
  */
@@ -836,7 +896,7 @@ void rcu_force_quiescent_state(void)
 EXPORT_SYMBOL_GPL(rcu_force_quiescent_state);
 
 /*
- * Because preemptable RCU does not exist, we never have to check for
+ * Because preemptible RCU does not exist, we never have to check for
  * CPUs being in quiescent states.
  */
 static void rcu_preempt_note_context_switch(int cpu)
@@ -844,10 +904,10 @@ static void rcu_preempt_note_context_switch(int cpu)
 }
 
 /*
- * Because preemptable RCU does not exist, there are never any preempted
+ * Because preemptible RCU does not exist, there are never any preempted
  * RCU readers.
  */
-static int rcu_preempted_readers(struct rcu_node *rnp)
+static int rcu_preempt_blocked_readers_cgp(struct rcu_node *rnp)
 {
        return 0;
 }
@@ -862,10 +922,8 @@ static void rcu_report_unblock_qs_rnp(struct rcu_node *rnp, unsigned long flags)
 
 #endif /* #ifdef CONFIG_HOTPLUG_CPU */
 
-#ifdef CONFIG_RCU_CPU_STALL_DETECTOR
-
 /*
- * Because preemptable RCU does not exist, we never have to check for
+ * Because preemptible RCU does not exist, we never have to check for
  * tasks blocked within RCU read-side critical sections.
  */
 static void rcu_print_detail_task_stall(struct rcu_state *rsp)
@@ -873,7 +931,7 @@ static void rcu_print_detail_task_stall(struct rcu_state *rsp)
 }
 
 /*
- * Because preemptable RCU does not exist, we never have to check for
+ * Because preemptible RCU does not exist, we never have to check for
  * tasks blocked within RCU read-side critical sections.
  */
 static void rcu_print_task_stall(struct rcu_node *rnp)
@@ -888,10 +946,8 @@ static void rcu_preempt_stall_reset(void)
 {
 }
 
-#endif /* #ifdef CONFIG_RCU_CPU_STALL_DETECTOR */
-
 /*
- * Because there is no preemptable RCU, there can be no readers blocked,
+ * Because there is no preemptible RCU, there can be no readers blocked,
  * so there is no need to check for blocked tasks.  So check only for
  * bogus qsmask values.
  */
@@ -903,7 +959,7 @@ static void rcu_preempt_check_blocked_tasks(struct rcu_node *rnp)
 #ifdef CONFIG_HOTPLUG_CPU
 
 /*
- * Because preemptable RCU does not exist, it never needs to migrate
+ * Because preemptible RCU does not exist, it never needs to migrate
  * tasks that were blocked within RCU read-side critical sections, and
  * such non-existent tasks cannot possibly have been blocking the current
  * grace period.
@@ -916,7 +972,7 @@ static int rcu_preempt_offline_tasks(struct rcu_state *rsp,
 }
 
 /*
- * Because preemptable RCU does not exist, it never needs CPU-offline
+ * Because preemptible RCU does not exist, it never needs CPU-offline
  * processing.
  */
 static void rcu_preempt_offline_cpu(int cpu)
@@ -926,7 +982,7 @@ static void rcu_preempt_offline_cpu(int cpu)
 #endif /* #ifdef CONFIG_HOTPLUG_CPU */
 
 /*
- * Because preemptable RCU does not exist, it never has any callbacks
+ * Because preemptible RCU does not exist, it never has any callbacks
  * to check.
  */
 static void rcu_preempt_check_callbacks(int cpu)
@@ -934,7 +990,7 @@ static void rcu_preempt_check_callbacks(int cpu)
 }
 
 /*
- * Because preemptable RCU does not exist, it never has any callbacks
+ * Because preemptible RCU does not exist, it never has any callbacks
  * to process.
  */
 static void rcu_preempt_process_callbacks(void)
@@ -943,7 +999,7 @@ static void rcu_preempt_process_callbacks(void)
 
 /*
  * Wait for an rcu-preempt grace period, but make it happen quickly.
- * But because preemptable RCU does not exist, map to rcu-sched.
+ * But because preemptible RCU does not exist, map to rcu-sched.
  */
 void synchronize_rcu_expedited(void)
 {
@@ -954,7 +1010,7 @@ EXPORT_SYMBOL_GPL(synchronize_rcu_expedited);
 #ifdef CONFIG_HOTPLUG_CPU
 
 /*
- * Because preemptable RCU does not exist, there is never any need to
+ * Because preemptible RCU does not exist, there is never any need to
  * report on tasks preempted in RCU read-side critical sections during
  * expedited RCU grace periods.
  */
@@ -966,7 +1022,7 @@ static void rcu_report_exp_rnp(struct rcu_state *rsp, struct rcu_node *rnp)
 #endif /* #ifdef CONFIG_HOTPLUG_CPU */
 
 /*
- * Because preemptable RCU does not exist, it never has any work to do.
+ * Because preemptible RCU does not exist, it never has any work to do.
  */
 static int rcu_preempt_pending(int cpu)
 {
@@ -974,7 +1030,7 @@ static int rcu_preempt_pending(int cpu)
 }
 
 /*
- * Because preemptable RCU does not exist, it never needs any CPU.
+ * Because preemptible RCU does not exist, it never needs any CPU.
  */
 static int rcu_preempt_needs_cpu(int cpu)
 {
@@ -982,7 +1038,7 @@ static int rcu_preempt_needs_cpu(int cpu)
 }
 
 /*
- * Because preemptable RCU does not exist, rcu_barrier() is just
+ * Because preemptible RCU does not exist, rcu_barrier() is just
  * another name for rcu_barrier_sched().
  */
 void rcu_barrier(void)
@@ -992,7 +1048,7 @@ void rcu_barrier(void)
 EXPORT_SYMBOL_GPL(rcu_barrier);
 
 /*
- * Because preemptable RCU does not exist, there is no per-CPU
+ * Because preemptible RCU does not exist, there is no per-CPU
  * data to initialize.
  */
 static void __cpuinit rcu_preempt_init_percpu_data(int cpu)
@@ -1000,14 +1056,14 @@ static void __cpuinit rcu_preempt_init_percpu_data(int cpu)
 }
 
 /*
- * Because there is no preemptable RCU, there are no callbacks to move.
+ * Because there is no preemptible RCU, there are no callbacks to move.
  */
 static void rcu_preempt_send_cbs_to_online(void)
 {
 }
 
 /*
- * Because preemptable RCU does not exist, it need not be initialized.
+ * Because preemptible RCU does not exist, it need not be initialized.
  */
 static void __init __rcu_init_preempt(void)
 {
@@ -1015,6 +1071,276 @@ static void __init __rcu_init_preempt(void)
 
 #endif /* #else #ifdef CONFIG_TREE_PREEMPT_RCU */
 
+#ifdef CONFIG_RCU_BOOST
+
+#include "rtmutex_common.h"
+
+#ifdef CONFIG_RCU_TRACE
+
+static void rcu_initiate_boost_trace(struct rcu_node *rnp)
+{
+       if (list_empty(&rnp->blkd_tasks))
+               rnp->n_balk_blkd_tasks++;
+       else if (rnp->exp_tasks == NULL && rnp->gp_tasks == NULL)
+               rnp->n_balk_exp_gp_tasks++;
+       else if (rnp->gp_tasks != NULL && rnp->boost_tasks != NULL)
+               rnp->n_balk_boost_tasks++;
+       else if (rnp->gp_tasks != NULL && rnp->qsmask != 0)
+               rnp->n_balk_notblocked++;
+       else if (rnp->gp_tasks != NULL &&
+                ULONG_CMP_LT(jiffies, rnp->boost_time))
+               rnp->n_balk_notyet++;
+       else
+               rnp->n_balk_nos++;
+}
+
+#else /* #ifdef CONFIG_RCU_TRACE */
+
+static void rcu_initiate_boost_trace(struct rcu_node *rnp)
+{
+}
+
+#endif /* #else #ifdef CONFIG_RCU_TRACE */
+
+/*
+ * Carry out RCU priority boosting on the task indicated by ->exp_tasks
+ * or ->boost_tasks, advancing the pointer to the next task in the
+ * ->blkd_tasks list.
+ *
+ * Note that irqs must be enabled: boosting the task can block.
+ * Returns 1 if there are more tasks needing to be boosted.
+ */
+static int rcu_boost(struct rcu_node *rnp)
+{
+       unsigned long flags;
+       struct rt_mutex mtx;
+       struct task_struct *t;
+       struct list_head *tb;
+
+       if (rnp->exp_tasks == NULL && rnp->boost_tasks == NULL)
+               return 0;  /* Nothing left to boost. */
+
+       raw_spin_lock_irqsave(&rnp->lock, flags);
+
+       /*
+        * Recheck under the lock: all tasks in need of boosting
+        * might exit their RCU read-side critical sections on their own.
+        */
+       if (rnp->exp_tasks == NULL && rnp->boost_tasks == NULL) {
+               raw_spin_unlock_irqrestore(&rnp->lock, flags);
+               return 0;
+       }
+
+       /*
+        * Preferentially boost tasks blocking expedited grace periods.
+        * This cannot starve the normal grace periods because a second
+        * expedited grace period must boost all blocked tasks, including
+        * those blocking the pre-existing normal grace period.
+        */
+       if (rnp->exp_tasks != NULL) {
+               tb = rnp->exp_tasks;
+               rnp->n_exp_boosts++;
+       } else {
+               tb = rnp->boost_tasks;
+               rnp->n_normal_boosts++;
+       }
+       rnp->n_tasks_boosted++;
+
+       /*
+        * We boost task t by manufacturing an rt_mutex that appears to
+        * be held by task t.  We leave a pointer to that rt_mutex where
+        * task t can find it, and task t will release the mutex when it
+        * exits its outermost RCU read-side critical section.  Then
+        * simply acquiring this artificial rt_mutex will boost task
+        * t's priority.  (Thanks to tglx for suggesting this approach!)
+        *
+        * Note that task t must acquire rnp->lock to remove itself from
+        * the ->blkd_tasks list, which it will do from exit() if from
+        * nowhere else.  We therefore are guaranteed that task t will
+        * stay around at least until we drop rnp->lock.  Note that
+        * rnp->lock also resolves races between our priority boosting
+        * and task t's exiting its outermost RCU read-side critical
+        * section.
+        */
+       t = container_of(tb, struct task_struct, rcu_node_entry);
+       rt_mutex_init_proxy_locked(&mtx, t);
+       t->rcu_boost_mutex = &mtx;
+       t->rcu_read_unlock_special |= RCU_READ_UNLOCK_BOOSTED;
+       raw_spin_unlock_irqrestore(&rnp->lock, flags);
+       rt_mutex_lock(&mtx);  /* Side effect: boosts task t's priority. */
+       rt_mutex_unlock(&mtx);  /* Keep lockdep happy. */
+
+       return rnp->exp_tasks != NULL || rnp->boost_tasks != NULL;
+}
+
+/*
+ * Timer handler to initiate waking up of boost kthreads that
+ * have yielded the CPU due to excessive numbers of tasks to
+ * boost.  We wake up the per-rcu_node kthread, which in turn
+ * will wake up the booster kthread.
+ */
+static void rcu_boost_kthread_timer(unsigned long arg)
+{
+       invoke_rcu_node_kthread((struct rcu_node *)arg);
+}
+
+/*
+ * Priority-boosting kthread.  One per leaf rcu_node and one for the
+ * root rcu_node.
+ */
+static int rcu_boost_kthread(void *arg)
+{
+       struct rcu_node *rnp = (struct rcu_node *)arg;
+       int spincnt = 0;
+       int more2boost;
+
+       for (;;) {
+               rnp->boost_kthread_status = RCU_KTHREAD_WAITING;
+               wait_event_interruptible(rnp->boost_wq, rnp->boost_tasks ||
+                                                       rnp->exp_tasks);
+               rnp->boost_kthread_status = RCU_KTHREAD_RUNNING;
+               more2boost = rcu_boost(rnp);
+               if (more2boost)
+                       spincnt++;
+               else
+                       spincnt = 0;
+               if (spincnt > 10) {
+                       rcu_yield(rcu_boost_kthread_timer, (unsigned long)rnp);
+                       spincnt = 0;
+               }
+       }
+       /* NOTREACHED */
+       return 0;
+}
+
+/*
+ * Check to see if it is time to start boosting RCU readers that are
+ * blocking the current grace period, and, if so, tell the per-rcu_node
+ * kthread to start boosting them.  If there is an expedited grace
+ * period in progress, it is always time to boost.
+ *
+ * The caller must hold rnp->lock, which this function releases,
+ * but irqs remain disabled.  The ->boost_kthread_task is immortal,
+ * so we don't need to worry about it going away.
+ */
+static void rcu_initiate_boost(struct rcu_node *rnp, unsigned long flags)
+{
+       struct task_struct *t;
+
+       if (!rcu_preempt_blocked_readers_cgp(rnp) && rnp->exp_tasks == NULL) {
+               rnp->n_balk_exp_gp_tasks++;
+               raw_spin_unlock_irqrestore(&rnp->lock, flags);
+               return;
+       }
+       if (rnp->exp_tasks != NULL ||
+           (rnp->gp_tasks != NULL &&
+            rnp->boost_tasks == NULL &&
+            rnp->qsmask == 0 &&
+            ULONG_CMP_GE(jiffies, rnp->boost_time))) {
+               if (rnp->exp_tasks == NULL)
+                       rnp->boost_tasks = rnp->gp_tasks;
+               raw_spin_unlock_irqrestore(&rnp->lock, flags);
+               t = rnp->boost_kthread_task;
+               if (t != NULL)
+                       wake_up_process(t);
+       } else {
+               rcu_initiate_boost_trace(rnp);
+               raw_spin_unlock_irqrestore(&rnp->lock, flags);
+       }
+}
+
+/*
+ * Set the affinity of the boost kthread.  The CPU-hotplug locks are
+ * held, so no one should be messing with the existence of the boost
+ * kthread.
+ */
+static void rcu_boost_kthread_setaffinity(struct rcu_node *rnp,
+                                         cpumask_var_t cm)
+{
+       struct task_struct *t;
+
+       t = rnp->boost_kthread_task;
+       if (t != NULL)
+               set_cpus_allowed_ptr(rnp->boost_kthread_task, cm);
+}
+
+#define RCU_BOOST_DELAY_JIFFIES DIV_ROUND_UP(CONFIG_RCU_BOOST_DELAY * HZ, 1000)
+
+/*
+ * Do priority-boost accounting for the start of a new grace period.
+ */
+static void rcu_preempt_boost_start_gp(struct rcu_node *rnp)
+{
+       rnp->boost_time = jiffies + RCU_BOOST_DELAY_JIFFIES;
+}
+
+/*
+ * Initialize the RCU-boost waitqueue.
+ */
+static void __init rcu_init_boost_waitqueue(struct rcu_node *rnp)
+{
+       init_waitqueue_head(&rnp->boost_wq);
+}
+
+/*
+ * Create an RCU-boost kthread for the specified node if one does not
+ * already exist.  We only create this kthread for preemptible RCU.
+ * Returns zero if all is well, a negated errno otherwise.
+ */
+static int __cpuinit rcu_spawn_one_boost_kthread(struct rcu_state *rsp,
+                                                struct rcu_node *rnp,
+                                                int rnp_index)
+{
+       unsigned long flags;
+       struct sched_param sp;
+       struct task_struct *t;
+
+       if (&rcu_preempt_state != rsp)
+               return 0;
+       if (rnp->boost_kthread_task != NULL)
+               return 0;
+       t = kthread_create(rcu_boost_kthread, (void *)rnp,
+                          "rcub%d", rnp_index);
+       if (IS_ERR(t))
+               return PTR_ERR(t);
+       raw_spin_lock_irqsave(&rnp->lock, flags);
+       rnp->boost_kthread_task = t;
+       raw_spin_unlock_irqrestore(&rnp->lock, flags);
+       wake_up_process(t);
+       sp.sched_priority = RCU_KTHREAD_PRIO;
+       sched_setscheduler_nocheck(t, SCHED_FIFO, &sp);
+       return 0;
+}
+
+#else /* #ifdef CONFIG_RCU_BOOST */
+
+static void rcu_initiate_boost(struct rcu_node *rnp, unsigned long flags)
+{
+       raw_spin_unlock_irqrestore(&rnp->lock, flags);
+}
+
+static void rcu_boost_kthread_setaffinity(struct rcu_node *rnp,
+                                         cpumask_var_t cm)
+{
+}
+
+static void rcu_preempt_boost_start_gp(struct rcu_node *rnp)
+{
+}
+
+static void __init rcu_init_boost_waitqueue(struct rcu_node *rnp)
+{
+}
+
+static int __cpuinit rcu_spawn_one_boost_kthread(struct rcu_state *rsp,
+                                                struct rcu_node *rnp,
+                                                int rnp_index)
+{
+       return 0;
+}
+
+#endif /* #else #ifdef CONFIG_RCU_BOOST */
+
 #ifndef CONFIG_SMP
 
 void synchronize_sched_expedited(void)
@@ -1187,8 +1513,8 @@ static DEFINE_PER_CPU(unsigned long, rcu_dyntick_holdoff);
  *
  * Because it is not legal to invoke rcu_process_callbacks() with irqs
  * disabled, we do one pass of force_quiescent_state(), then do a
- * raise_softirq() to cause rcu_process_callbacks() to be invoked later.
- * The per-cpu rcu_dyntick_drain variable controls the sequencing.
+ * invoke_rcu_cpu_kthread() to cause rcu_process_callbacks() to be invoked
+ * later.  The per-cpu rcu_dyntick_drain variable controls the sequencing.
  */
 int rcu_needs_cpu(int cpu)
 {
@@ -1239,7 +1565,7 @@ int rcu_needs_cpu(int cpu)
 
        /* If RCU callbacks are still pending, RCU still needs this CPU. */
        if (c)
-               raise_softirq(RCU_SOFTIRQ);
+               invoke_rcu_cpu_kthread();
        return c;
 }
 
index c8e9785..aa0fd72 100644 (file)
 #define RCU_TREE_NONCORE
 #include "rcutree.h"
 
+DECLARE_PER_CPU(unsigned int, rcu_cpu_kthread_status);
+DECLARE_PER_CPU(unsigned int, rcu_cpu_kthread_cpu);
+DECLARE_PER_CPU(unsigned int, rcu_cpu_kthread_loops);
+DECLARE_PER_CPU(char, rcu_cpu_has_work);
+
+static char convert_kthread_status(unsigned int kthread_status)
+{
+       if (kthread_status > RCU_KTHREAD_MAX)
+               return '?';
+       return "SRWOY"[kthread_status];
+}
+
 static void print_one_rcu_data(struct seq_file *m, struct rcu_data *rdp)
 {
        if (!rdp->beenonline)
@@ -64,7 +76,21 @@ static void print_one_rcu_data(struct seq_file *m, struct rcu_data *rdp)
                   rdp->dynticks_fqs);
 #endif /* #ifdef CONFIG_NO_HZ */
        seq_printf(m, " of=%lu ri=%lu", rdp->offline_fqs, rdp->resched_ipi);
-       seq_printf(m, " ql=%ld b=%ld", rdp->qlen, rdp->blimit);
+       seq_printf(m, " ql=%ld qs=%c%c%c%c kt=%d/%c/%d ktl=%x b=%ld",
+                  rdp->qlen,
+                  ".N"[rdp->nxttail[RCU_NEXT_READY_TAIL] !=
+                       rdp->nxttail[RCU_NEXT_TAIL]],
+                  ".R"[rdp->nxttail[RCU_WAIT_TAIL] !=
+                       rdp->nxttail[RCU_NEXT_READY_TAIL]],
+                  ".W"[rdp->nxttail[RCU_DONE_TAIL] !=
+                       rdp->nxttail[RCU_WAIT_TAIL]],
+                  ".D"[&rdp->nxtlist != rdp->nxttail[RCU_DONE_TAIL]],
+                  per_cpu(rcu_cpu_has_work, rdp->cpu),
+                  convert_kthread_status(per_cpu(rcu_cpu_kthread_status,
+                                         rdp->cpu)),
+                  per_cpu(rcu_cpu_kthread_cpu, rdp->cpu),
+                  per_cpu(rcu_cpu_kthread_loops, rdp->cpu) & 0xffff,
+                  rdp->blimit);
        seq_printf(m, " ci=%lu co=%lu ca=%lu\n",
                   rdp->n_cbs_invoked, rdp->n_cbs_orphaned, rdp->n_cbs_adopted);
 }
@@ -121,7 +147,18 @@ static void print_one_rcu_data_csv(struct seq_file *m, struct rcu_data *rdp)
                   rdp->dynticks_fqs);
 #endif /* #ifdef CONFIG_NO_HZ */
        seq_printf(m, ",%lu,%lu", rdp->offline_fqs, rdp->resched_ipi);
-       seq_printf(m, ",%ld,%ld", rdp->qlen, rdp->blimit);
+       seq_printf(m, ",%ld,\"%c%c%c%c\",%d,\"%c\",%ld", rdp->qlen,
+                  ".N"[rdp->nxttail[RCU_NEXT_READY_TAIL] !=
+                       rdp->nxttail[RCU_NEXT_TAIL]],
+                  ".R"[rdp->nxttail[RCU_WAIT_TAIL] !=
+                       rdp->nxttail[RCU_NEXT_READY_TAIL]],
+                  ".W"[rdp->nxttail[RCU_DONE_TAIL] !=
+                       rdp->nxttail[RCU_WAIT_TAIL]],
+                  ".D"[&rdp->nxtlist != rdp->nxttail[RCU_DONE_TAIL]],
+                  per_cpu(rcu_cpu_has_work, rdp->cpu),
+                  convert_kthread_status(per_cpu(rcu_cpu_kthread_status,
+                                         rdp->cpu)),
+                  rdp->blimit);
        seq_printf(m, ",%lu,%lu,%lu\n",
                   rdp->n_cbs_invoked, rdp->n_cbs_orphaned, rdp->n_cbs_adopted);
 }
@@ -157,11 +194,76 @@ static const struct file_operations rcudata_csv_fops = {
        .release = single_release,
 };
 
+#ifdef CONFIG_RCU_BOOST
+
+static void print_one_rcu_node_boost(struct seq_file *m, struct rcu_node *rnp)
+{
+       seq_printf(m,  "%d:%d tasks=%c%c%c%c kt=%c ntb=%lu neb=%lu nnb=%lu "
+                  "j=%04x bt=%04x\n",
+                  rnp->grplo, rnp->grphi,
+                  "T."[list_empty(&rnp->blkd_tasks)],
+                  "N."[!rnp->gp_tasks],
+                  "E."[!rnp->exp_tasks],
+                  "B."[!rnp->boost_tasks],
+                  convert_kthread_status(rnp->boost_kthread_status),
+                  rnp->n_tasks_boosted, rnp->n_exp_boosts,
+                  rnp->n_normal_boosts,
+                  (int)(jiffies & 0xffff),
+                  (int)(rnp->boost_time & 0xffff));
+       seq_printf(m, "%s: nt=%lu egt=%lu bt=%lu nb=%lu ny=%lu nos=%lu\n",
+                  "     balk",
+                  rnp->n_balk_blkd_tasks,
+                  rnp->n_balk_exp_gp_tasks,
+                  rnp->n_balk_boost_tasks,
+                  rnp->n_balk_notblocked,
+                  rnp->n_balk_notyet,
+                  rnp->n_balk_nos);
+}
+
+static int show_rcu_node_boost(struct seq_file *m, void *unused)
+{
+       struct rcu_node *rnp;
+
+       rcu_for_each_leaf_node(&rcu_preempt_state, rnp)
+               print_one_rcu_node_boost(m, rnp);
+       return 0;
+}
+
+static int rcu_node_boost_open(struct inode *inode, struct file *file)
+{
+       return single_open(file, show_rcu_node_boost, NULL);
+}
+
+static const struct file_operations rcu_node_boost_fops = {
+       .owner = THIS_MODULE,
+       .open = rcu_node_boost_open,
+       .read = seq_read,
+       .llseek = seq_lseek,
+       .release = single_release,
+};
+
+/*
+ * Create the rcuboost debugfs entry.  Standard error return.
+ */
+static int rcu_boost_trace_create_file(struct dentry *rcudir)
+{
+       return !debugfs_create_file("rcuboost", 0444, rcudir, NULL,
+                                   &rcu_node_boost_fops);
+}
+
+#else /* #ifdef CONFIG_RCU_BOOST */
+
+static int rcu_boost_trace_create_file(struct dentry *rcudir)
+{
+       return 0;  /* There cannot be an error if we didn't create it! */
+}
+
+#endif /* #else #ifdef CONFIG_RCU_BOOST */
+
 static void print_one_rcu_state(struct seq_file *m, struct rcu_state *rsp)
 {
        unsigned long gpnum;
        int level = 0;
-       int phase;
        struct rcu_node *rnp;
 
        gpnum = rsp->gpnum;
@@ -178,13 +280,11 @@ static void print_one_rcu_state(struct seq_file *m, struct rcu_state *rsp)
                        seq_puts(m, "\n");
                        level = rnp->level;
                }
-               phase = gpnum & 0x1;
-               seq_printf(m, "%lx/%lx %c%c>%c%c %d:%d ^%d    ",
+               seq_printf(m, "%lx/%lx %c%c>%c %d:%d ^%d    ",
                           rnp->qsmask, rnp->qsmaskinit,
-                          "T."[list_empty(&rnp->blocked_tasks[phase])],
-                          "E."[list_empty(&rnp->blocked_tasks[phase + 2])],
-                          "T."[list_empty(&rnp->blocked_tasks[!phase])],
-                          "E."[list_empty(&rnp->blocked_tasks[!phase + 2])],
+                          ".G"[rnp->gp_tasks != NULL],
+                          ".E"[rnp->exp_tasks != NULL],
+                          ".T"[!list_empty(&rnp->blkd_tasks)],
                           rnp->grplo, rnp->grphi, rnp->grpnum);
        }
        seq_puts(m, "\n");
@@ -216,16 +316,35 @@ static const struct file_operations rcuhier_fops = {
        .release = single_release,
 };
 
+static void show_one_rcugp(struct seq_file *m, struct rcu_state *rsp)
+{
+       unsigned long flags;
+       unsigned long completed;
+       unsigned long gpnum;
+       unsigned long gpage;
+       unsigned long gpmax;
+       struct rcu_node *rnp = &rsp->node[0];
+
+       raw_spin_lock_irqsave(&rnp->lock, flags);
+       completed = rsp->completed;
+       gpnum = rsp->gpnum;
+       if (rsp->completed == rsp->gpnum)
+               gpage = 0;
+       else
+               gpage = jiffies - rsp->gp_start;
+       gpmax = rsp->gp_max;
+       raw_spin_unlock_irqrestore(&rnp->lock, flags);
+       seq_printf(m, "%s: completed=%ld  gpnum=%lu  age=%ld  max=%ld\n",
+                  rsp->name, completed, gpnum, gpage, gpmax);
+}
+
 static int show_rcugp(struct seq_file *m, void *unused)
 {
 #ifdef CONFIG_TREE_PREEMPT_RCU
-       seq_printf(m, "rcu_preempt: completed=%ld  gpnum=%lu\n",
-                  rcu_preempt_state.completed, rcu_preempt_state.gpnum);
+       show_one_rcugp(m, &rcu_preempt_state);
 #endif /* #ifdef CONFIG_TREE_PREEMPT_RCU */
-       seq_printf(m, "rcu_sched: completed=%ld  gpnum=%lu\n",
-                  rcu_sched_state.completed, rcu_sched_state.gpnum);
-       seq_printf(m, "rcu_bh: completed=%ld  gpnum=%lu\n",
-                  rcu_bh_state.completed, rcu_bh_state.gpnum);
+       show_one_rcugp(m, &rcu_sched_state);
+       show_one_rcugp(m, &rcu_bh_state);
        return 0;
 }
 
@@ -298,6 +417,29 @@ static const struct file_operations rcu_pending_fops = {
        .release = single_release,
 };
 
+static int show_rcutorture(struct seq_file *m, void *unused)
+{
+       seq_printf(m, "rcutorture test sequence: %lu %s\n",
+                  rcutorture_testseq >> 1,
+                  (rcutorture_testseq & 0x1) ? "(test in progress)" : "");
+       seq_printf(m, "rcutorture update version number: %lu\n",
+                  rcutorture_vernum);
+       return 0;
+}
+
+static int rcutorture_open(struct inode *inode, struct file *file)
+{
+       return single_open(file, show_rcutorture, NULL);
+}
+
+static const struct file_operations rcutorture_fops = {
+       .owner = THIS_MODULE,
+       .open = rcutorture_open,
+       .read = seq_read,
+       .llseek = seq_lseek,
+       .release = single_release,
+};
+
 static struct dentry *rcudir;
 
 static int __init rcutree_trace_init(void)
@@ -318,6 +460,9 @@ static int __init rcutree_trace_init(void)
        if (!retval)
                goto free_out;
 
+       if (rcu_boost_trace_create_file(rcudir))
+               goto free_out;
+
        retval = debugfs_create_file("rcugp", 0444, rcudir, NULL, &rcugp_fops);
        if (!retval)
                goto free_out;
@@ -331,6 +476,11 @@ static int __init rcutree_trace_init(void)
                                                NULL, &rcu_pending_fops);
        if (!retval)
                goto free_out;
+
+       retval = debugfs_create_file("rcutorture", 0444, rcudir,
+                                               NULL, &rcutorture_fops);
+       if (!retval)
+               goto free_out;
        return 0;
 free_out:
        debugfs_remove_recursive(rcudir);
index 312f8b9..c62acf4 100644 (file)
@@ -231,7 +231,7 @@ static void destroy_rt_bandwidth(struct rt_bandwidth *rt_b)
 #endif
 
 /*
- * sched_domains_mutex serializes calls to arch_init_sched_domains,
+ * sched_domains_mutex serializes calls to init_sched_domains,
  * detach_destroy_domains and partition_sched_domains.
  */
 static DEFINE_MUTEX(sched_domains_mutex);
@@ -312,6 +312,9 @@ struct cfs_rq {
 
        u64 exec_clock;
        u64 min_vruntime;
+#ifndef CONFIG_64BIT
+       u64 min_vruntime_copy;
+#endif
 
        struct rb_root tasks_timeline;
        struct rb_node *rb_leftmost;
@@ -325,7 +328,9 @@ struct cfs_rq {
         */
        struct sched_entity *curr, *next, *last, *skip;
 
+#ifdef CONFIG_SCHED_DEBUG
        unsigned int nr_spread_over;
+#endif
 
 #ifdef CONFIG_FAIR_GROUP_SCHED
        struct rq *rq;  /* cpu runqueue to which this cfs_rq is attached */
@@ -417,6 +422,7 @@ struct rt_rq {
  */
 struct root_domain {
        atomic_t refcount;
+       struct rcu_head rcu;
        cpumask_var_t span;
        cpumask_var_t online;
 
@@ -460,7 +466,7 @@ struct rq {
        u64 nohz_stamp;
        unsigned char nohz_balance_kick;
 #endif
-       unsigned int skip_clock_update;
+       int skip_clock_update;
 
        /* capture load from *all* tasks on this cpu: */
        struct load_weight load;
@@ -553,6 +559,10 @@ struct rq {
        unsigned int ttwu_count;
        unsigned int ttwu_local;
 #endif
+
+#ifdef CONFIG_SMP
+       struct task_struct *wake_list;
+#endif
 };
 
 static DEFINE_PER_CPU_SHARED_ALIGNED(struct rq, runqueues);
@@ -571,7 +581,7 @@ static inline int cpu_of(struct rq *rq)
 
 #define rcu_dereference_check_sched_domain(p) \
        rcu_dereference_check((p), \
-                             rcu_read_lock_sched_held() || \
+                             rcu_read_lock_held() || \
                              lockdep_is_held(&sched_domains_mutex))
 
 /*
@@ -596,7 +606,7 @@ static inline int cpu_of(struct rq *rq)
  * Return the group to which this tasks belongs.
  *
  * We use task_subsys_state_check() and extend the RCU verification
- * with lockdep_is_held(&task_rq(p)->lock) because cpu_cgroup_attach()
+ * with lockdep_is_held(&p->pi_lock) because cpu_cgroup_attach()
  * holds that lock for each task it moves into the cgroup. Therefore
  * by holding that lock, we pin the task to the current cgroup.
  */
@@ -606,7 +616,7 @@ static inline struct task_group *task_group(struct task_struct *p)
        struct cgroup_subsys_state *css;
 
        css = task_subsys_state_check(p, cpu_cgroup_subsys_id,
-                       lockdep_is_held(&task_rq(p)->lock));
+                       lockdep_is_held(&p->pi_lock));
        tg = container_of(css, struct task_group, css);
 
        return autogroup_task_group(p, tg);
@@ -642,7 +652,7 @@ static void update_rq_clock(struct rq *rq)
 {
        s64 delta;
 
-       if (rq->skip_clock_update)
+       if (rq->skip_clock_update > 0)
                return;
 
        delta = sched_clock_cpu(cpu_of(rq)) - rq->clock;
@@ -838,18 +848,39 @@ static inline int task_current(struct rq *rq, struct task_struct *p)
        return rq->curr == p;
 }
 
-#ifndef __ARCH_WANT_UNLOCKED_CTXSW
 static inline int task_running(struct rq *rq, struct task_struct *p)
 {
+#ifdef CONFIG_SMP
+       return p->on_cpu;
+#else
        return task_current(rq, p);
+#endif
 }
 
+#ifndef __ARCH_WANT_UNLOCKED_CTXSW
 static inline void prepare_lock_switch(struct rq *rq, struct task_struct *next)
 {
+#ifdef CONFIG_SMP
+       /*
+        * We can optimise this out completely for !SMP, because the
+        * SMP rebalancing from interrupt is the only thing that cares
+        * here.
+        */
+       next->on_cpu = 1;
+#endif
 }
 
 static inline void finish_lock_switch(struct rq *rq, struct task_struct *prev)
 {
+#ifdef CONFIG_SMP
+       /*
+        * After ->on_cpu is cleared, the task can be moved to a different CPU.
+        * We must ensure this doesn't happen until the switch is completely
+        * finished.
+        */
+       smp_wmb();
+       prev->on_cpu = 0;
+#endif
 #ifdef CONFIG_DEBUG_SPINLOCK
        /* this is a valid case when another task releases the spinlock */
        rq->lock.owner = current;
@@ -865,15 +896,6 @@ static inline void finish_lock_switch(struct rq *rq, struct task_struct *prev)
 }
 
 #else /* __ARCH_WANT_UNLOCKED_CTXSW */
-static inline int task_running(struct rq *rq, struct task_struct *p)
-{
-#ifdef CONFIG_SMP
-       return p->oncpu;
-#else
-       return task_current(rq, p);
-#endif
-}
-
 static inline void prepare_lock_switch(struct rq *rq, struct task_struct *next)
 {
 #ifdef CONFIG_SMP
@@ -882,7 +904,7 @@ static inline void prepare_lock_switch(struct rq *rq, struct task_struct *next)
         * SMP rebalancing from interrupt is the only thing that cares
         * here.
         */
-       next->oncpu = 1;
+       next->on_cpu = 1;
 #endif
 #ifdef __ARCH_WANT_INTERRUPTS_ON_CTXSW
        raw_spin_unlock_irq(&rq->lock);
@@ -895,12 +917,12 @@ static inline void finish_lock_switch(struct rq *rq, struct task_struct *prev)
 {
 #ifdef CONFIG_SMP
        /*
-        * After ->oncpu is cleared, the task can be moved to a different CPU.
+        * After ->on_cpu is cleared, the task can be moved to a different CPU.
         * We must ensure this doesn't happen until the switch is completely
         * finished.
         */
        smp_wmb();
-       prev->oncpu = 0;
+       prev->on_cpu = 0;
 #endif
 #ifndef __ARCH_WANT_INTERRUPTS_ON_CTXSW
        local_irq_enable();
@@ -909,23 +931,15 @@ static inline void finish_lock_switch(struct rq *rq, struct task_struct *prev)
 #endif /* __ARCH_WANT_UNLOCKED_CTXSW */
 
 /*
- * Check whether the task is waking, we use this to synchronize ->cpus_allowed
- * against ttwu().
- */
-static inline int task_is_waking(struct task_struct *p)
-{
-       return unlikely(p->state == TASK_WAKING);
-}
-
-/*
- * __task_rq_lock - lock the runqueue a given task resides on.
- * Must be called interrupts disabled.
+ * __task_rq_lock - lock the rq @p resides on.
  */
 static inline struct rq *__task_rq_lock(struct task_struct *p)
        __acquires(rq->lock)
 {
        struct rq *rq;
 
+       lockdep_assert_held(&p->pi_lock);
+
        for (;;) {
                rq = task_rq(p);
                raw_spin_lock(&rq->lock);
@@ -936,22 +950,22 @@ static inline struct rq *__task_rq_lock(struct task_struct *p)
 }
 
 /*
- * task_rq_lock - lock the runqueue a given task resides on and disable
- * interrupts. Note the ordering: we can safely lookup the task_rq without
- * explicitly disabling preemption.
+ * task_rq_lock - lock p->pi_lock and lock the rq @p resides on.
  */
 static struct rq *task_rq_lock(struct task_struct *p, unsigned long *flags)
+       __acquires(p->pi_lock)
        __acquires(rq->lock)
 {
        struct rq *rq;
 
        for (;;) {
-               local_irq_save(*flags);
+               raw_spin_lock_irqsave(&p->pi_lock, *flags);
                rq = task_rq(p);
                raw_spin_lock(&rq->lock);
                if (likely(rq == task_rq(p)))
                        return rq;
-               raw_spin_unlock_irqrestore(&rq->lock, *flags);
+               raw_spin_unlock(&rq->lock);
+               raw_spin_unlock_irqrestore(&p->pi_lock, *flags);
        }
 }
 
@@ -961,10 +975,13 @@ static void __task_rq_unlock(struct rq *rq)
        raw_spin_unlock(&rq->lock);
 }
 
-static inline void task_rq_unlock(struct rq *rq, unsigned long *flags)
+static inline void
+task_rq_unlock(struct rq *rq, struct task_struct *p, unsigned long *flags)
        __releases(rq->lock)
+       __releases(p->pi_lock)
 {
-       raw_spin_unlock_irqrestore(&rq->lock, *flags);
+       raw_spin_unlock(&rq->lock);
+       raw_spin_unlock_irqrestore(&p->pi_lock, *flags);
 }
 
 /*
@@ -1193,11 +1210,17 @@ int get_nohz_timer_target(void)
        int i;
        struct sched_domain *sd;
 
+       rcu_read_lock();
        for_each_domain(cpu, sd) {
-               for_each_cpu(i, sched_domain_span(sd))
-                       if (!idle_cpu(i))
-                               return i;
+               for_each_cpu(i, sched_domain_span(sd)) {
+                       if (!idle_cpu(i)) {
+                               cpu = i;
+                               goto unlock;
+                       }
+               }
        }
+unlock:
+       rcu_read_unlock();
        return cpu;
 }
 /*
@@ -1307,15 +1330,15 @@ calc_delta_mine(unsigned long delta_exec, unsigned long weight,
 {
        u64 tmp;
 
+       tmp = (u64)delta_exec * weight;
+
        if (!lw->inv_weight) {
                if (BITS_PER_LONG > 32 && unlikely(lw->weight >= WMULT_CONST))
                        lw->inv_weight = 1;
                else
-                       lw->inv_weight = 1 + (WMULT_CONST-lw->weight/2)
-                               / (lw->weight+1);
+                       lw->inv_weight = WMULT_CONST / lw->weight;
        }
 
-       tmp = (u64)delta_exec * weight;
        /*
         * Check whether we'd overflow the 64-bit multiplication:
         */
@@ -1773,7 +1796,6 @@ static void enqueue_task(struct rq *rq, struct task_struct *p, int flags)
        update_rq_clock(rq);
        sched_info_queued(p);
        p->sched_class->enqueue_task(rq, p, flags);
-       p->se.on_rq = 1;
 }
 
 static void dequeue_task(struct rq *rq, struct task_struct *p, int flags)
@@ -1781,7 +1803,6 @@ static void dequeue_task(struct rq *rq, struct task_struct *p, int flags)
        update_rq_clock(rq);
        sched_info_dequeued(p);
        p->sched_class->dequeue_task(rq, p, flags);
-       p->se.on_rq = 0;
 }
 
 /*
@@ -2116,7 +2137,7 @@ static void check_preempt_curr(struct rq *rq, struct task_struct *p, int flags)
         * A queue event has occurred, and we're going to schedule.  In
         * this case, we can save a useless back to back clock update.
         */
-       if (rq->curr->se.on_rq && test_tsk_need_resched(rq->curr))
+       if (rq->curr->on_rq && test_tsk_need_resched(rq->curr))
                rq->skip_clock_update = 1;
 }
 
@@ -2162,6 +2183,11 @@ void set_task_cpu(struct task_struct *p, unsigned int new_cpu)
         */
        WARN_ON_ONCE(p->state != TASK_RUNNING && p->state != TASK_WAKING &&
                        !(task_thread_info(p)->preempt_count & PREEMPT_ACTIVE));
+
+#ifdef CONFIG_LOCKDEP
+       WARN_ON_ONCE(debug_locks && !(lockdep_is_held(&p->pi_lock) ||
+                                     lockdep_is_held(&task_rq(p)->lock)));
+#endif
 #endif
 
        trace_sched_migrate_task(p, new_cpu);
@@ -2182,19 +2208,6 @@ struct migration_arg {
 static int migration_cpu_stop(void *data);
 
 /*
- * The task's runqueue lock must be held.
- * Returns true if you have to wait for migration thread.
- */
-static bool migrate_task(struct task_struct *p, struct rq *rq)
-{
-       /*
-        * If the task is not on a runqueue (and not running), then
-        * the next wake-up will properly place the task.
-        */
-       return p->se.on_rq || task_running(rq, p);
-}
-
-/*
  * wait_task_inactive - wait for a thread to unschedule.
  *
  * If @match_state is nonzero, it's the @p->state value just checked and
@@ -2251,11 +2264,11 @@ unsigned long wait_task_inactive(struct task_struct *p, long match_state)
                rq = task_rq_lock(p, &flags);
                trace_sched_wait_task(p);
                running = task_running(rq, p);
-               on_rq = p->se.on_rq;
+               on_rq = p->on_rq;
                ncsw = 0;
                if (!match_state || p->state == match_state)
                        ncsw = p->nvcsw | LONG_MIN; /* sets MSB */
-               task_rq_unlock(rq, &flags);
+               task_rq_unlock(rq, p, &flags);
 
                /*
                 * If it changed from the expected state, bail out now.
@@ -2330,7 +2343,7 @@ EXPORT_SYMBOL_GPL(kick_process);
 
 #ifdef CONFIG_SMP
 /*
- * ->cpus_allowed is protected by either TASK_WAKING or rq->lock held.
+ * ->cpus_allowed is protected by both rq->lock and p->pi_lock
  */
 static int select_fallback_rq(int cpu, struct task_struct *p)
 {
@@ -2363,12 +2376,12 @@ static int select_fallback_rq(int cpu, struct task_struct *p)
 }
 
 /*
- * The caller (fork, wakeup) owns TASK_WAKING, ->cpus_allowed is stable.
+ * The caller (fork, wakeup) owns p->pi_lock, ->cpus_allowed is stable.
  */
 static inline
-int select_task_rq(struct rq *rq, struct task_struct *p, int sd_flags, int wake_flags)
+int select_task_rq(struct task_struct *p, int sd_flags, int wake_flags)
 {
-       int cpu = p->sched_class->select_task_rq(rq, p, sd_flags, wake_flags);
+       int cpu = p->sched_class->select_task_rq(p, sd_flags, wake_flags);
 
        /*
         * In order not to call set_task_cpu() on a blocking task we need
@@ -2394,27 +2407,62 @@ static void update_avg(u64 *avg, u64 sample)
 }
 #endif
 
-static inline void ttwu_activate(struct task_struct *p, struct rq *rq,
-                                bool is_sync, bool is_migrate, bool is_local,
-                                unsigned long en_flags)
+static void
+ttwu_stat(struct task_struct *p, int cpu, int wake_flags)
 {
+#ifdef CONFIG_SCHEDSTATS
+       struct rq *rq = this_rq();
+
+#ifdef CONFIG_SMP
+       int this_cpu = smp_processor_id();
+
+       if (cpu == this_cpu) {
+               schedstat_inc(rq, ttwu_local);
+               schedstat_inc(p, se.statistics.nr_wakeups_local);
+       } else {
+               struct sched_domain *sd;
+
+               schedstat_inc(p, se.statistics.nr_wakeups_remote);
+               rcu_read_lock();
+               for_each_domain(this_cpu, sd) {
+                       if (cpumask_test_cpu(cpu, sched_domain_span(sd))) {
+                               schedstat_inc(sd, ttwu_wake_remote);
+                               break;
+                       }
+               }
+               rcu_read_unlock();
+       }
+#endif /* CONFIG_SMP */
+
+       schedstat_inc(rq, ttwu_count);
        schedstat_inc(p, se.statistics.nr_wakeups);
-       if (is_sync)
+
+       if (wake_flags & WF_SYNC)
                schedstat_inc(p, se.statistics.nr_wakeups_sync);
-       if (is_migrate)
+
+       if (cpu != task_cpu(p))
                schedstat_inc(p, se.statistics.nr_wakeups_migrate);
-       if (is_local)
-               schedstat_inc(p, se.statistics.nr_wakeups_local);
-       else
-               schedstat_inc(p, se.statistics.nr_wakeups_remote);
 
+#endif /* CONFIG_SCHEDSTATS */
+}
+
+static void ttwu_activate(struct rq *rq, struct task_struct *p, int en_flags)
+{
        activate_task(rq, p, en_flags);
+       p->on_rq = 1;
+
+       /* if a worker is waking up, notify workqueue */
+       if (p->flags & PF_WQ_WORKER)
+               wq_worker_waking_up(p, cpu_of(rq));
 }
 
-static inline void ttwu_post_activation(struct task_struct *p, struct rq *rq,
-                                       int wake_flags, bool success)
+/*
+ * Mark the task runnable and perform wakeup-preemption.
+ */
+static void
+ttwu_do_wakeup(struct rq *rq, struct task_struct *p, int wake_flags)
 {
-       trace_sched_wakeup(p, success);
+       trace_sched_wakeup(p, true);
        check_preempt_curr(rq, p, wake_flags);
 
        p->state = TASK_RUNNING;
@@ -2433,9 +2481,99 @@ static inline void ttwu_post_activation(struct task_struct *p, struct rq *rq,
                rq->idle_stamp = 0;
        }
 #endif
-       /* if a worker is waking up, notify workqueue */
-       if ((p->flags & PF_WQ_WORKER) && success)
-               wq_worker_waking_up(p, cpu_of(rq));
+}
+
+static void
+ttwu_do_activate(struct rq *rq, struct task_struct *p, int wake_flags)
+{
+#ifdef CONFIG_SMP
+       if (p->sched_contributes_to_load)
+               rq->nr_uninterruptible--;
+#endif
+
+       ttwu_activate(rq, p, ENQUEUE_WAKEUP | ENQUEUE_WAKING);
+       ttwu_do_wakeup(rq, p, wake_flags);
+}
+
+/*
+ * Called in case the task @p isn't fully descheduled from its runqueue,
+ * in this case we must do a remote wakeup. Its a 'light' wakeup though,
+ * since all we need to do is flip p->state to TASK_RUNNING, since
+ * the task is still ->on_rq.
+ */
+static int ttwu_remote(struct task_struct *p, int wake_flags)
+{
+       struct rq *rq;
+       int ret = 0;
+
+       rq = __task_rq_lock(p);
+       if (p->on_rq) {
+               ttwu_do_wakeup(rq, p, wake_flags);
+               ret = 1;
+       }
+       __task_rq_unlock(rq);
+
+       return ret;
+}
+
+#ifdef CONFIG_SMP
+static void sched_ttwu_pending(void)
+{
+       struct rq *rq = this_rq();
+       struct task_struct *list = xchg(&rq->wake_list, NULL);
+
+       if (!list)
+               return;
+
+       raw_spin_lock(&rq->lock);
+
+       while (list) {
+               struct task_struct *p = list;
+               list = list->wake_entry;
+               ttwu_do_activate(rq, p, 0);
+       }
+
+       raw_spin_unlock(&rq->lock);
+}
+
+void scheduler_ipi(void)
+{
+       sched_ttwu_pending();
+}
+
+static void ttwu_queue_remote(struct task_struct *p, int cpu)
+{
+       struct rq *rq = cpu_rq(cpu);
+       struct task_struct *next = rq->wake_list;
+
+       for (;;) {
+               struct task_struct *old = next;
+
+               p->wake_entry = next;
+               next = cmpxchg(&rq->wake_list, old, p);
+               if (next == old)
+                       break;
+       }
+
+       if (!next)
+               smp_send_reschedule(cpu);
+}
+#endif
+
+static void ttwu_queue(struct task_struct *p, int cpu)
+{
+       struct rq *rq = cpu_rq(cpu);
+
+#if defined(CONFIG_SMP) && defined(CONFIG_SCHED_TTWU_QUEUE)
+       if (sched_feat(TTWU_QUEUE) && cpu != smp_processor_id()) {
+               ttwu_queue_remote(p, cpu);
+               return;
+       }
+#endif
+
+       raw_spin_lock(&rq->lock);
+       ttwu_do_activate(rq, p, 0);
+       raw_spin_unlock(&rq->lock);
 }
 
 /**
@@ -2453,92 +2591,64 @@ static inline void ttwu_post_activation(struct task_struct *p, struct rq *rq,
  * Returns %true if @p was woken up, %false if it was already running
  * or @state didn't match @p's state.
  */
-static int try_to_wake_up(struct task_struct *p, unsigned int state,
-                         int wake_flags)
+static int
+try_to_wake_up(struct task_struct *p, unsigned int state, int wake_flags)
 {
-       int cpu, orig_cpu, this_cpu, success = 0;
        unsigned long flags;
-       unsigned long en_flags = ENQUEUE_WAKEUP;
-       struct rq *rq;
-
-       this_cpu = get_cpu();
+       int cpu, success = 0;
 
        smp_wmb();
-       rq = task_rq_lock(p, &flags);
+       raw_spin_lock_irqsave(&p->pi_lock, flags);
        if (!(p->state & state))
                goto out;
 
-       if (p->se.on_rq)
-               goto out_running;
-
+       success = 1; /* we're going to change ->state */
        cpu = task_cpu(p);
-       orig_cpu = cpu;
 
-#ifdef CONFIG_SMP
-       if (unlikely(task_running(rq, p)))
-               goto out_activate;
+       if (p->on_rq && ttwu_remote(p, wake_flags))
+               goto stat;
 
+#ifdef CONFIG_SMP
        /*
-        * In order to handle concurrent wakeups and release the rq->lock
-        * we put the task in TASK_WAKING state.
-        *
-        * First fix up the nr_uninterruptible count:
+        * If the owning (remote) cpu is still in the middle of schedule() with
+        * this task as prev, wait until its done referencing the task.
         */
-       if (task_contributes_to_load(p)) {
-               if (likely(cpu_online(orig_cpu)))
-                       rq->nr_uninterruptible--;
-               else
-                       this_rq()->nr_uninterruptible--;
-       }
-       p->state = TASK_WAKING;
-
-       if (p->sched_class->task_waking) {
-               p->sched_class->task_waking(rq, p);
-               en_flags |= ENQUEUE_WAKING;
+       while (p->on_cpu) {
+#ifdef __ARCH_WANT_INTERRUPTS_ON_CTXSW
+               /*
+                * If called from interrupt context we could have landed in the
+                * middle of schedule(), in this case we should take care not
+                * to spin on ->on_cpu if p is current, since that would
+                * deadlock.
+                */
+               if (p == current) {
+                       ttwu_queue(p, cpu);
+                       goto stat;
+               }
+#endif
+               cpu_relax();
        }
-
-       cpu = select_task_rq(rq, p, SD_BALANCE_WAKE, wake_flags);
-       if (cpu != orig_cpu)
-               set_task_cpu(p, cpu);
-       __task_rq_unlock(rq);
-
-       rq = cpu_rq(cpu);
-       raw_spin_lock(&rq->lock);
-
        /*
-        * We migrated the task without holding either rq->lock, however
-        * since the task is not on the task list itself, nobody else
-        * will try and migrate the task, hence the rq should match the
-        * cpu we just moved it to.
+        * Pairs with the smp_wmb() in finish_lock_switch().
         */
-       WARN_ON(task_cpu(p) != cpu);
-       WARN_ON(p->state != TASK_WAKING);
+       smp_rmb();
 
-#ifdef CONFIG_SCHEDSTATS
-       schedstat_inc(rq, ttwu_count);
-       if (cpu == this_cpu)
-               schedstat_inc(rq, ttwu_local);
-       else {
-               struct sched_domain *sd;
-               for_each_domain(this_cpu, sd) {
-                       if (cpumask_test_cpu(cpu, sched_domain_span(sd))) {
-                               schedstat_inc(sd, ttwu_wake_remote);
-                               break;
-                       }
-               }
-       }
-#endif /* CONFIG_SCHEDSTATS */
+       p->sched_contributes_to_load = !!task_contributes_to_load(p);
+       p->state = TASK_WAKING;
 
-out_activate:
+       if (p->sched_class->task_waking)
+               p->sched_class->task_waking(p);
+
+       cpu = select_task_rq(p, SD_BALANCE_WAKE, wake_flags);
+       if (task_cpu(p) != cpu)
+               set_task_cpu(p, cpu);
 #endif /* CONFIG_SMP */
-       ttwu_activate(p, rq, wake_flags & WF_SYNC, orig_cpu != cpu,
-                     cpu == this_cpu, en_flags);
-       success = 1;
-out_running:
-       ttwu_post_activation(p, rq, wake_flags, success);
+
+       ttwu_queue(p, cpu);
+stat:
+       ttwu_stat(p, cpu, wake_flags);
 out:
-       task_rq_unlock(rq, &flags);
-       put_cpu();
+       raw_spin_unlock_irqrestore(&p->pi_lock, flags);
 
        return success;
 }
@@ -2547,31 +2657,34 @@ out:
  * try_to_wake_up_local - try to wake up a local task with rq lock held
  * @p: the thread to be awakened
  *
- * Put @p on the run-queue if it's not already there.  The caller must
+ * Put @p on the run-queue if it's not already there. The caller must
  * ensure that this_rq() is locked, @p is bound to this_rq() and not
- * the current task.  this_rq() stays locked over invocation.
+ * the current task.
  */
 static void try_to_wake_up_local(struct task_struct *p)
 {
        struct rq *rq = task_rq(p);
-       bool success = false;
 
        BUG_ON(rq != this_rq());
        BUG_ON(p == current);
        lockdep_assert_held(&rq->lock);
 
+       if (!raw_spin_trylock(&p->pi_lock)) {
+               raw_spin_unlock(&rq->lock);
+               raw_spin_lock(&p->pi_lock);
+               raw_spin_lock(&rq->lock);
+       }
+
        if (!(p->state & TASK_NORMAL))
-               return;
+               goto out;
 
-       if (!p->se.on_rq) {
-               if (likely(!task_running(rq, p))) {
-                       schedstat_inc(rq, ttwu_count);
-                       schedstat_inc(rq, ttwu_local);
-               }
-               ttwu_activate(p, rq, false, false, true, ENQUEUE_WAKEUP);
-               success = true;
-       }
-       ttwu_post_activation(p, rq, 0, success);
+       if (!p->on_rq)
+               ttwu_activate(rq, p, ENQUEUE_WAKEUP);
+
+       ttwu_do_wakeup(rq, p, 0);
+       ttwu_stat(p, smp_processor_id(), 0);
+out:
+       raw_spin_unlock(&p->pi_lock);
 }
 
 /**
@@ -2604,19 +2717,21 @@ int wake_up_state(struct task_struct *p, unsigned int state)
  */
 static void __sched_fork(struct task_struct *p)
 {
+       p->on_rq                        = 0;
+
+       p->se.on_rq                     = 0;
        p->se.exec_start                = 0;
        p->se.sum_exec_runtime          = 0;
        p->se.prev_sum_exec_runtime     = 0;
        p->se.nr_migrations             = 0;
        p->se.vruntime                  = 0;
+       INIT_LIST_HEAD(&p->se.group_node);
 
 #ifdef CONFIG_SCHEDSTATS
        memset(&p->se.statistics, 0, sizeof(p->se.statistics));
 #endif
 
        INIT_LIST_HEAD(&p->rt.run_list);
-       p->se.on_rq = 0;
-       INIT_LIST_HEAD(&p->se.group_node);
 
 #ifdef CONFIG_PREEMPT_NOTIFIERS
        INIT_HLIST_HEAD(&p->preempt_notifiers);
@@ -2626,8 +2741,9 @@ static void __sched_fork(struct task_struct *p)
 /*
  * fork()/clone()-time setup:
  */
-void sched_fork(struct task_struct *p, int clone_flags)
+void sched_fork(struct task_struct *p)
 {
+       unsigned long flags;
        int cpu = get_cpu();
 
        __sched_fork(p);
@@ -2678,16 +2794,16 @@ void sched_fork(struct task_struct *p, int clone_flags)
         *
         * Silence PROVE_RCU.
         */
-       rcu_read_lock();
+       raw_spin_lock_irqsave(&p->pi_lock, flags);
        set_task_cpu(p, cpu);
-       rcu_read_unlock();
+       raw_spin_unlock_irqrestore(&p->pi_lock, flags);
 
 #if defined(CONFIG_SCHEDSTATS) || defined(CONFIG_TASK_DELAY_ACCT)
        if (likely(sched_info_on()))
                memset(&p->sched_info, 0, sizeof(p->sched_info));
 #endif
-#if defined(CONFIG_SMP) && defined(__ARCH_WANT_UNLOCKED_CTXSW)
-       p->oncpu = 0;
+#if defined(CONFIG_SMP)
+       p->on_cpu = 0;
 #endif
 #ifdef CONFIG_PREEMPT
        /* Want to start with kernel preemption disabled. */
@@ -2707,41 +2823,31 @@ void sched_fork(struct task_struct *p, int clone_flags)
  * that must be done for every newly created context, then puts the task
  * on the runqueue and wakes it.
  */
-void wake_up_new_task(struct task_struct *p, unsigned long clone_flags)
+void wake_up_new_task(struct task_struct *p)
 {
        unsigned long flags;
        struct rq *rq;
-       int cpu __maybe_unused = get_cpu();
 
+       raw_spin_lock_irqsave(&p->pi_lock, flags);
 #ifdef CONFIG_SMP
-       rq = task_rq_lock(p, &flags);
-       p->state = TASK_WAKING;
-
        /*
         * Fork balancing, do it here and not earlier because:
         *  - cpus_allowed can change in the fork path
         *  - any previously selected cpu might disappear through hotplug
-        *
-        * We set TASK_WAKING so that select_task_rq() can drop rq->lock
-        * without people poking at ->cpus_allowed.
         */
-       cpu = select_task_rq(rq, p, SD_BALANCE_FORK, 0);
-       set_task_cpu(p, cpu);
-
-       p->state = TASK_RUNNING;
-       task_rq_unlock(rq, &flags);
+       set_task_cpu(p, select_task_rq(p, SD_BALANCE_FORK, 0));
 #endif
 
-       rq = task_rq_lock(p, &flags);
+       rq = __task_rq_lock(p);
        activate_task(rq, p, 0);
-       trace_sched_wakeup_new(p, 1);
+       p->on_rq = 1;
+       trace_sched_wakeup_new(p, true);
        check_preempt_curr(rq, p, WF_FORK);
 #ifdef CONFIG_SMP
        if (p->sched_class->task_woken)
                p->sched_class->task_woken(rq, p);
 #endif
-       task_rq_unlock(rq, &flags);
-       put_cpu();
+       task_rq_unlock(rq, p, &flags);
 }
 
 #ifdef CONFIG_PREEMPT_NOTIFIERS
@@ -3450,27 +3556,22 @@ void sched_exec(void)
 {
        struct task_struct *p = current;
        unsigned long flags;
-       struct rq *rq;
        int dest_cpu;
 
-       rq = task_rq_lock(p, &flags);
-       dest_cpu = p->sched_class->select_task_rq(rq, p, SD_BALANCE_EXEC, 0);
+       raw_spin_lock_irqsave(&p->pi_lock, flags);
+       dest_cpu = p->sched_class->select_task_rq(p, SD_BALANCE_EXEC, 0);
        if (dest_cpu == smp_processor_id())
                goto unlock;
 
-       /*
-        * select_task_rq() can race against ->cpus_allowed
-        */
-       if (cpumask_test_cpu(dest_cpu, &p->cpus_allowed) &&
-           likely(cpu_active(dest_cpu)) && migrate_task(p, rq)) {
+       if (likely(cpu_active(dest_cpu))) {
                struct migration_arg arg = { p, dest_cpu };
 
-               task_rq_unlock(rq, &flags);
-               stop_one_cpu(cpu_of(rq), migration_cpu_stop, &arg);
+               raw_spin_unlock_irqrestore(&p->pi_lock, flags);
+               stop_one_cpu(task_cpu(p), migration_cpu_stop, &arg);
                return;
        }
 unlock:
-       task_rq_unlock(rq, &flags);
+       raw_spin_unlock_irqrestore(&p->pi_lock, flags);
 }
 
 #endif
@@ -3507,7 +3608,7 @@ unsigned long long task_delta_exec(struct task_struct *p)
 
        rq = task_rq_lock(p, &flags);
        ns = do_task_delta_exec(p, rq);
-       task_rq_unlock(rq, &flags);
+       task_rq_unlock(rq, p, &flags);
 
        return ns;
 }
@@ -3525,7 +3626,7 @@ unsigned long long task_sched_runtime(struct task_struct *p)
 
        rq = task_rq_lock(p, &flags);
        ns = p->se.sum_exec_runtime + do_task_delta_exec(p, rq);
-       task_rq_unlock(rq, &flags);
+       task_rq_unlock(rq, p, &flags);
 
        return ns;
 }
@@ -3549,7 +3650,7 @@ unsigned long long thread_group_sched_runtime(struct task_struct *p)
        rq = task_rq_lock(p, &flags);
        thread_group_cputime(p, &totals);
        ns = totals.sum_exec_runtime + do_task_delta_exec(p, rq);
-       task_rq_unlock(rq, &flags);
+       task_rq_unlock(rq, p, &flags);
 
        return ns;
 }
@@ -3903,9 +4004,6 @@ void thread_group_times(struct task_struct *p, cputime_t *ut, cputime_t *st)
 /*
  * This function gets called by the timer code, with HZ frequency.
  * We call it with interrupts disabled.
- *
- * It also gets called by the fork code, when changing the parent's
- * timeslices.
  */
 void scheduler_tick(void)
 {
@@ -4025,17 +4123,11 @@ static inline void schedule_debug(struct task_struct *prev)
        profile_hit(SCHED_PROFILING, __builtin_return_address(0));
 
        schedstat_inc(this_rq(), sched_count);
-#ifdef CONFIG_SCHEDSTATS
-       if (unlikely(prev->lock_depth >= 0)) {
-               schedstat_inc(this_rq(), rq_sched_info.bkl_count);
-               schedstat_inc(prev, sched_info.bkl_count);
-       }
-#endif
 }
 
 static void put_prev_task(struct rq *rq, struct task_struct *prev)
 {
-       if (prev->se.on_rq)
+       if (prev->on_rq || rq->skip_clock_update < 0)
                update_rq_clock(rq);
        prev->sched_class->put_prev_task(rq, prev);
 }
@@ -4097,11 +4189,13 @@ need_resched:
                if (unlikely(signal_pending_state(prev->state, prev))) {
                        prev->state = TASK_RUNNING;
                } else {
+                       deactivate_task(rq, prev, DEQUEUE_SLEEP);
+                       prev->on_rq = 0;
+
                        /*
-                        * If a worker is going to sleep, notify and
-                        * ask workqueue whether it wants to wake up a
-                        * task to maintain concurrency.  If so, wake
-                        * up the task.
+                        * If a worker went to sleep, notify and ask workqueue
+                        * whether it wants to wake up a task to maintain
+                        * concurrency.
                         */
                        if (prev->flags & PF_WQ_WORKER) {
                                struct task_struct *to_wakeup;
@@ -4110,11 +4204,10 @@ need_resched:
                                if (to_wakeup)
                                        try_to_wake_up_local(to_wakeup);
                        }
-                       deactivate_task(rq, prev, DEQUEUE_SLEEP);
 
                        /*
-                        * If we are going to sleep and we have plugged IO queued, make
-                        * sure to submit it to avoid deadlocks.
+                        * If we are going to sleep and we have plugged IO
+                        * queued, make sure to submit it to avoid deadlocks.
                         */
                        if (blk_needs_flush_plug(prev)) {
                                raw_spin_unlock(&rq->lock);
@@ -4161,70 +4254,53 @@ need_resched:
 EXPORT_SYMBOL(schedule);
 
 #ifdef CONFIG_MUTEX_SPIN_ON_OWNER
-/*
- * Look out! "owner" is an entirely speculative pointer
- * access and not reliable.
- */
-int mutex_spin_on_owner(struct mutex *lock, struct thread_info *owner)
-{
-       unsigned int cpu;
-       struct rq *rq;
 
-       if (!sched_feat(OWNER_SPIN))
-               return 0;
+static inline bool owner_running(struct mutex *lock, struct task_struct *owner)
+{
+       bool ret = false;
 
-#ifdef CONFIG_DEBUG_PAGEALLOC
-       /*
-        * Need to access the cpu field knowing that
-        * DEBUG_PAGEALLOC could have unmapped it if
-        * the mutex owner just released it and exited.
-        */
-       if (probe_kernel_address(&owner->cpu, cpu))
-               return 0;
-#else
-       cpu = owner->cpu;
-#endif
+       rcu_read_lock();
+       if (lock->owner != owner)
+               goto fail;
 
        /*
-        * Even if the access succeeded (likely case),
-        * the cpu field may no longer be valid.
+        * Ensure we emit the owner->on_cpu, dereference _after_ checking
+        * lock->owner still matches owner, if that fails, owner might
+        * point to free()d memory, if it still matches, the rcu_read_lock()
+        * ensures the memory stays valid.
         */
-       if (cpu >= nr_cpumask_bits)
-               return 0;
+       barrier();
 
-       /*
-        * We need to validate that we can do a
-        * get_cpu() and that we have the percpu area.
-        */
-       if (!cpu_online(cpu))
-               return 0;
+       ret = owner->on_cpu;
+fail:
+       rcu_read_unlock();
 
-       rq = cpu_rq(cpu);
+       return ret;
+}
 
-       for (;;) {
-               /*
-                * Owner changed, break to re-assess state.
-                */
-               if (lock->owner != owner) {
-                       /*
-                        * If the lock has switched to a different owner,
-                        * we likely have heavy contention. Return 0 to quit
-                        * optimistic spinning and not contend further:
-                        */
-                       if (lock->owner)
-                               return 0;
-                       break;
-               }
+/*
+ * Look out! "owner" is an entirely speculative pointer
+ * access and not reliable.
+ */
+int mutex_spin_on_owner(struct mutex *lock, struct task_struct *owner)
+{
+       if (!sched_feat(OWNER_SPIN))
+               return 0;
 
-               /*
-                * Is that owner really running on that cpu?
-                */
-               if (task_thread_info(rq->curr) != owner || need_resched())
+       while (owner_running(lock, owner)) {
+               if (need_resched())
                        return 0;
 
                arch_mutex_cpu_relax();
        }
 
+       /*
+        * If the owner changed to another task there is likely
+        * heavy contention, stop spinning.
+        */
+       if (lock->owner)
+               return 0;
+
        return 1;
 }
 #endif
@@ -4684,19 +4760,18 @@ EXPORT_SYMBOL(sleep_on_timeout);
  */
 void rt_mutex_setprio(struct task_struct *p, int prio)
 {
-       unsigned long flags;
        int oldprio, on_rq, running;
        struct rq *rq;
        const struct sched_class *prev_class;
 
        BUG_ON(prio < 0 || prio > MAX_PRIO);
 
-       rq = task_rq_lock(p, &flags);
+       rq = __task_rq_lock(p);
 
        trace_sched_pi_setprio(p, prio);
        oldprio = p->prio;
        prev_class = p->sched_class;
-       on_rq = p->se.on_rq;
+       on_rq = p->on_rq;
        running = task_current(rq, p);
        if (on_rq)
                dequeue_task(rq, p, 0);
@@ -4716,7 +4791,7 @@ void rt_mutex_setprio(struct task_struct *p, int prio)
                enqueue_task(rq, p, oldprio < prio ? ENQUEUE_HEAD : 0);
 
        check_class_changed(rq, p, prev_class, oldprio);
-       task_rq_unlock(rq, &flags);
+       __task_rq_unlock(rq);
 }
 
 #endif
@@ -4744,7 +4819,7 @@ void set_user_nice(struct task_struct *p, long nice)
                p->static_prio = NICE_TO_PRIO(nice);
                goto out_unlock;
        }
-       on_rq = p->se.on_rq;
+       on_rq = p->on_rq;
        if (on_rq)
                dequeue_task(rq, p, 0);
 
@@ -4764,7 +4839,7 @@ void set_user_nice(struct task_struct *p, long nice)
                        resched_task(rq->curr);
        }
 out_unlock:
-       task_rq_unlock(rq, &flags);
+       task_rq_unlock(rq, p, &flags);
 }
 EXPORT_SYMBOL(set_user_nice);
 
@@ -4878,8 +4953,6 @@ static struct task_struct *find_process_by_pid(pid_t pid)
 static void
 __setscheduler(struct rq *rq, struct task_struct *p, int policy, int prio)
 {
-       BUG_ON(p->se.on_rq);
-
        p->policy = policy;
        p->rt_priority = prio;
        p->normal_prio = normal_prio(p);
@@ -4994,20 +5067,17 @@ recheck:
        /*
         * make sure no PI-waiters arrive (or leave) while we are
         * changing the priority of the task:
-        */
-       raw_spin_lock_irqsave(&p->pi_lock, flags);
-       /*
+        *
         * To be able to change p->policy safely, the appropriate
         * runqueue lock must be held.
         */
-       rq = __task_rq_lock(p);
+       rq = task_rq_lock(p, &flags);
 
        /*
         * Changing the policy of the stop threads its a very bad idea
         */
        if (p == rq->stop) {
-               __task_rq_unlock(rq);
-               raw_spin_unlock_irqrestore(&p->pi_lock, flags);
+               task_rq_unlock(rq, p, &flags);
                return -EINVAL;
        }
 
@@ -5031,8 +5101,7 @@ recheck:
                if (rt_bandwidth_enabled() && rt_policy(policy) &&
                                task_group(p)->rt_bandwidth.rt_runtime == 0 &&
                                !task_group_is_autogroup(task_group(p))) {
-                       __task_rq_unlock(rq);
-                       raw_spin_unlock_irqrestore(&p->pi_lock, flags);
+                       task_rq_unlock(rq, p, &flags);
                        return -EPERM;
                }
        }
@@ -5041,11 +5110,10 @@ recheck:
        /* recheck policy now with rq lock held */
        if (unlikely(oldpolicy != -1 && oldpolicy != p->policy)) {
                policy = oldpolicy = -1;
-               __task_rq_unlock(rq);
-               raw_spin_unlock_irqrestore(&p->pi_lock, flags);
+               task_rq_unlock(rq, p, &flags);
                goto recheck;
        }
-       on_rq = p->se.on_rq;
+       on_rq = p->on_rq;
        running = task_current(rq, p);
        if (on_rq)
                deactivate_task(rq, p, 0);
@@ -5064,8 +5132,7 @@ recheck:
                activate_task(rq, p, 0);
 
        check_class_changed(rq, p, prev_class, oldprio);
-       __task_rq_unlock(rq);
-       raw_spin_unlock_irqrestore(&p->pi_lock, flags);
+       task_rq_unlock(rq, p, &flags);
 
        rt_mutex_adjust_pi(p);
 
@@ -5316,7 +5383,6 @@ long sched_getaffinity(pid_t pid, struct cpumask *mask)
 {
        struct task_struct *p;
        unsigned long flags;
-       struct rq *rq;
        int retval;
 
        get_online_cpus();
@@ -5331,9 +5397,9 @@ long sched_getaffinity(pid_t pid, struct cpumask *mask)
        if (retval)
                goto out_unlock;
 
-       rq = task_rq_lock(p, &flags);
+       raw_spin_lock_irqsave(&p->pi_lock, flags);
        cpumask_and(mask, &p->cpus_allowed, cpu_online_mask);
-       task_rq_unlock(rq, &flags);
+       raw_spin_unlock_irqrestore(&p->pi_lock, flags);
 
 out_unlock:
        rcu_read_unlock();
@@ -5658,7 +5724,7 @@ SYSCALL_DEFINE2(sched_rr_get_interval, pid_t, pid,
 
        rq = task_rq_lock(p, &flags);
        time_slice = p->sched_class->get_rr_interval(rq, p);
-       task_rq_unlock(rq, &flags);
+       task_rq_unlock(rq, p, &flags);
 
        rcu_read_unlock();
        jiffies_to_timespec(time_slice, &t);
@@ -5776,17 +5842,14 @@ void __cpuinit init_idle(struct task_struct *idle, int cpu)
        rcu_read_unlock();
 
        rq->curr = rq->idle = idle;
-#if defined(CONFIG_SMP) && defined(__ARCH_WANT_UNLOCKED_CTXSW)
-       idle->oncpu = 1;
+#if defined(CONFIG_SMP)
+       idle->on_cpu = 1;
 #endif
        raw_spin_unlock_irqrestore(&rq->lock, flags);
 
        /* Set the preempt count _outside_ the spinlocks! */
-#if defined(CONFIG_PREEMPT)
-       task_thread_info(idle)->preempt_count = (idle->lock_depth >= 0);
-#else
        task_thread_info(idle)->preempt_count = 0;
-#endif
+
        /*
         * The idle tasks have their own, simple scheduling class:
         */
@@ -5881,26 +5944,17 @@ int set_cpus_allowed_ptr(struct task_struct *p, const struct cpumask *new_mask)
        unsigned int dest_cpu;
        int ret = 0;
 
-       /*
-        * Serialize against TASK_WAKING so that ttwu() and wunt() can
-        * drop the rq->lock and still rely on ->cpus_allowed.
-        */
-again:
-       while (task_is_waking(p))
-               cpu_relax();
        rq = task_rq_lock(p, &flags);
-       if (task_is_waking(p)) {
-               task_rq_unlock(rq, &flags);
-               goto again;
-       }
+
+       if (cpumask_equal(&p->cpus_allowed, new_mask))
+               goto out;
 
        if (!cpumask_intersects(new_mask, cpu_active_mask)) {
                ret = -EINVAL;
                goto out;
        }
 
-       if (unlikely((p->flags & PF_THREAD_BOUND) && p != current &&
-                    !cpumask_equal(&p->cpus_allowed, new_mask))) {
+       if (unlikely((p->flags & PF_THREAD_BOUND) && p != current)) {
                ret = -EINVAL;
                goto out;
        }
@@ -5917,16 +5971,16 @@ again:
                goto out;
 
        dest_cpu = cpumask_any_and(cpu_active_mask, new_mask);
-       if (migrate_task(p, rq)) {
+       if (p->on_rq) {
                struct migration_arg arg = { p, dest_cpu };
                /* Need help from migration thread: drop lock and wait. */
-               task_rq_unlock(rq, &flags);
+               task_rq_unlock(rq, p, &flags);
                stop_one_cpu(cpu_of(rq), migration_cpu_stop, &arg);
                tlb_migrate_finish(p->mm);
                return 0;
        }
 out:
-       task_rq_unlock(rq, &flags);
+       task_rq_unlock(rq, p, &flags);
 
        return ret;
 }
@@ -5954,6 +6008,7 @@ static int __migrate_task(struct task_struct *p, int src_cpu, int dest_cpu)
        rq_src = cpu_rq(src_cpu);
        rq_dest = cpu_rq(dest_cpu);
 
+       raw_spin_lock(&p->pi_lock);
        double_rq_lock(rq_src, rq_dest);
        /* Already moved. */
        if (task_cpu(p) != src_cpu)
@@ -5966,7 +6021,7 @@ static int __migrate_task(struct task_struct *p, int src_cpu, int dest_cpu)
         * If we're not on a rq, the next wake-up will ensure we're
         * placed properly.
         */
-       if (p->se.on_rq) {
+       if (p->on_rq) {
                deactivate_task(rq_src, p, 0);
                set_task_cpu(p, dest_cpu);
                activate_task(rq_dest, p, 0);
@@ -5976,6 +6031,7 @@ done:
        ret = 1;
 fail:
        double_rq_unlock(rq_src, rq_dest);
+       raw_spin_unlock(&p->pi_lock);
        return ret;
 }
 
@@ -6316,6 +6372,7 @@ migration_call(struct notifier_block *nfb, unsigned long action, void *hcpu)
 
 #ifdef CONFIG_HOTPLUG_CPU
        case CPU_DYING:
+               sched_ttwu_pending();
                /* Update our root-domain */
                raw_spin_lock_irqsave(&rq->lock, flags);
                if (rq->rd) {
@@ -6394,6 +6451,8 @@ early_initcall(migration_init);
 
 #ifdef CONFIG_SMP
 
+static cpumask_var_t sched_domains_tmpmask; /* sched_domains_mutex */
+
 #ifdef CONFIG_SCHED_DEBUG
 
 static __read_mostly int sched_domain_debug_enabled;
@@ -6489,7 +6548,6 @@ static int sched_domain_debug_one(struct sched_domain *sd, int cpu, int level,
 
 static void sched_domain_debug(struct sched_domain *sd, int cpu)
 {
-       cpumask_var_t groupmask;
        int level = 0;
 
        if (!sched_domain_debug_enabled)
@@ -6502,20 +6560,14 @@ static void sched_domain_debug(struct sched_domain *sd, int cpu)
 
        printk(KERN_DEBUG "CPU%d attaching sched-domain:\n", cpu);
 
-       if (!alloc_cpumask_var(&groupmask, GFP_KERNEL)) {
-               printk(KERN_DEBUG "Cannot load-balance (out of memory)\n");
-               return;
-       }
-
        for (;;) {
-               if (sched_domain_debug_one(sd, cpu, level, groupmask))
+               if (sched_domain_debug_one(sd, cpu, level, sched_domains_tmpmask))
                        break;
                level++;
                sd = sd->parent;
                if (!sd)
                        break;
        }
-       free_cpumask_var(groupmask);
 }
 #else /* !CONFIG_SCHED_DEBUG */
 # define sched_domain_debug(sd, cpu) do { } while (0)
@@ -6572,12 +6624,11 @@ sd_parent_degenerate(struct sched_domain *sd, struct sched_domain *parent)
        return 1;
 }
 
-static void free_rootdomain(struct root_domain *rd)
+static void free_rootdomain(struct rcu_head *rcu)
 {
-       synchronize_sched();
+       struct root_domain *rd = container_of(rcu, struct root_domain, rcu);
 
        cpupri_cleanup(&rd->cpupri);
-
        free_cpumask_var(rd->rto_mask);
        free_cpumask_var(rd->online);
        free_cpumask_var(rd->span);
@@ -6618,7 +6669,7 @@ static void rq_attach_root(struct rq *rq, struct root_domain *rd)
        raw_spin_unlock_irqrestore(&rq->lock, flags);
 
        if (old_rd)
-               free_rootdomain(old_rd);
+               call_rcu_sched(&old_rd->rcu, free_rootdomain);
 }
 
 static int init_rootdomain(struct root_domain *rd)
@@ -6669,6 +6720,25 @@ static struct root_domain *alloc_rootdomain(void)
        return rd;
 }
 
+static void free_sched_domain(struct rcu_head *rcu)
+{
+       struct sched_domain *sd = container_of(rcu, struct sched_domain, rcu);
+       if (atomic_dec_and_test(&sd->groups->ref))
+               kfree(sd->groups);
+       kfree(sd);
+}
+
+static void destroy_sched_domain(struct sched_domain *sd, int cpu)
+{
+       call_rcu(&sd->rcu, free_sched_domain);
+}
+
+static void destroy_sched_domains(struct sched_domain *sd, int cpu)
+{
+       for (; sd; sd = sd->parent)
+               destroy_sched_domain(sd, cpu);
+}
+
 /*
  * Attach the domain 'sd' to 'cpu' as its base domain. Callers must
  * hold the hotplug lock.
@@ -6679,9 +6749,6 @@ cpu_attach_domain(struct sched_domain *sd, struct root_domain *rd, int cpu)
        struct rq *rq = cpu_rq(cpu);
        struct sched_domain *tmp;
 
-       for (tmp = sd; tmp; tmp = tmp->parent)
-               tmp->span_weight = cpumask_weight(sched_domain_span(tmp));
-
        /* Remove the sched domains which do not contribute to scheduling. */
        for (tmp = sd; tmp; ) {
                struct sched_domain *parent = tmp->parent;
@@ -6692,12 +6759,15 @@ cpu_attach_domain(struct sched_domain *sd, struct root_domain *rd, int cpu)
                        tmp->parent = parent->parent;
                        if (parent->parent)
                                parent->parent->child = tmp;
+                       destroy_sched_domain(parent, cpu);
                } else
                        tmp = tmp->parent;
        }
 
        if (sd && sd_degenerate(sd)) {
+               tmp = sd;
                sd = sd->parent;
+               destroy_sched_domain(tmp, cpu);
                if (sd)
                        sd->child = NULL;
        }
@@ -6705,7 +6775,9 @@ cpu_attach_domain(struct sched_domain *sd, struct root_domain *rd, int cpu)
        sched_domain_debug(sd, cpu);
 
        rq_attach_root(rq, rd);
+       tmp = rq->sd;
        rcu_assign_pointer(rq->sd, sd);
+       destroy_sched_domains(tmp, cpu);
 }
 
 /* cpus with isolated domains */
@@ -6721,56 +6793,6 @@ static int __init isolated_cpu_setup(char *str)
 
 __setup("isolcpus=", isolated_cpu_setup);
 
-/*
- * init_sched_build_groups takes the cpumask we wish to span, and a pointer
- * to a function which identifies what group(along with sched group) a CPU
- * belongs to. The return value of group_fn must be a >= 0 and < nr_cpu_ids
- * (due to the fact that we keep track of groups covered with a struct cpumask).
- *
- * init_sched_build_groups will build a circular linked list of the groups
- * covered by the given span, and will set each group's ->cpumask correctly,
- * and ->cpu_power to 0.
- */
-static void
-init_sched_build_groups(const struct cpumask *span,
-                       const struct cpumask *cpu_map,
-                       int (*group_fn)(int cpu, const struct cpumask *cpu_map,
-                                       struct sched_group **sg,
-                                       struct cpumask *tmpmask),
-                       struct cpumask *covered, struct cpumask *tmpmask)
-{
-       struct sched_group *first = NULL, *last = NULL;
-       int i;
-
-       cpumask_clear(covered);
-
-       for_each_cpu(i, span) {
-               struct sched_group *sg;
-               int group = group_fn(i, cpu_map, &sg, tmpmask);
-               int j;
-
-               if (cpumask_test_cpu(i, covered))
-                       continue;
-
-               cpumask_clear(sched_group_cpus(sg));
-               sg->cpu_power = 0;
-
-               for_each_cpu(j, span) {
-                       if (group_fn(j, cpu_map, NULL, tmpmask) != group)
-                               continue;
-
-                       cpumask_set_cpu(j, covered);
-                       cpumask_set_cpu(j, sched_group_cpus(sg));
-               }
-               if (!first)
-                       first = sg;
-               if (last)
-                       last->next = sg;
-               last = sg;
-       }
-       last->next = first;
-}
-
 #define SD_NODES_PER_DOMAIN 16
 
 #ifdef CONFIG_NUMA
@@ -6787,7 +6809,7 @@ init_sched_build_groups(const struct cpumask *span,
  */
 static int find_next_best_node(int node, nodemask_t *used_nodes)
 {
-       int i, n, val, min_val, best_node = 0;
+       int i, n, val, min_val, best_node = -1;
 
        min_val = INT_MAX;
 
@@ -6811,7 +6833,8 @@ static int find_next_best_node(int node, nodemask_t *used_nodes)
                }
        }
 
-       node_set(best_node, *used_nodes);
+       if (best_node != -1)
+               node_set(best_node, *used_nodes);
        return best_node;
 }
 
@@ -6837,315 +6860,130 @@ static void sched_domain_node_span(int node, struct cpumask *span)
 
        for (i = 1; i < SD_NODES_PER_DOMAIN; i++) {
                int next_node = find_next_best_node(node, &used_nodes);
-
+               if (next_node < 0)
+                       break;
                cpumask_or(span, span, cpumask_of_node(next_node));
        }
 }
+
+static const struct cpumask *cpu_node_mask(int cpu)
+{
+       lockdep_assert_held(&sched_domains_mutex);
+
+       sched_domain_node_span(cpu_to_node(cpu), sched_domains_tmpmask);
+
+       return sched_domains_tmpmask;
+}
+
+static const struct cpumask *cpu_allnodes_mask(int cpu)
+{
+       return cpu_possible_mask;
+}
 #endif /* CONFIG_NUMA */
 
-int sched_smt_power_savings = 0, sched_mc_power_savings = 0;
+static const struct cpumask *cpu_cpu_mask(int cpu)
+{
+       return cpumask_of_node(cpu_to_node(cpu));
+}
 
-/*
- * The cpus mask in sched_group and sched_domain hangs off the end.
- *
- * ( See the the comments in include/linux/sched.h:struct sched_group
- *   and struct sched_domain. )
- */
-struct static_sched_group {
-       struct sched_group sg;
-       DECLARE_BITMAP(cpus, CONFIG_NR_CPUS);
-};
+int sched_smt_power_savings = 0, sched_mc_power_savings = 0;
 
-struct static_sched_domain {
-       struct sched_domain sd;
-       DECLARE_BITMAP(span, CONFIG_NR_CPUS);
+struct sd_data {
+       struct sched_domain **__percpu sd;
+       struct sched_group **__percpu sg;
 };
 
 struct s_data {
-#ifdef CONFIG_NUMA
-       int                     sd_allnodes;
-       cpumask_var_t           domainspan;
-       cpumask_var_t           covered;
-       cpumask_var_t           notcovered;
-#endif
-       cpumask_var_t           nodemask;
-       cpumask_var_t           this_sibling_map;
-       cpumask_var_t           this_core_map;
-       cpumask_var_t           this_book_map;
-       cpumask_var_t           send_covered;
-       cpumask_var_t           tmpmask;
-       struct sched_group      **sched_group_nodes;
+       struct sched_domain ** __percpu sd;
        struct root_domain      *rd;
 };
 
 enum s_alloc {
-       sa_sched_groups = 0,
        sa_rootdomain,
-       sa_tmpmask,
-       sa_send_covered,
-       sa_this_book_map,
-       sa_this_core_map,
-       sa_this_sibling_map,
-       sa_nodemask,
-       sa_sched_group_nodes,
-#ifdef CONFIG_NUMA
-       sa_notcovered,
-       sa_covered,
-       sa_domainspan,
-#endif
+       sa_sd,
+       sa_sd_storage,
        sa_none,
 };
 
-/*
- * SMT sched-domains:
- */
-#ifdef CONFIG_SCHED_SMT
-static DEFINE_PER_CPU(struct static_sched_domain, cpu_domains);
-static DEFINE_PER_CPU(struct static_sched_group, sched_groups);
-
-static int
-cpu_to_cpu_group(int cpu, const struct cpumask *cpu_map,
-                struct sched_group **sg, struct cpumask *unused)
-{
-       if (sg)
-               *sg = &per_cpu(sched_groups, cpu).sg;
-       return cpu;
-}
-#endif /* CONFIG_SCHED_SMT */
+struct sched_domain_topology_level;
 
-/*
- * multi-core sched-domains:
- */
-#ifdef CONFIG_SCHED_MC
-static DEFINE_PER_CPU(struct static_sched_domain, core_domains);
-static DEFINE_PER_CPU(struct static_sched_group, sched_group_core);
+typedef struct sched_domain *(*sched_domain_init_f)(struct sched_domain_topology_level *tl, int cpu);
+typedef const struct cpumask *(*sched_domain_mask_f)(int cpu);
 
-static int
-cpu_to_core_group(int cpu, const struct cpumask *cpu_map,
-                 struct sched_group **sg, struct cpumask *mask)
-{
-       int group;
-#ifdef CONFIG_SCHED_SMT
-       cpumask_and(mask, topology_thread_cpumask(cpu), cpu_map);
-       group = cpumask_first(mask);
-#else
-       group = cpu;
-#endif
-       if (sg)
-               *sg = &per_cpu(sched_group_core, group).sg;
-       return group;
-}
-#endif /* CONFIG_SCHED_MC */
+struct sched_domain_topology_level {
+       sched_domain_init_f init;
+       sched_domain_mask_f mask;
+       struct sd_data      data;
+};
 
 /*
- * book sched-domains:
+ * Assumes the sched_domain tree is fully constructed
  */
-#ifdef CONFIG_SCHED_BOOK
-static DEFINE_PER_CPU(struct static_sched_domain, book_domains);
-static DEFINE_PER_CPU(struct static_sched_group, sched_group_book);
-
-static int
-cpu_to_book_group(int cpu, const struct cpumask *cpu_map,
-                 struct sched_group **sg, struct cpumask *mask)
+static int get_group(int cpu, struct sd_data *sdd, struct sched_group **sg)
 {
-       int group = cpu;
-#ifdef CONFIG_SCHED_MC
-       cpumask_and(mask, cpu_coregroup_mask(cpu), cpu_map);
-       group = cpumask_first(mask);
-#elif defined(CONFIG_SCHED_SMT)
-       cpumask_and(mask, topology_thread_cpumask(cpu), cpu_map);
-       group = cpumask_first(mask);
-#endif
-       if (sg)
-               *sg = &per_cpu(sched_group_book, group).sg;
-       return group;
-}
-#endif /* CONFIG_SCHED_BOOK */
+       struct sched_domain *sd = *per_cpu_ptr(sdd->sd, cpu);
+       struct sched_domain *child = sd->child;
 
-static DEFINE_PER_CPU(struct static_sched_domain, phys_domains);
-static DEFINE_PER_CPU(struct static_sched_group, sched_group_phys);
+       if (child)
+               cpu = cpumask_first(sched_domain_span(child));
 
-static int
-cpu_to_phys_group(int cpu, const struct cpumask *cpu_map,
-                 struct sched_group **sg, struct cpumask *mask)
-{
-       int group;
-#ifdef CONFIG_SCHED_BOOK
-       cpumask_and(mask, cpu_book_mask(cpu), cpu_map);
-       group = cpumask_first(mask);
-#elif defined(CONFIG_SCHED_MC)
-       cpumask_and(mask, cpu_coregroup_mask(cpu), cpu_map);
-       group = cpumask_first(mask);
-#elif defined(CONFIG_SCHED_SMT)
-       cpumask_and(mask, topology_thread_cpumask(cpu), cpu_map);
-       group = cpumask_first(mask);
-#else
-       group = cpu;
-#endif
        if (sg)
-               *sg = &per_cpu(sched_group_phys, group).sg;
-       return group;
+               *sg = *per_cpu_ptr(sdd->sg, cpu);
+
+       return cpu;
 }
 
-#ifdef CONFIG_NUMA
 /*
- * The init_sched_build_groups can't handle what we want to do with node
- * groups, so roll our own. Now each node has its own list of groups which
- * gets dynamically allocated.
+ * build_sched_groups takes the cpumask we wish to span, and a pointer
+ * to a function which identifies what group(along with sched group) a CPU
+ * belongs to. The return value of group_fn must be a >= 0 and < nr_cpu_ids
+ * (due to the fact that we keep track of groups covered with a struct cpumask).
+ *
+ * build_sched_groups will build a circular linked list of the groups
+ * covered by the given span, and will set each group's ->cpumask correctly,
+ * and ->cpu_power to 0.
  */
-static DEFINE_PER_CPU(struct static_sched_domain, node_domains);
-static struct sched_group ***sched_group_nodes_bycpu;
-
-static DEFINE_PER_CPU(struct static_sched_domain, allnodes_domains);
-static DEFINE_PER_CPU(struct static_sched_group, sched_group_allnodes);
-
-static int cpu_to_allnodes_group(int cpu, const struct cpumask *cpu_map,
-                                struct sched_group **sg,
-                                struct cpumask *nodemask)
-{
-       int group;
-
-       cpumask_and(nodemask, cpumask_of_node(cpu_to_node(cpu)), cpu_map);
-       group = cpumask_first(nodemask);
-
-       if (sg)
-               *sg = &per_cpu(sched_group_allnodes, group).sg;
-       return group;
-}
-
-static void init_numa_sched_groups_power(struct sched_group *group_head)
-{
-       struct sched_group *sg = group_head;
-       int j;
-
-       if (!sg)
-               return;
-       do {
-               for_each_cpu(j, sched_group_cpus(sg)) {
-                       struct sched_domain *sd;
-
-                       sd = &per_cpu(phys_domains, j).sd;
-                       if (j != group_first_cpu(sd->groups)) {
-                               /*
-                                * Only add "power" once for each
-                                * physical package.
-                                */
-                               continue;
-                       }
-
-                       sg->cpu_power += sd->groups->cpu_power;
-               }
-               sg = sg->next;
-       } while (sg != group_head);
-}
-
-static int build_numa_sched_groups(struct s_data *d,
-                                  const struct cpumask *cpu_map, int num)
+static void
+build_sched_groups(struct sched_domain *sd)
 {
-       struct sched_domain *sd;
-       struct sched_group *sg, *prev;
-       int n, j;
-
-       cpumask_clear(d->covered);
-       cpumask_and(d->nodemask, cpumask_of_node(num), cpu_map);
-       if (cpumask_empty(d->nodemask)) {
-               d->sched_group_nodes[num] = NULL;
-               goto out;
-       }
-
-       sched_domain_node_span(num, d->domainspan);
-       cpumask_and(d->domainspan, d->domainspan, cpu_map);
-
-       sg = kmalloc_node(sizeof(struct sched_group) + cpumask_size(),
-                         GFP_KERNEL, num);
-       if (!sg) {
-               printk(KERN_WARNING "Can not alloc domain group for node %d\n",
-                      num);
-               return -ENOMEM;
-       }
-       d->sched_group_nodes[num] = sg;
-
-       for_each_cpu(j, d->nodemask) {
-               sd = &per_cpu(node_domains, j).sd;
-               sd->groups = sg;
-       }
-
-       sg->cpu_power = 0;
-       cpumask_copy(sched_group_cpus(sg), d->nodemask);
-       sg->next = sg;
-       cpumask_or(d->covered, d->covered, d->nodemask);
+       struct sched_group *first = NULL, *last = NULL;
+       struct sd_data *sdd = sd->private;
+       const struct cpumask *span = sched_domain_span(sd);
+       struct cpumask *covered;
+       int i;
 
-       prev = sg;
-       for (j = 0; j < nr_node_ids; j++) {
-               n = (num + j) % nr_node_ids;
-               cpumask_complement(d->notcovered, d->covered);
-               cpumask_and(d->tmpmask, d->notcovered, cpu_map);
-               cpumask_and(d->tmpmask, d->tmpmask, d->domainspan);
-               if (cpumask_empty(d->tmpmask))
-                       break;
-               cpumask_and(d->tmpmask, d->tmpmask, cpumask_of_node(n));
-               if (cpumask_empty(d->tmpmask))
-                       continue;
-               sg = kmalloc_node(sizeof(struct sched_group) + cpumask_size(),
-                                 GFP_KERNEL, num);
-               if (!sg) {
-                       printk(KERN_WARNING
-                              "Can not alloc domain group for node %d\n", j);
-                       return -ENOMEM;
-               }
-               sg->cpu_power = 0;
-               cpumask_copy(sched_group_cpus(sg), d->tmpmask);
-               sg->next = prev->next;
-               cpumask_or(d->covered, d->covered, d->tmpmask);
-               prev->next = sg;
-               prev = sg;
-       }
-out:
-       return 0;
-}
-#endif /* CONFIG_NUMA */
+       lockdep_assert_held(&sched_domains_mutex);
+       covered = sched_domains_tmpmask;
 
-#ifdef CONFIG_NUMA
-/* Free memory allocated for various sched_group structures */
-static void free_sched_groups(const struct cpumask *cpu_map,
-                             struct cpumask *nodemask)
-{
-       int cpu, i;
+       cpumask_clear(covered);
 
-       for_each_cpu(cpu, cpu_map) {
-               struct sched_group **sched_group_nodes
-                       = sched_group_nodes_bycpu[cpu];
+       for_each_cpu(i, span) {
+               struct sched_group *sg;
+               int group = get_group(i, sdd, &sg);
+               int j;
 
-               if (!sched_group_nodes)
+               if (cpumask_test_cpu(i, covered))
                        continue;
 
-               for (i = 0; i < nr_node_ids; i++) {
-                       struct sched_group *oldsg, *sg = sched_group_nodes[i];
+               cpumask_clear(sched_group_cpus(sg));
+               sg->cpu_power = 0;
 
-                       cpumask_and(nodemask, cpumask_of_node(i), cpu_map);
-                       if (cpumask_empty(nodemask))
+               for_each_cpu(j, span) {
+                       if (get_group(j, sdd, NULL) != group)
                                continue;
 
-                       if (sg == NULL)
-                               continue;
-                       sg = sg->next;
-next_sg:
-                       oldsg = sg;
-                       sg = sg->next;
-                       kfree(oldsg);
-                       if (oldsg != sched_group_nodes[i])
-                               goto next_sg;
+                       cpumask_set_cpu(j, covered);
+                       cpumask_set_cpu(j, sched_group_cpus(sg));
                }
-               kfree(sched_group_nodes);
-               sched_group_nodes_bycpu[cpu] = NULL;
+
+               if (!first)
+                       first = sg;
+               if (last)
+                       last->next = sg;
+               last = sg;
        }
+       last->next = first;
 }
-#else /* !CONFIG_NUMA */
-static void free_sched_groups(const struct cpumask *cpu_map,
-                             struct cpumask *nodemask)
-{
-}
-#endif /* CONFIG_NUMA */
 
 /*
  * Initialize sched groups cpu_power.
@@ -7159,11 +6997,6 @@ static void free_sched_groups(const struct cpumask *cpu_map,
  */
 static void init_sched_groups_power(int cpu, struct sched_domain *sd)
 {
-       struct sched_domain *child;
-       struct sched_group *group;
-       long power;
-       int weight;
-
        WARN_ON(!sd || !sd->groups);
 
        if (cpu != group_first_cpu(sd->groups))
@@ -7171,36 +7004,7 @@ static void init_sched_groups_power(int cpu, struct sched_domain *sd)
 
        sd->groups->group_weight = cpumask_weight(sched_group_cpus(sd->groups));
 
-       child = sd->child;
-
-       sd->groups->cpu_power = 0;
-
-       if (!child) {
-               power = SCHED_LOAD_SCALE;
-               weight = cpumask_weight(sched_domain_span(sd));
-               /*
-                * SMT siblings share the power of a single core.
-                * Usually multiple threads get a better yield out of
-                * that one core than a single thread would have,
-                * reflect that in sd->smt_gain.
-                */
-               if ((sd->flags & SD_SHARE_CPUPOWER) && weight > 1) {
-                       power *= sd->smt_gain;
-                       power /= weight;
-                       power >>= SCHED_LOAD_SHIFT;
-               }
-               sd->groups->cpu_power += power;
-               return;
-       }
-
-       /*
-        * Add cpu_power of each child group to this groups cpu_power.
-        */
-       group = child->groups;
-       do {
-               sd->groups->cpu_power += group->cpu_power;
-               group = group->next;
-       } while (group != child->groups);
+       update_group_power(sd, cpu);
 }
 
 /*
@@ -7214,15 +7018,15 @@ static void init_sched_groups_power(int cpu, struct sched_domain *sd)
 # define SD_INIT_NAME(sd, type)                do { } while (0)
 #endif
 
-#define        SD_INIT(sd, type)       sd_init_##type(sd)
-
-#define SD_INIT_FUNC(type)     \
-static noinline void sd_init_##type(struct sched_domain *sd)   \
-{                                                              \
-       memset(sd, 0, sizeof(*sd));                             \
-       *sd = SD_##type##_INIT;                                 \
-       sd->level = SD_LV_##type;                               \
-       SD_INIT_NAME(sd, type);                                 \
+#define SD_INIT_FUNC(type)                                             \
+static noinline struct sched_domain *                                  \
+sd_init_##type(struct sched_domain_topology_level *tl, int cpu)        \
+{                                                                      \
+       struct sched_domain *sd = *per_cpu_ptr(tl->data.sd, cpu);       \
+       *sd = SD_##type##_INIT;                                         \
+       SD_INIT_NAME(sd, type);                                         \
+       sd->private = &tl->data;                                        \
+       return sd;                                                      \
 }
 
 SD_INIT_FUNC(CPU)
@@ -7241,13 +7045,14 @@ SD_INIT_FUNC(CPU)
 #endif
 
 static int default_relax_domain_level = -1;
+int sched_domain_level_max;
 
 static int __init setup_relax_domain_level(char *str)
 {
        unsigned long val;
 
        val = simple_strtoul(str, NULL, 0);
-       if (val < SD_LV_MAX)
+       if (val < sched_domain_level_max)
                default_relax_domain_level = val;
 
        return 1;
@@ -7275,37 +7080,20 @@ static void set_domain_attribute(struct sched_domain *sd,
        }
 }
 
+static void __sdt_free(const struct cpumask *cpu_map);
+static int __sdt_alloc(const struct cpumask *cpu_map);
+
 static void __free_domain_allocs(struct s_data *d, enum s_alloc what,
                                 const struct cpumask *cpu_map)
 {
        switch (what) {
-       case sa_sched_groups:
-               free_sched_groups(cpu_map, d->tmpmask); /* fall through */
-               d->sched_group_nodes = NULL;
        case sa_rootdomain:
-               free_rootdomain(d->rd); /* fall through */
-       case sa_tmpmask:
-               free_cpumask_var(d->tmpmask); /* fall through */
-       case sa_send_covered:
-               free_cpumask_var(d->send_covered); /* fall through */
-       case sa_this_book_map:
-               free_cpumask_var(d->this_book_map); /* fall through */
-       case sa_this_core_map:
-               free_cpumask_var(d->this_core_map); /* fall through */
-       case sa_this_sibling_map:
-               free_cpumask_var(d->this_sibling_map); /* fall through */
-       case sa_nodemask:
-               free_cpumask_var(d->nodemask); /* fall through */
-       case sa_sched_group_nodes:
-#ifdef CONFIG_NUMA
-               kfree(d->sched_group_nodes); /* fall through */
-       case sa_notcovered:
-               free_cpumask_var(d->notcovered); /* fall through */
-       case sa_covered:
-               free_cpumask_var(d->covered); /* fall through */
-       case sa_domainspan:
-               free_cpumask_var(d->domainspan); /* fall through */
-#endif
+               if (!atomic_read(&d->rd->refcount))
+                       free_rootdomain(&d->rd->rcu); /* fall through */
+       case sa_sd:
+               free_percpu(d->sd); /* fall through */
+       case sa_sd_storage:
+               __sdt_free(cpu_map); /* fall through */
        case sa_none:
                break;
        }
@@ -7314,308 +7102,212 @@ static void __free_domain_allocs(struct s_data *d, enum s_alloc what,
 static enum s_alloc __visit_domain_allocation_hell(struct s_data *d,
                                                   const struct cpumask *cpu_map)
 {
-#ifdef CONFIG_NUMA
-       if (!alloc_cpumask_var(&d->domainspan, GFP_KERNEL))
-               return sa_none;
-       if (!alloc_cpumask_var(&d->covered, GFP_KERNEL))
-               return sa_domainspan;
-       if (!alloc_cpumask_var(&d->notcovered, GFP_KERNEL))
-               return sa_covered;
-       /* Allocate the per-node list of sched groups */
-       d->sched_group_nodes = kcalloc(nr_node_ids,
-                                     sizeof(struct sched_group *), GFP_KERNEL);
-       if (!d->sched_group_nodes) {
-               printk(KERN_WARNING "Can not alloc sched group node list\n");
-               return sa_notcovered;
-       }
-       sched_group_nodes_bycpu[cpumask_first(cpu_map)] = d->sched_group_nodes;
-#endif
-       if (!alloc_cpumask_var(&d->nodemask, GFP_KERNEL))
-               return sa_sched_group_nodes;
-       if (!alloc_cpumask_var(&d->this_sibling_map, GFP_KERNEL))
-               return sa_nodemask;
-       if (!alloc_cpumask_var(&d->this_core_map, GFP_KERNEL))
-               return sa_this_sibling_map;
-       if (!alloc_cpumask_var(&d->this_book_map, GFP_KERNEL))
-               return sa_this_core_map;
-       if (!alloc_cpumask_var(&d->send_covered, GFP_KERNEL))
-               return sa_this_book_map;
-       if (!alloc_cpumask_var(&d->tmpmask, GFP_KERNEL))
-               return sa_send_covered;
+       memset(d, 0, sizeof(*d));
+
+       if (__sdt_alloc(cpu_map))
+               return sa_sd_storage;
+       d->sd = alloc_percpu(struct sched_domain *);
+       if (!d->sd)
+               return sa_sd_storage;
        d->rd = alloc_rootdomain();
-       if (!d->rd) {
-               printk(KERN_WARNING "Cannot alloc root domain\n");
-               return sa_tmpmask;
-       }
+       if (!d->rd)
+               return sa_sd;
        return sa_rootdomain;
 }
 
-static struct sched_domain *__build_numa_sched_domains(struct s_data *d,
-       const struct cpumask *cpu_map, struct sched_domain_attr *attr, int i)
+/*
+ * NULL the sd_data elements we've used to build the sched_domain and
+ * sched_group structure so that the subsequent __free_domain_allocs()
+ * will not free the data we're using.
+ */
+static void claim_allocations(int cpu, struct sched_domain *sd)
 {
-       struct sched_domain *sd = NULL;
-#ifdef CONFIG_NUMA
-       struct sched_domain *parent;
-
-       d->sd_allnodes = 0;
-       if (cpumask_weight(cpu_map) >
-           SD_NODES_PER_DOMAIN * cpumask_weight(d->nodemask)) {
-               sd = &per_cpu(allnodes_domains, i).sd;
-               SD_INIT(sd, ALLNODES);
-               set_domain_attribute(sd, attr);
-               cpumask_copy(sched_domain_span(sd), cpu_map);
-               cpu_to_allnodes_group(i, cpu_map, &sd->groups, d->tmpmask);
-               d->sd_allnodes = 1;
-       }
-       parent = sd;
-
-       sd = &per_cpu(node_domains, i).sd;
-       SD_INIT(sd, NODE);
-       set_domain_attribute(sd, attr);
-       sched_domain_node_span(cpu_to_node(i), sched_domain_span(sd));
-       sd->parent = parent;
-       if (parent)
-               parent->child = sd;
-       cpumask_and(sched_domain_span(sd), sched_domain_span(sd), cpu_map);
-#endif
-       return sd;
-}
+       struct sd_data *sdd = sd->private;
+       struct sched_group *sg = sd->groups;
 
-static struct sched_domain *__build_cpu_sched_domain(struct s_data *d,
-       const struct cpumask *cpu_map, struct sched_domain_attr *attr,
-       struct sched_domain *parent, int i)
-{
-       struct sched_domain *sd;
-       sd = &per_cpu(phys_domains, i).sd;
-       SD_INIT(sd, CPU);
-       set_domain_attribute(sd, attr);
-       cpumask_copy(sched_domain_span(sd), d->nodemask);
-       sd->parent = parent;
-       if (parent)
-               parent->child = sd;
-       cpu_to_phys_group(i, cpu_map, &sd->groups, d->tmpmask);
-       return sd;
-}
+       WARN_ON_ONCE(*per_cpu_ptr(sdd->sd, cpu) != sd);
+       *per_cpu_ptr(sdd->sd, cpu) = NULL;
 
-static struct sched_domain *__build_book_sched_domain(struct s_data *d,
-       const struct cpumask *cpu_map, struct sched_domain_attr *attr,
-       struct sched_domain *parent, int i)
-{
-       struct sched_domain *sd = parent;
-#ifdef CONFIG_SCHED_BOOK
-       sd = &per_cpu(book_domains, i).sd;
-       SD_INIT(sd, BOOK);
-       set_domain_attribute(sd, attr);
-       cpumask_and(sched_domain_span(sd), cpu_map, cpu_book_mask(i));
-       sd->parent = parent;
-       parent->child = sd;
-       cpu_to_book_group(i, cpu_map, &sd->groups, d->tmpmask);
-#endif
-       return sd;
+       if (cpu == cpumask_first(sched_group_cpus(sg))) {
+               WARN_ON_ONCE(*per_cpu_ptr(sdd->sg, cpu) != sg);
+               *per_cpu_ptr(sdd->sg, cpu) = NULL;
+       }
 }
 
-static struct sched_domain *__build_mc_sched_domain(struct s_data *d,
-       const struct cpumask *cpu_map, struct sched_domain_attr *attr,
-       struct sched_domain *parent, int i)
+#ifdef CONFIG_SCHED_SMT
+static const struct cpumask *cpu_smt_mask(int cpu)
 {
-       struct sched_domain *sd = parent;
-#ifdef CONFIG_SCHED_MC
-       sd = &per_cpu(core_domains, i).sd;
-       SD_INIT(sd, MC);
-       set_domain_attribute(sd, attr);
-       cpumask_and(sched_domain_span(sd), cpu_map, cpu_coregroup_mask(i));
-       sd->parent = parent;
-       parent->child = sd;
-       cpu_to_core_group(i, cpu_map, &sd->groups, d->tmpmask);
-#endif
-       return sd;
+       return topology_thread_cpumask(cpu);
 }
-
-static struct sched_domain *__build_smt_sched_domain(struct s_data *d,
-       const struct cpumask *cpu_map, struct sched_domain_attr *attr,
-       struct sched_domain *parent, int i)
-{
-       struct sched_domain *sd = parent;
-#ifdef CONFIG_SCHED_SMT
-       sd = &per_cpu(cpu_domains, i).sd;
-       SD_INIT(sd, SIBLING);
-       set_domain_attribute(sd, attr);
-       cpumask_and(sched_domain_span(sd), cpu_map, topology_thread_cpumask(i));
-       sd->parent = parent;
-       parent->child = sd;
-       cpu_to_cpu_group(i, cpu_map, &sd->groups, d->tmpmask);
 #endif
-       return sd;
-}
 
-static void build_sched_groups(struct s_data *d, enum sched_domain_level l,
-                              const struct cpumask *cpu_map, int cpu)
-{
-       switch (l) {
+/*
+ * Topology list, bottom-up.
+ */
+static struct sched_domain_topology_level default_topology[] = {
 #ifdef CONFIG_SCHED_SMT
-       case SD_LV_SIBLING: /* set up CPU (sibling) groups */
-               cpumask_and(d->this_sibling_map, cpu_map,
-                           topology_thread_cpumask(cpu));
-               if (cpu == cpumask_first(d->this_sibling_map))
-                       init_sched_build_groups(d->this_sibling_map, cpu_map,
-                                               &cpu_to_cpu_group,
-                                               d->send_covered, d->tmpmask);
-               break;
+       { sd_init_SIBLING, cpu_smt_mask, },
 #endif
 #ifdef CONFIG_SCHED_MC
-       case SD_LV_MC: /* set up multi-core groups */
-               cpumask_and(d->this_core_map, cpu_map, cpu_coregroup_mask(cpu));
-               if (cpu == cpumask_first(d->this_core_map))
-                       init_sched_build_groups(d->this_core_map, cpu_map,
-                                               &cpu_to_core_group,
-                                               d->send_covered, d->tmpmask);
-               break;
+       { sd_init_MC, cpu_coregroup_mask, },
 #endif
 #ifdef CONFIG_SCHED_BOOK
-       case SD_LV_BOOK: /* set up book groups */
-               cpumask_and(d->this_book_map, cpu_map, cpu_book_mask(cpu));
-               if (cpu == cpumask_first(d->this_book_map))
-                       init_sched_build_groups(d->this_book_map, cpu_map,
-                                               &cpu_to_book_group,
-                                               d->send_covered, d->tmpmask);
-               break;
+       { sd_init_BOOK, cpu_book_mask, },
 #endif
-       case SD_LV_CPU: /* set up physical groups */
-               cpumask_and(d->nodemask, cpumask_of_node(cpu), cpu_map);
-               if (!cpumask_empty(d->nodemask))
-                       init_sched_build_groups(d->nodemask, cpu_map,
-                                               &cpu_to_phys_group,
-                                               d->send_covered, d->tmpmask);
-               break;
+       { sd_init_CPU, cpu_cpu_mask, },
 #ifdef CONFIG_NUMA
-       case SD_LV_ALLNODES:
-               init_sched_build_groups(cpu_map, cpu_map, &cpu_to_allnodes_group,
-                                       d->send_covered, d->tmpmask);
-               break;
+       { sd_init_NODE, cpu_node_mask, },
+       { sd_init_ALLNODES, cpu_allnodes_mask, },
 #endif
-       default:
-               break;
+       { NULL, },
+};
+
+static struct sched_domain_topology_level *sched_domain_topology = default_topology;
+
+static int __sdt_alloc(const struct cpumask *cpu_map)
+{
+       struct sched_domain_topology_level *tl;
+       int j;
+
+       for (tl = sched_domain_topology; tl->init; tl++) {
+               struct sd_data *sdd = &tl->data;
+
+               sdd->sd = alloc_percpu(struct sched_domain *);
+               if (!sdd->sd)
+                       return -ENOMEM;
+
+               sdd->sg = alloc_percpu(struct sched_group *);
+               if (!sdd->sg)
+                       return -ENOMEM;
+
+               for_each_cpu(j, cpu_map) {
+                       struct sched_domain *sd;
+                       struct sched_group *sg;
+
+                       sd = kzalloc_node(sizeof(struct sched_domain) + cpumask_size(),
+                                       GFP_KERNEL, cpu_to_node(j));
+                       if (!sd)
+                               return -ENOMEM;
+
+                       *per_cpu_ptr(sdd->sd, j) = sd;
+
+                       sg = kzalloc_node(sizeof(struct sched_group) + cpumask_size(),
+                                       GFP_KERNEL, cpu_to_node(j));
+                       if (!sg)
+                               return -ENOMEM;
+
+                       *per_cpu_ptr(sdd->sg, j) = sg;
+               }
        }
+
+       return 0;
+}
+
+static void __sdt_free(const struct cpumask *cpu_map)
+{
+       struct sched_domain_topology_level *tl;
+       int j;
+
+       for (tl = sched_domain_topology; tl->init; tl++) {
+               struct sd_data *sdd = &tl->data;
+
+               for_each_cpu(j, cpu_map) {
+                       kfree(*per_cpu_ptr(sdd->sd, j));
+                       kfree(*per_cpu_ptr(sdd->sg, j));
+               }
+               free_percpu(sdd->sd);
+               free_percpu(sdd->sg);
+       }
+}
+
+struct sched_domain *build_sched_domain(struct sched_domain_topology_level *tl,
+               struct s_data *d, const struct cpumask *cpu_map,
+               struct sched_domain_attr *attr, struct sched_domain *child,
+               int cpu)
+{
+       struct sched_domain *sd = tl->init(tl, cpu);
+       if (!sd)
+               return child;
+
+       set_domain_attribute(sd, attr);
+       cpumask_and(sched_domain_span(sd), cpu_map, tl->mask(cpu));
+       if (child) {
+               sd->level = child->level + 1;
+               sched_domain_level_max = max(sched_domain_level_max, sd->level);
+               child->parent = sd;
+       }
+       sd->child = child;
+
+       return sd;
 }
 
 /*
  * Build sched domains for a given set of cpus and attach the sched domains
  * to the individual cpus
  */
-static int __build_sched_domains(const struct cpumask *cpu_map,
-                                struct sched_domain_attr *attr)
+static int build_sched_domains(const struct cpumask *cpu_map,
+                              struct sched_domain_attr *attr)
 {
        enum s_alloc alloc_state = sa_none;
-       struct s_data d;
        struct sched_domain *sd;
-       int i;
-#ifdef CONFIG_NUMA
-       d.sd_allnodes = 0;
-#endif
+       struct s_data d;
+       int i, ret = -ENOMEM;
 
        alloc_state = __visit_domain_allocation_hell(&d, cpu_map);
        if (alloc_state != sa_rootdomain)
                goto error;
-       alloc_state = sa_sched_groups;
-
-       /*
-        * Set up domains for cpus specified by the cpu_map.
-        */
-       for_each_cpu(i, cpu_map) {
-               cpumask_and(d.nodemask, cpumask_of_node(cpu_to_node(i)),
-                           cpu_map);
-
-               sd = __build_numa_sched_domains(&d, cpu_map, attr, i);
-               sd = __build_cpu_sched_domain(&d, cpu_map, attr, sd, i);
-               sd = __build_book_sched_domain(&d, cpu_map, attr, sd, i);
-               sd = __build_mc_sched_domain(&d, cpu_map, attr, sd, i);
-               sd = __build_smt_sched_domain(&d, cpu_map, attr, sd, i);
-       }
 
+       /* Set up domains for cpus specified by the cpu_map. */
        for_each_cpu(i, cpu_map) {
-               build_sched_groups(&d, SD_LV_SIBLING, cpu_map, i);
-               build_sched_groups(&d, SD_LV_BOOK, cpu_map, i);
-               build_sched_groups(&d, SD_LV_MC, cpu_map, i);
-       }
+               struct sched_domain_topology_level *tl;
 
-       /* Set up physical groups */
-       for (i = 0; i < nr_node_ids; i++)
-               build_sched_groups(&d, SD_LV_CPU, cpu_map, i);
+               sd = NULL;
+               for (tl = sched_domain_topology; tl->init; tl++)
+                       sd = build_sched_domain(tl, &d, cpu_map, attr, sd, i);
 
-#ifdef CONFIG_NUMA
-       /* Set up node groups */
-       if (d.sd_allnodes)
-               build_sched_groups(&d, SD_LV_ALLNODES, cpu_map, 0);
+               while (sd->child)
+                       sd = sd->child;
 
-       for (i = 0; i < nr_node_ids; i++)
-               if (build_numa_sched_groups(&d, cpu_map, i))
-                       goto error;
-#endif
-
-       /* Calculate CPU power for physical packages and nodes */
-#ifdef CONFIG_SCHED_SMT
-       for_each_cpu(i, cpu_map) {
-               sd = &per_cpu(cpu_domains, i).sd;
-               init_sched_groups_power(i, sd);
-       }
-#endif
-#ifdef CONFIG_SCHED_MC
-       for_each_cpu(i, cpu_map) {
-               sd = &per_cpu(core_domains, i).sd;
-               init_sched_groups_power(i, sd);
+               *per_cpu_ptr(d.sd, i) = sd;
        }
-#endif
-#ifdef CONFIG_SCHED_BOOK
-       for_each_cpu(i, cpu_map) {
-               sd = &per_cpu(book_domains, i).sd;
-               init_sched_groups_power(i, sd);
-       }
-#endif
 
+       /* Build the groups for the domains */
        for_each_cpu(i, cpu_map) {
-               sd = &per_cpu(phys_domains, i).sd;
-               init_sched_groups_power(i, sd);
-       }
+               for (sd = *per_cpu_ptr(d.sd, i); sd; sd = sd->parent) {
+                       sd->span_weight = cpumask_weight(sched_domain_span(sd));
+                       get_group(i, sd->private, &sd->groups);
+                       atomic_inc(&sd->groups->ref);
 
-#ifdef CONFIG_NUMA
-       for (i = 0; i < nr_node_ids; i++)
-               init_numa_sched_groups_power(d.sched_group_nodes[i]);
+                       if (i != cpumask_first(sched_domain_span(sd)))
+                               continue;
 
-       if (d.sd_allnodes) {
-               struct sched_group *sg;
+                       build_sched_groups(sd);
+               }
+       }
 
-               cpu_to_allnodes_group(cpumask_first(cpu_map), cpu_map, &sg,
-                                                               d.tmpmask);
-               init_numa_sched_groups_power(sg);
+       /* Calculate CPU power for physical packages and nodes */
+       for (i = nr_cpumask_bits-1; i >= 0; i--) {
+               if (!cpumask_test_cpu(i, cpu_map))
+                       continue;
+
+               for (sd = *per_cpu_ptr(d.sd, i); sd; sd = sd->parent) {
+                       claim_allocations(i, sd);
+                       init_sched_groups_power(i, sd);
+               }
        }
-#endif
 
        /* Attach the domains */
+       rcu_read_lock();
        for_each_cpu(i, cpu_map) {
-#ifdef CONFIG_SCHED_SMT
-               sd = &per_cpu(cpu_domains, i).sd;
-#elif defined(CONFIG_SCHED_MC)
-               sd = &per_cpu(core_domains, i).sd;
-#elif defined(CONFIG_SCHED_BOOK)
-               sd = &per_cpu(book_domains, i).sd;
-#else
-               sd = &per_cpu(phys_domains, i).sd;
-#endif
+               sd = *per_cpu_ptr(d.sd, i);
                cpu_attach_domain(sd, d.rd, i);
        }
+       rcu_read_unlock();
 
-       d.sched_group_nodes = NULL; /* don't free this we still need it */
-       __free_domain_allocs(&d, sa_tmpmask, cpu_map);
-       return 0;
-
+       ret = 0;
 error:
        __free_domain_allocs(&d, alloc_state, cpu_map);
-       return -ENOMEM;
-}
-
-static int build_sched_domains(const struct cpumask *cpu_map)
-{
-       return __build_sched_domains(cpu_map, NULL);
+       return ret;
 }
 
 static cpumask_var_t *doms_cur;        /* current sched domains */
@@ -7670,7 +7362,7 @@ void free_sched_domains(cpumask_var_t doms[], unsigned int ndoms)
  * For now this just excludes isolated cpus, but could be used to
  * exclude other special cases in the future.
  */
-static int arch_init_sched_domains(const struct cpumask *cpu_map)
+static int init_sched_domains(const struct cpumask *cpu_map)
 {
        int err;
 
@@ -7681,32 +7373,24 @@ static int arch_init_sched_domains(const struct cpumask *cpu_map)
                doms_cur = &fallback_doms;
        cpumask_andnot(doms_cur[0], cpu_map, cpu_isolated_map);
        dattr_cur = NULL;
-       err = build_sched_domains(doms_cur[0]);
+       err = build_sched_domains(doms_cur[0], NULL);
        register_sched_domain_sysctl();
 
        return err;
 }
 
-static void arch_destroy_sched_domains(const struct cpumask *cpu_map,
-                                      struct cpumask *tmpmask)
-{
-       free_sched_groups(cpu_map, tmpmask);
-}
-
 /*
  * Detach sched domains from a group of cpus specified in cpu_map
  * These cpus will now be attached to the NULL domain
  */
 static void detach_destroy_domains(const struct cpumask *cpu_map)
 {
-       /* Save because hotplug lock held. */
-       static DECLARE_BITMAP(tmpmask, CONFIG_NR_CPUS);
        int i;
 
+       rcu_read_lock();
        for_each_cpu(i, cpu_map)
                cpu_attach_domain(NULL, &def_root_domain, i);
-       synchronize_sched();
-       arch_destroy_sched_domains(cpu_map, to_cpumask(tmpmask));
+       rcu_read_unlock();
 }
 
 /* handle null as "default" */
@@ -7795,8 +7479,7 @@ match1:
                                goto match2;
                }
                /* no match - add a new doms_new */
-               __build_sched_domains(doms_new[i],
-                                       dattr_new ? dattr_new + i : NULL);
+               build_sched_domains(doms_new[i], dattr_new ? dattr_new + i : NULL);
 match2:
                ;
        }
@@ -7815,7 +7498,7 @@ match2:
 }
 
 #if defined(CONFIG_SCHED_MC) || defined(CONFIG_SCHED_SMT)
-static void arch_reinit_sched_domains(void)
+static void reinit_sched_domains(void)
 {
        get_online_cpus();
 
@@ -7848,7 +7531,7 @@ static ssize_t sched_power_savings_store(const char *buf, size_t count, int smt)
        else
                sched_mc_power_savings = level;
 
-       arch_reinit_sched_domains();
+       reinit_sched_domains();
 
        return count;
 }
@@ -7967,14 +7650,9 @@ void __init sched_init_smp(void)
        alloc_cpumask_var(&non_isolated_cpus, GFP_KERNEL);
        alloc_cpumask_var(&fallback_doms, GFP_KERNEL);
 
-#if defined(CONFIG_NUMA)
-       sched_group_nodes_bycpu = kzalloc(nr_cpu_ids * sizeof(void **),
-                                                               GFP_KERNEL);
-       BUG_ON(sched_group_nodes_bycpu == NULL);
-#endif
        get_online_cpus();
        mutex_lock(&sched_domains_mutex);
-       arch_init_sched_domains(cpu_active_mask);
+       init_sched_domains(cpu_active_mask);
        cpumask_andnot(non_isolated_cpus, cpu_possible_mask, cpu_isolated_map);
        if (cpumask_empty(non_isolated_cpus))
                cpumask_set_cpu(smp_processor_id(), non_isolated_cpus);
@@ -8281,6 +7959,7 @@ void __init sched_init(void)
        /* Allocate the nohz_cpu_mask if CONFIG_CPUMASK_OFFSTACK */
        zalloc_cpumask_var(&nohz_cpu_mask, GFP_NOWAIT);
 #ifdef CONFIG_SMP
+       zalloc_cpumask_var(&sched_domains_tmpmask, GFP_NOWAIT);
 #ifdef CONFIG_NO_HZ
        zalloc_cpumask_var(&nohz.idle_cpus_mask, GFP_NOWAIT);
        alloc_cpumask_var(&nohz.grp_idle_mask, GFP_NOWAIT);
@@ -8340,7 +8019,7 @@ static void normalize_task(struct rq *rq, struct task_struct *p)
        int old_prio = p->prio;
        int on_rq;
 
-       on_rq = p->se.on_rq;
+       on_rq = p->on_rq;
        if (on_rq)
                deactivate_task(rq, p, 0);
        __setscheduler(rq, p, SCHED_NORMAL, 0);
@@ -8553,7 +8232,6 @@ int alloc_rt_sched_group(struct task_group *tg, struct task_group *parent)
 {
        struct rt_rq *rt_rq;
        struct sched_rt_entity *rt_se;
-       struct rq *rq;
        int i;
 
        tg->rt_rq = kzalloc(sizeof(rt_rq) * nr_cpu_ids, GFP_KERNEL);
@@ -8567,8 +8245,6 @@ int alloc_rt_sched_group(struct task_group *tg, struct task_group *parent)
                        ktime_to_ns(def_rt_bandwidth.rt_period), 0);
 
        for_each_possible_cpu(i) {
-               rq = cpu_rq(i);
-
                rt_rq = kzalloc_node(sizeof(struct rt_rq),
                                     GFP_KERNEL, cpu_to_node(i));
                if (!rt_rq)
@@ -8683,7 +8359,7 @@ void sched_move_task(struct task_struct *tsk)
        rq = task_rq_lock(tsk, &flags);
 
        running = task_current(rq, tsk);
-       on_rq = tsk->se.on_rq;
+       on_rq = tsk->on_rq;
 
        if (on_rq)
                dequeue_task(rq, tsk, 0);
@@ -8702,7 +8378,7 @@ void sched_move_task(struct task_struct *tsk)
        if (on_rq)
                enqueue_task(rq, tsk, 0);
 
-       task_rq_unlock(rq, &flags);
+       task_rq_unlock(rq, tsk, &flags);
 }
 #endif /* CONFIG_CGROUP_SCHED */
 
index 7bacd83..a6710a1 100644 (file)
@@ -152,7 +152,7 @@ static void print_rq(struct seq_file *m, struct rq *rq, int rq_cpu)
        read_lock_irqsave(&tasklist_lock, flags);
 
        do_each_thread(g, p) {
-               if (!p->se.on_rq || task_cpu(p) != rq_cpu)
+               if (!p->on_rq || task_cpu(p) != rq_cpu)
                        continue;
 
                print_task(m, rq, p);
@@ -296,9 +296,6 @@ static void print_cpu(struct seq_file *m, int cpu)
        P(ttwu_count);
        P(ttwu_local);
 
-       SEQ_printf(m, "  .%-30s: %d\n", "bkl_count",
-                               rq->rq_sched_info.bkl_count);
-
 #undef P
 #undef P64
 #endif
@@ -441,7 +438,6 @@ void proc_sched_show_task(struct task_struct *p, struct seq_file *m)
        P(se.statistics.wait_count);
        PN(se.statistics.iowait_sum);
        P(se.statistics.iowait_count);
-       P(sched_info.bkl_count);
        P(se.nr_migrations);
        P(se.statistics.nr_migrations_cold);
        P(se.statistics.nr_failed_migrations_affine);
index 6fa833a..37f2262 100644 (file)
@@ -358,6 +358,10 @@ static void update_min_vruntime(struct cfs_rq *cfs_rq)
        }
 
        cfs_rq->min_vruntime = max_vruntime(cfs_rq->min_vruntime, vruntime);
+#ifndef CONFIG_64BIT
+       smp_wmb();
+       cfs_rq->min_vruntime_copy = cfs_rq->min_vruntime;
+#endif
 }
 
 /*
@@ -1340,6 +1344,8 @@ enqueue_task_fair(struct rq *rq, struct task_struct *p, int flags)
        hrtick_update(rq);
 }
 
+static void set_next_buddy(struct sched_entity *se);
+
 /*
  * The dequeue_task method is called before nr_running is
  * decreased. We remove the task from the rbtree and
@@ -1349,14 +1355,22 @@ static void dequeue_task_fair(struct rq *rq, struct task_struct *p, int flags)
 {
        struct cfs_rq *cfs_rq;
        struct sched_entity *se = &p->se;
+       int task_sleep = flags & DEQUEUE_SLEEP;
 
        for_each_sched_entity(se) {
                cfs_rq = cfs_rq_of(se);
                dequeue_entity(cfs_rq, se, flags);
 
                /* Don't dequeue parent if it has other entities besides us */
-               if (cfs_rq->load.weight)
+               if (cfs_rq->load.weight) {
+                       /*
+                        * Bias pick_next to pick a task from this cfs_rq, as
+                        * p is sleeping when it is within its sched_slice.
+                        */
+                       if (task_sleep && parent_entity(se))
+                               set_next_buddy(parent_entity(se));
                        break;
+               }
                flags |= DEQUEUE_SLEEP;
        }
 
@@ -1372,12 +1386,25 @@ static void dequeue_task_fair(struct rq *rq, struct task_struct *p, int flags)
 
 #ifdef CONFIG_SMP
 
-static void task_waking_fair(struct rq *rq, struct task_struct *p)
+static void task_waking_fair(struct task_struct *p)
 {
        struct sched_entity *se = &p->se;
        struct cfs_rq *cfs_rq = cfs_rq_of(se);
+       u64 min_vruntime;
 
-       se->vruntime -= cfs_rq->min_vruntime;
+#ifndef CONFIG_64BIT
+       u64 min_vruntime_copy;
+
+       do {
+               min_vruntime_copy = cfs_rq->min_vruntime_copy;
+               smp_rmb();
+               min_vruntime = cfs_rq->min_vruntime;
+       } while (min_vruntime != min_vruntime_copy);
+#else
+       min_vruntime = cfs_rq->min_vruntime;
+#endif
+
+       se->vruntime -= min_vruntime;
 }
 
 #ifdef CONFIG_FAIR_GROUP_SCHED
@@ -1622,6 +1649,7 @@ static int select_idle_sibling(struct task_struct *p, int target)
        /*
         * Otherwise, iterate the domains and find an elegible idle cpu.
         */
+       rcu_read_lock();
        for_each_domain(target, sd) {
                if (!(sd->flags & SD_SHARE_PKG_RESOURCES))
                        break;
@@ -1641,6 +1669,7 @@ static int select_idle_sibling(struct task_struct *p, int target)
                    cpumask_test_cpu(prev_cpu, sched_domain_span(sd)))
                        break;
        }
+       rcu_read_unlock();
 
        return target;
 }
@@ -1657,7 +1686,7 @@ static int select_idle_sibling(struct task_struct *p, int target)
  * preempt must be disabled.
  */
 static int
-select_task_rq_fair(struct rq *rq, struct task_struct *p, int sd_flag, int wake_flags)
+select_task_rq_fair(struct task_struct *p, int sd_flag, int wake_flags)
 {
        struct sched_domain *tmp, *affine_sd = NULL, *sd = NULL;
        int cpu = smp_processor_id();
@@ -1673,6 +1702,7 @@ select_task_rq_fair(struct rq *rq, struct task_struct *p, int sd_flag, int wake_
                new_cpu = prev_cpu;
        }
 
+       rcu_read_lock();
        for_each_domain(cpu, tmp) {
                if (!(tmp->flags & SD_LOAD_BALANCE))
                        continue;
@@ -1723,9 +1753,10 @@ select_task_rq_fair(struct rq *rq, struct task_struct *p, int sd_flag, int wake_
 
        if (affine_sd) {
                if (cpu == prev_cpu || wake_affine(affine_sd, p, sync))
-                       return select_idle_sibling(p, cpu);
-               else
-                       return select_idle_sibling(p, prev_cpu);
+                       prev_cpu = cpu;
+
+               new_cpu = select_idle_sibling(p, prev_cpu);
+               goto unlock;
        }
 
        while (sd) {
@@ -1766,6 +1797,8 @@ select_task_rq_fair(struct rq *rq, struct task_struct *p, int sd_flag, int wake_
                }
                /* while loop will break here if sd == NULL */
        }
+unlock:
+       rcu_read_unlock();
 
        return new_cpu;
 }
@@ -1789,10 +1822,7 @@ wakeup_gran(struct sched_entity *curr, struct sched_entity *se)
         * This is especially important for buddies when the leftmost
         * task is higher priority than the buddy.
         */
-       if (unlikely(se->load.weight != NICE_0_LOAD))
-               gran = calc_delta_fair(gran, se);
-
-       return gran;
+       return calc_delta_fair(gran, se);
 }
 
 /*
@@ -1826,26 +1856,26 @@ wakeup_preempt_entity(struct sched_entity *curr, struct sched_entity *se)
 
 static void set_last_buddy(struct sched_entity *se)
 {
-       if (likely(task_of(se)->policy != SCHED_IDLE)) {
-               for_each_sched_entity(se)
-                       cfs_rq_of(se)->last = se;
-       }
+       if (entity_is_task(se) && unlikely(task_of(se)->policy == SCHED_IDLE))
+               return;
+
+       for_each_sched_entity(se)
+               cfs_rq_of(se)->last = se;
 }
 
 static void set_next_buddy(struct sched_entity *se)
 {
-       if (likely(task_of(se)->policy != SCHED_IDLE)) {
-               for_each_sched_entity(se)
-                       cfs_rq_of(se)->next = se;
-       }
+       if (entity_is_task(se) && unlikely(task_of(se)->policy == SCHED_IDLE))
+               return;
+
+       for_each_sched_entity(se)
+               cfs_rq_of(se)->next = se;
 }
 
 static void set_skip_buddy(struct sched_entity *se)
 {
-       if (likely(task_of(se)->policy != SCHED_IDLE)) {
-               for_each_sched_entity(se)
-                       cfs_rq_of(se)->skip = se;
-       }
+       for_each_sched_entity(se)
+               cfs_rq_of(se)->skip = se;
 }
 
 /*
@@ -1857,12 +1887,15 @@ static void check_preempt_wakeup(struct rq *rq, struct task_struct *p, int wake_
        struct sched_entity *se = &curr->se, *pse = &p->se;
        struct cfs_rq *cfs_rq = task_cfs_rq(curr);
        int scale = cfs_rq->nr_running >= sched_nr_latency;
+       int next_buddy_marked = 0;
 
        if (unlikely(se == pse))
                return;
 
-       if (sched_feat(NEXT_BUDDY) && scale && !(wake_flags & WF_FORK))
+       if (sched_feat(NEXT_BUDDY) && scale && !(wake_flags & WF_FORK)) {
                set_next_buddy(pse);
+               next_buddy_marked = 1;
+       }
 
        /*
         * We can come here with TIF_NEED_RESCHED already set from new task
@@ -1890,8 +1923,15 @@ static void check_preempt_wakeup(struct rq *rq, struct task_struct *p, int wake_
        update_curr(cfs_rq);
        find_matching_se(&se, &pse);
        BUG_ON(!pse);
-       if (wakeup_preempt_entity(se, pse) == 1)
+       if (wakeup_preempt_entity(se, pse) == 1) {
+               /*
+                * Bias pick_next to pick the sched entity that is
+                * triggering this preemption.
+                */
+               if (!next_buddy_marked)
+                       set_next_buddy(pse);
                goto preempt;
+       }
 
        return;
 
@@ -2102,7 +2142,7 @@ static unsigned long
 balance_tasks(struct rq *this_rq, int this_cpu, struct rq *busiest,
              unsigned long max_load_move, struct sched_domain *sd,
              enum cpu_idle_type idle, int *all_pinned,
-             int *this_best_prio, struct cfs_rq *busiest_cfs_rq)
+             struct cfs_rq *busiest_cfs_rq)
 {
        int loops = 0, pulled = 0;
        long rem_load_move = max_load_move;
@@ -2140,9 +2180,6 @@ balance_tasks(struct rq *this_rq, int this_cpu, struct rq *busiest,
                 */
                if (rem_load_move <= 0)
                        break;
-
-               if (p->prio < *this_best_prio)
-                       *this_best_prio = p->prio;
        }
 out:
        /*
@@ -2202,7 +2239,7 @@ static unsigned long
 load_balance_fair(struct rq *this_rq, int this_cpu, struct rq *busiest,
                  unsigned long max_load_move,
                  struct sched_domain *sd, enum cpu_idle_type idle,
-                 int *all_pinned, int *this_best_prio)
+                 int *all_pinned)
 {
        long rem_load_move = max_load_move;
        int busiest_cpu = cpu_of(busiest);
@@ -2227,7 +2264,7 @@ load_balance_fair(struct rq *this_rq, int this_cpu, struct rq *busiest,
                rem_load = div_u64(rem_load, busiest_h_load + 1);
 
                moved_load = balance_tasks(this_rq, this_cpu, busiest,
-                               rem_load, sd, idle, all_pinned, this_best_prio,
+                               rem_load, sd, idle, all_pinned,
                                busiest_cfs_rq);
 
                if (!moved_load)
@@ -2253,11 +2290,11 @@ static unsigned long
 load_balance_fair(struct rq *this_rq, int this_cpu, struct rq *busiest,
                  unsigned long max_load_move,
                  struct sched_domain *sd, enum cpu_idle_type idle,
-                 int *all_pinned, int *this_best_prio)
+                 int *all_pinned)
 {
        return balance_tasks(this_rq, this_cpu, busiest,
                        max_load_move, sd, idle, all_pinned,
-                       this_best_prio, &busiest->cfs);
+                       &busiest->cfs);
 }
 #endif
 
@@ -2274,12 +2311,11 @@ static int move_tasks(struct rq *this_rq, int this_cpu, struct rq *busiest,
                      int *all_pinned)
 {
        unsigned long total_load_moved = 0, load_moved;
-       int this_best_prio = this_rq->curr->prio;
 
        do {
                load_moved = load_balance_fair(this_rq, this_cpu, busiest,
                                max_load_move - total_load_moved,
-                               sd, idle, all_pinned, &this_best_prio);
+                               sd, idle, all_pinned);
 
                total_load_moved += load_moved;
 
@@ -2648,7 +2684,7 @@ fix_small_capacity(struct sched_domain *sd, struct sched_group *group)
        /*
         * Only siblings can have significantly less than SCHED_LOAD_SCALE
         */
-       if (sd->level != SD_LV_SIBLING)
+       if (!(sd->flags & SD_SHARE_CPUPOWER))
                return 0;
 
        /*
@@ -3465,6 +3501,7 @@ static void idle_balance(int this_cpu, struct rq *this_rq)
        raw_spin_unlock(&this_rq->lock);
 
        update_shares(this_cpu);
+       rcu_read_lock();
        for_each_domain(this_cpu, sd) {
                unsigned long interval;
                int balance = 1;
@@ -3486,6 +3523,7 @@ static void idle_balance(int this_cpu, struct rq *this_rq)
                        break;
                }
        }
+       rcu_read_unlock();
 
        raw_spin_lock(&this_rq->lock);
 
@@ -3534,6 +3572,7 @@ static int active_load_balance_cpu_stop(void *data)
        double_lock_balance(busiest_rq, target_rq);
 
        /* Search for an sd spanning us and the target CPU. */
+       rcu_read_lock();
        for_each_domain(target_cpu, sd) {
                if ((sd->flags & SD_LOAD_BALANCE) &&
                    cpumask_test_cpu(busiest_cpu, sched_domain_span(sd)))
@@ -3549,6 +3588,7 @@ static int active_load_balance_cpu_stop(void *data)
                else
                        schedstat_inc(sd, alb_failed);
        }
+       rcu_read_unlock();
        double_unlock_balance(busiest_rq, target_rq);
 out_unlock:
        busiest_rq->active_balance = 0;
@@ -3675,6 +3715,7 @@ static int find_new_ilb(int cpu)
 {
        struct sched_domain *sd;
        struct sched_group *ilb_group;
+       int ilb = nr_cpu_ids;
 
        /*
         * Have idle load balancer selection from semi-idle packages only
@@ -3690,20 +3731,25 @@ static int find_new_ilb(int cpu)
        if (cpumask_weight(nohz.idle_cpus_mask) < 2)
                goto out_done;
 
+       rcu_read_lock();
        for_each_flag_domain(cpu, sd, SD_POWERSAVINGS_BALANCE) {
                ilb_group = sd->groups;
 
                do {
-                       if (is_semi_idle_group(ilb_group))
-                               return cpumask_first(nohz.grp_idle_mask);
+                       if (is_semi_idle_group(ilb_group)) {
+                               ilb = cpumask_first(nohz.grp_idle_mask);
+                               goto unlock;
+                       }
 
                        ilb_group = ilb_group->next;
 
                } while (ilb_group != sd->groups);
        }
+unlock:
+       rcu_read_unlock();
 
 out_done:
-       return nr_cpu_ids;
+       return ilb;
 }
 #else /*  (CONFIG_SCHED_MC || CONFIG_SCHED_SMT) */
 static inline int find_new_ilb(int call_cpu)
@@ -3848,6 +3894,7 @@ static void rebalance_domains(int cpu, enum cpu_idle_type idle)
 
        update_shares(cpu);
 
+       rcu_read_lock();
        for_each_domain(cpu, sd) {
                if (!(sd->flags & SD_LOAD_BALANCE))
                        continue;
@@ -3893,6 +3940,7 @@ out:
                if (!balance)
                        break;
        }
+       rcu_read_unlock();
 
        /*
         * next_balance will be updated only when there is a need.
index 68e69ac..be40f73 100644 (file)
@@ -64,3 +64,9 @@ SCHED_FEAT(OWNER_SPIN, 1)
  * Decrement CPU power based on irq activity
  */
 SCHED_FEAT(NONIRQ_POWER, 1)
+
+/*
+ * Queue remote wakeups on the target CPU and process them
+ * using the scheduler IPI. Reduces rq->lock contention/bounces.
+ */
+SCHED_FEAT(TTWU_QUEUE, 1)
index a776a63..0a51882 100644 (file)
@@ -7,7 +7,7 @@
 
 #ifdef CONFIG_SMP
 static int
-select_task_rq_idle(struct rq *rq, struct task_struct *p, int sd_flag, int flags)
+select_task_rq_idle(struct task_struct *p, int sd_flag, int flags)
 {
        return task_cpu(p); /* IDLE tasks as never migrated */
 }
index e7cebdc..64b2a37 100644 (file)
@@ -183,6 +183,14 @@ static inline u64 sched_rt_period(struct rt_rq *rt_rq)
        return ktime_to_ns(rt_rq->tg->rt_bandwidth.rt_period);
 }
 
+typedef struct task_group *rt_rq_iter_t;
+
+#define for_each_rt_rq(rt_rq, iter, rq) \
+       for (iter = list_entry_rcu(task_groups.next, typeof(*iter), list); \
+            (&iter->list != &task_groups) && \
+            (rt_rq = iter->rt_rq[cpu_of(rq)]); \
+            iter = list_entry_rcu(iter->list.next, typeof(*iter), list))
+
 static inline void list_add_leaf_rt_rq(struct rt_rq *rt_rq)
 {
        list_add_rcu(&rt_rq->leaf_rt_rq_list,
@@ -288,6 +296,11 @@ static inline u64 sched_rt_period(struct rt_rq *rt_rq)
        return ktime_to_ns(def_rt_bandwidth.rt_period);
 }
 
+typedef struct rt_rq *rt_rq_iter_t;
+
+#define for_each_rt_rq(rt_rq, iter, rq) \
+       for ((void) iter, rt_rq = &rq->rt; rt_rq; rt_rq = NULL)
+
 static inline void list_add_leaf_rt_rq(struct rt_rq *rt_rq)
 {
 }
@@ -402,12 +415,13 @@ next:
 static void __disable_runtime(struct rq *rq)
 {
        struct root_domain *rd = rq->rd;
+       rt_rq_iter_t iter;
        struct rt_rq *rt_rq;
 
        if (unlikely(!scheduler_running))
                return;
 
-       for_each_leaf_rt_rq(rt_rq, rq) {
+       for_each_rt_rq(rt_rq, iter, rq) {
                struct rt_bandwidth *rt_b = sched_rt_bandwidth(rt_rq);
                s64 want;
                int i;
@@ -487,6 +501,7 @@ static void disable_runtime(struct rq *rq)
 
 static void __enable_runtime(struct rq *rq)
 {
+       rt_rq_iter_t iter;
        struct rt_rq *rt_rq;
 
        if (unlikely(!scheduler_running))
@@ -495,7 +510,7 @@ static void __enable_runtime(struct rq *rq)
        /*
         * Reset each runqueue's bandwidth settings
         */
-       for_each_leaf_rt_rq(rt_rq, rq) {
+       for_each_rt_rq(rt_rq, iter, rq) {
                struct rt_bandwidth *rt_b = sched_rt_bandwidth(rt_rq);
 
                raw_spin_lock(&rt_b->rt_runtime_lock);
@@ -562,6 +577,13 @@ static int do_sched_rt_period_timer(struct rt_bandwidth *rt_b, int overrun)
                        if (rt_rq->rt_throttled && rt_rq->rt_time < runtime) {
                                rt_rq->rt_throttled = 0;
                                enqueue = 1;
+
+                               /*
+                                * Force a clock update if the CPU was idle,
+                                * lest wakeup -> unthrottle time accumulate.
+                                */
+                               if (rt_rq->rt_nr_running && rq->curr == rq->idle)
+                                       rq->skip_clock_update = -1;
                        }
                        if (rt_rq->rt_time || rt_rq->rt_nr_running)
                                idle = 0;
@@ -977,13 +999,23 @@ static void yield_task_rt(struct rq *rq)
 static int find_lowest_rq(struct task_struct *task);
 
 static int
-select_task_rq_rt(struct rq *rq, struct task_struct *p, int sd_flag, int flags)
+select_task_rq_rt(struct task_struct *p, int sd_flag, int flags)
 {
+       struct task_struct *curr;
+       struct rq *rq;
+       int cpu;
+
        if (sd_flag != SD_BALANCE_WAKE)
                return smp_processor_id();
 
+       cpu = task_cpu(p);
+       rq = cpu_rq(cpu);
+
+       rcu_read_lock();
+       curr = ACCESS_ONCE(rq->curr); /* unlocked access */
+
        /*
-        * If the current task is an RT task, then
+        * If the current task on @p's runqueue is an RT task, then
         * try to see if we can wake this RT task up on another
         * runqueue. Otherwise simply start this RT task
         * on its current runqueue.
@@ -997,21 +1029,25 @@ select_task_rq_rt(struct rq *rq, struct task_struct *p, int sd_flag, int flags)
         * lock?
         *
         * For equal prio tasks, we just let the scheduler sort it out.
+        *
+        * Otherwise, just let it ride on the affined RQ and the
+        * post-schedule router will push the preempted task away
+        *
+        * This test is optimistic, if we get it wrong the load-balancer
+        * will have to sort it out.
         */
-       if (unlikely(rt_task(rq->curr)) &&
-           (rq->curr->rt.nr_cpus_allowed < 2 ||
-            rq->curr->prio < p->prio) &&
+       if (curr && unlikely(rt_task(curr)) &&
+           (curr->rt.nr_cpus_allowed < 2 ||
+            curr->prio < p->prio) &&
            (p->rt.nr_cpus_allowed > 1)) {
-               int cpu = find_lowest_rq(p);
+               int target = find_lowest_rq(p);
 
-               return (cpu == -1) ? task_cpu(p) : cpu;
+               if (target != -1)
+                       cpu = target;
        }
+       rcu_read_unlock();
 
-       /*
-        * Otherwise, just let it ride on the affined RQ and the
-        * post-schedule router will push the preempted task away
-        */
-       return task_cpu(p);
+       return cpu;
 }
 
 static void check_preempt_equal_prio(struct rq *rq, struct task_struct *p)
@@ -1136,7 +1172,7 @@ static void put_prev_task_rt(struct rq *rq, struct task_struct *p)
         * The previous task needs to be made eligible for pushing
         * if it is still active
         */
-       if (p->se.on_rq && p->rt.nr_cpus_allowed > 1)
+       if (on_rt_rq(&p->rt) && p->rt.nr_cpus_allowed > 1)
                enqueue_pushable_task(rq, p);
 }
 
@@ -1287,7 +1323,7 @@ static struct rq *find_lock_lowest_rq(struct task_struct *task, struct rq *rq)
                                     !cpumask_test_cpu(lowest_rq->cpu,
                                                       &task->cpus_allowed) ||
                                     task_running(rq, task) ||
-                                    !task->se.on_rq)) {
+                                    !task->on_rq)) {
 
                                raw_spin_unlock(&lowest_rq->lock);
                                lowest_rq = NULL;
@@ -1321,7 +1357,7 @@ static struct task_struct *pick_next_pushable_task(struct rq *rq)
        BUG_ON(task_current(rq, p));
        BUG_ON(p->rt.nr_cpus_allowed <= 1);
 
-       BUG_ON(!p->se.on_rq);
+       BUG_ON(!p->on_rq);
        BUG_ON(!rt_task(p));
 
        return p;
@@ -1467,7 +1503,7 @@ static int pull_rt_task(struct rq *this_rq)
                 */
                if (p && (p->prio < this_rq->rt.highest_prio.curr)) {
                        WARN_ON(p == src_rq->curr);
-                       WARN_ON(!p->se.on_rq);
+                       WARN_ON(!p->on_rq);
 
                        /*
                         * There's a chance that p is higher in priority
@@ -1538,7 +1574,7 @@ static void set_cpus_allowed_rt(struct task_struct *p,
         * Update the migration status of the RQ if we have an RT task
         * which is running AND changing its weight value.
         */
-       if (p->se.on_rq && (weight != p->rt.nr_cpus_allowed)) {
+       if (p->on_rq && (weight != p->rt.nr_cpus_allowed)) {
                struct rq *rq = task_rq(p);
 
                if (!task_current(rq, p)) {
@@ -1608,7 +1644,7 @@ static void switched_from_rt(struct rq *rq, struct task_struct *p)
         * we may need to handle the pulling of RT tasks
         * now.
         */
-       if (p->se.on_rq && !rq->rt.rt_nr_running)
+       if (p->on_rq && !rq->rt.rt_nr_running)
                pull_rt_task(rq);
 }
 
@@ -1638,7 +1674,7 @@ static void switched_to_rt(struct rq *rq, struct task_struct *p)
         * If that current running task is also an RT task
         * then see if we can move to another run queue.
         */
-       if (p->se.on_rq && rq->curr != p) {
+       if (p->on_rq && rq->curr != p) {
 #ifdef CONFIG_SMP
                if (rq->rt.overloaded && push_rt_task(rq) &&
                    /* Don't resched if we changed runqueues */
@@ -1657,7 +1693,7 @@ static void switched_to_rt(struct rq *rq, struct task_struct *p)
 static void
 prio_changed_rt(struct rq *rq, struct task_struct *p, int oldprio)
 {
-       if (!p->se.on_rq)
+       if (!p->on_rq)
                return;
 
        if (rq->curr == p) {
@@ -1796,10 +1832,11 @@ extern void print_rt_rq(struct seq_file *m, int cpu, struct rt_rq *rt_rq);
 
 static void print_rt_stats(struct seq_file *m, int cpu)
 {
+       rt_rq_iter_t iter;
        struct rt_rq *rt_rq;
 
        rcu_read_lock();
-       for_each_leaf_rt_rq(rt_rq, cpu_rq(cpu))
+       for_each_rt_rq(rt_rq, iter, cpu_rq(cpu))
                print_rt_rq(m, cpu, rt_rq);
        rcu_read_unlock();
 }
index 1ba2bd4..6f43763 100644 (file)
@@ -9,8 +9,7 @@
 
 #ifdef CONFIG_SMP
 static int
-select_task_rq_stop(struct rq *rq, struct task_struct *p,
-                   int sd_flag, int flags)
+select_task_rq_stop(struct task_struct *p, int sd_flag, int flags)
 {
        return task_cpu(p); /* stop tasks as never migrate */
 }
@@ -26,7 +25,7 @@ static struct task_struct *pick_next_task_stop(struct rq *rq)
 {
        struct task_struct *stop = rq->stop;
 
-       if (stop && stop->se.on_rq)
+       if (stop && stop->on_rq)
                return stop;
 
        return NULL;
index 174f976..1396017 100644 (file)
@@ -58,7 +58,7 @@ DEFINE_PER_CPU(struct task_struct *, ksoftirqd);
 
 char *softirq_to_name[NR_SOFTIRQS] = {
        "HI", "TIMER", "NET_TX", "NET_RX", "BLOCK", "BLOCK_IOPOLL",
-       "TASKLET", "SCHED", "HRTIMER",  "RCU"
+       "TASKLET", "SCHED", "HRTIMER"
 };
 
 /*
index af468ed..e4128b2 100644 (file)
@@ -314,8 +314,8 @@ void kernel_restart_prepare(char *cmd)
 {
        blocking_notifier_call_chain(&reboot_notifier_list, SYS_RESTART, cmd);
        system_state = SYSTEM_RESTART;
+       usermodehelper_disable();
        device_shutdown();
-       sysdev_shutdown();
        syscore_shutdown();
 }
 
@@ -344,6 +344,7 @@ static void kernel_shutdown_prepare(enum system_states state)
        blocking_notifier_call_chain(&reboot_notifier_list,
                (state == SYSTEM_HALT)?SYS_HALT:SYS_POWER_OFF, NULL);
        system_state = state;
+       usermodehelper_disable();
        device_shutdown();
 }
 /**
@@ -354,7 +355,6 @@ static void kernel_shutdown_prepare(enum system_states state)
 void kernel_halt(void)
 {
        kernel_shutdown_prepare(SYSTEM_HALT);
-       sysdev_shutdown();
        syscore_shutdown();
        printk(KERN_EMERG "System halted.\n");
        kmsg_dump(KMSG_DUMP_HALT);
@@ -374,7 +374,6 @@ void kernel_power_off(void)
        if (pm_power_off_prepare)
                pm_power_off_prepare();
        disable_nonboot_cpus();
-       sysdev_shutdown();
        syscore_shutdown();
        printk(KERN_EMERG "Power down.\n");
        kmsg_dump(KMSG_DUMP_POWEROFF);
index b042599..e2fd74b 100644 (file)
@@ -1,5 +1,5 @@
 obj-y += timekeeping.o ntp.o clocksource.o jiffies.o timer_list.o timecompare.o
-obj-y += timeconv.o posix-clock.o
+obj-y += timeconv.o posix-clock.o alarmtimer.o
 
 obj-$(CONFIG_GENERIC_CLOCKEVENTS_BUILD)                += clockevents.o
 obj-$(CONFIG_GENERIC_CLOCKEVENTS)              += tick-common.o
diff --git a/kernel/time/alarmtimer.c b/kernel/time/alarmtimer.c
new file mode 100644 (file)
index 0000000..9265014
--- /dev/null
@@ -0,0 +1,694 @@
+/*
+ * Alarmtimer interface
+ *
+ * This interface provides a timer which is similarto hrtimers,
+ * but triggers a RTC alarm if the box is suspend.
+ *
+ * This interface is influenced by the Android RTC Alarm timer
+ * interface.
+ *
+ * Copyright (C) 2010 IBM Corperation
+ *
+ * Author: John Stultz <john.stultz@linaro.org>
+ *
+ * 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/time.h>
+#include <linux/hrtimer.h>
+#include <linux/timerqueue.h>
+#include <linux/rtc.h>
+#include <linux/alarmtimer.h>
+#include <linux/mutex.h>
+#include <linux/platform_device.h>
+#include <linux/posix-timers.h>
+#include <linux/workqueue.h>
+#include <linux/freezer.h>
+
+/**
+ * struct alarm_base - Alarm timer bases
+ * @lock:              Lock for syncrhonized access to the base
+ * @timerqueue:                Timerqueue head managing the list of events
+ * @timer:             hrtimer used to schedule events while running
+ * @gettime:           Function to read the time correlating to the base
+ * @base_clockid:      clockid for the base
+ */
+static struct alarm_base {
+       spinlock_t              lock;
+       struct timerqueue_head  timerqueue;
+       struct hrtimer          timer;
+       ktime_t                 (*gettime)(void);
+       clockid_t               base_clockid;
+} alarm_bases[ALARM_NUMTYPE];
+
+#ifdef CONFIG_RTC_CLASS
+/* rtc timer and device for setting alarm wakeups at suspend */
+static struct rtc_timer                rtctimer;
+static struct rtc_device       *rtcdev;
+#endif
+
+/* freezer delta & lock used to handle clock_nanosleep triggered wakeups */
+static ktime_t freezer_delta;
+static DEFINE_SPINLOCK(freezer_delta_lock);
+
+
+/**
+ * alarmtimer_enqueue - Adds an alarm timer to an alarm_base timerqueue
+ * @base: pointer to the base where the timer is being run
+ * @alarm: pointer to alarm being enqueued.
+ *
+ * Adds alarm to a alarm_base timerqueue and if necessary sets
+ * an hrtimer to run.
+ *
+ * Must hold base->lock when calling.
+ */
+static void alarmtimer_enqueue(struct alarm_base *base, struct alarm *alarm)
+{
+       timerqueue_add(&base->timerqueue, &alarm->node);
+       if (&alarm->node == timerqueue_getnext(&base->timerqueue)) {
+               hrtimer_try_to_cancel(&base->timer);
+               hrtimer_start(&base->timer, alarm->node.expires,
+                               HRTIMER_MODE_ABS);
+       }
+}
+
+/**
+ * alarmtimer_remove - Removes an alarm timer from an alarm_base timerqueue
+ * @base: pointer to the base where the timer is running
+ * @alarm: pointer to alarm being removed
+ *
+ * Removes alarm to a alarm_base timerqueue and if necessary sets
+ * a new timer to run.
+ *
+ * Must hold base->lock when calling.
+ */
+static void alarmtimer_remove(struct alarm_base *base, struct alarm *alarm)
+{
+       struct timerqueue_node *next = timerqueue_getnext(&base->timerqueue);
+
+       timerqueue_del(&base->timerqueue, &alarm->node);
+       if (next == &alarm->node) {
+               hrtimer_try_to_cancel(&base->timer);
+               next = timerqueue_getnext(&base->timerqueue);
+               if (!next)
+                       return;
+               hrtimer_start(&base->timer, next->expires, HRTIMER_MODE_ABS);
+       }
+}
+
+
+/**
+ * alarmtimer_fired - Handles alarm hrtimer being fired.
+ * @timer: pointer to hrtimer being run
+ *
+ * When a alarm timer fires, this runs through the timerqueue to
+ * see which alarms expired, and runs those. If there are more alarm
+ * timers queued for the future, we set the hrtimer to fire when
+ * when the next future alarm timer expires.
+ */
+static enum hrtimer_restart alarmtimer_fired(struct hrtimer *timer)
+{
+       struct alarm_base *base = container_of(timer, struct alarm_base, timer);
+       struct timerqueue_node *next;
+       unsigned long flags;
+       ktime_t now;
+       int ret = HRTIMER_NORESTART;
+
+       spin_lock_irqsave(&base->lock, flags);
+       now = base->gettime();
+       while ((next = timerqueue_getnext(&base->timerqueue))) {
+               struct alarm *alarm;
+               ktime_t expired = next->expires;
+
+               if (expired.tv64 >= now.tv64)
+                       break;
+
+               alarm = container_of(next, struct alarm, node);
+
+               timerqueue_del(&base->timerqueue, &alarm->node);
+               alarm->enabled = 0;
+               /* Re-add periodic timers */
+               if (alarm->period.tv64) {
+                       alarm->node.expires = ktime_add(expired, alarm->period);
+                       timerqueue_add(&base->timerqueue, &alarm->node);
+                       alarm->enabled = 1;
+               }
+               spin_unlock_irqrestore(&base->lock, flags);
+               if (alarm->function)
+                       alarm->function(alarm);
+               spin_lock_irqsave(&base->lock, flags);
+       }
+
+       if (next) {
+               hrtimer_set_expires(&base->timer, next->expires);
+               ret = HRTIMER_RESTART;
+       }
+       spin_unlock_irqrestore(&base->lock, flags);
+
+       return ret;
+
+}
+
+#ifdef CONFIG_RTC_CLASS
+/**
+ * alarmtimer_suspend - Suspend time callback
+ * @dev: unused
+ * @state: unused
+ *
+ * When we are going into suspend, we look through the bases
+ * to see which is the soonest timer to expire. We then
+ * set an rtc timer to fire that far into the future, which
+ * will wake us from suspend.
+ */
+static int alarmtimer_suspend(struct device *dev)
+{
+       struct rtc_time tm;
+       ktime_t min, now;
+       unsigned long flags;
+       int i;
+
+       spin_lock_irqsave(&freezer_delta_lock, flags);
+       min = freezer_delta;
+       freezer_delta = ktime_set(0, 0);
+       spin_unlock_irqrestore(&freezer_delta_lock, flags);
+
+       /* If we have no rtcdev, just return */
+       if (!rtcdev)
+               return 0;
+
+       /* Find the soonest timer to expire*/
+       for (i = 0; i < ALARM_NUMTYPE; i++) {
+               struct alarm_base *base = &alarm_bases[i];
+               struct timerqueue_node *next;
+               ktime_t delta;
+
+               spin_lock_irqsave(&base->lock, flags);
+               next = timerqueue_getnext(&base->timerqueue);
+               spin_unlock_irqrestore(&base->lock, flags);
+               if (!next)
+                       continue;
+               delta = ktime_sub(next->expires, base->gettime());
+               if (!min.tv64 || (delta.tv64 < min.tv64))
+                       min = delta;
+       }
+       if (min.tv64 == 0)
+               return 0;
+
+       /* XXX - Should we enforce a minimum sleep time? */
+       WARN_ON(min.tv64 < NSEC_PER_SEC);
+
+       /* Setup an rtc timer to fire that far in the future */
+       rtc_timer_cancel(rtcdev, &rtctimer);
+       rtc_read_time(rtcdev, &tm);
+       now = rtc_tm_to_ktime(tm);
+       now = ktime_add(now, min);
+
+       rtc_timer_start(rtcdev, &rtctimer, now, ktime_set(0, 0));
+
+       return 0;
+}
+#else
+static int alarmtimer_suspend(struct device *dev)
+{
+       return 0;
+}
+#endif
+
+static void alarmtimer_freezerset(ktime_t absexp, enum alarmtimer_type type)
+{
+       ktime_t delta;
+       unsigned long flags;
+       struct alarm_base *base = &alarm_bases[type];
+
+       delta = ktime_sub(absexp, base->gettime());
+
+       spin_lock_irqsave(&freezer_delta_lock, flags);
+       if (!freezer_delta.tv64 || (delta.tv64 < freezer_delta.tv64))
+               freezer_delta = delta;
+       spin_unlock_irqrestore(&freezer_delta_lock, flags);
+}
+
+
+/**
+ * alarm_init - Initialize an alarm structure
+ * @alarm: ptr to alarm to be initialized
+ * @type: the type of the alarm
+ * @function: callback that is run when the alarm fires
+ */
+void alarm_init(struct alarm *alarm, enum alarmtimer_type type,
+               void (*function)(struct alarm *))
+{
+       timerqueue_init(&alarm->node);
+       alarm->period = ktime_set(0, 0);
+       alarm->function = function;
+       alarm->type = type;
+       alarm->enabled = 0;
+}
+
+/**
+ * alarm_start - Sets an alarm to fire
+ * @alarm: ptr to alarm to set
+ * @start: time to run the alarm
+ * @period: period at which the alarm will recur
+ */
+void alarm_start(struct alarm *alarm, ktime_t start, ktime_t period)
+{
+       struct alarm_base *base = &alarm_bases[alarm->type];
+       unsigned long flags;
+
+       spin_lock_irqsave(&base->lock, flags);
+       if (alarm->enabled)
+               alarmtimer_remove(base, alarm);
+       alarm->node.expires = start;
+       alarm->period = period;
+       alarmtimer_enqueue(base, alarm);
+       alarm->enabled = 1;
+       spin_unlock_irqrestore(&base->lock, flags);
+}
+
+/**
+ * alarm_cancel - Tries to cancel an alarm timer
+ * @alarm: ptr to alarm to be canceled
+ */
+void alarm_cancel(struct alarm *alarm)
+{
+       struct alarm_base *base = &alarm_bases[alarm->type];
+       unsigned long flags;
+
+       spin_lock_irqsave(&base->lock, flags);
+       if (alarm->enabled)
+               alarmtimer_remove(base, alarm);
+       alarm->enabled = 0;
+       spin_unlock_irqrestore(&base->lock, flags);
+}
+
+
+/**
+ * clock2alarm - helper that converts from clockid to alarmtypes
+ * @clockid: clockid.
+ */
+static enum alarmtimer_type clock2alarm(clockid_t clockid)
+{
+       if (clockid == CLOCK_REALTIME_ALARM)
+               return ALARM_REALTIME;
+       if (clockid == CLOCK_BOOTTIME_ALARM)
+               return ALARM_BOOTTIME;
+       return -1;
+}
+
+/**
+ * alarm_handle_timer - Callback for posix timers
+ * @alarm: alarm that fired
+ *
+ * Posix timer callback for expired alarm timers.
+ */
+static void alarm_handle_timer(struct alarm *alarm)
+{
+       struct k_itimer *ptr = container_of(alarm, struct k_itimer,
+                                               it.alarmtimer);
+       if (posix_timer_event(ptr, 0) != 0)
+               ptr->it_overrun++;
+}
+
+/**
+ * alarm_clock_getres - posix getres interface
+ * @which_clock: clockid
+ * @tp: timespec to fill
+ *
+ * Returns the granularity of underlying alarm base clock
+ */
+static int alarm_clock_getres(const clockid_t which_clock, struct timespec *tp)
+{
+       clockid_t baseid = alarm_bases[clock2alarm(which_clock)].base_clockid;
+
+       return hrtimer_get_res(baseid, tp);
+}
+
+/**
+ * alarm_clock_get - posix clock_get interface
+ * @which_clock: clockid
+ * @tp: timespec to fill.
+ *
+ * Provides the underlying alarm base time.
+ */
+static int alarm_clock_get(clockid_t which_clock, struct timespec *tp)
+{
+       struct alarm_base *base = &alarm_bases[clock2alarm(which_clock)];
+
+       *tp = ktime_to_timespec(base->gettime());
+       return 0;
+}
+
+/**
+ * alarm_timer_create - posix timer_create interface
+ * @new_timer: k_itimer pointer to manage
+ *
+ * Initializes the k_itimer structure.
+ */
+static int alarm_timer_create(struct k_itimer *new_timer)
+{
+       enum  alarmtimer_type type;
+       struct alarm_base *base;
+
+       if (!capable(CAP_WAKE_ALARM))
+               return -EPERM;
+
+       type = clock2alarm(new_timer->it_clock);
+       base = &alarm_bases[type];
+       alarm_init(&new_timer->it.alarmtimer, type, alarm_handle_timer);
+       return 0;
+}
+
+/**
+ * alarm_timer_get - posix timer_get interface
+ * @new_timer: k_itimer pointer
+ * @cur_setting: itimerspec data to fill
+ *
+ * Copies the itimerspec data out from the k_itimer
+ */
+static void alarm_timer_get(struct k_itimer *timr,
+                               struct itimerspec *cur_setting)
+{
+       cur_setting->it_interval =
+                       ktime_to_timespec(timr->it.alarmtimer.period);
+       cur_setting->it_value =
+                       ktime_to_timespec(timr->it.alarmtimer.node.expires);
+       return;
+}
+
+/**
+ * alarm_timer_del - posix timer_del interface
+ * @timr: k_itimer pointer to be deleted
+ *
+ * Cancels any programmed alarms for the given timer.
+ */
+static int alarm_timer_del(struct k_itimer *timr)
+{
+       alarm_cancel(&timr->it.alarmtimer);
+       return 0;
+}
+
+/**
+ * alarm_timer_set - posix timer_set interface
+ * @timr: k_itimer pointer to be deleted
+ * @flags: timer flags
+ * @new_setting: itimerspec to be used
+ * @old_setting: itimerspec being replaced
+ *
+ * Sets the timer to new_setting, and starts the timer.
+ */
+static int alarm_timer_set(struct k_itimer *timr, int flags,
+                               struct itimerspec *new_setting,
+                               struct itimerspec *old_setting)
+{
+       /* Save old values */
+       old_setting->it_interval =
+                       ktime_to_timespec(timr->it.alarmtimer.period);
+       old_setting->it_value =
+                       ktime_to_timespec(timr->it.alarmtimer.node.expires);
+
+       /* If the timer was already set, cancel it */
+       alarm_cancel(&timr->it.alarmtimer);
+
+       /* start the timer */
+       alarm_start(&timr->it.alarmtimer,
+                       timespec_to_ktime(new_setting->it_value),
+                       timespec_to_ktime(new_setting->it_interval));
+       return 0;
+}
+
+/**
+ * alarmtimer_nsleep_wakeup - Wakeup function for alarm_timer_nsleep
+ * @alarm: ptr to alarm that fired
+ *
+ * Wakes up the task that set the alarmtimer
+ */
+static void alarmtimer_nsleep_wakeup(struct alarm *alarm)
+{
+       struct task_struct *task = (struct task_struct *)alarm->data;
+
+       alarm->data = NULL;
+       if (task)
+               wake_up_process(task);
+}
+
+/**
+ * alarmtimer_do_nsleep - Internal alarmtimer nsleep implementation
+ * @alarm: ptr to alarmtimer
+ * @absexp: absolute expiration time
+ *
+ * Sets the alarm timer and sleeps until it is fired or interrupted.
+ */
+static int alarmtimer_do_nsleep(struct alarm *alarm, ktime_t absexp)
+{
+       alarm->data = (void *)current;
+       do {
+               set_current_state(TASK_INTERRUPTIBLE);
+               alarm_start(alarm, absexp, ktime_set(0, 0));
+               if (likely(alarm->data))
+                       schedule();
+
+               alarm_cancel(alarm);
+       } while (alarm->data && !signal_pending(current));
+
+       __set_current_state(TASK_RUNNING);
+
+       return (alarm->data == NULL);
+}
+
+
+/**
+ * update_rmtp - Update remaining timespec value
+ * @exp: expiration time
+ * @type: timer type
+ * @rmtp: user pointer to remaining timepsec value
+ *
+ * Helper function that fills in rmtp value with time between
+ * now and the exp value
+ */
+static int update_rmtp(ktime_t exp, enum  alarmtimer_type type,
+                       struct timespec __user *rmtp)
+{
+       struct timespec rmt;
+       ktime_t rem;
+
+       rem = ktime_sub(exp, alarm_bases[type].gettime());
+
+       if (rem.tv64 <= 0)
+               return 0;
+       rmt = ktime_to_timespec(rem);
+
+       if (copy_to_user(rmtp, &rmt, sizeof(*rmtp)))
+               return -EFAULT;
+
+       return 1;
+
+}
+
+/**
+ * alarm_timer_nsleep_restart - restartblock alarmtimer nsleep
+ * @restart: ptr to restart block
+ *
+ * Handles restarted clock_nanosleep calls
+ */
+static long __sched alarm_timer_nsleep_restart(struct restart_block *restart)
+{
+       enum  alarmtimer_type type = restart->nanosleep.index;
+       ktime_t exp;
+       struct timespec __user  *rmtp;
+       struct alarm alarm;
+       int ret = 0;
+
+       exp.tv64 = restart->nanosleep.expires;
+       alarm_init(&alarm, type, alarmtimer_nsleep_wakeup);
+
+       if (alarmtimer_do_nsleep(&alarm, exp))
+               goto out;
+
+       if (freezing(current))
+               alarmtimer_freezerset(exp, type);
+
+       rmtp = restart->nanosleep.rmtp;
+       if (rmtp) {
+               ret = update_rmtp(exp, type, rmtp);
+               if (ret <= 0)
+                       goto out;
+       }
+
+
+       /* The other values in restart are already filled in */
+       ret = -ERESTART_RESTARTBLOCK;
+out:
+       return ret;
+}
+
+/**
+ * alarm_timer_nsleep - alarmtimer nanosleep
+ * @which_clock: clockid
+ * @flags: determins abstime or relative
+ * @tsreq: requested sleep time (abs or rel)
+ * @rmtp: remaining sleep time saved
+ *
+ * Handles clock_nanosleep calls against _ALARM clockids
+ */
+static int alarm_timer_nsleep(const clockid_t which_clock, int flags,
+                    struct timespec *tsreq, struct timespec __user *rmtp)
+{
+       enum  alarmtimer_type type = clock2alarm(which_clock);
+       struct alarm alarm;
+       ktime_t exp;
+       int ret = 0;
+       struct restart_block *restart;
+
+       if (!capable(CAP_WAKE_ALARM))
+               return -EPERM;
+
+       alarm_init(&alarm, type, alarmtimer_nsleep_wakeup);
+
+       exp = timespec_to_ktime(*tsreq);
+       /* Convert (if necessary) to absolute time */
+       if (flags != TIMER_ABSTIME) {
+               ktime_t now = alarm_bases[type].gettime();
+               exp = ktime_add(now, exp);
+       }
+
+       if (alarmtimer_do_nsleep(&alarm, exp))
+               goto out;
+
+       if (freezing(current))
+               alarmtimer_freezerset(exp, type);
+
+       /* abs timers don't set remaining time or restart */
+       if (flags == TIMER_ABSTIME) {
+               ret = -ERESTARTNOHAND;
+               goto out;
+       }
+
+       if (rmtp) {
+               ret = update_rmtp(exp, type, rmtp);
+               if (ret <= 0)
+                       goto out;
+       }
+
+       restart = &current_thread_info()->restart_block;
+       restart->fn = alarm_timer_nsleep_restart;
+       restart->nanosleep.index = type;
+       restart->nanosleep.expires = exp.tv64;
+       restart->nanosleep.rmtp = rmtp;
+       ret = -ERESTART_RESTARTBLOCK;
+
+out:
+       return ret;
+}
+
+
+/* Suspend hook structures */
+static const struct dev_pm_ops alarmtimer_pm_ops = {
+       .suspend = alarmtimer_suspend,
+};
+
+static struct platform_driver alarmtimer_driver = {
+       .driver = {
+               .name = "alarmtimer",
+               .pm = &alarmtimer_pm_ops,
+       }
+};
+
+/**
+ * alarmtimer_init - Initialize alarm timer code
+ *
+ * This function initializes the alarm bases and registers
+ * the posix clock ids.
+ */
+static int __init alarmtimer_init(void)
+{
+       int error = 0;
+       int i;
+       struct k_clock alarm_clock = {
+               .clock_getres   = alarm_clock_getres,
+               .clock_get      = alarm_clock_get,
+               .timer_create   = alarm_timer_create,
+               .timer_set      = alarm_timer_set,
+               .timer_del      = alarm_timer_del,
+               .timer_get      = alarm_timer_get,
+               .nsleep         = alarm_timer_nsleep,
+       };
+
+       posix_timers_register_clock(CLOCK_REALTIME_ALARM, &alarm_clock);
+       posix_timers_register_clock(CLOCK_BOOTTIME_ALARM, &alarm_clock);
+
+       /* Initialize alarm bases */
+       alarm_bases[ALARM_REALTIME].base_clockid = CLOCK_REALTIME;
+       alarm_bases[ALARM_REALTIME].gettime = &ktime_get_real;
+       alarm_bases[ALARM_BOOTTIME].base_clockid = CLOCK_BOOTTIME;
+       alarm_bases[ALARM_BOOTTIME].gettime = &ktime_get_boottime;
+       for (i = 0; i < ALARM_NUMTYPE; i++) {
+               timerqueue_init_head(&alarm_bases[i].timerqueue);
+               spin_lock_init(&alarm_bases[i].lock);
+               hrtimer_init(&alarm_bases[i].timer,
+                               alarm_bases[i].base_clockid,
+                               HRTIMER_MODE_ABS);
+               alarm_bases[i].timer.function = alarmtimer_fired;
+       }
+       error = platform_driver_register(&alarmtimer_driver);
+       platform_device_register_simple("alarmtimer", -1, NULL, 0);
+
+       return error;
+}
+device_initcall(alarmtimer_init);
+
+#ifdef CONFIG_RTC_CLASS
+/**
+ * has_wakealarm - check rtc device has wakealarm ability
+ * @dev: current device
+ * @name_ptr: name to be returned
+ *
+ * This helper function checks to see if the rtc device can wake
+ * from suspend.
+ */
+static int __init has_wakealarm(struct device *dev, void *name_ptr)
+{
+       struct rtc_device *candidate = to_rtc_device(dev);
+
+       if (!candidate->ops->set_alarm)
+               return 0;
+       if (!device_may_wakeup(candidate->dev.parent))
+               return 0;
+
+       *(const char **)name_ptr = dev_name(dev);
+       return 1;
+}
+
+/**
+ * alarmtimer_init_late - Late initializing of alarmtimer code
+ *
+ * This function locates a rtc device to use for wakealarms.
+ * Run as late_initcall to make sure rtc devices have been
+ * registered.
+ */
+static int __init alarmtimer_init_late(void)
+{
+       char *str;
+
+       /* Find an rtc device and init the rtc_timer */
+       class_find_device(rtc_class, NULL, &str, has_wakealarm);
+       if (str)
+               rtcdev = rtc_class_open(str);
+       if (!rtcdev) {
+               printk(KERN_WARNING "No RTC device found, ALARM timers will"
+                       " not wake from suspend");
+       }
+       rtc_timer_init(&rtctimer, NULL, NULL);
+
+       return 0;
+}
+#else
+static int __init alarmtimer_init_late(void)
+{
+       printk(KERN_WARNING "Kernel not built with RTC support, ALARM timers"
+               " will not wake from suspend");
+       return 0;
+}
+#endif
+late_initcall(alarmtimer_init_late);
index 0d74b9b..22a9da9 100644 (file)
@@ -194,6 +194,70 @@ void clockevents_register_device(struct clock_event_device *dev)
 }
 EXPORT_SYMBOL_GPL(clockevents_register_device);
 
+static void clockevents_config(struct clock_event_device *dev,
+                              u32 freq)
+{
+       unsigned long sec;
+
+       if (!(dev->features & CLOCK_EVT_FEAT_ONESHOT))
+               return;
+
+       /*
+        * Calculate the maximum number of seconds we can sleep. Limit
+        * to 10 minutes for hardware which can program more than
+        * 32bit ticks so we still get reasonable conversion values.
+        */
+       sec = dev->max_delta_ticks;
+       do_div(sec, freq);
+       if (!sec)
+               sec = 1;
+       else if (sec > 600 && dev->max_delta_ticks > UINT_MAX)
+               sec = 600;
+
+       clockevents_calc_mult_shift(dev, freq, sec);
+       dev->min_delta_ns = clockevent_delta2ns(dev->min_delta_ticks, dev);
+       dev->max_delta_ns = clockevent_delta2ns(dev->max_delta_ticks, dev);
+}
+
+/**
+ * clockevents_config_and_register - Configure and register a clock event device
+ * @dev:       device to register
+ * @freq:      The clock frequency
+ * @min_delta: The minimum clock ticks to program in oneshot mode
+ * @max_delta: The maximum clock ticks to program in oneshot mode
+ *
+ * min/max_delta can be 0 for devices which do not support oneshot mode.
+ */
+void clockevents_config_and_register(struct clock_event_device *dev,
+                                    u32 freq, unsigned long min_delta,
+                                    unsigned long max_delta)
+{
+       dev->min_delta_ticks = min_delta;
+       dev->max_delta_ticks = max_delta;
+       clockevents_config(dev, freq);
+       clockevents_register_device(dev);
+}
+
+/**
+ * clockevents_update_freq - Update frequency and reprogram a clock event device.
+ * @dev:       device to modify
+ * @freq:      new device frequency
+ *
+ * Reconfigure and reprogram a clock event device in oneshot
+ * mode. Must be called on the cpu for which the device delivers per
+ * cpu timer events with interrupts disabled!  Returns 0 on success,
+ * -ETIME when the event is in the past.
+ */
+int clockevents_update_freq(struct clock_event_device *dev, u32 freq)
+{
+       clockevents_config(dev, freq);
+
+       if (dev->mode != CLOCK_EVT_MODE_ONESHOT)
+               return 0;
+
+       return clockevents_program_event(dev, dev->next_event, ktime_get());
+}
+
 /*
  * Noop handler when we shut down an event device
  */
index 6519cf6..d9d5f8c 100644 (file)
@@ -626,19 +626,6 @@ static void clocksource_enqueue(struct clocksource *cs)
        list_add(&cs->list, entry);
 }
 
-
-/*
- * Maximum time we expect to go between ticks. This includes idle
- * tickless time. It provides the trade off between selecting a
- * mult/shift pair that is very precise but can only handle a short
- * period of time, vs. a mult/shift pair that can handle long periods
- * of time but isn't as precise.
- *
- * This is a subsystem constant, and actual hardware limitations
- * may override it (ie: clocksources that wrap every 3 seconds).
- */
-#define MAX_UPDATE_LENGTH 5 /* Seconds */
-
 /**
  * __clocksource_updatefreq_scale - Used update clocksource with new freq
  * @t:         clocksource to be registered
@@ -652,15 +639,28 @@ static void clocksource_enqueue(struct clocksource *cs)
  */
 void __clocksource_updatefreq_scale(struct clocksource *cs, u32 scale, u32 freq)
 {
+       unsigned long sec;
+
        /*
-        * Ideally we want to use  some of the limits used in
-        * clocksource_max_deferment, to provide a more informed
-        * MAX_UPDATE_LENGTH. But for now this just gets the
-        * register interface working properly.
+        * Calc the maximum number of seconds which we can run before
+        * wrapping around. For clocksources which have a mask > 32bit
+        * we need to limit the max sleep time to have a good
+        * conversion precision. 10 minutes is still a reasonable
+        * amount. That results in a shift value of 24 for a
+        * clocksource with mask >= 40bit and f >= 4GHz. That maps to
+        * ~ 0.06ppm granularity for NTP. We apply the same 12.5%
+        * margin as we do in clocksource_max_deferment()
         */
+       sec = (cs->mask - (cs->mask >> 5));
+       do_div(sec, freq);
+       do_div(sec, scale);
+       if (!sec)
+               sec = 1;
+       else if (sec > 600 && cs->mask > UINT_MAX)
+               sec = 600;
+
        clocks_calc_mult_shift(&cs->mult, &cs->shift, freq,
-                                     NSEC_PER_SEC/scale,
-                                     MAX_UPDATE_LENGTH*scale);
+                              NSEC_PER_SEC / scale, sec * scale);
        cs->max_idle_ns = clocksource_max_deferment(cs);
 }
 EXPORT_SYMBOL_GPL(__clocksource_updatefreq_scale);
@@ -685,8 +685,8 @@ int __clocksource_register_scale(struct clocksource *cs, u32 scale, u32 freq)
        /* Add clocksource to the clcoksource list */
        mutex_lock(&clocksource_mutex);
        clocksource_enqueue(cs);
-       clocksource_select();
        clocksource_enqueue_watchdog(cs);
+       clocksource_select();
        mutex_unlock(&clocksource_mutex);
        return 0;
 }
@@ -706,8 +706,8 @@ int clocksource_register(struct clocksource *cs)
 
        mutex_lock(&clocksource_mutex);
        clocksource_enqueue(cs);
-       clocksource_select();
        clocksource_enqueue_watchdog(cs);
+       clocksource_select();
        mutex_unlock(&clocksource_mutex);
        return 0;
 }
index da800ff..723c763 100644 (file)
@@ -522,10 +522,11 @@ static void tick_broadcast_init_next_event(struct cpumask *mask,
  */
 void tick_broadcast_setup_oneshot(struct clock_event_device *bc)
 {
+       int cpu = smp_processor_id();
+
        /* Set it up only once ! */
        if (bc->event_handler != tick_handle_oneshot_broadcast) {
                int was_periodic = bc->mode == CLOCK_EVT_MODE_PERIODIC;
-               int cpu = smp_processor_id();
 
                bc->event_handler = tick_handle_oneshot_broadcast;
                clockevents_set_mode(bc, CLOCK_EVT_MODE_ONESHOT);
@@ -551,6 +552,15 @@ void tick_broadcast_setup_oneshot(struct clock_event_device *bc)
                        tick_broadcast_set_event(tick_next_period, 1);
                } else
                        bc->next_event.tv64 = KTIME_MAX;
+       } else {
+               /*
+                * The first cpu which switches to oneshot mode sets
+                * the bit for all other cpus which are in the general
+                * (periodic) broadcast mask. So the bit is set and
+                * would prevent the first broadcast enter after this
+                * to program the bc device.
+                */
+               tick_broadcast_clear_oneshot(cpu);
        }
 }
 
index 8ad5d57..8e6a05a 100644 (file)
@@ -596,6 +596,58 @@ void __init timekeeping_init(void)
 static struct timespec timekeeping_suspend_time;
 
 /**
+ * __timekeeping_inject_sleeptime - Internal function to add sleep interval
+ * @delta: pointer to a timespec delta value
+ *
+ * Takes a timespec offset measuring a suspend interval and properly
+ * adds the sleep offset to the timekeeping variables.
+ */
+static void __timekeeping_inject_sleeptime(struct timespec *delta)
+{
+       xtime = timespec_add(xtime, *delta);
+       wall_to_monotonic = timespec_sub(wall_to_monotonic, *delta);
+       total_sleep_time = timespec_add(total_sleep_time, *delta);
+}
+
+
+/**
+ * timekeeping_inject_sleeptime - Adds suspend interval to timeekeeping values
+ * @delta: pointer to a timespec delta value
+ *
+ * This hook is for architectures that cannot support read_persistent_clock
+ * because their RTC/persistent clock is only accessible when irqs are enabled.
+ *
+ * This function should only be called by rtc_resume(), and allows
+ * a suspend offset to be injected into the timekeeping values.
+ */
+void timekeeping_inject_sleeptime(struct timespec *delta)
+{
+       unsigned long flags;
+       struct timespec ts;
+
+       /* Make sure we don't set the clock twice */
+       read_persistent_clock(&ts);
+       if (!(ts.tv_sec == 0 && ts.tv_nsec == 0))
+               return;
+
+       write_seqlock_irqsave(&xtime_lock, flags);
+       timekeeping_forward_now();
+
+       __timekeeping_inject_sleeptime(delta);
+
+       timekeeper.ntp_error = 0;
+       ntp_clear();
+       update_vsyscall(&xtime, &wall_to_monotonic, timekeeper.clock,
+                               timekeeper.mult);
+
+       write_sequnlock_irqrestore(&xtime_lock, flags);
+
+       /* signal hrtimers about time change */
+       clock_was_set();
+}
+
+
+/**
  * timekeeping_resume - Resumes the generic timekeeping subsystem.
  *
  * This is for the generic clocksource timekeeping.
@@ -615,9 +667,7 @@ static void timekeeping_resume(void)
 
        if (timespec_compare(&ts, &timekeeping_suspend_time) > 0) {
                ts = timespec_sub(ts, timekeeping_suspend_time);
-               xtime = timespec_add(xtime, ts);
-               wall_to_monotonic = timespec_sub(wall_to_monotonic, ts);
-               total_sleep_time = timespec_add(total_sleep_time, ts);
+               __timekeeping_inject_sleeptime(&ts);
        }
        /* re-base the last cycle value */
        timekeeper.clock->cycle_last = timekeeper.clock->read(timekeeper.clock);
index 35d55a3..f925c45 100644 (file)
@@ -53,7 +53,6 @@ const char *reserved_field_names[] = {
        "common_preempt_count",
        "common_pid",
        "common_tgid",
-       "common_lock_depth",
        FIELD_STRING_IP,
        FIELD_STRING_RETIP,
        FIELD_STRING_FUNC,
index c768bcd..10ef619 100644 (file)
@@ -238,6 +238,21 @@ config DETECT_HUNG_TASK
          enabled then all held locks will also be reported. This
          feature has negligible overhead.
 
+config DEFAULT_HUNG_TASK_TIMEOUT
+       int "Default timeout for hung task detection (in seconds)"
+       depends on DETECT_HUNG_TASK
+       default 120
+       help
+         This option controls the default timeout (in seconds) used
+         to determine when a task has become non-responsive and should
+         be considered hung.
+
+         It can be adjusted at runtime via the kernel.hung_task_timeout
+         sysctl or by writing a value to /proc/sys/kernel/hung_task_timeout.
+
+         A timeout of 0 disables the check.  The default is two minutes.
+         Keeping the default should be fine in most cases.
+
 config BOOTPARAM_HUNG_TASK_PANIC
        bool "Panic (Reboot) On Hung Tasks"
        depends on DETECT_HUNG_TASK
@@ -337,7 +352,7 @@ config DEBUG_OBJECTS_WORK
 
 config DEBUG_OBJECTS_RCU_HEAD
        bool "Debug RCU callbacks objects"
-       depends on DEBUG_OBJECTS && PREEMPT
+       depends on DEBUG_OBJECTS
        help
          Enable this to turn on debugging of RCU list heads (call_rcu() usage).
 
@@ -398,9 +413,9 @@ config SLUB_STATS
 config DEBUG_KMEMLEAK
        bool "Kernel memory leak detector"
        depends on DEBUG_KERNEL && EXPERIMENTAL && !MEMORY_HOTPLUG && \
-               (X86 || ARM || PPC || S390 || SPARC64 || SUPERH || MICROBLAZE || TILE)
+               (X86 || ARM || PPC || MIPS || S390 || SPARC64 || SUPERH || MICROBLAZE || TILE)
 
-       select DEBUG_FS if SYSFS
+       select DEBUG_FS
        select STACKTRACE if STACKTRACE_SUPPORT
        select KALLSYMS
        select CRC32
@@ -875,22 +890,9 @@ config RCU_TORTURE_TEST_RUNNABLE
          Say N here if you want the RCU torture tests to start only
          after being manually enabled via /proc.
 
-config RCU_CPU_STALL_DETECTOR
-       bool "Check for stalled CPUs delaying RCU grace periods"
-       depends on TREE_RCU || TREE_PREEMPT_RCU
-       default y
-       help
-         This option causes RCU to printk information on which
-         CPUs are delaying the current grace period, but only when
-         the grace period extends for excessive time periods.
-
-         Say N if you want to disable such checks.
-
-         Say Y if you are unsure.
-
 config RCU_CPU_STALL_TIMEOUT
        int "RCU CPU stall timeout in seconds"
-       depends on RCU_CPU_STALL_DETECTOR
+       depends on TREE_RCU || TREE_PREEMPT_RCU
        range 3 300
        default 60
        help
@@ -899,22 +901,9 @@ config RCU_CPU_STALL_TIMEOUT
          RCU grace period persists, additional CPU stall warnings are
          printed at more widely spaced intervals.
 
-config RCU_CPU_STALL_DETECTOR_RUNNABLE
-       bool "RCU CPU stall checking starts automatically at boot"
-       depends on RCU_CPU_STALL_DETECTOR
-       default y
-       help
-         If set, start checking for RCU CPU stalls immediately on
-         boot.  Otherwise, RCU CPU stall checking must be manually
-         enabled.
-
-         Say Y if you are unsure.
-
-         Say N if you wish to suppress RCU CPU stall checking during boot.
-
 config RCU_CPU_STALL_VERBOSE
        bool "Print additional per-task information for RCU_CPU_STALL_DETECTOR"
-       depends on RCU_CPU_STALL_DETECTOR && TREE_PREEMPT_RCU
+       depends on TREE_PREEMPT_RCU
        default y
        help
          This option causes RCU to printk detailed per-task information
index ef0f285..4b49a24 100644 (file)
@@ -21,7 +21,8 @@ lib-y += kobject.o kref.o klist.o
 
 obj-y += bcd.o div64.o sort.o parser.o halfmd4.o debug_locks.o random32.o \
         bust_spinlocks.o hexdump.o kasprintf.o bitmap.o scatterlist.o \
-        string_helpers.o gcd.o lcm.o list_sort.o uuid.o flex_array.o
+        string_helpers.o gcd.o lcm.o list_sort.o uuid.o flex_array.o \
+        bsearch.o
 obj-y += kstrtox.o
 obj-$(CONFIG_TEST_KSTRTOX) += test-kstrtox.o
 
diff --git a/lib/bsearch.c b/lib/bsearch.c
new file mode 100644 (file)
index 0000000..5b54758
--- /dev/null
@@ -0,0 +1,53 @@
+/*
+ * A generic implementation of binary search for the Linux kernel
+ *
+ * Copyright (C) 2008-2009 Ksplice, Inc.
+ * Author: Tim Abbott <tabbott@ksplice.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; version 2.
+ */
+
+#include <linux/module.h>
+#include <linux/bsearch.h>
+
+/*
+ * bsearch - binary search an array of elements
+ * @key: pointer to item being searched for
+ * @base: pointer to first element to search
+ * @num: number of elements
+ * @size: size of each element
+ * @cmp: pointer to comparison function
+ *
+ * This function does a binary search on the given array.  The
+ * contents of the array should already be in ascending sorted order
+ * under the provided comparison function.
+ *
+ * Note that the key need not have the same type as the elements in
+ * the array, e.g. key could be a string and the comparison function
+ * could compare the string with the struct's name field.  However, if
+ * the key and elements in the array are of the same type, you can use
+ * the same comparison function for both sort() and bsearch().
+ */
+void *bsearch(const void *key, const void *base, size_t num, size_t size,
+             int (*cmp)(const void *key, const void *elt))
+{
+       size_t start = 0, end = num;
+       int result;
+
+       while (start < end) {
+               size_t mid = start + (end - start) / 2;
+
+               result = cmp(key, base + mid * size);
+               if (result < 0)
+                       end = mid;
+               else if (result > 0)
+                       start = mid + 1;
+               else
+                       return (void *)base + mid * size;
+       }
+
+       return NULL;
+}
+EXPORT_SYMBOL(bsearch);
index 4bfb047..db07bfd 100644 (file)
@@ -649,7 +649,7 @@ out_err:
        return -ENOMEM;
 }
 
-static int device_dma_allocations(struct device *dev)
+static int device_dma_allocations(struct device *dev, struct dma_debug_entry **out_entry)
 {
        struct dma_debug_entry *entry;
        unsigned long flags;
@@ -660,8 +660,10 @@ static int device_dma_allocations(struct device *dev)
        for (i = 0; i < HASH_SIZE; ++i) {
                spin_lock(&dma_entry_hash[i].lock);
                list_for_each_entry(entry, &dma_entry_hash[i].list, list) {
-                       if (entry->dev == dev)
+                       if (entry->dev == dev) {
                                count += 1;
+                               *out_entry = entry;
+                       }
                }
                spin_unlock(&dma_entry_hash[i].lock);
        }
@@ -674,6 +676,7 @@ static int device_dma_allocations(struct device *dev)
 static int dma_debug_device_change(struct notifier_block *nb, unsigned long action, void *data)
 {
        struct device *dev = data;
+       struct dma_debug_entry *uninitialized_var(entry);
        int count;
 
        if (global_disable)
@@ -681,12 +684,17 @@ static int dma_debug_device_change(struct notifier_block *nb, unsigned long acti
 
        switch (action) {
        case BUS_NOTIFY_UNBOUND_DRIVER:
-               count = device_dma_allocations(dev);
+               count = device_dma_allocations(dev, &entry);
                if (count == 0)
                        break;
-               err_printk(dev, NULL, "DMA-API: device driver has pending "
+               err_printk(dev, entry, "DMA-API: device driver has pending "
                                "DMA allocations while released from device "
-                               "[count=%d]\n", count);
+                               "[count=%d]\n"
+                               "One of leaked entries details: "
+                               "[device address=0x%016llx] [size=%llu bytes] "
+                               "[mapped with %s] [mapped as %s]\n",
+                       count, entry->dev_addr, entry->size,
+                       dir2name[entry->direction], type2name[entry->type]);
                break;
        default:
                break;
index f71bead..01fad9b 100644 (file)
@@ -535,6 +535,35 @@ bool sysfs_streq(const char *s1, const char *s2)
 }
 EXPORT_SYMBOL(sysfs_streq);
 
+/**
+ * strtobool - convert common user inputs into boolean values
+ * @s: input string
+ * @res: result
+ *
+ * This routine returns 0 iff the first character is one of 'Yy1Nn0'.
+ * Otherwise it will return -EINVAL.  Value pointed to by res is
+ * updated upon finding a match.
+ */
+int strtobool(const char *s, bool *res)
+{
+       switch (s[0]) {
+       case 'y':
+       case 'Y':
+       case '1':
+               *res = true;
+               break;
+       case 'n':
+       case 'N':
+       case '0':
+               *res = false;
+               break;
+       default:
+               return -EINVAL;
+       }
+       return 0;
+}
+EXPORT_SYMBOL(strtobool);
+
 #ifndef __HAVE_ARCH_MEMSET
 /**
  * memset - Fill a region of memory with the given value
index bc0ac6b..dfd6019 100644 (file)
@@ -797,7 +797,7 @@ char *uuid_string(char *buf, char *end, const u8 *addr,
        return string(buf, end, uuid, spec);
 }
 
-int kptr_restrict = 1;
+int kptr_restrict __read_mostly;
 
 /*
  * Show a '%p' thing.  A kernel extension is that the '%p' is followed
index c1d5867..aacee45 100644 (file)
@@ -1414,9 +1414,12 @@ static void *kmemleak_seq_next(struct seq_file *seq, void *v, loff_t *pos)
        ++(*pos);
 
        list_for_each_continue_rcu(n, &object_list) {
-               next_obj = list_entry(n, struct kmemleak_object, object_list);
-               if (get_object(next_obj))
+               struct kmemleak_object *obj =
+                       list_entry(n, struct kmemleak_object, object_list);
+               if (get_object(obj)) {
+                       next_obj = obj;
                        break;
+               }
        }
 
        put_object(prev_obj);
index 9f8a97b..3f8bce2 100644 (file)
@@ -2317,6 +2317,21 @@ void free_pages(unsigned long addr, unsigned int order)
 
 EXPORT_SYMBOL(free_pages);
 
+static void *make_alloc_exact(unsigned long addr, unsigned order, size_t size)
+{
+       if (addr) {
+               unsigned long alloc_end = addr + (PAGE_SIZE << order);
+               unsigned long used = addr + PAGE_ALIGN(size);
+
+               split_page(virt_to_page((void *)addr), order);
+               while (used < alloc_end) {
+                       free_page(used);
+                       used += PAGE_SIZE;
+               }
+       }
+       return (void *)addr;
+}
+
 /**
  * alloc_pages_exact - allocate an exact number physically-contiguous pages.
  * @size: the number of bytes to allocate
@@ -2336,22 +2351,33 @@ void *alloc_pages_exact(size_t size, gfp_t gfp_mask)
        unsigned long addr;
 
        addr = __get_free_pages(gfp_mask, order);
-       if (addr) {
-               unsigned long alloc_end = addr + (PAGE_SIZE << order);
-               unsigned long used = addr + PAGE_ALIGN(size);
-
-               split_page(virt_to_page((void *)addr), order);
-               while (used < alloc_end) {
-                       free_page(used);
-                       used += PAGE_SIZE;
-               }
-       }
-
-       return (void *)addr;
+       return make_alloc_exact(addr, order, size);
 }
 EXPORT_SYMBOL(alloc_pages_exact);
 
 /**
+ * alloc_pages_exact_nid - allocate an exact number of physically-contiguous
+ *                        pages on a node.
+ * @nid: the preferred node ID where memory should be allocated
+ * @size: the number of bytes to allocate
+ * @gfp_mask: GFP flags for the allocation
+ *
+ * Like alloc_pages_exact(), but try to allocate on node nid first before falling
+ * back.
+ * Note this is not alloc_pages_exact_node() which allocates on a specific node,
+ * but is not exact.
+ */
+void *alloc_pages_exact_nid(int nid, size_t size, gfp_t gfp_mask)
+{
+       unsigned order = get_order(size);
+       struct page *p = alloc_pages_node(nid, gfp_mask, order);
+       if (!p)
+               return NULL;
+       return make_alloc_exact((unsigned long)page_address(p), order, size);
+}
+EXPORT_SYMBOL(alloc_pages_exact_nid);
+
+/**
  * free_pages_exact - release memory allocated via alloc_pages_exact()
  * @virt: the value returned by alloc_pages_exact.
  * @size: size of allocation, same value as passed to alloc_pages_exact().
@@ -3564,7 +3590,7 @@ int zone_wait_table_init(struct zone *zone, unsigned long zone_size_pages)
 
        if (!slab_is_available()) {
                zone->wait_table = (wait_queue_head_t *)
-                       alloc_bootmem_node(pgdat, alloc_size);
+                       alloc_bootmem_node_nopanic(pgdat, alloc_size);
        } else {
                /*
                 * This case means that a zone whose size was 0 gets new memory
@@ -4141,7 +4167,8 @@ static void __init setup_usemap(struct pglist_data *pgdat,
        unsigned long usemapsize = usemap_size(zonesize);
        zone->pageblock_flags = NULL;
        if (usemapsize)
-               zone->pageblock_flags = alloc_bootmem_node(pgdat, usemapsize);
+               zone->pageblock_flags = alloc_bootmem_node_nopanic(pgdat,
+                                                                  usemapsize);
 }
 #else
 static inline void setup_usemap(struct pglist_data *pgdat,
@@ -4307,7 +4334,7 @@ static void __init_refok alloc_node_mem_map(struct pglist_data *pgdat)
                size =  (end - start) * sizeof(struct page);
                map = alloc_remap(pgdat->node_id, size);
                if (!map)
-                       map = alloc_bootmem_node(pgdat, size);
+                       map = alloc_bootmem_node_nopanic(pgdat, size);
                pgdat->node_mem_map = map + (pgdat->node_start_pfn - start);
        }
 #ifndef CONFIG_NEED_MULTIPLE_NODES
index 9905501..2daadc3 100644 (file)
@@ -134,7 +134,7 @@ static void *__init_refok alloc_page_cgroup(size_t size, int nid)
 {
        void *addr = NULL;
 
-       addr = alloc_pages_exact(size, GFP_KERNEL | __GFP_NOWARN);
+       addr = alloc_pages_exact_nid(nid, size, GFP_KERNEL | __GFP_NOWARN);
        if (addr)
                return addr;
 
index 8fa27e4..dfc7069 100644 (file)
@@ -852,7 +852,7 @@ static inline int shmem_find_swp(swp_entry_t entry, swp_entry_t *dir, swp_entry_
 
 static int shmem_unuse_inode(struct shmem_inode_info *info, swp_entry_t entry, struct page *page)
 {
-       struct inode *inode;
+       struct address_space *mapping;
        unsigned long idx;
        unsigned long size;
        unsigned long limit;
@@ -875,8 +875,10 @@ static int shmem_unuse_inode(struct shmem_inode_info *info, swp_entry_t entry, s
        if (size > SHMEM_NR_DIRECT)
                size = SHMEM_NR_DIRECT;
        offset = shmem_find_swp(entry, ptr, ptr+size);
-       if (offset >= 0)
+       if (offset >= 0) {
+               shmem_swp_balance_unmap();
                goto found;
+       }
        if (!info->i_indirect)
                goto lost2;
 
@@ -914,11 +916,11 @@ static int shmem_unuse_inode(struct shmem_inode_info *info, swp_entry_t entry, s
                        if (size > ENTRIES_PER_PAGE)
                                size = ENTRIES_PER_PAGE;
                        offset = shmem_find_swp(entry, ptr, ptr+size);
-                       shmem_swp_unmap(ptr);
                        if (offset >= 0) {
                                shmem_dir_unmap(dir);
                                goto found;
                        }
+                       shmem_swp_unmap(ptr);
                }
        }
 lost1:
@@ -928,8 +930,7 @@ lost2:
        return 0;
 found:
        idx += offset;
-       inode = igrab(&info->vfs_inode);
-       spin_unlock(&info->lock);
+       ptr += offset;
 
        /*
         * Move _head_ to start search for next from here.
@@ -940,37 +941,18 @@ found:
         */
        if (shmem_swaplist.next != &info->swaplist)
                list_move_tail(&shmem_swaplist, &info->swaplist);
-       mutex_unlock(&shmem_swaplist_mutex);
 
-       error = 1;
-       if (!inode)
-               goto out;
        /*
-        * Charge page using GFP_KERNEL while we can wait.
-        * Charged back to the user(not to caller) when swap account is used.
-        * add_to_page_cache() will be called with GFP_NOWAIT.
+        * We rely on shmem_swaplist_mutex, not only to protect the swaplist,
+        * but also to hold up shmem_evict_inode(): so inode cannot be freed
+        * beneath us (pagelock doesn't help until the page is in pagecache).
         */
-       error = mem_cgroup_cache_charge(page, current->mm, GFP_KERNEL);
-       if (error)
-               goto out;
-       error = radix_tree_preload(GFP_KERNEL);
-       if (error) {
-               mem_cgroup_uncharge_cache_page(page);
-               goto out;
-       }
-       error = 1;
-
-       spin_lock(&info->lock);
-       ptr = shmem_swp_entry(info, idx, NULL);
-       if (ptr && ptr->val == entry.val) {
-               error = add_to_page_cache_locked(page, inode->i_mapping,
-                                               idx, GFP_NOWAIT);
-               /* does mem_cgroup_uncharge_cache_page on error */
-       } else  /* we must compensate for our precharge above */
-               mem_cgroup_uncharge_cache_page(page);
+       mapping = info->vfs_inode.i_mapping;
+       error = add_to_page_cache_locked(page, mapping, idx, GFP_NOWAIT);
+       /* which does mem_cgroup_uncharge_cache_page on error */
 
        if (error == -EEXIST) {
-               struct page *filepage = find_get_page(inode->i_mapping, idx);
+               struct page *filepage = find_get_page(mapping, idx);
                error = 1;
                if (filepage) {
                        /*
@@ -990,14 +972,8 @@ found:
                swap_free(entry);
                error = 1;      /* not an error, but entry was found */
        }
-       if (ptr)
-               shmem_swp_unmap(ptr);
+       shmem_swp_unmap(ptr);
        spin_unlock(&info->lock);
-       radix_tree_preload_end();
-out:
-       unlock_page(page);
-       page_cache_release(page);
-       iput(inode);            /* allows for NULL */
        return error;
 }
 
@@ -1009,6 +985,26 @@ int shmem_unuse(swp_entry_t entry, struct page *page)
        struct list_head *p, *next;
        struct shmem_inode_info *info;
        int found = 0;
+       int error;
+
+       /*
+        * Charge page using GFP_KERNEL while we can wait, before taking
+        * the shmem_swaplist_mutex which might hold up shmem_writepage().
+        * Charged back to the user (not to caller) when swap account is used.
+        * add_to_page_cache() will be called with GFP_NOWAIT.
+        */
+       error = mem_cgroup_cache_charge(page, current->mm, GFP_KERNEL);
+       if (error)
+               goto out;
+       /*
+        * Try to preload while we can wait, to not make a habit of
+        * draining atomic reserves; but don't latch on to this cpu,
+        * it's okay if sometimes we get rescheduled after this.
+        */
+       error = radix_tree_preload(GFP_KERNEL);
+       if (error)
+               goto uncharge;
+       radix_tree_preload_end();
 
        mutex_lock(&shmem_swaplist_mutex);
        list_for_each_safe(p, next, &shmem_swaplist) {
@@ -1016,17 +1012,19 @@ int shmem_unuse(swp_entry_t entry, struct page *page)
                found = shmem_unuse_inode(info, entry, page);
                cond_resched();
                if (found)
-                       goto out;
+                       break;
        }
        mutex_unlock(&shmem_swaplist_mutex);
-       /*
-        * Can some race bring us here?  We've been holding page lock,
-        * so I think not; but would rather try again later than BUG()
-        */
+
+uncharge:
+       if (!found)
+               mem_cgroup_uncharge_cache_page(page);
+       if (found < 0)
+               error = found;
+out:
        unlock_page(page);
        page_cache_release(page);
-out:
-       return (found < 0) ? found : 0;
+       return error;
 }
 
 /*
@@ -1064,7 +1062,25 @@ static int shmem_writepage(struct page *page, struct writeback_control *wbc)
        else
                swap.val = 0;
 
+       /*
+        * Add inode to shmem_unuse()'s list of swapped-out inodes,
+        * if it's not already there.  Do it now because we cannot take
+        * mutex while holding spinlock, and must do so before the page
+        * is moved to swap cache, when its pagelock no longer protects
+        * the inode from eviction.  But don't unlock the mutex until
+        * we've taken the spinlock, because shmem_unuse_inode() will
+        * prune a !swapped inode from the swaplist under both locks.
+        */
+       if (swap.val) {
+               mutex_lock(&shmem_swaplist_mutex);
+               if (list_empty(&info->swaplist))
+                       list_add_tail(&info->swaplist, &shmem_swaplist);
+       }
+
        spin_lock(&info->lock);
+       if (swap.val)
+               mutex_unlock(&shmem_swaplist_mutex);
+
        if (index >= info->next_index) {
                BUG_ON(!(info->flags & SHMEM_TRUNCATE));
                goto unlock;
@@ -1084,21 +1100,10 @@ static int shmem_writepage(struct page *page, struct writeback_control *wbc)
                delete_from_page_cache(page);
                shmem_swp_set(info, entry, swap.val);
                shmem_swp_unmap(entry);
-               if (list_empty(&info->swaplist))
-                       inode = igrab(inode);
-               else
-                       inode = NULL;
                spin_unlock(&info->lock);
                swap_shmem_alloc(swap);
                BUG_ON(page_mapped(page));
                swap_writepage(page, wbc);
-               if (inode) {
-                       mutex_lock(&shmem_swaplist_mutex);
-                       /* move instead of add in case we're racing */
-                       list_move_tail(&info->swaplist, &shmem_swaplist);
-                       mutex_unlock(&shmem_swaplist_mutex);
-                       iput(inode);
-               }
                return 0;
        }
 
@@ -1400,20 +1405,14 @@ repeat:
                if (sbinfo->max_blocks) {
                        if (percpu_counter_compare(&sbinfo->used_blocks,
                                                sbinfo->max_blocks) >= 0 ||
-                           shmem_acct_block(info->flags)) {
-                               spin_unlock(&info->lock);
-                               error = -ENOSPC;
-                               goto failed;
-                       }
+                           shmem_acct_block(info->flags))
+                               goto nospace;
                        percpu_counter_inc(&sbinfo->used_blocks);
                        spin_lock(&inode->i_lock);
                        inode->i_blocks += BLOCKS_PER_PAGE;
                        spin_unlock(&inode->i_lock);
-               } else if (shmem_acct_block(info->flags)) {
-                       spin_unlock(&info->lock);
-                       error = -ENOSPC;
-                       goto failed;
-               }
+               } else if (shmem_acct_block(info->flags))
+                       goto nospace;
 
                if (!filepage) {
                        int ret;
@@ -1493,6 +1492,24 @@ done:
        error = 0;
        goto out;
 
+nospace:
+       /*
+        * Perhaps the page was brought in from swap between find_lock_page
+        * and taking info->lock?  We allow for that at add_to_page_cache_lru,
+        * but must also avoid reporting a spurious ENOSPC while working on a
+        * full tmpfs.  (When filepage has been passed in to shmem_getpage, it
+        * is already in page cache, which prevents this race from occurring.)
+        */
+       if (!filepage) {
+               struct page *page = find_get_page(mapping, idx);
+               if (page) {
+                       spin_unlock(&info->lock);
+                       page_cache_release(page);
+                       goto repeat;
+               }
+       }
+       spin_unlock(&info->lock);
+       error = -ENOSPC;
 failed:
        if (*pagep != filepage) {
                unlock_page(filepage);
index a448db3..5602f1a 100644 (file)
--- a/mm/swap.c
+++ b/mm/swap.c
@@ -396,6 +396,9 @@ static void lru_deactivate_fn(struct page *page, void *arg)
        if (!PageLRU(page))
                return;
 
+       if (PageUnevictable(page))
+               return;
+
        /* Some processes are using the page */
        if (page_mapped(page))
                return;
index f6b435c..8bfd450 100644 (file)
@@ -937,7 +937,7 @@ keep_lumpy:
         * back off and wait for congestion to clear because further reclaim
         * will encounter the same problem
         */
-       if (nr_dirty == nr_congested && nr_dirty != 0)
+       if (nr_dirty && nr_dirty == nr_congested && scanning_global_lru(sc))
                zone_set_flag(zone, ZONE_CONGESTED);
 
        free_page_list(&free_pages);
index 7850412..0eb1a88 100644 (file)
@@ -124,6 +124,9 @@ void unregister_vlan_dev(struct net_device *dev, struct list_head *head)
 
        grp->nr_vlans--;
 
+       if (vlan->flags & VLAN_FLAG_GVRP)
+               vlan_gvrp_request_leave(dev);
+
        vlan_group_set_device(grp, vlan_id, NULL);
        if (!grp->killall)
                synchronize_net();
index e34ea9e..b2ff6c8 100644 (file)
@@ -487,9 +487,6 @@ static int vlan_dev_stop(struct net_device *dev)
        struct vlan_dev_info *vlan = vlan_dev_info(dev);
        struct net_device *real_dev = vlan->real_dev;
 
-       if (vlan->flags & VLAN_FLAG_GVRP)
-               vlan_gvrp_request_leave(dev);
-
        dev_mc_unsync(real_dev, dev);
        dev_uc_unsync(real_dev, dev);
        if (dev->flags & IFF_ALLMULTI)
index 7736774..a9aa2dd 100644 (file)
@@ -614,7 +614,7 @@ p9_client_rpc(struct p9_client *c, int8_t type, const char *fmt, ...)
 
        err = c->trans_mod->request(c, req);
        if (err < 0) {
-               if (err != -ERESTARTSYS)
+               if (err != -ERESTARTSYS && err != -EFAULT)
                        c->status = Disconnected;
                goto reterr;
        }
index b58a501..a873277 100644 (file)
@@ -674,6 +674,7 @@ int p9dirent_read(char *buf, int len, struct p9_dirent *dirent,
        }
 
        strcpy(dirent->d_name, nameptr);
+       kfree(nameptr);
 
 out:
        return fake_pdu.offset;
index e883172..9a70ebd 100644 (file)
@@ -63,7 +63,7 @@ p9_payload_gup(struct p9_req_t *req, size_t *pdata_off, int *pdata_len,
                int nr_pages, u8 rw)
 {
        uint32_t first_page_bytes = 0;
-       uint32_t pdata_mapped_pages;
+       int32_t pdata_mapped_pages;
        struct trans_rpage_info  *rpinfo;
 
        *pdata_off = (__force size_t)req->tc->pubuf & (PAGE_SIZE-1);
@@ -75,14 +75,9 @@ p9_payload_gup(struct p9_req_t *req, size_t *pdata_off, int *pdata_len,
        rpinfo = req->tc->private;
        pdata_mapped_pages = get_user_pages_fast((unsigned long)req->tc->pubuf,
                        nr_pages, rw, &rpinfo->rp_data[0]);
+       if (pdata_mapped_pages <= 0)
+               return pdata_mapped_pages;
 
-       if (pdata_mapped_pages < 0) {
-               printk(KERN_ERR "get_user_pages_fast failed:%d udata:%p"
-                               "nr_pages:%d\n", pdata_mapped_pages,
-                               req->tc->pubuf, nr_pages);
-               pdata_mapped_pages = 0;
-               return -EIO;
-       }
        rpinfo->rp_nr_pages = pdata_mapped_pages;
        if (*pdata_off) {
                *pdata_len = first_page_bytes;
index 3cc4355..150b6ce 100644 (file)
 #include <linux/udp.h>
 #include <linux/if_vlan.h>
 
-static void gw_node_free_rcu(struct rcu_head *rcu)
-{
-       struct gw_node *gw_node;
-
-       gw_node = container_of(rcu, struct gw_node, rcu);
-       kfree(gw_node);
-}
-
 static void gw_node_free_ref(struct gw_node *gw_node)
 {
        if (atomic_dec_and_test(&gw_node->refcount))
-               call_rcu(&gw_node->rcu, gw_node_free_rcu);
+               kfree_rcu(gw_node, rcu);
 }
 
 void *gw_get_selected(struct bat_priv *bat_priv)
index 0b91330..ed23a58 100644 (file)
@@ -56,18 +56,10 @@ err:
        return 0;
 }
 
-static void neigh_node_free_rcu(struct rcu_head *rcu)
-{
-       struct neigh_node *neigh_node;
-
-       neigh_node = container_of(rcu, struct neigh_node, rcu);
-       kfree(neigh_node);
-}
-
 void neigh_node_free_ref(struct neigh_node *neigh_node)
 {
        if (atomic_dec_and_test(&neigh_node->refcount))
-               call_rcu(&neigh_node->rcu, neigh_node_free_rcu);
+               kfree_rcu(neigh_node, rcu);
 }
 
 struct neigh_node *create_neighbor(struct orig_node *orig_node,
index 824e1f6..04efe02 100644 (file)
@@ -76,18 +76,10 @@ int my_skb_head_push(struct sk_buff *skb, unsigned int len)
        return 0;
 }
 
-static void softif_neigh_free_rcu(struct rcu_head *rcu)
-{
-       struct softif_neigh *softif_neigh;
-
-       softif_neigh = container_of(rcu, struct softif_neigh, rcu);
-       kfree(softif_neigh);
-}
-
 static void softif_neigh_free_ref(struct softif_neigh *softif_neigh)
 {
        if (atomic_dec_and_test(&softif_neigh->refcount))
-               call_rcu(&softif_neigh->rcu, softif_neigh_free_rcu);
+               kfree_rcu(softif_neigh, rcu);
 }
 
 void softif_neigh_purge(struct bat_priv *bat_priv)
index 94954c7..42fdffd 100644 (file)
@@ -369,15 +369,6 @@ static void __sco_sock_close(struct sock *sk)
 
        case BT_CONNECTED:
        case BT_CONFIG:
-               if (sco_pi(sk)->conn) {
-                       sk->sk_state = BT_DISCONN;
-                       sco_sock_set_timer(sk, SCO_DISCONN_TIMEOUT);
-                       hci_conn_put(sco_pi(sk)->conn->hcon);
-                       sco_pi(sk)->conn = NULL;
-               } else
-                       sco_chan_del(sk, ECONNRESET);
-               break;
-
        case BT_CONNECT:
        case BT_DISCONN:
                sco_chan_del(sk, ECONNRESET);
index f3bc322..74ef4d4 100644 (file)
@@ -737,7 +737,7 @@ static unsigned int br_nf_forward_ip(unsigned int hook, struct sk_buff *skb,
                nf_bridge->mask |= BRNF_PKT_TYPE;
        }
 
-       if (br_parse_ip_options(skb))
+       if (pf == PF_INET && br_parse_ip_options(skb))
                return NF_DROP;
 
        /* The physdev module checks on this */
index 893669c..1a92b36 100644 (file)
@@ -1766,7 +1766,7 @@ static int compat_table_info(const struct ebt_table_info *info,
 
        newinfo->entries_size = size;
 
-       xt_compat_init_offsets(AF_INET, info->nentries);
+       xt_compat_init_offsets(NFPROTO_BRIDGE, info->nentries);
        return EBT_ENTRY_ITERATE(entries, size, compat_calc_entry, info,
                                                        entries, newinfo);
 }
@@ -1882,7 +1882,7 @@ static int compat_mtw_from_user(struct compat_ebt_entry_mwt *mwt,
        struct xt_match *match;
        struct xt_target *wt;
        void *dst = NULL;
-       int off, pad = 0, ret = 0;
+       int off, pad = 0;
        unsigned int size_kern, entry_offset, match_size = mwt->match_size;
 
        strlcpy(name, mwt->u.name, sizeof(name));
@@ -1935,13 +1935,6 @@ static int compat_mtw_from_user(struct compat_ebt_entry_mwt *mwt,
                break;
        }
 
-       if (!dst) {
-               ret = xt_compat_add_offset(NFPROTO_BRIDGE, entry_offset,
-                                       off + ebt_compat_entry_padsize());
-               if (ret < 0)
-                       return ret;
-       }
-
        state->buf_kern_offset += match_size + off;
        state->buf_user_offset += match_size;
        pad = XT_ALIGN(size_kern) - size_kern;
@@ -2016,50 +2009,6 @@ static int ebt_size_mwt(struct compat_ebt_entry_mwt *match32,
        return growth;
 }
 
-#define EBT_COMPAT_WATCHER_ITERATE(e, fn, args...)          \
-({                                                          \
-       unsigned int __i;                                   \
-       int __ret = 0;                                      \
-       struct compat_ebt_entry_mwt *__watcher;             \
-                                                           \
-       for (__i = e->watchers_offset;                      \
-            __i < (e)->target_offset;                      \
-            __i += __watcher->watcher_size +               \
-            sizeof(struct compat_ebt_entry_mwt)) {         \
-               __watcher = (void *)(e) + __i;              \
-               __ret = fn(__watcher , ## args);            \
-               if (__ret != 0)                             \
-                       break;                              \
-       }                                                   \
-       if (__ret == 0) {                                   \
-               if (__i != (e)->target_offset)              \
-                       __ret = -EINVAL;                    \
-       }                                                   \
-       __ret;                                              \
-})
-
-#define EBT_COMPAT_MATCH_ITERATE(e, fn, args...)            \
-({                                                          \
-       unsigned int __i;                                   \
-       int __ret = 0;                                      \
-       struct compat_ebt_entry_mwt *__match;               \
-                                                           \
-       for (__i = sizeof(struct ebt_entry);                \
-            __i < (e)->watchers_offset;                    \
-            __i += __match->match_size +                   \
-            sizeof(struct compat_ebt_entry_mwt)) {         \
-               __match = (void *)(e) + __i;                \
-               __ret = fn(__match , ## args);              \
-               if (__ret != 0)                             \
-                       break;                              \
-       }                                                   \
-       if (__ret == 0) {                                   \
-               if (__i != (e)->watchers_offset)            \
-                       __ret = -EINVAL;                    \
-       }                                                   \
-       __ret;                                              \
-})
-
 /* called for all ebt_entry structures. */
 static int size_entry_mwt(struct ebt_entry *entry, const unsigned char *base,
                          unsigned int *total,
@@ -2132,6 +2081,14 @@ static int size_entry_mwt(struct ebt_entry *entry, const unsigned char *base,
                }
        }
 
+       if (state->buf_kern_start == NULL) {
+               unsigned int offset = buf_start - (char *) base;
+
+               ret = xt_compat_add_offset(NFPROTO_BRIDGE, offset, new_offset);
+               if (ret < 0)
+                       return ret;
+       }
+
        startoff = state->buf_user_offset - startoff;
 
        BUG_ON(*total < startoff);
@@ -2240,6 +2197,7 @@ static int compat_do_replace(struct net *net, void __user *user,
 
        xt_compat_lock(NFPROTO_BRIDGE);
 
+       xt_compat_init_offsets(NFPROTO_BRIDGE, tmp.nentries);
        ret = compat_copy_entries(entries_tmp, tmp.entries_size, &state);
        if (ret < 0)
                goto out_unlock;
index 856b6ee..b624fe4 100644 (file)
@@ -1284,11 +1284,13 @@ static int dev_close_many(struct list_head *head)
  */
 int dev_close(struct net_device *dev)
 {
-       LIST_HEAD(single);
+       if (dev->flags & IFF_UP) {
+               LIST_HEAD(single);
 
-       list_add(&dev->unreg_list, &single);
-       dev_close_many(&single);
-       list_del(&single);
+               list_add(&dev->unreg_list, &single);
+               dev_close_many(&single);
+               list_del(&single);
+       }
        return 0;
 }
 EXPORT_SYMBOL(dev_close);
@@ -5184,27 +5186,27 @@ u32 netdev_fix_features(struct net_device *dev, u32 features)
        /* Fix illegal checksum combinations */
        if ((features & NETIF_F_HW_CSUM) &&
            (features & (NETIF_F_IP_CSUM|NETIF_F_IPV6_CSUM))) {
-               netdev_info(dev, "mixed HW and IP checksum settings.\n");
+               netdev_warn(dev, "mixed HW and IP checksum settings.\n");
                features &= ~(NETIF_F_IP_CSUM|NETIF_F_IPV6_CSUM);
        }
 
        if ((features & NETIF_F_NO_CSUM) &&
            (features & (NETIF_F_HW_CSUM|NETIF_F_IP_CSUM|NETIF_F_IPV6_CSUM))) {
-               netdev_info(dev, "mixed no checksumming and other settings.\n");
+               netdev_warn(dev, "mixed no checksumming and other settings.\n");
                features &= ~(NETIF_F_IP_CSUM|NETIF_F_IPV6_CSUM|NETIF_F_HW_CSUM);
        }
 
        /* Fix illegal SG+CSUM combinations. */
        if ((features & NETIF_F_SG) &&
            !(features & NETIF_F_ALL_CSUM)) {
-               netdev_info(dev,
-                           "Dropping NETIF_F_SG since no checksum feature.\n");
+               netdev_dbg(dev,
+                       "Dropping NETIF_F_SG since no checksum feature.\n");
                features &= ~NETIF_F_SG;
        }
 
        /* TSO requires that SG is present as well. */
        if ((features & NETIF_F_ALL_TSO) && !(features & NETIF_F_SG)) {
-               netdev_info(dev, "Dropping TSO features since no SG feature.\n");
+               netdev_dbg(dev, "Dropping TSO features since no SG feature.\n");
                features &= ~NETIF_F_ALL_TSO;
        }
 
@@ -5214,7 +5216,7 @@ u32 netdev_fix_features(struct net_device *dev, u32 features)
 
        /* Software GSO depends on SG. */
        if ((features & NETIF_F_GSO) && !(features & NETIF_F_SG)) {
-               netdev_info(dev, "Dropping NETIF_F_GSO since no SG feature.\n");
+               netdev_dbg(dev, "Dropping NETIF_F_GSO since no SG feature.\n");
                features &= ~NETIF_F_GSO;
        }
 
@@ -5224,13 +5226,13 @@ u32 netdev_fix_features(struct net_device *dev, u32 features)
                if (!((features & NETIF_F_GEN_CSUM) ||
                    (features & (NETIF_F_IP_CSUM|NETIF_F_IPV6_CSUM))
                            == (NETIF_F_IP_CSUM|NETIF_F_IPV6_CSUM))) {
-                       netdev_info(dev,
+                       netdev_dbg(dev,
                                "Dropping NETIF_F_UFO since no checksum offload features.\n");
                        features &= ~NETIF_F_UFO;
                }
 
                if (!(features & NETIF_F_SG)) {
-                       netdev_info(dev,
+                       netdev_dbg(dev,
                                "Dropping NETIF_F_UFO since no NETIF_F_SG feature.\n");
                        features &= ~NETIF_F_UFO;
                }
@@ -5412,12 +5414,6 @@ int register_netdevice(struct net_device *dev)
        dev->features |= NETIF_F_SOFT_FEATURES;
        dev->wanted_features = dev->features & dev->hw_features;
 
-       /* Avoid warning from netdev_fix_features() for GSO without SG */
-       if (!(dev->wanted_features & NETIF_F_SG)) {
-               dev->wanted_features &= ~NETIF_F_GSO;
-               dev->features &= ~NETIF_F_GSO;
-       }
-
        /* Enable GRO and NETIF_F_HIGHDMA for vlans by default,
         * vlan_dev_init() will do the dev->features check, so these features
         * are enabled only if supported by underlying device.
index 7b39f3e..e2e6693 100644 (file)
@@ -68,14 +68,6 @@ static int __hw_addr_add(struct netdev_hw_addr_list *list, unsigned char *addr,
        return __hw_addr_add_ex(list, addr, addr_len, addr_type, false);
 }
 
-static void ha_rcu_free(struct rcu_head *head)
-{
-       struct netdev_hw_addr *ha;
-
-       ha = container_of(head, struct netdev_hw_addr, rcu_head);
-       kfree(ha);
-}
-
 static int __hw_addr_del_ex(struct netdev_hw_addr_list *list,
                            unsigned char *addr, int addr_len,
                            unsigned char addr_type, bool global)
@@ -94,7 +86,7 @@ static int __hw_addr_del_ex(struct netdev_hw_addr_list *list,
                        if (--ha->refcount)
                                return 0;
                        list_del_rcu(&ha->list);
-                       call_rcu(&ha->rcu_head, ha_rcu_free);
+                       kfree_rcu(ha, rcu_head);
                        list->count--;
                        return 0;
                }
@@ -197,7 +189,7 @@ void __hw_addr_flush(struct netdev_hw_addr_list *list)
 
        list_for_each_entry_safe(ha, tmp, &list->list, list) {
                list_del_rcu(&ha->list);
-               call_rcu(&ha->rcu_head, ha_rcu_free);
+               kfree_rcu(ha, rcu_head);
        }
        list->count = 0;
 }
index 706502f..7f36b38 100644 (file)
@@ -207,14 +207,6 @@ static void trace_napi_poll_hit(void *ignore, struct napi_struct *napi)
        rcu_read_unlock();
 }
 
-
-static void free_dm_hw_stat(struct rcu_head *head)
-{
-       struct dm_hw_stat_delta *n;
-       n = container_of(head, struct dm_hw_stat_delta, rcu);
-       kfree(n);
-}
-
 static int set_all_monitor_traces(int state)
 {
        int rc = 0;
@@ -245,7 +237,7 @@ static int set_all_monitor_traces(int state)
                list_for_each_entry_safe(new_stat, temp, &hw_stats_list, list) {
                        if (new_stat->dev == NULL) {
                                list_del_rcu(&new_stat->list);
-                               call_rcu(&new_stat->rcu, free_dm_hw_stat);
+                               kfree_rcu(new_stat, rcu);
                        }
                }
                break;
@@ -314,7 +306,7 @@ static int dropmon_net_event(struct notifier_block *ev_block,
                                new_stat->dev = NULL;
                                if (trace_state == TRACE_OFF) {
                                        list_del_rcu(&new_stat->list);
-                                       call_rcu(&new_stat->rcu, free_dm_hw_stat);
+                                       kfree_rcu(new_stat, rcu);
                                        break;
                                }
                        }
index 7c23733..43b03dd 100644 (file)
@@ -249,13 +249,6 @@ int gen_new_estimator(struct gnet_stats_basic_packed *bstats,
 }
 EXPORT_SYMBOL(gen_new_estimator);
 
-static void __gen_kill_estimator(struct rcu_head *head)
-{
-       struct gen_estimator *e = container_of(head,
-                                       struct gen_estimator, e_rcu);
-       kfree(e);
-}
-
 /**
  * gen_kill_estimator - remove a rate estimator
  * @bstats: basic statistics
@@ -279,7 +272,7 @@ void gen_kill_estimator(struct gnet_stats_basic_packed *bstats,
                write_unlock(&est_lock);
 
                list_del_rcu(&e->list);
-               call_rcu(&e->e_rcu, __gen_kill_estimator);
+               kfree_rcu(e, e_rcu);
        }
        spin_unlock_bh(&est_tree_lock);
 }
index 5ceb257..80b2aad 100644 (file)
@@ -565,13 +565,6 @@ static ssize_t show_rps_map(struct netdev_rx_queue *queue,
        return len;
 }
 
-static void rps_map_release(struct rcu_head *rcu)
-{
-       struct rps_map *map = container_of(rcu, struct rps_map, rcu);
-
-       kfree(map);
-}
-
 static ssize_t store_rps_map(struct netdev_rx_queue *queue,
                      struct rx_queue_attribute *attribute,
                      const char *buf, size_t len)
@@ -619,7 +612,7 @@ static ssize_t store_rps_map(struct netdev_rx_queue *queue,
        spin_unlock(&rps_map_lock);
 
        if (old_map)
-               call_rcu(&old_map->rcu, rps_map_release);
+               kfree_rcu(old_map, rcu);
 
        free_cpumask_var(mask);
        return len;
@@ -728,7 +721,7 @@ static void rx_queue_release(struct kobject *kobj)
        map = rcu_dereference_raw(queue->rps_map);
        if (map) {
                RCU_INIT_POINTER(queue->rps_map, NULL);
-               call_rcu(&map->rcu, rps_map_release);
+               kfree_rcu(map, rcu);
        }
 
        flow_table = rcu_dereference_raw(queue->rps_flow_table);
@@ -898,21 +891,6 @@ static ssize_t show_xps_map(struct netdev_queue *queue,
        return len;
 }
 
-static void xps_map_release(struct rcu_head *rcu)
-{
-       struct xps_map *map = container_of(rcu, struct xps_map, rcu);
-
-       kfree(map);
-}
-
-static void xps_dev_maps_release(struct rcu_head *rcu)
-{
-       struct xps_dev_maps *dev_maps =
-           container_of(rcu, struct xps_dev_maps, rcu);
-
-       kfree(dev_maps);
-}
-
 static DEFINE_MUTEX(xps_map_mutex);
 #define xmap_dereference(P)            \
        rcu_dereference_protected((P), lockdep_is_held(&xps_map_mutex))
@@ -1009,7 +987,7 @@ static ssize_t store_xps_map(struct netdev_queue *queue,
                map = dev_maps ?
                        xmap_dereference(dev_maps->cpu_map[cpu]) : NULL;
                if (map && xmap_dereference(new_dev_maps->cpu_map[cpu]) != map)
-                       call_rcu(&map->rcu, xps_map_release);
+                       kfree_rcu(map, rcu);
                if (new_dev_maps->cpu_map[cpu])
                        nonempty = 1;
        }
@@ -1022,7 +1000,7 @@ static ssize_t store_xps_map(struct netdev_queue *queue,
        }
 
        if (dev_maps)
-               call_rcu(&dev_maps->rcu, xps_dev_maps_release);
+               kfree_rcu(dev_maps, rcu);
 
        netdev_queue_numa_node_write(queue, (numa_node >= 0) ? numa_node :
                                            NUMA_NO_NODE);
@@ -1084,7 +1062,7 @@ static void netdev_queue_release(struct kobject *kobj)
                                else {
                                        RCU_INIT_POINTER(dev_maps->cpu_map[i],
                                            NULL);
-                                       call_rcu(&map->rcu, xps_map_release);
+                                       kfree_rcu(map, rcu);
                                        map = NULL;
                                }
                        }
@@ -1094,7 +1072,7 @@ static void netdev_queue_release(struct kobject *kobj)
 
                if (!nonempty) {
                        RCU_INIT_POINTER(dev->xps_maps, NULL);
-                       call_rcu(&dev_maps->rcu, xps_dev_maps_release);
+                       kfree_rcu(dev_maps, rcu);
                }
        }
 
index 3f86026..297bb92 100644 (file)
@@ -27,14 +27,6 @@ EXPORT_SYMBOL(init_net);
 
 #define INITIAL_NET_GEN_PTRS   13 /* +1 for len +2 for rcu_head */
 
-static void net_generic_release(struct rcu_head *rcu)
-{
-       struct net_generic *ng;
-
-       ng = container_of(rcu, struct net_generic, rcu);
-       kfree(ng);
-}
-
 static int net_assign_generic(struct net *net, int id, void *data)
 {
        struct net_generic *ng, *old_ng;
@@ -68,7 +60,7 @@ static int net_assign_generic(struct net *net, int id, void *data)
        memcpy(&ng->ptr, &old_ng->ptr, old_ng->len * sizeof(void*));
 
        rcu_assign_pointer(net->gen, ng);
-       call_rcu(&old_ng->rcu, net_generic_release);
+       kfree_rcu(old_ng, rcu);
 assign:
        ng->ptr[id - 1] = data;
        return 0;
index f06ffcf..4b2ab65 100644 (file)
@@ -123,6 +123,8 @@ int dccp_parse_options(struct sock *sk, struct dccp_request_sock *dreq,
                case DCCPO_CHANGE_L ... DCCPO_CONFIRM_R:
                        if (pkt_type == DCCP_PKT_DATA)      /* RFC 4340, 6 */
                                break;
+                       if (len == 0)
+                               goto out_invalid_option;
                        rc = dccp_feat_parse_options(sk, dreq, mandatory, opt,
                                                    *value, value + 1, len - 1);
                        if (rc)
index 0dcaa90..4c27615 100644 (file)
@@ -332,14 +332,9 @@ static struct dn_ifaddr *dn_dev_alloc_ifa(void)
        return ifa;
 }
 
-static void dn_dev_free_ifa_rcu(struct rcu_head *head)
-{
-       kfree(container_of(head, struct dn_ifaddr, rcu));
-}
-
 static void dn_dev_free_ifa(struct dn_ifaddr *ifa)
 {
-       call_rcu(&ifa->rcu, dn_dev_free_ifa_rcu);
+       kfree_rcu(ifa, rcu);
 }
 
 static void dn_dev_del_ifa(struct dn_dev *dn_db, struct dn_ifaddr __rcu **ifap, int destroy)
index 641a5a2..33e2c35 100644 (file)
@@ -141,18 +141,8 @@ const struct fib_prop fib_props[RTN_MAX + 1] = {
        },
 };
 
-
 /* Release a nexthop info record */
 
-static void free_fib_info_rcu(struct rcu_head *head)
-{
-       struct fib_info *fi = container_of(head, struct fib_info, rcu);
-
-       if (fi->fib_metrics != (u32 *) dst_default_metrics)
-               kfree(fi->fib_metrics);
-       kfree(fi);
-}
-
 void free_fib_info(struct fib_info *fi)
 {
        if (fi->fib_dead == 0) {
@@ -166,7 +156,7 @@ void free_fib_info(struct fib_info *fi)
        } endfor_nexthops(fi);
        fib_info_cnt--;
        release_net(fi->fib_net);
-       call_rcu(&fi->rcu, free_fib_info_rcu);
+       kfree_rcu(fi, rcu);
 }
 
 void fib_release_info(struct fib_info *fi)
index 5fe9b8b..11d4d28 100644 (file)
@@ -350,14 +350,9 @@ static inline void free_leaf(struct leaf *l)
        call_rcu_bh(&l->rcu, __leaf_free_rcu);
 }
 
-static void __leaf_info_free_rcu(struct rcu_head *head)
-{
-       kfree(container_of(head, struct leaf_info, rcu));
-}
-
 static inline void free_leaf_info(struct leaf_info *leaf)
 {
-       call_rcu(&leaf->rcu, __leaf_info_free_rcu);
+       kfree_rcu(leaf, rcu);
 }
 
 static struct tnode *tnode_alloc(size_t size)
index 1fd3d9c..8f62d66 100644 (file)
@@ -149,17 +149,11 @@ static void ip_mc_clear_src(struct ip_mc_list *pmc);
 static int ip_mc_add_src(struct in_device *in_dev, __be32 *pmca, int sfmode,
                         int sfcount, __be32 *psfsrc, int delta);
 
-
-static void ip_mc_list_reclaim(struct rcu_head *head)
-{
-       kfree(container_of(head, struct ip_mc_list, rcu));
-}
-
 static void ip_ma_put(struct ip_mc_list *im)
 {
        if (atomic_dec_and_test(&im->refcnt)) {
                in_dev_put(im->interface);
-               call_rcu(&im->rcu, ip_mc_list_reclaim);
+               kfree_rcu(im, rcu);
        }
 }
 
@@ -1836,12 +1830,6 @@ done:
 }
 EXPORT_SYMBOL(ip_mc_join_group);
 
-static void ip_sf_socklist_reclaim(struct rcu_head *rp)
-{
-       kfree(container_of(rp, struct ip_sf_socklist, rcu));
-       /* sk_omem_alloc should have been decreased by the caller*/
-}
-
 static int ip_mc_leave_src(struct sock *sk, struct ip_mc_socklist *iml,
                           struct in_device *in_dev)
 {
@@ -1858,18 +1846,10 @@ static int ip_mc_leave_src(struct sock *sk, struct ip_mc_socklist *iml,
        rcu_assign_pointer(iml->sflist, NULL);
        /* decrease mem now to avoid the memleak warning */
        atomic_sub(IP_SFLSIZE(psf->sl_max), &sk->sk_omem_alloc);
-       call_rcu(&psf->rcu, ip_sf_socklist_reclaim);
+       kfree_rcu(psf, rcu);
        return err;
 }
 
-
-static void ip_mc_socklist_reclaim(struct rcu_head *rp)
-{
-       kfree(container_of(rp, struct ip_mc_socklist, rcu));
-       /* sk_omem_alloc should have been decreased by the caller*/
-}
-
-
 /*
  *     Ask a socket to leave a group.
  */
@@ -1909,7 +1889,7 @@ int ip_mc_leave_group(struct sock *sk, struct ip_mreqn *imr)
                rtnl_unlock();
                /* decrease mem now to avoid the memleak warning */
                atomic_sub(sizeof(*iml), &sk->sk_omem_alloc);
-               call_rcu(&iml->rcu, ip_mc_socklist_reclaim);
+               kfree_rcu(iml, rcu);
                return 0;
        }
        if (!in_dev)
@@ -2026,7 +2006,7 @@ int ip_mc_source(int add, int omode, struct sock *sk, struct
                                newpsl->sl_addr[i] = psl->sl_addr[i];
                        /* decrease mem now to avoid the memleak warning */
                        atomic_sub(IP_SFLSIZE(psl->sl_max), &sk->sk_omem_alloc);
-                       call_rcu(&psl->rcu, ip_sf_socklist_reclaim);
+                       kfree_rcu(psl, rcu);
                }
                rcu_assign_pointer(pmc->sflist, newpsl);
                psl = newpsl;
@@ -2127,7 +2107,7 @@ int ip_mc_msfilter(struct sock *sk, struct ip_msfilter *msf, int ifindex)
                        psl->sl_count, psl->sl_addr, 0);
                /* decrease mem now to avoid the memleak warning */
                atomic_sub(IP_SFLSIZE(psl->sl_max), &sk->sk_omem_alloc);
-               call_rcu(&psl->rcu, ip_sf_socklist_reclaim);
+               kfree_rcu(psl, rcu);
        } else
                (void) ip_mc_del_src(in_dev, &msf->imsf_multiaddr, pmc->sfmode,
                        0, NULL, 0);
@@ -2324,7 +2304,7 @@ void ip_mc_drop_socket(struct sock *sk)
                        ip_mc_dec_group(in_dev, iml->multi.imr_multiaddr.s_addr);
                /* decrease mem now to avoid the memleak warning */
                atomic_sub(sizeof(*iml), &sk->sk_omem_alloc);
-               call_rcu(&iml->rcu, ip_mc_socklist_reclaim);
+               kfree_rcu(iml, rcu);
        }
        rtnl_unlock();
 }
index a1151b8..b1d282f 100644 (file)
@@ -223,31 +223,30 @@ static void ip_expire(unsigned long arg)
 
        if ((qp->q.last_in & INET_FRAG_FIRST_IN) && qp->q.fragments != NULL) {
                struct sk_buff *head = qp->q.fragments;
+               const struct iphdr *iph;
+               int err;
 
                rcu_read_lock();
                head->dev = dev_get_by_index_rcu(net, qp->iif);
                if (!head->dev)
                        goto out_rcu_unlock;
 
+               /* skb dst is stale, drop it, and perform route lookup again */
+               skb_dst_drop(head);
+               iph = ip_hdr(head);
+               err = ip_route_input_noref(head, iph->daddr, iph->saddr,
+                                          iph->tos, head->dev);
+               if (err)
+                       goto out_rcu_unlock;
+
                /*
-                * Only search router table for the head fragment,
-                * when defraging timeout at PRE_ROUTING HOOK.
+                * Only an end host needs to send an ICMP
+                * "Fragment Reassembly Timeout" message, per RFC792.
                 */
-               if (qp->user == IP_DEFRAG_CONNTRACK_IN && !skb_dst(head)) {
-                       const struct iphdr *iph = ip_hdr(head);
-                       int err = ip_route_input(head, iph->daddr, iph->saddr,
-                                                iph->tos, head->dev);
-                       if (unlikely(err))
-                               goto out_rcu_unlock;
-
-                       /*
-                        * Only an end host needs to send an ICMP
-                        * "Fragment Reassembly Timeout" message, per RFC792.
-                        */
-                       if (skb_rtable(head)->rt_type != RTN_LOCAL)
-                               goto out_rcu_unlock;
+               if (qp->user == IP_DEFRAG_CONNTRACK_IN &&
+                   skb_rtable(head)->rt_type != RTN_LOCAL)
+                       goto out_rcu_unlock;
 
-               }
 
                /* Send an ICMP "Fragment Reassembly Timeout" message. */
                icmp_send(head, ICMP_TIME_EXCEEDED, ICMP_EXC_FRAGTIME, 0);
index 34340c9..f376b05 100644 (file)
@@ -93,6 +93,7 @@ struct bictcp {
        u32     ack_cnt;        /* number of acks */
        u32     tcp_cwnd;       /* estimated tcp cwnd */
 #define ACK_RATIO_SHIFT        4
+#define ACK_RATIO_LIMIT (32u << ACK_RATIO_SHIFT)
        u16     delayed_ack;    /* estimate the ratio of Packets/ACKs << 4 */
        u8      sample_cnt;     /* number of samples to decide curr_rtt */
        u8      found;          /* the exit point is found? */
@@ -398,8 +399,12 @@ static void bictcp_acked(struct sock *sk, u32 cnt, s32 rtt_us)
        u32 delay;
 
        if (icsk->icsk_ca_state == TCP_CA_Open) {
-               cnt -= ca->delayed_ack >> ACK_RATIO_SHIFT;
-               ca->delayed_ack += cnt;
+               u32 ratio = ca->delayed_ack;
+
+               ratio -= ca->delayed_ack >> ACK_RATIO_SHIFT;
+               ratio += cnt;
+
+               ca->delayed_ack = min(ratio, ACK_RATIO_LIMIT);
        }
 
        /* Some calls are for duplicates without timetamps */
index 571aa96..2d51840 100644 (file)
@@ -69,7 +69,7 @@ int xfrm4_prepare_output(struct xfrm_state *x, struct sk_buff *skb)
 }
 EXPORT_SYMBOL(xfrm4_prepare_output);
 
-static int xfrm4_output_finish(struct sk_buff *skb)
+int xfrm4_output_finish(struct sk_buff *skb)
 {
 #ifdef CONFIG_NETFILTER
        if (!skb_dst(skb)->xfrm) {
@@ -86,7 +86,11 @@ static int xfrm4_output_finish(struct sk_buff *skb)
 
 int xfrm4_output(struct sk_buff *skb)
 {
+       struct dst_entry *dst = skb_dst(skb);
+       struct xfrm_state *x = dst->xfrm;
+
        return NF_HOOK_COND(NFPROTO_IPV4, NF_INET_POST_ROUTING, skb,
-                           NULL, skb_dst(skb)->dev, xfrm4_output_finish,
+                           NULL, dst->dev,
+                           x->outer_mode->afinfo->output_finish,
                            !(IPCB(skb)->flags & IPSKB_REROUTED));
 }
index 1717c64..805d63e 100644 (file)
@@ -78,6 +78,7 @@ static struct xfrm_state_afinfo xfrm4_state_afinfo = {
        .init_tempsel           = __xfrm4_init_tempsel,
        .init_temprop           = xfrm4_init_temprop,
        .output                 = xfrm4_output,
+       .output_finish          = xfrm4_output_finish,
        .extract_input          = xfrm4_extract_input,
        .extract_output         = xfrm4_extract_output,
        .transport_finish       = xfrm4_transport_finish,
index a7bda07..8f13d88 100644 (file)
@@ -317,12 +317,6 @@ static void snmp6_free_dev(struct inet6_dev *idev)
 
 /* Nobody refers to this device, we may destroy it. */
 
-static void in6_dev_finish_destroy_rcu(struct rcu_head *head)
-{
-       struct inet6_dev *idev = container_of(head, struct inet6_dev, rcu);
-       kfree(idev);
-}
-
 void in6_dev_finish_destroy(struct inet6_dev *idev)
 {
        struct net_device *dev = idev->dev;
@@ -339,7 +333,7 @@ void in6_dev_finish_destroy(struct inet6_dev *idev)
                return;
        }
        snmp6_free_dev(idev);
-       call_rcu(&idev->rcu, in6_dev_finish_destroy_rcu);
+       kfree_rcu(idev, rcu);
 }
 
 EXPORT_SYMBOL(in6_dev_finish_destroy);
@@ -535,12 +529,6 @@ static int addrconf_fixup_forwarding(struct ctl_table *table, int *p, int old)
 }
 #endif
 
-static void inet6_ifa_finish_destroy_rcu(struct rcu_head *head)
-{
-       struct inet6_ifaddr *ifp = container_of(head, struct inet6_ifaddr, rcu);
-       kfree(ifp);
-}
-
 /* Nobody refers to this ifaddr, destroy it */
 void inet6_ifa_finish_destroy(struct inet6_ifaddr *ifp)
 {
@@ -561,7 +549,7 @@ void inet6_ifa_finish_destroy(struct inet6_ifaddr *ifp)
        }
        dst_release(&ifp->rt->dst);
 
-       call_rcu(&ifp->rcu, inet6_ifa_finish_destroy_rcu);
+       kfree_rcu(ifp, rcu);
 }
 
 static void
index 76b8937..f2d98ca 100644 (file)
@@ -201,10 +201,6 @@ int ipv6_sock_mc_join(struct sock *sk, int ifindex, const struct in6_addr *addr)
        return 0;
 }
 
-static void ipv6_mc_socklist_reclaim(struct rcu_head *head)
-{
-       kfree(container_of(head, struct ipv6_mc_socklist, rcu));
-}
 /*
  *     socket leave on multicast group
  */
@@ -239,7 +235,7 @@ int ipv6_sock_mc_drop(struct sock *sk, int ifindex, const struct in6_addr *addr)
                                (void) ip6_mc_leave_src(sk, mc_lst, NULL);
                        rcu_read_unlock();
                        atomic_sub(sizeof(*mc_lst), &sk->sk_omem_alloc);
-                       call_rcu(&mc_lst->rcu, ipv6_mc_socklist_reclaim);
+                       kfree_rcu(mc_lst, rcu);
                        return 0;
                }
        }
@@ -307,7 +303,7 @@ void ipv6_sock_mc_close(struct sock *sk)
                rcu_read_unlock();
 
                atomic_sub(sizeof(*mc_lst), &sk->sk_omem_alloc);
-               call_rcu(&mc_lst->rcu, ipv6_mc_socklist_reclaim);
+               kfree_rcu(mc_lst, rcu);
 
                spin_lock(&ipv6_sk_mc_lock);
        }
index 28e7448..a5a4c5d 100644 (file)
@@ -45,6 +45,8 @@ static void send_reset(struct net *net, struct sk_buff *oldskb)
        int tcphoff, needs_ack;
        const struct ipv6hdr *oip6h = ipv6_hdr(oldskb);
        struct ipv6hdr *ip6h;
+#define DEFAULT_TOS_VALUE      0x0U
+       const __u8 tclass = DEFAULT_TOS_VALUE;
        struct dst_entry *dst = NULL;
        u8 proto;
        struct flowi6 fl6;
@@ -124,7 +126,7 @@ static void send_reset(struct net *net, struct sk_buff *oldskb)
        skb_put(nskb, sizeof(struct ipv6hdr));
        skb_reset_network_header(nskb);
        ip6h = ipv6_hdr(nskb);
-       ip6h->version = 6;
+       *(__be32 *)ip6h =  htonl(0x60000000 | (tclass << 20));
        ip6h->hop_limit = ip6_dst_hoplimit(dst);
        ip6h->nexthdr = IPPROTO_TCP;
        ipv6_addr_copy(&ip6h->saddr, &oip6h->daddr);
index 43b3337..5f35d59 100644 (file)
@@ -401,11 +401,6 @@ out:
        return err;
 }
 
-static void prl_entry_destroy_rcu(struct rcu_head *head)
-{
-       kfree(container_of(head, struct ip_tunnel_prl_entry, rcu_head));
-}
-
 static void prl_list_destroy_rcu(struct rcu_head *head)
 {
        struct ip_tunnel_prl_entry *p, *n;
@@ -433,7 +428,7 @@ ipip6_tunnel_del_prl(struct ip_tunnel *t, struct ip_tunnel_prl *a)
                     p = &x->next) {
                        if (x->addr == a->addr) {
                                *p = x->next;
-                               call_rcu(&x->rcu_head, prl_entry_destroy_rcu);
+                               kfree_rcu(x, rcu_head);
                                t->prl_count--;
                                goto out;
                        }
index 8e688b3..49a91c5 100644 (file)
@@ -79,7 +79,7 @@ int xfrm6_prepare_output(struct xfrm_state *x, struct sk_buff *skb)
 }
 EXPORT_SYMBOL(xfrm6_prepare_output);
 
-static int xfrm6_output_finish(struct sk_buff *skb)
+int xfrm6_output_finish(struct sk_buff *skb)
 {
 #ifdef CONFIG_NETFILTER
        IP6CB(skb)->flags |= IP6SKB_XFRM_TRANSFORMED;
@@ -97,9 +97,9 @@ static int __xfrm6_output(struct sk_buff *skb)
        if ((x && x->props.mode == XFRM_MODE_TUNNEL) &&
            ((skb->len > ip6_skb_dst_mtu(skb) && !skb_is_gso(skb)) ||
                dst_allfrag(skb_dst(skb)))) {
-                       return ip6_fragment(skb, xfrm6_output_finish);
+                       return ip6_fragment(skb, x->outer_mode->afinfo->output_finish);
        }
-       return xfrm6_output_finish(skb);
+       return x->outer_mode->afinfo->output_finish(skb);
 }
 
 int xfrm6_output(struct sk_buff *skb)
index afe941e..248f0b2 100644 (file)
@@ -178,6 +178,7 @@ static struct xfrm_state_afinfo xfrm6_state_afinfo = {
        .tmpl_sort              = __xfrm6_tmpl_sort,
        .state_sort             = __xfrm6_state_sort,
        .output                 = xfrm6_output,
+       .output_finish          = xfrm6_output_finish,
        .extract_input          = xfrm6_extract_input,
        .extract_output         = xfrm6_extract_output,
        .transport_finish       = xfrm6_transport_finish,
index 63d852c..53defaf 100644 (file)
@@ -136,14 +136,6 @@ void ieee80211_send_bar(struct ieee80211_sub_if_data *sdata, u8 *ra, u16 tid, u1
        ieee80211_tx_skb(sdata, skb);
 }
 
-static void kfree_tid_tx(struct rcu_head *rcu_head)
-{
-       struct tid_ampdu_tx *tid_tx =
-           container_of(rcu_head, struct tid_ampdu_tx, rcu_head);
-
-       kfree(tid_tx);
-}
-
 int ___ieee80211_stop_tx_ba_session(struct sta_info *sta, u16 tid,
                                    enum ieee80211_back_parties initiator,
                                    bool tx)
@@ -163,7 +155,7 @@ int ___ieee80211_stop_tx_ba_session(struct sta_info *sta, u16 tid,
                /* not even started yet! */
                rcu_assign_pointer(sta->ampdu_mlme.tid_tx[tid], NULL);
                spin_unlock_bh(&sta->lock);
-               call_rcu(&tid_tx->rcu_head, kfree_tid_tx);
+               kfree_rcu(tid_tx, rcu_head);
                return 0;
        }
 
@@ -322,7 +314,7 @@ void ieee80211_tx_ba_session_handle_start(struct sta_info *sta, int tid)
                spin_unlock_bh(&sta->lock);
 
                ieee80211_wake_queue_agg(local, tid);
-               call_rcu(&tid_tx->rcu_head, kfree_tid_tx);
+               kfree_rcu(tid_tx, rcu_head);
                return;
        }
 
@@ -701,7 +693,7 @@ void ieee80211_stop_tx_ba_cb(struct ieee80211_vif *vif, u8 *ra, u8 tid)
 
        ieee80211_agg_splice_finish(local, tid);
 
-       call_rcu(&tid_tx->rcu_head, kfree_tid_tx);
+       kfree_rcu(tid_tx, rcu_head);
 
  unlock_sta:
        spin_unlock_bh(&sta->lock);
index ce4596e..bd1224f 100644 (file)
@@ -237,6 +237,10 @@ ieee80211_tx_h_dynamic_ps(struct ieee80211_tx_data *tx)
                                     &local->dynamic_ps_disable_work);
        }
 
+       /* Don't restart the timer if we're not disassociated */
+       if (!ifmgd->associated)
+               return TX_CONTINUE;
+
        mod_timer(&local->dynamic_ps_timer, jiffies +
                  msecs_to_jiffies(local->hw.conf.dynamic_ps_timeout));
 
index e73c8ca..ac35496 100644 (file)
@@ -65,17 +65,9 @@ static void run_again(struct ieee80211_local *local,
                mod_timer(&local->work_timer, timeout);
 }
 
-static void work_free_rcu(struct rcu_head *head)
-{
-       struct ieee80211_work *wk =
-               container_of(head, struct ieee80211_work, rcu_head);
-
-       kfree(wk);
-}
-
 void free_work(struct ieee80211_work *wk)
 {
-       call_rcu(&wk->rcu_head, work_free_rcu);
+       kfree_rcu(wk, rcu_head);
 }
 
 static int ieee80211_compatible_rates(const u8 *supp_rates, int supp_rates_len,
index 2dc6de1..059af31 100644 (file)
@@ -572,11 +572,11 @@ static const struct file_operations ip_vs_app_fops = {
        .open    = ip_vs_app_open,
        .read    = seq_read,
        .llseek  = seq_lseek,
-       .release = seq_release,
+       .release = seq_release_net,
 };
 #endif
 
-static int __net_init __ip_vs_app_init(struct net *net)
+int __net_init __ip_vs_app_init(struct net *net)
 {
        struct netns_ipvs *ipvs = net_ipvs(net);
 
@@ -585,26 +585,17 @@ static int __net_init __ip_vs_app_init(struct net *net)
        return 0;
 }
 
-static void __net_exit __ip_vs_app_cleanup(struct net *net)
+void __net_exit __ip_vs_app_cleanup(struct net *net)
 {
        proc_net_remove(net, "ip_vs_app");
 }
 
-static struct pernet_operations ip_vs_app_ops = {
-       .init = __ip_vs_app_init,
-       .exit = __ip_vs_app_cleanup,
-};
-
 int __init ip_vs_app_init(void)
 {
-       int rv;
-
-       rv = register_pernet_subsys(&ip_vs_app_ops);
-       return rv;
+       return 0;
 }
 
 
 void ip_vs_app_cleanup(void)
 {
-       unregister_pernet_subsys(&ip_vs_app_ops);
 }
index c97bd45..bf28ac2 100644 (file)
@@ -1046,7 +1046,7 @@ static const struct file_operations ip_vs_conn_fops = {
        .open    = ip_vs_conn_open,
        .read    = seq_read,
        .llseek  = seq_lseek,
-       .release = seq_release,
+       .release = seq_release_net,
 };
 
 static const char *ip_vs_origin_name(unsigned flags)
@@ -1114,7 +1114,7 @@ static const struct file_operations ip_vs_conn_sync_fops = {
        .open    = ip_vs_conn_sync_open,
        .read    = seq_read,
        .llseek  = seq_lseek,
-       .release = seq_release,
+       .release = seq_release_net,
 };
 
 #endif
@@ -1258,22 +1258,17 @@ int __net_init __ip_vs_conn_init(struct net *net)
        return 0;
 }
 
-static void __net_exit __ip_vs_conn_cleanup(struct net *net)
+void __net_exit __ip_vs_conn_cleanup(struct net *net)
 {
        /* flush all the connection entries first */
        ip_vs_conn_flush(net);
        proc_net_remove(net, "ip_vs_conn");
        proc_net_remove(net, "ip_vs_conn_sync");
 }
-static struct pernet_operations ipvs_conn_ops = {
-       .init = __ip_vs_conn_init,
-       .exit = __ip_vs_conn_cleanup,
-};
 
 int __init ip_vs_conn_init(void)
 {
        int idx;
-       int retc;
 
        /* Compute size and mask */
        ip_vs_conn_tab_size = 1 << ip_vs_conn_tab_bits;
@@ -1309,17 +1304,14 @@ int __init ip_vs_conn_init(void)
                rwlock_init(&__ip_vs_conntbl_lock_array[idx].l);
        }
 
-       retc = register_pernet_subsys(&ipvs_conn_ops);
-
        /* calculate the random value for connection hash */
        get_random_bytes(&ip_vs_conn_rnd, sizeof(ip_vs_conn_rnd));
 
-       return retc;
+       return 0;
 }
 
 void ip_vs_conn_cleanup(void)
 {
-       unregister_pernet_subsys(&ipvs_conn_ops);
        /* Release the empty cache */
        kmem_cache_destroy(ip_vs_conn_cachep);
        vfree(ip_vs_conn_tab);
index 07accf6..a74dae6 100644 (file)
@@ -1113,6 +1113,9 @@ ip_vs_out(unsigned int hooknum, struct sk_buff *skb, int af)
                return NF_ACCEPT;
 
        net = skb_net(skb);
+       if (!net_ipvs(net)->enable)
+               return NF_ACCEPT;
+
        ip_vs_fill_iphdr(af, skb_network_header(skb), &iph);
 #ifdef CONFIG_IP_VS_IPV6
        if (af == AF_INET6) {
@@ -1343,6 +1346,7 @@ ip_vs_in_icmp(struct sk_buff *skb, int *related, unsigned int hooknum)
                return NF_ACCEPT; /* The packet looks wrong, ignore */
 
        net = skb_net(skb);
+
        pd = ip_vs_proto_data_get(net, cih->protocol);
        if (!pd)
                return NF_ACCEPT;
@@ -1529,6 +1533,11 @@ ip_vs_in(unsigned int hooknum, struct sk_buff *skb, int af)
                              IP_VS_DBG_ADDR(af, &iph.daddr), hooknum);
                return NF_ACCEPT;
        }
+       /* ipvs enabled in this netns ? */
+       net = skb_net(skb);
+       if (!net_ipvs(net)->enable)
+               return NF_ACCEPT;
+
        ip_vs_fill_iphdr(af, skb_network_header(skb), &iph);
 
        /* Bad... Do not break raw sockets */
@@ -1562,7 +1571,6 @@ ip_vs_in(unsigned int hooknum, struct sk_buff *skb, int af)
                        ip_vs_fill_iphdr(af, skb_network_header(skb), &iph);
                }
 
-       net = skb_net(skb);
        /* Protocol supported? */
        pd = ip_vs_proto_data_get(net, iph.protocol);
        if (unlikely(!pd))
@@ -1588,7 +1596,6 @@ ip_vs_in(unsigned int hooknum, struct sk_buff *skb, int af)
        }
 
        IP_VS_DBG_PKT(11, af, pp, skb, 0, "Incoming packet");
-       net = skb_net(skb);
        ipvs = net_ipvs(net);
        /* Check the server status */
        if (cp->dest && !(cp->dest->flags & IP_VS_DEST_F_AVAILABLE)) {
@@ -1743,10 +1750,16 @@ ip_vs_forward_icmp(unsigned int hooknum, struct sk_buff *skb,
                   int (*okfn)(struct sk_buff *))
 {
        int r;
+       struct net *net;
 
        if (ip_hdr(skb)->protocol != IPPROTO_ICMP)
                return NF_ACCEPT;
 
+       /* ipvs enabled in this netns ? */
+       net = skb_net(skb);
+       if (!net_ipvs(net)->enable)
+               return NF_ACCEPT;
+
        return ip_vs_in_icmp(skb, &r, hooknum);
 }
 
@@ -1757,10 +1770,16 @@ ip_vs_forward_icmp_v6(unsigned int hooknum, struct sk_buff *skb,
                      int (*okfn)(struct sk_buff *))
 {
        int r;
+       struct net *net;
 
        if (ipv6_hdr(skb)->nexthdr != IPPROTO_ICMPV6)
                return NF_ACCEPT;
 
+       /* ipvs enabled in this netns ? */
+       net = skb_net(skb);
+       if (!net_ipvs(net)->enable)
+               return NF_ACCEPT;
+
        return ip_vs_in_icmp_v6(skb, &r, hooknum);
 }
 #endif
@@ -1884,19 +1903,70 @@ static int __net_init __ip_vs_init(struct net *net)
                pr_err("%s(): no memory.\n", __func__);
                return -ENOMEM;
        }
+       /* Hold the beast until a service is registerd */
+       ipvs->enable = 0;
        ipvs->net = net;
        /* Counters used for creating unique names */
        ipvs->gen = atomic_read(&ipvs_netns_cnt);
        atomic_inc(&ipvs_netns_cnt);
        net->ipvs = ipvs;
+
+       if (__ip_vs_estimator_init(net) < 0)
+               goto estimator_fail;
+
+       if (__ip_vs_control_init(net) < 0)
+               goto control_fail;
+
+       if (__ip_vs_protocol_init(net) < 0)
+               goto protocol_fail;
+
+       if (__ip_vs_app_init(net) < 0)
+               goto app_fail;
+
+       if (__ip_vs_conn_init(net) < 0)
+               goto conn_fail;
+
+       if (__ip_vs_sync_init(net) < 0)
+               goto sync_fail;
+
        printk(KERN_INFO "IPVS: Creating netns size=%zu id=%d\n",
                         sizeof(struct netns_ipvs), ipvs->gen);
        return 0;
+/*
+ * Error handling
+ */
+
+sync_fail:
+       __ip_vs_conn_cleanup(net);
+conn_fail:
+       __ip_vs_app_cleanup(net);
+app_fail:
+       __ip_vs_protocol_cleanup(net);
+protocol_fail:
+       __ip_vs_control_cleanup(net);
+control_fail:
+       __ip_vs_estimator_cleanup(net);
+estimator_fail:
+       return -ENOMEM;
 }
 
 static void __net_exit __ip_vs_cleanup(struct net *net)
 {
-       IP_VS_DBG(10, "ipvs netns %d released\n", net_ipvs(net)->gen);
+       __ip_vs_service_cleanup(net);   /* ip_vs_flush() with locks */
+       __ip_vs_conn_cleanup(net);
+       __ip_vs_app_cleanup(net);
+       __ip_vs_protocol_cleanup(net);
+       __ip_vs_control_cleanup(net);
+       __ip_vs_estimator_cleanup(net);
+       IP_VS_DBG(2, "ipvs netns %d released\n", net_ipvs(net)->gen);
+}
+
+static void __net_exit __ip_vs_dev_cleanup(struct net *net)
+{
+       EnterFunction(2);
+       net_ipvs(net)->enable = 0;      /* Disable packet reception */
+       __ip_vs_sync_cleanup(net);
+       LeaveFunction(2);
 }
 
 static struct pernet_operations ipvs_core_ops = {
@@ -1906,6 +1976,10 @@ static struct pernet_operations ipvs_core_ops = {
        .size = sizeof(struct netns_ipvs),
 };
 
+static struct pernet_operations ipvs_core_dev_ops = {
+       .exit = __ip_vs_dev_cleanup,
+};
+
 /*
  *     Initialize IP Virtual Server
  */
@@ -1913,10 +1987,6 @@ static int __init ip_vs_init(void)
 {
        int ret;
 
-       ret = register_pernet_subsys(&ipvs_core_ops);   /* Alloc ip_vs struct */
-       if (ret < 0)
-               return ret;
-
        ip_vs_estimator_init();
        ret = ip_vs_control_init();
        if (ret < 0) {
@@ -1944,15 +2014,28 @@ static int __init ip_vs_init(void)
                goto cleanup_conn;
        }
 
+       ret = register_pernet_subsys(&ipvs_core_ops);   /* Alloc ip_vs struct */
+       if (ret < 0)
+               goto cleanup_sync;
+
+       ret = register_pernet_device(&ipvs_core_dev_ops);
+       if (ret < 0)
+               goto cleanup_sub;
+
        ret = nf_register_hooks(ip_vs_ops, ARRAY_SIZE(ip_vs_ops));
        if (ret < 0) {
                pr_err("can't register hooks.\n");
-               goto cleanup_sync;
+               goto cleanup_dev;
        }
 
        pr_info("ipvs loaded.\n");
+
        return ret;
 
+cleanup_dev:
+       unregister_pernet_device(&ipvs_core_dev_ops);
+cleanup_sub:
+       unregister_pernet_subsys(&ipvs_core_ops);
 cleanup_sync:
        ip_vs_sync_cleanup();
   cleanup_conn:
@@ -1964,20 +2047,20 @@ cleanup_sync:
        ip_vs_control_cleanup();
   cleanup_estimator:
        ip_vs_estimator_cleanup();
-       unregister_pernet_subsys(&ipvs_core_ops);       /* free ip_vs struct */
        return ret;
 }
 
 static void __exit ip_vs_cleanup(void)
 {
        nf_unregister_hooks(ip_vs_ops, ARRAY_SIZE(ip_vs_ops));
+       unregister_pernet_device(&ipvs_core_dev_ops);
+       unregister_pernet_subsys(&ipvs_core_ops);       /* free ip_vs struct */
        ip_vs_sync_cleanup();
        ip_vs_conn_cleanup();
        ip_vs_app_cleanup();
        ip_vs_protocol_cleanup();
        ip_vs_control_cleanup();
        ip_vs_estimator_cleanup();
-       unregister_pernet_subsys(&ipvs_core_ops);       /* free ip_vs struct */
        pr_info("ipvs unloaded.\n");
 }
 
index ae47090..37890f2 100644 (file)
@@ -69,6 +69,11 @@ int ip_vs_get_debug_level(void)
 }
 #endif
 
+
+/*  Protos */
+static void __ip_vs_del_service(struct ip_vs_service *svc);
+
+
 #ifdef CONFIG_IP_VS_IPV6
 /* Taken from rt6_fill_node() in net/ipv6/route.c, is there a better way? */
 static int __ip_vs_addr_is_local_v6(struct net *net,
@@ -1214,6 +1219,8 @@ ip_vs_add_service(struct net *net, struct ip_vs_service_user_kern *u,
        write_unlock_bh(&__ip_vs_svc_lock);
 
        *svc_p = svc;
+       /* Now there is a service - full throttle */
+       ipvs->enable = 1;
        return 0;
 
 
@@ -1472,6 +1479,84 @@ static int ip_vs_flush(struct net *net)
        return 0;
 }
 
+/*
+ *     Delete service by {netns} in the service table.
+ *     Called by __ip_vs_cleanup()
+ */
+void __ip_vs_service_cleanup(struct net *net)
+{
+       EnterFunction(2);
+       /* Check for "full" addressed entries */
+       mutex_lock(&__ip_vs_mutex);
+       ip_vs_flush(net);
+       mutex_unlock(&__ip_vs_mutex);
+       LeaveFunction(2);
+}
+/*
+ * Release dst hold by dst_cache
+ */
+static inline void
+__ip_vs_dev_reset(struct ip_vs_dest *dest, struct net_device *dev)
+{
+       spin_lock_bh(&dest->dst_lock);
+       if (dest->dst_cache && dest->dst_cache->dev == dev) {
+               IP_VS_DBG_BUF(3, "Reset dev:%s dest %s:%u ,dest->refcnt=%d\n",
+                             dev->name,
+                             IP_VS_DBG_ADDR(dest->af, &dest->addr),
+                             ntohs(dest->port),
+                             atomic_read(&dest->refcnt));
+               ip_vs_dst_reset(dest);
+       }
+       spin_unlock_bh(&dest->dst_lock);
+
+}
+/*
+ * Netdev event receiver
+ * Currently only NETDEV_UNREGISTER is handled, i.e. if we hold a reference to
+ * a device that is "unregister" it must be released.
+ */
+static int ip_vs_dst_event(struct notifier_block *this, unsigned long event,
+                           void *ptr)
+{
+       struct net_device *dev = ptr;
+       struct net *net = dev_net(dev);
+       struct ip_vs_service *svc;
+       struct ip_vs_dest *dest;
+       unsigned int idx;
+
+       if (event != NETDEV_UNREGISTER)
+               return NOTIFY_DONE;
+       IP_VS_DBG(3, "%s() dev=%s\n", __func__, dev->name);
+       EnterFunction(2);
+       mutex_lock(&__ip_vs_mutex);
+       for (idx = 0; idx < IP_VS_SVC_TAB_SIZE; idx++) {
+               list_for_each_entry(svc, &ip_vs_svc_table[idx], s_list) {
+                       if (net_eq(svc->net, net)) {
+                               list_for_each_entry(dest, &svc->destinations,
+                                                   n_list) {
+                                       __ip_vs_dev_reset(dest, dev);
+                               }
+                       }
+               }
+
+               list_for_each_entry(svc, &ip_vs_svc_fwm_table[idx], f_list) {
+                       if (net_eq(svc->net, net)) {
+                               list_for_each_entry(dest, &svc->destinations,
+                                                   n_list) {
+                                       __ip_vs_dev_reset(dest, dev);
+                               }
+                       }
+
+               }
+       }
+
+       list_for_each_entry(dest, &net_ipvs(net)->dest_trash, n_list) {
+               __ip_vs_dev_reset(dest, dev);
+       }
+       mutex_unlock(&__ip_vs_mutex);
+       LeaveFunction(2);
+       return NOTIFY_DONE;
+}
 
 /*
  *     Zero counters in a service or all services
@@ -1981,7 +2066,7 @@ static const struct file_operations ip_vs_info_fops = {
        .open    = ip_vs_info_open,
        .read    = seq_read,
        .llseek  = seq_lseek,
-       .release = seq_release_private,
+       .release = seq_release_net,
 };
 
 #endif
@@ -2024,7 +2109,7 @@ static const struct file_operations ip_vs_stats_fops = {
        .open = ip_vs_stats_seq_open,
        .read = seq_read,
        .llseek = seq_lseek,
-       .release = single_release,
+       .release = single_release_net,
 };
 
 static int ip_vs_stats_percpu_show(struct seq_file *seq, void *v)
@@ -2093,7 +2178,7 @@ static const struct file_operations ip_vs_stats_percpu_fops = {
        .open = ip_vs_stats_percpu_seq_open,
        .read = seq_read,
        .llseek = seq_lseek,
-       .release = single_release,
+       .release = single_release_net,
 };
 #endif
 
@@ -3588,6 +3673,10 @@ void __net_init __ip_vs_control_cleanup_sysctl(struct net *net) { }
 
 #endif
 
+static struct notifier_block ip_vs_dst_notifier = {
+       .notifier_call = ip_vs_dst_event,
+};
+
 int __net_init __ip_vs_control_init(struct net *net)
 {
        int idx;
@@ -3626,7 +3715,7 @@ err:
        return -ENOMEM;
 }
 
-static void __net_exit __ip_vs_control_cleanup(struct net *net)
+void __net_exit __ip_vs_control_cleanup(struct net *net)
 {
        struct netns_ipvs *ipvs = net_ipvs(net);
 
@@ -3639,11 +3728,6 @@ static void __net_exit __ip_vs_control_cleanup(struct net *net)
        free_percpu(ipvs->tot_stats.cpustats);
 }
 
-static struct pernet_operations ipvs_control_ops = {
-       .init = __ip_vs_control_init,
-       .exit = __ip_vs_control_cleanup,
-};
-
 int __init ip_vs_control_init(void)
 {
        int idx;
@@ -3657,33 +3741,32 @@ int __init ip_vs_control_init(void)
                INIT_LIST_HEAD(&ip_vs_svc_fwm_table[idx]);
        }
 
-       ret = register_pernet_subsys(&ipvs_control_ops);
-       if (ret) {
-               pr_err("cannot register namespace.\n");
-               goto err;
-       }
-
        smp_wmb();      /* Do we really need it now ? */
 
        ret = nf_register_sockopt(&ip_vs_sockopts);
        if (ret) {
                pr_err("cannot register sockopt.\n");
-               goto err_net;
+               goto err_sock;
        }
 
        ret = ip_vs_genl_register();
        if (ret) {
                pr_err("cannot register Generic Netlink interface.\n");
-               nf_unregister_sockopt(&ip_vs_sockopts);
-               goto err_net;
+               goto err_genl;
        }
 
+       ret = register_netdevice_notifier(&ip_vs_dst_notifier);
+       if (ret < 0)
+               goto err_notf;
+
        LeaveFunction(2);
        return 0;
 
-err_net:
-       unregister_pernet_subsys(&ipvs_control_ops);
-err:
+err_notf:
+       ip_vs_genl_unregister();
+err_genl:
+       nf_unregister_sockopt(&ip_vs_sockopts);
+err_sock:
        return ret;
 }
 
@@ -3691,7 +3774,6 @@ err:
 void ip_vs_control_cleanup(void)
 {
        EnterFunction(2);
-       unregister_pernet_subsys(&ipvs_control_ops);
        ip_vs_genl_unregister();
        nf_unregister_sockopt(&ip_vs_sockopts);
        LeaveFunction(2);
index 8c8766c..508cce9 100644 (file)
@@ -192,7 +192,7 @@ void ip_vs_read_estimator(struct ip_vs_stats_user *dst,
        dst->outbps = (e->outbps + 0xF) >> 5;
 }
 
-static int __net_init __ip_vs_estimator_init(struct net *net)
+int __net_init __ip_vs_estimator_init(struct net *net)
 {
        struct netns_ipvs *ipvs = net_ipvs(net);
 
@@ -203,24 +203,16 @@ static int __net_init __ip_vs_estimator_init(struct net *net)
        return 0;
 }
 
-static void __net_exit __ip_vs_estimator_exit(struct net *net)
+void __net_exit __ip_vs_estimator_cleanup(struct net *net)
 {
        del_timer_sync(&net_ipvs(net)->est_timer);
 }
-static struct pernet_operations ip_vs_app_ops = {
-       .init = __ip_vs_estimator_init,
-       .exit = __ip_vs_estimator_exit,
-};
 
 int __init ip_vs_estimator_init(void)
 {
-       int rv;
-
-       rv = register_pernet_subsys(&ip_vs_app_ops);
-       return rv;
+       return 0;
 }
 
 void ip_vs_estimator_cleanup(void)
 {
-       unregister_pernet_subsys(&ip_vs_app_ops);
 }
index 17484a4..eb86028 100644 (file)
@@ -316,7 +316,7 @@ ip_vs_tcpudp_debug_packet(int af, struct ip_vs_protocol *pp,
 /*
  * per network name-space init
  */
-static int __net_init __ip_vs_protocol_init(struct net *net)
+int __net_init __ip_vs_protocol_init(struct net *net)
 {
 #ifdef CONFIG_IP_VS_PROTO_TCP
        register_ip_vs_proto_netns(net, &ip_vs_protocol_tcp);
@@ -336,7 +336,7 @@ static int __net_init __ip_vs_protocol_init(struct net *net)
        return 0;
 }
 
-static void __net_exit __ip_vs_protocol_cleanup(struct net *net)
+void __net_exit __ip_vs_protocol_cleanup(struct net *net)
 {
        struct netns_ipvs *ipvs = net_ipvs(net);
        struct ip_vs_proto_data *pd;
@@ -349,11 +349,6 @@ static void __net_exit __ip_vs_protocol_cleanup(struct net *net)
        }
 }
 
-static struct pernet_operations ipvs_proto_ops = {
-       .init = __ip_vs_protocol_init,
-       .exit = __ip_vs_protocol_cleanup,
-};
-
 int __init ip_vs_protocol_init(void)
 {
        char protocols[64];
@@ -382,7 +377,6 @@ int __init ip_vs_protocol_init(void)
        REGISTER_PROTOCOL(&ip_vs_protocol_esp);
 #endif
        pr_info("Registered protocols (%s)\n", &protocols[2]);
-       return register_pernet_subsys(&ipvs_proto_ops);
 
        return 0;
 }
@@ -393,7 +387,6 @@ void ip_vs_protocol_cleanup(void)
        struct ip_vs_protocol *pp;
        int i;
 
-       unregister_pernet_subsys(&ipvs_proto_ops);
        /* unregister all the ipvs protocols */
        for (i = 0; i < IP_VS_PROTO_TAB_SIZE; i++) {
                while ((pp = ip_vs_proto_table[i]) != NULL)
index 3e7961e..e292e5b 100644 (file)
@@ -1303,13 +1303,18 @@ static struct socket *make_send_sock(struct net *net)
        struct socket *sock;
        int result;
 
-       /* First create a socket */
-       result = __sock_create(net, PF_INET, SOCK_DGRAM, IPPROTO_UDP, &sock, 1);
+       /* First create a socket move it to right name space later */
+       result = sock_create_kern(PF_INET, SOCK_DGRAM, IPPROTO_UDP, &sock);
        if (result < 0) {
                pr_err("Error during creation of socket; terminating\n");
                return ERR_PTR(result);
        }
-
+       /*
+        * Kernel sockets that are a part of a namespace, should not
+        * hold a reference to a namespace in order to allow to stop it.
+        * After sk_change_net should be released using sk_release_kernel.
+        */
+       sk_change_net(sock->sk, net);
        result = set_mcast_if(sock->sk, ipvs->master_mcast_ifn);
        if (result < 0) {
                pr_err("Error setting outbound mcast interface\n");
@@ -1334,8 +1339,8 @@ static struct socket *make_send_sock(struct net *net)
 
        return sock;
 
-  error:
-       sock_release(sock);
+error:
+       sk_release_kernel(sock->sk);
        return ERR_PTR(result);
 }
 
@@ -1350,12 +1355,17 @@ static struct socket *make_receive_sock(struct net *net)
        int result;
 
        /* First create a socket */
-       result = __sock_create(net, PF_INET, SOCK_DGRAM, IPPROTO_UDP, &sock, 1);
+       result = sock_create_kern(PF_INET, SOCK_DGRAM, IPPROTO_UDP, &sock);
        if (result < 0) {
                pr_err("Error during creation of socket; terminating\n");
                return ERR_PTR(result);
        }
-
+       /*
+        * Kernel sockets that are a part of a namespace, should not
+        * hold a reference to a namespace in order to allow to stop it.
+        * After sk_change_net should be released using sk_release_kernel.
+        */
+       sk_change_net(sock->sk, net);
        /* it is equivalent to the REUSEADDR option in user-space */
        sock->sk->sk_reuse = 1;
 
@@ -1377,8 +1387,8 @@ static struct socket *make_receive_sock(struct net *net)
 
        return sock;
 
-  error:
-       sock_release(sock);
+error:
+       sk_release_kernel(sock->sk);
        return ERR_PTR(result);
 }
 
@@ -1473,7 +1483,7 @@ static int sync_thread_master(void *data)
                ip_vs_sync_buff_release(sb);
 
        /* release the sending multicast socket */
-       sock_release(tinfo->sock);
+       sk_release_kernel(tinfo->sock->sk);
        kfree(tinfo);
 
        return 0;
@@ -1513,7 +1523,7 @@ static int sync_thread_backup(void *data)
        }
 
        /* release the sending multicast socket */
-       sock_release(tinfo->sock);
+       sk_release_kernel(tinfo->sock->sk);
        kfree(tinfo->buf);
        kfree(tinfo);
 
@@ -1601,7 +1611,7 @@ outtinfo:
 outbuf:
        kfree(buf);
 outsocket:
-       sock_release(sock);
+       sk_release_kernel(sock->sk);
 out:
        return result;
 }
@@ -1610,6 +1620,7 @@ out:
 int stop_sync_thread(struct net *net, int state)
 {
        struct netns_ipvs *ipvs = net_ipvs(net);
+       int retc = -EINVAL;
 
        IP_VS_DBG(7, "%s(): pid %d\n", __func__, task_pid_nr(current));
 
@@ -1629,7 +1640,7 @@ int stop_sync_thread(struct net *net, int state)
                spin_lock_bh(&ipvs->sync_lock);
                ipvs->sync_state &= ~IP_VS_STATE_MASTER;
                spin_unlock_bh(&ipvs->sync_lock);
-               kthread_stop(ipvs->master_thread);
+               retc = kthread_stop(ipvs->master_thread);
                ipvs->master_thread = NULL;
        } else if (state == IP_VS_STATE_BACKUP) {
                if (!ipvs->backup_thread)
@@ -1639,22 +1650,20 @@ int stop_sync_thread(struct net *net, int state)
                        task_pid_nr(ipvs->backup_thread));
 
                ipvs->sync_state &= ~IP_VS_STATE_BACKUP;
-               kthread_stop(ipvs->backup_thread);
+               retc = kthread_stop(ipvs->backup_thread);
                ipvs->backup_thread = NULL;
-       } else {
-               return -EINVAL;
        }
 
        /* decrease the module use count */
        ip_vs_use_count_dec();
 
-       return 0;
+       return retc;
 }
 
 /*
  * Initialize data struct for each netns
  */
-static int __net_init __ip_vs_sync_init(struct net *net)
+int __net_init __ip_vs_sync_init(struct net *net)
 {
        struct netns_ipvs *ipvs = net_ipvs(net);
 
@@ -1668,24 +1677,24 @@ static int __net_init __ip_vs_sync_init(struct net *net)
        return 0;
 }
 
-static void __ip_vs_sync_cleanup(struct net *net)
+void __ip_vs_sync_cleanup(struct net *net)
 {
-       stop_sync_thread(net, IP_VS_STATE_MASTER);
-       stop_sync_thread(net, IP_VS_STATE_BACKUP);
-}
+       int retc;
 
-static struct pernet_operations ipvs_sync_ops = {
-       .init = __ip_vs_sync_init,
-       .exit = __ip_vs_sync_cleanup,
-};
+       retc = stop_sync_thread(net, IP_VS_STATE_MASTER);
+       if (retc && retc != -ESRCH)
+               pr_err("Failed to stop Master Daemon\n");
 
+       retc = stop_sync_thread(net, IP_VS_STATE_BACKUP);
+       if (retc && retc != -ESRCH)
+               pr_err("Failed to stop Backup Daemon\n");
+}
 
 int __init ip_vs_sync_init(void)
 {
-       return register_pernet_subsys(&ipvs_sync_ops);
+       return 0;
 }
 
 void ip_vs_sync_cleanup(void)
 {
-       unregister_pernet_subsys(&ipvs_sync_ops);
 }
index 80a23ed..05ecdc2 100644 (file)
@@ -68,12 +68,6 @@ nf_ct_ext_create(struct nf_ct_ext **ext, enum nf_ct_ext_id id, gfp_t gfp)
        return (void *)(*ext) + off;
 }
 
-static void __nf_ct_ext_free_rcu(struct rcu_head *head)
-{
-       struct nf_ct_ext *ext = container_of(head, struct nf_ct_ext, rcu);
-       kfree(ext);
-}
-
 void *__nf_ct_ext_add(struct nf_conn *ct, enum nf_ct_ext_id id, gfp_t gfp)
 {
        struct nf_ct_ext *old, *new;
@@ -114,7 +108,7 @@ void *__nf_ct_ext_add(struct nf_conn *ct, enum nf_ct_ext_id id, gfp_t gfp)
                                        (void *)old + old->offset[i]);
                        rcu_read_unlock();
                }
-               call_rcu(&old->rcu, __nf_ct_ext_free_rcu);
+               kfree_rcu(old, rcu);
                ct->ext = new;
        }
 
index 30bf8a1..482e90c 100644 (file)
@@ -1334,6 +1334,7 @@ ctnetlink_create_conntrack(struct net *net, u16 zone,
        struct nf_conn *ct;
        int err = -EINVAL;
        struct nf_conntrack_helper *helper;
+       struct nf_conn_tstamp *tstamp;
 
        ct = nf_conntrack_alloc(net, zone, otuple, rtuple, GFP_ATOMIC);
        if (IS_ERR(ct))
@@ -1451,6 +1452,9 @@ ctnetlink_create_conntrack(struct net *net, u16 zone,
                __set_bit(IPS_EXPECTED_BIT, &ct->status);
                ct->master = master_ct;
        }
+       tstamp = nf_conn_tstamp_find(ct);
+       if (tstamp)
+               tstamp->start = ktime_to_ns(ktime_get_real());
 
        add_timer(&ct->timeout);
        nf_conntrack_hash_insert(ct);
index a9adf4c..8a025a5 100644 (file)
@@ -455,6 +455,7 @@ void xt_compat_flush_offsets(u_int8_t af)
                vfree(xt[af].compat_tab);
                xt[af].compat_tab = NULL;
                xt[af].number = 0;
+               xt[af].cur = 0;
        }
 }
 EXPORT_SYMBOL_GPL(xt_compat_flush_offsets);
@@ -473,8 +474,7 @@ int xt_compat_calc_jump(u_int8_t af, unsigned int offset)
                else
                        return mid ? tmp[mid - 1].delta : 0;
        }
-       WARN_ON_ONCE(1);
-       return 0;
+       return left ? tmp[left - 1].delta : 0;
 }
 EXPORT_SYMBOL_GPL(xt_compat_calc_jump);
 
index 0a22919..ae82716 100644 (file)
@@ -99,7 +99,7 @@ tos_tg6(struct sk_buff *skb, const struct xt_action_param *par)
        u_int8_t orig, nv;
 
        orig = ipv6_get_dsfield(iph);
-       nv   = (orig & info->tos_mask) ^ info->tos_value;
+       nv   = (orig & ~info->tos_mask) ^ info->tos_value;
 
        if (orig != nv) {
                if (!skb_make_writable(skb, sizeof(struct iphdr)))
index 481a86f..61805d7 100644 (file)
@@ -272,11 +272,6 @@ static int conntrack_mt_check(const struct xt_mtchk_param *par)
 {
        int ret;
 
-       if (strcmp(par->table, "raw") == 0) {
-               pr_info("state is undetermined at the time of raw table\n");
-               return -EINVAL;
-       }
-
        ret = nf_ct_l3proto_try_module_get(par->family);
        if (ret < 0)
                pr_info("cannot load conntrack support for proto=%u\n",
index 4327e10..846f895 100644 (file)
@@ -62,13 +62,6 @@ static const struct nla_policy xt_osf_policy[OSF_ATTR_MAX + 1] = {
        [OSF_ATTR_FINGER]       = { .len = sizeof(struct xt_osf_user_finger) },
 };
 
-static void xt_osf_finger_free_rcu(struct rcu_head *rcu_head)
-{
-       struct xt_osf_finger *f = container_of(rcu_head, struct xt_osf_finger, rcu_head);
-
-       kfree(f);
-}
-
 static int xt_osf_add_callback(struct sock *ctnl, struct sk_buff *skb,
                               const struct nlmsghdr *nlh,
                               const struct nlattr * const osf_attrs[])
@@ -133,7 +126,7 @@ static int xt_osf_remove_callback(struct sock *ctnl, struct sk_buff *skb,
                 * We are protected by nfnl mutex.
                 */
                list_del_rcu(&sf->finger_entry);
-               call_rcu(&sf->rcu_head, xt_osf_finger_free_rcu);
+               kfree_rcu(sf, rcu_head);
 
                err = 0;
                break;
@@ -414,7 +407,7 @@ static void __exit xt_osf_fini(void)
 
                list_for_each_entry_rcu(f, &xt_osf_fingers[i], finger_entry) {
                        list_del_rcu(&f->finger_entry);
-                       call_rcu(&f->rcu_head, xt_osf_finger_free_rcu);
+                       kfree_rcu(f, rcu_head);
                }
        }
        rcu_read_unlock();
index e2b0a68..9c38658 100644 (file)
@@ -154,44 +154,6 @@ static const struct nla_policy netlbl_unlabel_genl_policy[NLBL_UNLABEL_A_MAX + 1
  */
 
 /**
- * netlbl_unlhsh_free_addr4 - Frees an IPv4 address entry from the hash table
- * @entry: the entry's RCU field
- *
- * Description:
- * This function is designed to be used as a callback to the call_rcu()
- * function so that memory allocated to a hash table address entry can be
- * released safely.
- *
- */
-static void netlbl_unlhsh_free_addr4(struct rcu_head *entry)
-{
-       struct netlbl_unlhsh_addr4 *ptr;
-
-       ptr = container_of(entry, struct netlbl_unlhsh_addr4, rcu);
-       kfree(ptr);
-}
-
-#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
-/**
- * netlbl_unlhsh_free_addr6 - Frees an IPv6 address entry from the hash table
- * @entry: the entry's RCU field
- *
- * Description:
- * This function is designed to be used as a callback to the call_rcu()
- * function so that memory allocated to a hash table address entry can be
- * released safely.
- *
- */
-static void netlbl_unlhsh_free_addr6(struct rcu_head *entry)
-{
-       struct netlbl_unlhsh_addr6 *ptr;
-
-       ptr = container_of(entry, struct netlbl_unlhsh_addr6, rcu);
-       kfree(ptr);
-}
-#endif /* IPv6 */
-
-/**
  * netlbl_unlhsh_free_iface - Frees an interface entry from the hash table
  * @entry: the entry's RCU field
  *
@@ -568,7 +530,7 @@ static int netlbl_unlhsh_remove_addr4(struct net *net,
        if (entry == NULL)
                return -ENOENT;
 
-       call_rcu(&entry->rcu, netlbl_unlhsh_free_addr4);
+       kfree_rcu(entry, rcu);
        return 0;
 }
 
@@ -629,7 +591,7 @@ static int netlbl_unlhsh_remove_addr6(struct net *net,
        if (entry == NULL)
                return -ENOENT;
 
-       call_rcu(&entry->rcu, netlbl_unlhsh_free_addr6);
+       kfree_rcu(entry, rcu);
        return 0;
 }
 #endif /* IPv6 */
index c8f35b5..5fe4f3b 100644 (file)
@@ -1566,12 +1566,6 @@ netlink_kernel_release(struct sock *sk)
 }
 EXPORT_SYMBOL(netlink_kernel_release);
 
-
-static void listeners_free_rcu(struct rcu_head *head)
-{
-       kfree(container_of(head, struct listeners, rcu));
-}
-
 int __netlink_change_ngroups(struct sock *sk, unsigned int groups)
 {
        struct listeners *new, *old;
@@ -1588,7 +1582,7 @@ int __netlink_change_ngroups(struct sock *sk, unsigned int groups)
                memcpy(new->masks, old->masks, NLGRPSZ(tbl->groups));
                rcu_assign_pointer(tbl->listeners, new);
 
-               call_rcu(&old->rcu, listeners_free_rcu);
+               kfree_rcu(old, rcu);
        }
        tbl->groups = groups;
 
index 947038d..1566672 100644 (file)
@@ -162,14 +162,6 @@ int phonet_address_add(struct net_device *dev, u8 addr)
        return err;
 }
 
-static void phonet_device_rcu_free(struct rcu_head *head)
-{
-       struct phonet_device *pnd;
-
-       pnd = container_of(head, struct phonet_device, rcu);
-       kfree(pnd);
-}
-
 int phonet_address_del(struct net_device *dev, u8 addr)
 {
        struct phonet_device_list *pndevs = phonet_device_list(dev_net(dev));
@@ -188,7 +180,7 @@ int phonet_address_del(struct net_device *dev, u8 addr)
        mutex_unlock(&pndevs->lock);
 
        if (pnd)
-               call_rcu(&pnd->rcu, phonet_device_rcu_free);
+               kfree_rcu(pnd, rcu);
 
        return err;
 }
index 14b42f4..a606025 100644 (file)
 #include <net/act_api.h>
 #include <net/netlink.h>
 
-static void tcf_common_free_rcu(struct rcu_head *head)
-{
-       kfree(container_of(head, struct tcf_common, tcfc_rcu));
-}
-
 void tcf_hash_destroy(struct tcf_common *p, struct tcf_hashinfo *hinfo)
 {
        unsigned int h = tcf_hash(p->tcfc_index, hinfo->hmask);
@@ -47,7 +42,7 @@ void tcf_hash_destroy(struct tcf_common *p, struct tcf_hashinfo *hinfo)
                         * gen_estimator est_timer() might access p->tcfc_lock
                         * or bstats, wait a RCU grace period before freeing p
                         */
-                       call_rcu(&p->tcfc_rcu, tcf_common_free_rcu);
+                       kfree_rcu(p, tcfc_rcu);
                        return;
                }
        }
index 8a16307..b3b9b32 100644 (file)
@@ -96,11 +96,6 @@ nla_put_failure:
        goto done;
 }
 
-static void tcf_police_free_rcu(struct rcu_head *head)
-{
-       kfree(container_of(head, struct tcf_police, tcf_rcu));
-}
-
 static void tcf_police_destroy(struct tcf_police *p)
 {
        unsigned int h = tcf_hash(p->tcf_index, POL_TAB_MASK);
@@ -121,7 +116,7 @@ static void tcf_police_destroy(struct tcf_police *p)
                         * gen_estimator est_timer() might access p->tcf_lock
                         * or bstats, wait a RCU grace period before freeing p
                         */
-                       call_rcu(&p->tcf_rcu, tcf_police_free_rcu);
+                       kfree_rcu(p, tcf_rcu);
                        return;
                }
        }
@@ -401,7 +396,6 @@ static void __exit
 police_cleanup_module(void)
 {
        tcf_unregister_action(&act_police_ops);
-       rcu_barrier(); /* Wait for completion of call_rcu()'s (tcf_police_free_rcu) */
 }
 
 module_init(police_init_module);
index faf71d1..3c06c87 100644 (file)
@@ -219,7 +219,7 @@ int sctp_del_bind_addr(struct sctp_bind_addr *bp, union sctp_addr *del_addr)
        }
 
        if (found) {
-               call_rcu(&addr->rcu, sctp_local_addr_free);
+               kfree_rcu(addr, rcu);
                SCTP_DBG_OBJCNT_DEC(addr);
                return 0;
        }
index 865ce7b..185fe05 100644 (file)
@@ -123,7 +123,7 @@ static int sctp_inet6addr_event(struct notifier_block *this, unsigned long ev,
                }
                spin_unlock_bh(&sctp_local_addr_lock);
                if (found)
-                       call_rcu(&addr->rcu, sctp_local_addr_free);
+                       kfree_rcu(addr, rcu);
                break;
        }
 
index d5bf91d..065d999 100644 (file)
@@ -230,13 +230,6 @@ static void sctp_free_local_addr_list(void)
        }
 }
 
-void sctp_local_addr_free(struct rcu_head *head)
-{
-       struct sctp_sockaddr_entry *e = container_of(head,
-                               struct sctp_sockaddr_entry, rcu);
-       kfree(e);
-}
-
 /* Copy the local addresses which are valid for 'scope' into 'bp'.  */
 int sctp_copy_local_addr_list(struct sctp_bind_addr *bp, sctp_scope_t scope,
                              gfp_t gfp, int copy_flags)
@@ -681,7 +674,7 @@ static int sctp_inetaddr_event(struct notifier_block *this, unsigned long ev,
                }
                spin_unlock_bh(&sctp_local_addr_lock);
                if (found)
-                       call_rcu(&addr->rcu, sctp_local_addr_free);
+                       kfree_rcu(addr, rcu);
                break;
        }
 
index 310d16b..c2ed7c9 100644 (file)
@@ -263,15 +263,6 @@ static struct inode *sock_alloc_inode(struct super_block *sb)
        return &ei->vfs_inode;
 }
 
-
-
-static void wq_free_rcu(struct rcu_head *head)
-{
-       struct socket_wq *wq = container_of(head, struct socket_wq, rcu);
-
-       kfree(wq);
-}
-
 static void sock_destroy_inode(struct inode *inode)
 {
        struct socket_alloc *ei;
@@ -279,7 +270,7 @@ static void sock_destroy_inode(struct inode *inode)
 
        ei = container_of(inode, struct socket_alloc, vfs_inode);
        wq = rcu_dereference_protected(ei->socket.wq, 1);
-       call_rcu(&wq->rcu, wq_free_rcu);
+       kfree_rcu(wq, rcu);
        kmem_cache_free(sock_inode_cachep, ei);
 }
 
index 15792d8..b4d745e 100644 (file)
@@ -1406,6 +1406,7 @@ static struct dst_entry *xfrm_bundle_create(struct xfrm_policy *policy,
        struct net *net = xp_net(policy);
        unsigned long now = jiffies;
        struct net_device *dev;
+       struct xfrm_mode *inner_mode;
        struct dst_entry *dst_prev = NULL;
        struct dst_entry *dst0 = NULL;
        int i = 0;
@@ -1436,6 +1437,17 @@ static struct dst_entry *xfrm_bundle_create(struct xfrm_policy *policy,
                        goto put_states;
                }
 
+               if (xfrm[i]->sel.family == AF_UNSPEC) {
+                       inner_mode = xfrm_ip2inner_mode(xfrm[i],
+                                                       xfrm_af2proto(family));
+                       if (!inner_mode) {
+                               err = -EAFNOSUPPORT;
+                               dst_release(dst);
+                               goto put_states;
+                       }
+               } else
+                       inner_mode = xfrm[i]->inner_mode;
+
                if (!dst_prev)
                        dst0 = dst1;
                else {
@@ -1464,7 +1476,7 @@ static struct dst_entry *xfrm_bundle_create(struct xfrm_policy *policy,
                dst1->lastuse = now;
 
                dst1->input = dst_discard;
-               dst1->output = xfrm[i]->outer_mode->afinfo->output;
+               dst1->output = inner_mode->afinfo->output;
 
                dst1->next = dst_prev;
                dst_prev = dst1;
index e8a7814..47f1b86 100644 (file)
@@ -535,6 +535,9 @@ int xfrm_init_replay(struct xfrm_state *x)
                    replay_esn->bmp_len * sizeof(__u32) * 8)
                        return -EINVAL;
 
+       if ((x->props.flags & XFRM_STATE_ESN) && replay_esn->replay_window == 0)
+               return -EINVAL;
+
        if ((x->props.flags & XFRM_STATE_ESN) && x->replay_esn)
                x->repl = &xfrm_replay_esn;
        else
index cd104af..413c536 100644 (file)
@@ -420,11 +420,10 @@ static int parse_elf(struct elf_info *info, const char *filename)
                return 0;
        }
 
-       if (hdr->e_shnum == 0) {
+       if (hdr->e_shnum == SHN_UNDEF) {
                /*
                 * There are more than 64k sections,
                 * read count from .sh_size.
-                * note: it doesn't need shndx2secindex()
                 */
                info->num_sections = TO_NATIVE(sechdrs[0].sh_size);
        }
@@ -432,8 +431,7 @@ static int parse_elf(struct elf_info *info, const char *filename)
                info->num_sections = hdr->e_shnum;
        }
        if (hdr->e_shstrndx == SHN_XINDEX) {
-               info->secindex_strings =
-                   shndx2secindex(TO_NATIVE(sechdrs[0].sh_link));
+               info->secindex_strings = TO_NATIVE(sechdrs[0].sh_link);
        }
        else {
                info->secindex_strings = hdr->e_shstrndx;
@@ -489,7 +487,7 @@ static int parse_elf(struct elf_info *info, const char *filename)
                            sechdrs[i].sh_offset;
                        info->symtab_stop  = (void *)hdr +
                            sechdrs[i].sh_offset + sechdrs[i].sh_size;
-                       sh_link_idx = shndx2secindex(sechdrs[i].sh_link);
+                       sh_link_idx = sechdrs[i].sh_link;
                        info->strtab       = (void *)hdr +
                            sechdrs[sh_link_idx].sh_offset;
                }
@@ -516,11 +514,9 @@ static int parse_elf(struct elf_info *info, const char *filename)
 
        if (symtab_shndx_idx != ~0U) {
                Elf32_Word *p;
-               if (symtab_idx !=
-                   shndx2secindex(sechdrs[symtab_shndx_idx].sh_link))
+               if (symtab_idx != sechdrs[symtab_shndx_idx].sh_link)
                        fatal("%s: SYMTAB_SHNDX has bad sh_link: %u!=%u\n",
-                             filename,
-                             shndx2secindex(sechdrs[symtab_shndx_idx].sh_link),
+                             filename, sechdrs[symtab_shndx_idx].sh_link,
                              symtab_idx);
                /* Fix endianness */
                for (p = info->symtab_shndx_start; p < info->symtab_shndx_stop;
@@ -1446,7 +1442,7 @@ static unsigned int *reloc_location(struct elf_info *elf,
                                    Elf_Shdr *sechdr, Elf_Rela *r)
 {
        Elf_Shdr *sechdrs = elf->sechdrs;
-       int section = shndx2secindex(sechdr->sh_info);
+       int section = sechdr->sh_info;
 
        return (void *)elf->hdr + sechdrs[section].sh_offset +
                r->r_offset;
index 0388cfc..2031119 100644 (file)
@@ -145,33 +145,22 @@ static inline int is_shndx_special(unsigned int i)
        return i != SHN_XINDEX && i >= SHN_LORESERVE && i <= SHN_HIRESERVE;
 }
 
-/* shndx is in [0..SHN_LORESERVE) U (SHN_HIRESERVE, 0xfffffff], thus:
- * shndx == 0               <=> sechdrs[0]
- * ......
- * shndx == SHN_LORESERVE-1 <=> sechdrs[SHN_LORESERVE-1]
- * shndx == SHN_HIRESERVE+1 <=> sechdrs[SHN_LORESERVE]
- * shndx == SHN_HIRESERVE+2 <=> sechdrs[SHN_LORESERVE+1]
- * ......
- * fyi: sym->st_shndx is uint16, SHN_LORESERVE = ff00, SHN_HIRESERVE = ffff,
- * so basically we map  0000..feff -> 0000..feff
- *                      ff00..ffff -> (you are a bad boy, dont do it)
- *                     10000..xxxx -> ff00..(xxxx-0x100)
+/*
+ * Move reserved section indices SHN_LORESERVE..SHN_HIRESERVE out of
+ * the way to -256..-1, to avoid conflicting with real section
+ * indices.
  */
-static inline unsigned int shndx2secindex(unsigned int i)
-{
-       if (i <= SHN_HIRESERVE)
-               return i;
-       return i - (SHN_HIRESERVE + 1 - SHN_LORESERVE);
-}
+#define SPECIAL(i) ((i) - (SHN_HIRESERVE + 1))
 
 /* Accessor for sym->st_shndx, hides ugliness of "64k sections" */
 static inline unsigned int get_secindex(const struct elf_info *info,
                                        const Elf_Sym *sym)
 {
+       if (is_shndx_special(sym->st_shndx))
+               return SPECIAL(sym->st_shndx);
        if (sym->st_shndx != SHN_XINDEX)
                return sym->st_shndx;
-       return shndx2secindex(info->symtab_shndx_start[sym -
-                                                      info->symtab_start]);
+       return info->symtab_shndx_start[sym - info->symtab_start];
 }
 
 /* file2alias.c */
index 47a1f9a..0865b3e 100644 (file)
@@ -5,4 +5,15 @@
  */
 SECTIONS {
        /DISCARD/ : { *(.discard) }
+
+       __ksymtab               : { *(SORT(___ksymtab+*)) }
+       __ksymtab_gpl           : { *(SORT(___ksymtab_gpl+*)) }
+       __ksymtab_unused        : { *(SORT(___ksymtab_unused+*)) }
+       __ksymtab_unused_gpl    : { *(SORT(___ksymtab_unused_gpl+*)) }
+       __ksymtab_gpl_future    : { *(SORT(___ksymtab_gpl_future+*)) }
+       __kcrctab               : { *(SORT(___kcrctab+*)) }
+       __kcrctab_gpl           : { *(SORT(___kcrctab_gpl+*)) }
+       __kcrctab_unused        : { *(SORT(___kcrctab_unused+*)) }
+       __kcrctab_unused_gpl    : { *(SORT(___kcrctab_unused_gpl+*)) }
+       __kcrctab_gpl_future    : { *(SORT(___kcrctab_gpl_future+*)) }
 }
index c6ca866..f66baf4 100644 (file)
@@ -69,18 +69,6 @@ error:
 EXPORT_SYMBOL_GPL(user_instantiate);
 
 /*
- * dispose of the old data from an updated user defined key
- */
-static void user_update_rcu_disposal(struct rcu_head *rcu)
-{
-       struct user_key_payload *upayload;
-
-       upayload = container_of(rcu, struct user_key_payload, rcu);
-
-       kfree(upayload);
-}
-
-/*
  * update a user defined key
  * - the key's semaphore is write-locked
  */
@@ -114,7 +102,7 @@ int user_update(struct key *key, const void *data, size_t datalen)
                key->expiry = 0;
        }
 
-       call_rcu(&zap->rcu, user_update_rcu_disposal);
+       kfree_rcu(zap, rcu);
 
 error:
        return ret;
@@ -145,7 +133,7 @@ void user_revoke(struct key *key)
 
        if (upayload) {
                rcu_assign_pointer(key->payload.data, NULL);
-               call_rcu(&upayload->rcu, user_update_rcu_disposal);
+               kfree_rcu(upayload, rcu);
        }
 }
 
index 1d027e2..3d2715f 100644 (file)
 #define AVC_CACHE_RECLAIM              16
 
 #ifdef CONFIG_SECURITY_SELINUX_AVC_STATS
-#define avc_cache_stats_incr(field)                            \
-do {                                                           \
-       per_cpu(avc_cache_stats, get_cpu()).field++;            \
-       put_cpu();                                              \
-} while (0)
+#define avc_cache_stats_incr(field)    this_cpu_inc(avc_cache_stats.field)
 #else
 #define avc_cache_stats_incr(field)    do {} while (0)
 #endif
@@ -347,11 +343,10 @@ static struct avc_node *avc_lookup(u32 ssid, u32 tsid, u16 tclass)
        node = avc_search_node(ssid, tsid, tclass);
 
        if (node)
-               avc_cache_stats_incr(hits);
-       else
-               avc_cache_stats_incr(misses);
+               return node;
 
-       return node;
+       avc_cache_stats_incr(misses);
+       return NULL;
 }
 
 static int avc_latest_notif_update(int seqno, int is_insert)
@@ -769,7 +764,7 @@ int avc_has_perm_noaudit(u32 ssid, u32 tsid,
        rcu_read_lock();
 
        node = avc_lookup(ssid, tsid, tclass);
-       if (!node) {
+       if (unlikely(!node)) {
                rcu_read_unlock();
 
                if (in_avd)
index e77b2ac..47fda96 100644 (file)
@@ -41,7 +41,6 @@ struct sk_buff;
  */
 struct avc_cache_stats {
        unsigned int lookups;
-       unsigned int hits;
        unsigned int misses;
        unsigned int allocations;
        unsigned int reclaims;
index d6095d6..58cc481 100644 (file)
@@ -104,22 +104,6 @@ static int sel_netif_insert(struct sel_netif *netif)
 }
 
 /**
- * sel_netif_free - Frees an interface entry
- * @p: the entry's RCU field
- *
- * Description:
- * This function is designed to be used as a callback to the call_rcu()
- * function so that memory allocated to a hash table interface entry can be
- * released safely.
- *
- */
-static void sel_netif_free(struct rcu_head *p)
-{
-       struct sel_netif *netif = container_of(p, struct sel_netif, rcu_head);
-       kfree(netif);
-}
-
-/**
  * sel_netif_destroy - Remove an interface record from the table
  * @netif: the existing interface record
  *
@@ -131,7 +115,7 @@ static void sel_netif_destroy(struct sel_netif *netif)
 {
        list_del_rcu(&netif->list);
        sel_netif_total--;
-       call_rcu(&netif->rcu_head, sel_netif_free);
+       kfree_rcu(netif, rcu_head);
 }
 
 /**
index ea39cb7..c0e1a0f 100644 (file)
@@ -1380,10 +1380,14 @@ static int sel_avc_stats_seq_show(struct seq_file *seq, void *v)
        if (v == SEQ_START_TOKEN)
                seq_printf(seq, "lookups hits misses allocations reclaims "
                           "frees\n");
-       else
-               seq_printf(seq, "%u %u %u %u %u %u\n", st->lookups,
-                          st->hits, st->misses, st->allocations,
+       else {
+               unsigned int lookups = st->lookups;
+               unsigned int misses = st->misses;
+               unsigned int hits = lookups - misses;
+               seq_printf(seq, "%u %u %u %u %u %u\n", lookups,
+                          hits, misses, st->allocations,
                           st->reclaims, st->frees);
+       }
        return 0;
 }
 
index e6e7ce0..7102457 100644 (file)
@@ -1819,8 +1819,6 @@ static int filename_trans_read(struct policydb *p, void *fp)
                goto out;
        nel = le32_to_cpu(buf[0]);
 
-       printk(KERN_ERR "%s: nel=%d\n", __func__, nel);
-
        last = p->filename_trans;
        while (last && last->next)
                last = last->next;
@@ -1857,8 +1855,6 @@ static int filename_trans_read(struct policydb *p, void *fp)
                        goto out;
                name[len] = 0;
 
-               printk(KERN_ERR "%s: ft=%p ft->name=%p ft->name=%s\n", __func__, ft, ft->name, ft->name);
-
                rc = next_entry(buf, fp, sizeof(u32) * 4);
                if (rc)
                        goto out;
index 2727bef..b04d280 100644 (file)
@@ -139,7 +139,7 @@ SOC_DOUBLE_R("Capture Volume", SSM2602_LINVOL, SSM2602_RINVOL, 0, 31, 0),
 SOC_DOUBLE_R("Capture Switch", SSM2602_LINVOL, SSM2602_RINVOL, 7, 1, 1),
 
 SOC_SINGLE("Mic Boost (+20dB)", SSM2602_APANA, 0, 1, 0),
-SOC_SINGLE("Mic Boost2 (+20dB)", SSM2602_APANA, 7, 1, 0),
+SOC_SINGLE("Mic Boost2 (+20dB)", SSM2602_APANA, 8, 1, 0),
 SOC_SINGLE("Mic Switch", SSM2602_APANA, 1, 1, 1),
 
 SOC_SINGLE("Sidetone Playback Volume", SSM2602_APANA, 6, 3, 1),
@@ -602,7 +602,7 @@ static struct snd_soc_codec_driver soc_codec_dev_ssm2602 = {
        .read = ssm2602_read_reg_cache,
        .write = ssm2602_write,
        .set_bias_level = ssm2602_set_bias_level,
-       .reg_cache_size = sizeof(ssm2602_reg),
+       .reg_cache_size = ARRAY_SIZE(ssm2602_reg),
        .reg_word_size = sizeof(u16),
        .reg_cache_default = ssm2602_reg,
 };
@@ -614,7 +614,7 @@ static struct snd_soc_codec_driver soc_codec_dev_ssm2602 = {
  *    low  = 0x1a
  *    high = 0x1b
  */
-static int ssm2602_i2c_probe(struct i2c_client *i2c,
+static int __devinit ssm2602_i2c_probe(struct i2c_client *i2c,
                             const struct i2c_device_id *id)
 {
        struct ssm2602_priv *ssm2602;
@@ -635,7 +635,7 @@ static int ssm2602_i2c_probe(struct i2c_client *i2c,
        return ret;
 }
 
-static int ssm2602_i2c_remove(struct i2c_client *client)
+static int __devexit ssm2602_i2c_remove(struct i2c_client *client)
 {
        snd_soc_unregister_codec(&client->dev);
        kfree(i2c_get_clientdata(client));
@@ -655,7 +655,7 @@ static struct i2c_driver ssm2602_i2c_driver = {
                .owner = THIS_MODULE,
        },
        .probe = ssm2602_i2c_probe,
-       .remove = ssm2602_i2c_remove,
+       .remove = __devexit_p(ssm2602_i2c_remove),
        .id_table = ssm2602_i2c_id,
 };
 #endif
index 48ffd40..a7b8f30 100644 (file)
@@ -601,9 +601,7 @@ static struct snd_soc_codec_driver soc_codec_dev_uda134x = {
        .reg_cache_step = 1,
        .read = uda134x_read_reg_cache,
        .write = uda134x_write,
-#ifdef POWER_OFF_ON_STANDBY
        .set_bias_level = uda134x_set_bias_level,
-#endif
 };
 
 static int __devinit uda134x_codec_probe(struct platform_device *pdev)
index f52b623..824d1c8 100644 (file)
@@ -692,7 +692,7 @@ SOC_ENUM("DRC Smoothing Threshold", drc_smoothing),
 SOC_SINGLE_TLV("DRC Startup Volume", WM8903_DRC_0, 6, 18, 0, drc_tlv_startup),
 
 SOC_DOUBLE_R_TLV("Digital Capture Volume", WM8903_ADC_DIGITAL_VOLUME_LEFT,
-                WM8903_ADC_DIGITAL_VOLUME_RIGHT, 1, 96, 0, digital_tlv),
+                WM8903_ADC_DIGITAL_VOLUME_RIGHT, 1, 120, 0, digital_tlv),
 SOC_ENUM("ADC Companding Mode", adc_companding),
 SOC_SINGLE("ADC Companding Switch", WM8903_AUDIO_INTERFACE_0, 3, 1, 0),
 
index 419bf4f..cd22a54 100644 (file)
@@ -133,7 +133,7 @@ static void jz4740_i2s_shutdown(struct snd_pcm_substream *substream,
        struct jz4740_i2s *i2s = snd_soc_dai_get_drvdata(dai);
        uint32_t conf;
 
-       if (!dai->active)
+       if (dai->active)
                return;
 
        conf = jz4740_i2s_read(i2s, JZ_REG_AIC_CONF);
index d567c32..6b1f9d3 100644 (file)
@@ -376,6 +376,11 @@ static int sst_platform_pcm_hw_params(struct snd_pcm_substream *substream,
        return 0;
 }
 
+static int sst_platform_pcm_hw_free(struct snd_pcm_substream *substream)
+{
+       return snd_pcm_lib_free_pages(substream);
+}
+
 static struct snd_pcm_ops sst_platform_ops = {
        .open = sst_platform_open,
        .close = sst_platform_close,
@@ -384,6 +389,7 @@ static struct snd_pcm_ops sst_platform_ops = {
        .trigger = sst_platform_pcm_trigger,
        .pointer = sst_platform_pcm_pointer,
        .hw_params = sst_platform_pcm_hw_params,
+       .hw_free = sst_platform_pcm_hw_free,
 };
 
 static void sst_pcm_free(struct snd_pcm *pcm)
index d8562ce..dd55d10 100644 (file)
@@ -3291,6 +3291,8 @@ int snd_soc_register_card(struct snd_soc_card *card)
        if (!card->name || !card->dev)
                return -EINVAL;
 
+       dev_set_drvdata(card->dev, card);
+
        snd_soc_initialize_card_lists(card);
 
        soc_init_card_debugfs(card);
index 5bb41e5..3152cca 100644 (file)
@@ -63,7 +63,6 @@ The format file for the sched_wakep event defines the following fields
         field:unsigned char common_flags;
         field:unsigned char common_preempt_count;
         field:int common_pid;
-        field:int common_lock_depth;
 
         field:char comm[TASK_COMM_LEN];
         field:pid_t pid;
index 36b3827..4710220 100644 (file)
@@ -463,7 +463,6 @@ The format file for the sched_wakep event defines the following fields
         field:unsigned char common_flags;
         field:unsigned char common_preempt_count;
         field:int common_pid;
-        field:int common_lock_depth;
 
         field:char comm[TASK_COMM_LEN];
         field:pid_t pid;
index 4165382..0974f95 100644 (file)
@@ -427,7 +427,7 @@ static void mmap_read_all(void)
 {
        int i;
 
-       for (i = 0; i < evsel_list->cpus->nr; i++) {
+       for (i = 0; i < evsel_list->nr_mmaps; i++) {
                if (evsel_list->mmap[i].base)
                        mmap_read(&evsel_list->mmap[i]);
        }
index 1fa9f58..b671862 100644 (file)
@@ -550,7 +550,7 @@ static int test__basic_mmap(void)
                        ++foo;
                }
 
-       while ((event = perf_evlist__read_on_cpu(evlist, 0)) != NULL) {
+       while ((event = perf_evlist__mmap_read(evlist, 0)) != NULL) {
                struct perf_sample sample;
 
                if (event->header.type != PERF_RECORD_SAMPLE) {
index 74f533c..2d7934e 100644 (file)
@@ -801,13 +801,13 @@ static void perf_event__process_sample(const union perf_event *event,
        }
 }
 
-static void perf_session__mmap_read_cpu(struct perf_session *self, int cpu)
+static void perf_session__mmap_read_idx(struct perf_session *self, int idx)
 {
        struct perf_sample sample;
        union perf_event *event;
        int ret;
 
-       while ((event = perf_evlist__read_on_cpu(top.evlist, cpu)) != NULL) {
+       while ((event = perf_evlist__mmap_read(top.evlist, idx)) != NULL) {
                ret = perf_session__parse_sample(self, event, &sample);
                if (ret) {
                        pr_err("Can't parse sample, err = %d\n", ret);
@@ -825,8 +825,8 @@ static void perf_session__mmap_read(struct perf_session *self)
 {
        int i;
 
-       for (i = 0; i < top.evlist->cpus->nr; i++)
-               perf_session__mmap_read_cpu(self, i);
+       for (i = 0; i < top.evlist->nr_mmaps; i++)
+               perf_session__mmap_read_idx(self, i);
 }
 
 static void start_counters(struct perf_evlist *evlist)
index 98cb1f3..50aa348 100644 (file)
@@ -166,11 +166,11 @@ struct perf_evsel *perf_evlist__id2evsel(struct perf_evlist *evlist, u64 id)
        return NULL;
 }
 
-union perf_event *perf_evlist__read_on_cpu(struct perf_evlist *evlist, int cpu)
+union perf_event *perf_evlist__mmap_read(struct perf_evlist *evlist, int idx)
 {
        /* XXX Move this to perf.c, making it generally available */
        unsigned int page_size = sysconf(_SC_PAGE_SIZE);
-       struct perf_mmap *md = &evlist->mmap[cpu];
+       struct perf_mmap *md = &evlist->mmap[idx];
        unsigned int head = perf_mmap__read_head(md);
        unsigned int old = md->prev;
        unsigned char *data = md->base + page_size;
@@ -235,31 +235,37 @@ union perf_event *perf_evlist__read_on_cpu(struct perf_evlist *evlist, int cpu)
 
 void perf_evlist__munmap(struct perf_evlist *evlist)
 {
-       int cpu;
+       int i;
 
-       for (cpu = 0; cpu < evlist->cpus->nr; cpu++) {
-               if (evlist->mmap[cpu].base != NULL) {
-                       munmap(evlist->mmap[cpu].base, evlist->mmap_len);
-                       evlist->mmap[cpu].base = NULL;
+       for (i = 0; i < evlist->nr_mmaps; i++) {
+               if (evlist->mmap[i].base != NULL) {
+                       munmap(evlist->mmap[i].base, evlist->mmap_len);
+                       evlist->mmap[i].base = NULL;
                }
        }
+
+       free(evlist->mmap);
+       evlist->mmap = NULL;
 }
 
 int perf_evlist__alloc_mmap(struct perf_evlist *evlist)
 {
-       evlist->mmap = zalloc(evlist->cpus->nr * sizeof(struct perf_mmap));
+       evlist->nr_mmaps = evlist->cpus->nr;
+       if (evlist->cpus->map[0] == -1)
+               evlist->nr_mmaps = evlist->threads->nr;
+       evlist->mmap = zalloc(evlist->nr_mmaps * sizeof(struct perf_mmap));
        return evlist->mmap != NULL ? 0 : -ENOMEM;
 }
 
 static int __perf_evlist__mmap(struct perf_evlist *evlist, struct perf_evsel *evsel,
-                              int cpu, int prot, int mask, int fd)
+                              int idx, int prot, int mask, int fd)
 {
-       evlist->mmap[cpu].prev = 0;
-       evlist->mmap[cpu].mask = mask;
-       evlist->mmap[cpu].base = mmap(NULL, evlist->mmap_len, prot,
+       evlist->mmap[idx].prev = 0;
+       evlist->mmap[idx].mask = mask;
+       evlist->mmap[idx].base = mmap(NULL, evlist->mmap_len, prot,
                                      MAP_SHARED, fd, 0);
-       if (evlist->mmap[cpu].base == MAP_FAILED) {
-               if (evlist->cpus->map[cpu] == -1 && evsel->attr.inherit)
+       if (evlist->mmap[idx].base == MAP_FAILED) {
+               if (evlist->cpus->map[idx] == -1 && evsel->attr.inherit)
                        ui__warning("Inherit is not allowed on per-task "
                                    "events using mmap.\n");
                return -1;
@@ -269,6 +275,86 @@ static int __perf_evlist__mmap(struct perf_evlist *evlist, struct perf_evsel *ev
        return 0;
 }
 
+static int perf_evlist__mmap_per_cpu(struct perf_evlist *evlist, int prot, int mask)
+{
+       struct perf_evsel *evsel;
+       int cpu, thread;
+
+       for (cpu = 0; cpu < evlist->cpus->nr; cpu++) {
+               int output = -1;
+
+               for (thread = 0; thread < evlist->threads->nr; thread++) {
+                       list_for_each_entry(evsel, &evlist->entries, node) {
+                               int fd = FD(evsel, cpu, thread);
+
+                               if (output == -1) {
+                                       output = fd;
+                                       if (__perf_evlist__mmap(evlist, evsel, cpu,
+                                                               prot, mask, output) < 0)
+                                               goto out_unmap;
+                               } else {
+                                       if (ioctl(fd, PERF_EVENT_IOC_SET_OUTPUT, output) != 0)
+                                               goto out_unmap;
+                               }
+
+                               if ((evsel->attr.read_format & PERF_FORMAT_ID) &&
+                                   perf_evlist__id_add_fd(evlist, evsel, cpu, thread, fd) < 0)
+                                       goto out_unmap;
+                       }
+               }
+       }
+
+       return 0;
+
+out_unmap:
+       for (cpu = 0; cpu < evlist->cpus->nr; cpu++) {
+               if (evlist->mmap[cpu].base != NULL) {
+                       munmap(evlist->mmap[cpu].base, evlist->mmap_len);
+                       evlist->mmap[cpu].base = NULL;
+               }
+       }
+       return -1;
+}
+
+static int perf_evlist__mmap_per_thread(struct perf_evlist *evlist, int prot, int mask)
+{
+       struct perf_evsel *evsel;
+       int thread;
+
+       for (thread = 0; thread < evlist->threads->nr; thread++) {
+               int output = -1;
+
+               list_for_each_entry(evsel, &evlist->entries, node) {
+                       int fd = FD(evsel, 0, thread);
+
+                       if (output == -1) {
+                               output = fd;
+                               if (__perf_evlist__mmap(evlist, evsel, thread,
+                                                       prot, mask, output) < 0)
+                                       goto out_unmap;
+                       } else {
+                               if (ioctl(fd, PERF_EVENT_IOC_SET_OUTPUT, output) != 0)
+                                       goto out_unmap;
+                       }
+
+                       if ((evsel->attr.read_format & PERF_FORMAT_ID) &&
+                           perf_evlist__id_add_fd(evlist, evsel, 0, thread, fd) < 0)
+                               goto out_unmap;
+               }
+       }
+
+       return 0;
+
+out_unmap:
+       for (thread = 0; thread < evlist->threads->nr; thread++) {
+               if (evlist->mmap[thread].base != NULL) {
+                       munmap(evlist->mmap[thread].base, evlist->mmap_len);
+                       evlist->mmap[thread].base = NULL;
+               }
+       }
+       return -1;
+}
+
 /** perf_evlist__mmap - Create per cpu maps to receive events
  *
  * @evlist - list of events
@@ -287,11 +373,11 @@ static int __perf_evlist__mmap(struct perf_evlist *evlist, struct perf_evsel *ev
 int perf_evlist__mmap(struct perf_evlist *evlist, int pages, bool overwrite)
 {
        unsigned int page_size = sysconf(_SC_PAGE_SIZE);
-       int mask = pages * page_size - 1, cpu;
-       struct perf_evsel *first_evsel, *evsel;
+       int mask = pages * page_size - 1;
+       struct perf_evsel *evsel;
        const struct cpu_map *cpus = evlist->cpus;
        const struct thread_map *threads = evlist->threads;
-       int thread, prot = PROT_READ | (overwrite ? 0 : PROT_WRITE);
+       int prot = PROT_READ | (overwrite ? 0 : PROT_WRITE);
 
        if (evlist->mmap == NULL && perf_evlist__alloc_mmap(evlist) < 0)
                return -ENOMEM;
@@ -301,43 +387,18 @@ int perf_evlist__mmap(struct perf_evlist *evlist, int pages, bool overwrite)
 
        evlist->overwrite = overwrite;
        evlist->mmap_len = (pages + 1) * page_size;
-       first_evsel = list_entry(evlist->entries.next, struct perf_evsel, node);
 
        list_for_each_entry(evsel, &evlist->entries, node) {
                if ((evsel->attr.read_format & PERF_FORMAT_ID) &&
                    evsel->sample_id == NULL &&
                    perf_evsel__alloc_id(evsel, cpus->nr, threads->nr) < 0)
                        return -ENOMEM;
-
-               for (cpu = 0; cpu < cpus->nr; cpu++) {
-                       for (thread = 0; thread < threads->nr; thread++) {
-                               int fd = FD(evsel, cpu, thread);
-
-                               if (evsel->idx || thread) {
-                                       if (ioctl(fd, PERF_EVENT_IOC_SET_OUTPUT,
-                                                 FD(first_evsel, cpu, 0)) != 0)
-                                               goto out_unmap;
-                               } else if (__perf_evlist__mmap(evlist, evsel, cpu,
-                                                              prot, mask, fd) < 0)
-                                       goto out_unmap;
-
-                               if ((evsel->attr.read_format & PERF_FORMAT_ID) &&
-                                   perf_evlist__id_add_fd(evlist, evsel, cpu, thread, fd) < 0)
-                                       goto out_unmap;
-                       }
-               }
        }
 
-       return 0;
+       if (evlist->cpus->map[0] == -1)
+               return perf_evlist__mmap_per_thread(evlist, prot, mask);
 
-out_unmap:
-       for (cpu = 0; cpu < cpus->nr; cpu++) {
-               if (evlist->mmap[cpu].base != NULL) {
-                       munmap(evlist->mmap[cpu].base, evlist->mmap_len);
-                       evlist->mmap[cpu].base = NULL;
-               }
-       }
-       return -1;
+       return perf_evlist__mmap_per_cpu(evlist, prot, mask);
 }
 
 int perf_evlist__create_maps(struct perf_evlist *evlist, pid_t target_pid,
@@ -348,7 +409,7 @@ int perf_evlist__create_maps(struct perf_evlist *evlist, pid_t target_pid,
        if (evlist->threads == NULL)
                return -1;
 
-       if (target_tid != -1)
+       if (cpu_list == NULL && target_tid != -1)
                evlist->cpus = cpu_map__dummy_new();
        else
                evlist->cpus = cpu_map__new(cpu_list);
index a8556b6..0a1ef1f 100644 (file)
@@ -17,6 +17,7 @@ struct perf_evlist {
        struct hlist_head heads[PERF_EVLIST__HLIST_SIZE];
        int              nr_entries;
        int              nr_fds;
+       int              nr_mmaps;
        int              mmap_len;
        bool             overwrite;
        union perf_event event_copy;
@@ -46,7 +47,7 @@ void perf_evlist__add_pollfd(struct perf_evlist *evlist, int fd);
 
 struct perf_evsel *perf_evlist__id2evsel(struct perf_evlist *evlist, u64 id);
 
-union perf_event *perf_evlist__read_on_cpu(struct perf_evlist *self, int cpu);
+union perf_event *perf_evlist__mmap_read(struct perf_evlist *self, int idx);
 
 int perf_evlist__alloc_mmap(struct perf_evlist *evlist);
 int perf_evlist__mmap(struct perf_evlist *evlist, int pages, bool overwrite);
index 356c7e4..ed33609 100644 (file)
@@ -1,4 +1,6 @@
 #include <linux/kernel.h>
+#include <linux/prefetch.h>
+
 #include "../../../../include/linux/list.h"
 
 #ifndef PERF_LIST_H
index 3344d6e..69436b3 100644 (file)
@@ -681,7 +681,7 @@ static PyObject *pyrf_evlist__read_on_cpu(struct pyrf_evlist *pevlist,
                                         &cpu, &sample_id_all))
                return NULL;
 
-       event = perf_evlist__read_on_cpu(evlist, cpu);
+       event = perf_evlist__mmap_read(evlist, cpu);
        if (event != NULL) {
                struct perf_evsel *first;
                PyObject *pyevent = pyrf_event__new(event);
index 0a7ed5b..1e88485 100644 (file)
@@ -2187,7 +2187,6 @@ static const struct flag flags[] = {
        { "TASKLET_SOFTIRQ", 6 },
        { "SCHED_SOFTIRQ", 7 },
        { "HRTIMER_SOFTIRQ", 8 },
-       { "RCU_SOFTIRQ", 9 },
 
        { "HRTIMER_NORESTART", 0 },
        { "HRTIMER_RESTART", 1 },